88d8069f8e
Gelände mit Grabregeln, Kacheln mit Schaden und eine rechteckige Karte, die sich kodieren lässt und unmögliche Eingaben ablehnt. Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com>
133 lines
3.8 KiB
Rust
133 lines
3.8 KiB
Rust
use grovewright_core::codec::{DecodeError, Reader, Writer};
|
|
use grovewright_core::map::{Map, Pos, Terrain, Tile};
|
|
|
|
#[test]
|
|
fn a_filled_map_has_the_requested_size_and_terrain() {
|
|
let map = Map::filled(4, 3, Terrain::SoftRock);
|
|
assert_eq!(map.width(), 4);
|
|
assert_eq!(map.height(), 3);
|
|
assert_eq!(map.tiles().len(), 12);
|
|
assert_eq!(map.get(Pos::new(3, 2)), Some(Tile::new(Terrain::SoftRock)));
|
|
}
|
|
|
|
#[test]
|
|
fn positions_outside_the_map_are_rejected() {
|
|
let mut map = Map::filled(4, 3, Terrain::Ground);
|
|
for pos in [
|
|
Pos::new(-1, 0),
|
|
Pos::new(0, -1),
|
|
Pos::new(4, 0),
|
|
Pos::new(0, 3),
|
|
] {
|
|
assert!(!map.in_bounds(pos), "{pos:?}");
|
|
assert_eq!(map.get(pos), None, "{pos:?}");
|
|
assert!(!map.set(pos, Tile::new(Terrain::Bedrock)), "{pos:?}");
|
|
}
|
|
assert!(map.in_bounds(Pos::new(3, 2)));
|
|
}
|
|
|
|
#[test]
|
|
fn set_changes_exactly_one_tile() {
|
|
let mut map = Map::filled(4, 3, Terrain::Ground);
|
|
assert!(map.set(Pos::new(1, 2), Tile::new(Terrain::HardRock)));
|
|
let hard_rock = map
|
|
.tiles()
|
|
.iter()
|
|
.filter(|tile| tile.terrain == Terrain::HardRock)
|
|
.count();
|
|
assert_eq!(hard_rock, 1);
|
|
assert_eq!(map.tiles()[2 * 4 + 1].terrain, Terrain::HardRock);
|
|
}
|
|
|
|
#[test]
|
|
fn only_rock_can_be_dug() {
|
|
assert_eq!(Terrain::Ground.hits_to_break(), None);
|
|
assert_eq!(Terrain::Bedrock.hits_to_break(), None);
|
|
assert_eq!(Terrain::SoftRock.hits_to_break(), Some(3));
|
|
assert_eq!(Terrain::HardRock.hits_to_break(), Some(6));
|
|
assert_eq!(Terrain::Ground.required_tool_tier(), None);
|
|
assert_eq!(Terrain::Bedrock.required_tool_tier(), None);
|
|
assert_eq!(Terrain::SoftRock.required_tool_tier(), Some(1));
|
|
assert_eq!(Terrain::HardRock.required_tool_tier(), Some(2));
|
|
}
|
|
|
|
#[test]
|
|
fn only_ground_can_be_walked_on() {
|
|
assert!(Terrain::Ground.is_walkable());
|
|
assert!(!Terrain::SoftRock.is_walkable());
|
|
assert!(!Terrain::HardRock.is_walkable());
|
|
assert!(!Terrain::Bedrock.is_walkable());
|
|
}
|
|
|
|
#[test]
|
|
fn terrain_numbers_are_stable() {
|
|
for terrain in [
|
|
Terrain::Ground,
|
|
Terrain::SoftRock,
|
|
Terrain::HardRock,
|
|
Terrain::Bedrock,
|
|
] {
|
|
assert_eq!(Terrain::from_u8(terrain as u8), Some(terrain));
|
|
}
|
|
assert_eq!(Terrain::from_u8(4), None);
|
|
}
|
|
|
|
#[test]
|
|
fn a_map_survives_encoding() {
|
|
let mut map = Map::filled(5, 4, Terrain::Ground);
|
|
map.set(
|
|
Pos::new(2, 1),
|
|
Tile {
|
|
terrain: Terrain::SoftRock,
|
|
damage: 2,
|
|
},
|
|
);
|
|
let mut w = Writer::new();
|
|
map.encode(&mut w);
|
|
let bytes = w.into_bytes();
|
|
let mut r = Reader::new(&bytes);
|
|
assert_eq!(Map::decode(&mut r), Ok(map));
|
|
assert_eq!(r.finish(), Ok(()));
|
|
}
|
|
|
|
fn encoded_map(width: u32, height: u32, tiles: &[(u8, u8)]) -> Vec<u8> {
|
|
let mut w = Writer::new();
|
|
w.u32(width);
|
|
w.u32(height);
|
|
for (terrain, damage) in tiles {
|
|
w.u8(*terrain);
|
|
w.u8(*damage);
|
|
}
|
|
w.into_bytes()
|
|
}
|
|
|
|
#[test]
|
|
fn decoding_rejects_impossible_maps() {
|
|
let cases: [(Vec<u8>, DecodeError); 6] = [
|
|
(
|
|
encoded_map(0, 4, &[]),
|
|
DecodeError::InvalidValue("map size"),
|
|
),
|
|
(
|
|
encoded_map(2_000, 4, &[]),
|
|
DecodeError::InvalidValue("map size"),
|
|
),
|
|
(
|
|
encoded_map(1, 1, &[(9, 0)]),
|
|
DecodeError::InvalidValue("terrain"),
|
|
),
|
|
(
|
|
encoded_map(1, 1, &[(0, 1)]),
|
|
DecodeError::InvalidValue("tile damage"),
|
|
),
|
|
(
|
|
encoded_map(1, 1, &[(1, 3)]),
|
|
DecodeError::InvalidValue("tile damage"),
|
|
),
|
|
(encoded_map(2, 2, &[(0, 0)]), DecodeError::UnexpectedEnd),
|
|
];
|
|
for (bytes, expected) in cases {
|
|
assert_eq!(Map::decode(&mut Reader::new(&bytes)), Err(expected));
|
|
}
|
|
}
|