diff --git a/examples/the-dungeon-puzzlers-lament/build.rs b/examples/the-dungeon-puzzlers-lament/build.rs index 805a7839..7a41a96a 100644 --- a/examples/the-dungeon-puzzlers-lament/build.rs +++ b/examples/the-dungeon-puzzlers-lament/build.rs @@ -5,6 +5,7 @@ use std::{ io::{BufWriter, Write}, str::FromStr, }; +use tiled::{Map, ObjectLayer, TileLayer}; use proc_macro2::TokenStream; @@ -259,6 +260,7 @@ impl quote::ToTokens for EntityWithPosition { struct Level { starting_items: Vec, fixed_positions: Vec, + solution_positions: Vec, directions: Vec, wall_bitmap: Vec, name: String, @@ -268,6 +270,7 @@ impl quote::ToTokens for Level { fn to_tokens(&self, tokens: &mut TokenStream) { let wall_bitmap = &self.wall_bitmap; let fixed_positions = &self.fixed_positions; + let solution_positions = &self.solution_positions; let directions = &self.directions; let starting_items = &self.starting_items; let name = &self.name; @@ -276,6 +279,7 @@ impl quote::ToTokens for Level { Level::new( Map::new(11, 10, &[#(#wall_bitmap),*]), &[#(#fixed_positions),*], + &[#(#solution_positions),*], &[#(#directions),*], &[#(#starting_items),*], #name, @@ -284,10 +288,10 @@ impl quote::ToTokens for Level { } } -fn export_level(map: &tiled::Map) -> Level { - let objects = map.get_layer(1).unwrap().as_object_layer().unwrap(); - - let fixed_positions = objects.objects().map(|obj| { +fn extract_objects_from_layer( + objects: ObjectLayer<'_>, +) -> impl Iterator + '_ { + objects.objects().map(|obj| { let entity: Entity = obj .name .parse() @@ -297,7 +301,20 @@ fn export_level(map: &tiled::Map) -> Level { let y = (obj.y / 16.0) as i32; EntityWithPosition(entity, (x, y)) - }); + }) +} + +fn export_level(map: &tiled::Map) -> Level { + let objects = map + .get_object_layer("Puzzle") + .expect("The puzzle object layer should exist"); + + let fixed_positions = extract_objects_from_layer(objects); + + let solution_positions = extract_objects_from_layer( + map.get_object_layer("Solution") + .expect("Should have an object layer called 'Solution'"), + ); let Some(tiled::PropertyValue::StringValue(starting_items)) = map.properties.get("ITEMS") else { @@ -352,6 +369,7 @@ fn export_level(map: &tiled::Map) -> Level { Level { starting_items: starting_items.collect(), fixed_positions: fixed_positions.collect(), + solution_positions: solution_positions.collect(), directions: directions.collect(), wall_bitmap: bool_to_bit(&are_walls.collect::>()), name: level_name.clone(), @@ -359,7 +377,9 @@ fn export_level(map: &tiled::Map) -> Level { } fn export_tiles(map: &tiled::Map, background: TokenStream) -> TokenStream { - let map_tiles = map.get_layer(0).unwrap().as_tile_layer().unwrap(); + let map_tiles = map + .get_tile_layer("Ground") + .expect("The ground layer should exist"); let width = map_tiles.width().unwrap() * 2; let height = map_tiles.height().unwrap() * 2; @@ -446,3 +466,22 @@ fn check_bool_to_bit() { let bools = [true, false, false, false, true, true, true, true]; assert_eq!(bool_to_bit(&bools), [0b11110001]); } + +trait TiledMapExtensions { + fn get_object_layer(&self, name: &str) -> Option; + fn get_tile_layer(&self, name: &str) -> Option; +} + +impl TiledMapExtensions for Map { + fn get_object_layer(&self, name: &str) -> Option { + self.layers() + .find(|x| x.name == name) + .and_then(|x| x.as_object_layer()) + } + + fn get_tile_layer(&self, name: &str) -> Option { + self.layers() + .find(|x| x.name == name) + .and_then(|x| x.as_tile_layer()) + } +} diff --git a/examples/the-dungeon-puzzlers-lament/maps/levels/a_familiar_sight.tmx b/examples/the-dungeon-puzzlers-lament/maps/levels/a_familiar_sight.tmx index 4a4d07d1..e6583806 100644 --- a/examples/the-dungeon-puzzlers-lament/maps/levels/a_familiar_sight.tmx +++ b/examples/the-dungeon-puzzlers-lament/maps/levels/a_familiar_sight.tmx @@ -1,12 +1,12 @@ - + - + 0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0, @@ -20,7 +20,7 @@ 0,0,0,0,0,0,0,0,0,0,0 - + @@ -28,4 +28,9 @@ + + + + + diff --git a/examples/the-dungeon-puzzlers-lament/maps/levels/another_ice.tmx b/examples/the-dungeon-puzzlers-lament/maps/levels/another_ice.tmx index 2487605d..5b79dfd8 100644 --- a/examples/the-dungeon-puzzlers-lament/maps/levels/another_ice.tmx +++ b/examples/the-dungeon-puzzlers-lament/maps/levels/another_ice.tmx @@ -1,12 +1,12 @@ - + - + 0,0,0,1,2,9,0,1,8,6,9, 0,0,0,10,17,18,1,1073741852,17,12,18, @@ -20,7 +20,7 @@ 0,0,0,0,0,0,19,26,23,27,0 - + @@ -43,4 +43,21 @@ + + + + + + + + + + + + + + + + + diff --git a/examples/the-dungeon-puzzlers-lament/maps/levels/another_ice_2.tmx b/examples/the-dungeon-puzzlers-lament/maps/levels/another_ice_2.tmx index 79c166ef..5d1d638b 100644 --- a/examples/the-dungeon-puzzlers-lament/maps/levels/another_ice_2.tmx +++ b/examples/the-dungeon-puzzlers-lament/maps/levels/another_ice_2.tmx @@ -1,12 +1,12 @@ - + - + 1,8,2,7,8,8,3,7,4,2,9, 46,17,13,17,13,12,12,15,11,16,38, @@ -20,7 +20,7 @@ 0,19,24,20,25,20,27,0,0,0,0 - + @@ -103,4 +103,30 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/examples/the-dungeon-puzzlers-lament/maps/levels/another_ice_3.tmx b/examples/the-dungeon-puzzlers-lament/maps/levels/another_ice_3.tmx index 04f0ee15..8004709d 100644 --- a/examples/the-dungeon-puzzlers-lament/maps/levels/another_ice_3.tmx +++ b/examples/the-dungeon-puzzlers-lament/maps/levels/another_ice_3.tmx @@ -1,12 +1,12 @@ - + - + 1,8,2,7,8,8,3,9,1,2,9, 46,2147483676,22,23,28,12,12,38,19,26,27, @@ -20,7 +20,7 @@ 19,22,22,20,25,22,26,25,26,24,27 - + @@ -46,4 +46,27 @@ + + + + + + + + + + + + + + + + + + + + + + + diff --git a/examples/the-dungeon-puzzlers-lament/maps/levels/another_ice_4.tmx b/examples/the-dungeon-puzzlers-lament/maps/levels/another_ice_4.tmx index 98140e23..8069e5f1 100644 --- a/examples/the-dungeon-puzzlers-lament/maps/levels/another_ice_4.tmx +++ b/examples/the-dungeon-puzzlers-lament/maps/levels/another_ice_4.tmx @@ -1,12 +1,12 @@ - + - + 0,0,0,1,7,9,0,0,0,0,0, 0,0,1,1073741852,13,3221225500,8,9,0,0,0, @@ -20,7 +20,7 @@ 0,0,0,0,0,19,24,27,0,0,0 - + @@ -40,4 +40,15 @@ + + + + + + + + + + + diff --git a/examples/the-dungeon-puzzlers-lament/maps/levels/block_push_1.tmx b/examples/the-dungeon-puzzlers-lament/maps/levels/block_push_1.tmx index 4deac7d6..883df163 100644 --- a/examples/the-dungeon-puzzlers-lament/maps/levels/block_push_1.tmx +++ b/examples/the-dungeon-puzzlers-lament/maps/levels/block_push_1.tmx @@ -1,12 +1,12 @@ - + - + 0,1,3,2,6,9,0,0,0,0,0, 0,46,15,14,13,3221225500,4,6,7,7,9, @@ -20,7 +20,7 @@ 0,0,0,0,0,0,0,0,0,0,0 - + @@ -34,4 +34,12 @@ + + + + + + + + diff --git a/examples/the-dungeon-puzzlers-lament/maps/levels/block_push_2.tmx b/examples/the-dungeon-puzzlers-lament/maps/levels/block_push_2.tmx index 560a1c96..2aaef9c0 100644 --- a/examples/the-dungeon-puzzlers-lament/maps/levels/block_push_2.tmx +++ b/examples/the-dungeon-puzzlers-lament/maps/levels/block_push_2.tmx @@ -1,12 +1,12 @@ - + - + 0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0, @@ -20,7 +20,7 @@ 0,0,0,0,0,0,0,0,0,0,0 - + @@ -37,4 +37,9 @@ + + + + + diff --git a/examples/the-dungeon-puzzlers-lament/maps/levels/block_push_3.tmx b/examples/the-dungeon-puzzlers-lament/maps/levels/block_push_3.tmx index 178c36c1..48c2c3ec 100644 --- a/examples/the-dungeon-puzzlers-lament/maps/levels/block_push_3.tmx +++ b/examples/the-dungeon-puzzlers-lament/maps/levels/block_push_3.tmx @@ -1,12 +1,12 @@ - + - + 0,0,0,0,0,0,0,0,0,0,0, 0,0,1,6,2,8,8,9,0,0,0, @@ -20,7 +20,7 @@ 0,0,0,0,0,0,0,0,0,0,0 - + @@ -37,4 +37,12 @@ + + + + + + + + diff --git a/examples/the-dungeon-puzzlers-lament/maps/levels/glove_key.tmx b/examples/the-dungeon-puzzlers-lament/maps/levels/glove_key.tmx index c66b3ee2..ff6161be 100644 --- a/examples/the-dungeon-puzzlers-lament/maps/levels/glove_key.tmx +++ b/examples/the-dungeon-puzzlers-lament/maps/levels/glove_key.tmx @@ -1,12 +1,12 @@ - + - + 0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0, @@ -20,7 +20,7 @@ 0,0,0,0,0,0,0,0,0,0,0 - + @@ -37,4 +37,12 @@ + + + + + + + + diff --git a/examples/the-dungeon-puzzlers-lament/maps/levels/hole_introduction.tmx b/examples/the-dungeon-puzzlers-lament/maps/levels/hole_introduction.tmx index 8da8ed63..434cc987 100644 --- a/examples/the-dungeon-puzzlers-lament/maps/levels/hole_introduction.tmx +++ b/examples/the-dungeon-puzzlers-lament/maps/levels/hole_introduction.tmx @@ -1,12 +1,12 @@ - + - + 0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0, @@ -20,7 +20,7 @@ 0,0,0,0,0,0,0,0,0,0,0 - + @@ -31,4 +31,9 @@ + + + + + diff --git a/examples/the-dungeon-puzzlers-lament/maps/levels/ice_ice.tmx b/examples/the-dungeon-puzzlers-lament/maps/levels/ice_ice.tmx index 332ecc02..616beb28 100644 --- a/examples/the-dungeon-puzzlers-lament/maps/levels/ice_ice.tmx +++ b/examples/the-dungeon-puzzlers-lament/maps/levels/ice_ice.tmx @@ -1,12 +1,12 @@ - + - + 0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0, @@ -20,7 +20,7 @@ 0,0,0,0,0,19,26,27,0,0,0 - + @@ -46,4 +46,15 @@ + + + + + + + + + + + diff --git a/examples/the-dungeon-puzzlers-lament/maps/levels/just_rocks.tmx b/examples/the-dungeon-puzzlers-lament/maps/levels/just_rocks.tmx index 3798b556..d0fc2bcc 100644 --- a/examples/the-dungeon-puzzlers-lament/maps/levels/just_rocks.tmx +++ b/examples/the-dungeon-puzzlers-lament/maps/levels/just_rocks.tmx @@ -1,12 +1,12 @@ - + - + 0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0, @@ -20,7 +20,7 @@ 0,0,0,0,0,0,0,0,0,0,0 - + @@ -40,4 +40,9 @@ + + + + + diff --git a/examples/the-dungeon-puzzlers-lament/maps/levels/level1.tmx b/examples/the-dungeon-puzzlers-lament/maps/levels/level1.tmx index 2db372a0..047ea962 100644 --- a/examples/the-dungeon-puzzlers-lament/maps/levels/level1.tmx +++ b/examples/the-dungeon-puzzlers-lament/maps/levels/level1.tmx @@ -1,12 +1,12 @@ - + - + 0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0, @@ -20,7 +20,7 @@ 0,0,0,0,0,0,0,0,0,0,0 - + @@ -31,4 +31,9 @@ + + + + + diff --git a/examples/the-dungeon-puzzlers-lament/maps/levels/level2.tmx b/examples/the-dungeon-puzzlers-lament/maps/levels/level2.tmx index 39e6acef..d8464078 100644 --- a/examples/the-dungeon-puzzlers-lament/maps/levels/level2.tmx +++ b/examples/the-dungeon-puzzlers-lament/maps/levels/level2.tmx @@ -1,12 +1,12 @@ - + - + 0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,1,3,9,0,0,0,0, @@ -20,7 +20,7 @@ 0,0,0,0,0,0,0,0,0,0,0 - + @@ -28,4 +28,9 @@ + + + + + diff --git a/examples/the-dungeon-puzzlers-lament/maps/levels/level3.tmx b/examples/the-dungeon-puzzlers-lament/maps/levels/level3.tmx index 28abd513..d4d8e227 100644 --- a/examples/the-dungeon-puzzlers-lament/maps/levels/level3.tmx +++ b/examples/the-dungeon-puzzlers-lament/maps/levels/level3.tmx @@ -1,12 +1,12 @@ - + - + 0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0, @@ -20,7 +20,7 @@ 0,0,0,0,0,0,0,0,0,0,0 - + @@ -34,4 +34,9 @@ + + + + + diff --git a/examples/the-dungeon-puzzlers-lament/maps/levels/level4.tmx b/examples/the-dungeon-puzzlers-lament/maps/levels/level4.tmx index f306fbfc..e6337c49 100644 --- a/examples/the-dungeon-puzzlers-lament/maps/levels/level4.tmx +++ b/examples/the-dungeon-puzzlers-lament/maps/levels/level4.tmx @@ -1,12 +1,12 @@ - + - + 0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0, @@ -20,7 +20,7 @@ 0,0,0,0,0,0,0,0,0,0,0 - + @@ -31,4 +31,9 @@ + + + + + diff --git a/examples/the-dungeon-puzzlers-lament/maps/levels/level5.tmx b/examples/the-dungeon-puzzlers-lament/maps/levels/level5.tmx index c1fe7171..35b5a899 100644 --- a/examples/the-dungeon-puzzlers-lament/maps/levels/level5.tmx +++ b/examples/the-dungeon-puzzlers-lament/maps/levels/level5.tmx @@ -1,12 +1,12 @@ - + - + 0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0, @@ -20,7 +20,7 @@ 0,0,0,0,0,0,0,0,0,0,0 - + @@ -28,4 +28,12 @@ + + + + + + + + diff --git a/examples/the-dungeon-puzzlers-lament/maps/levels/level6.tmx b/examples/the-dungeon-puzzlers-lament/maps/levels/level6.tmx index 5e1bc8cd..5d433dcc 100644 --- a/examples/the-dungeon-puzzlers-lament/maps/levels/level6.tmx +++ b/examples/the-dungeon-puzzlers-lament/maps/levels/level6.tmx @@ -1,12 +1,12 @@ - + - + 0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0, @@ -20,7 +20,7 @@ 0,0,0,0,0,0,0,0,0,0,0 - + @@ -37,4 +37,9 @@ + + + + + diff --git a/examples/the-dungeon-puzzlers-lament/maps/levels/level_around.tmx b/examples/the-dungeon-puzzlers-lament/maps/levels/level_around.tmx index 5a59fbdf..ce43a108 100644 --- a/examples/the-dungeon-puzzlers-lament/maps/levels/level_around.tmx +++ b/examples/the-dungeon-puzzlers-lament/maps/levels/level_around.tmx @@ -1,12 +1,12 @@ - + - + 0,0,0,0,1,7,5,6,9,0,0, 0,0,1,4,1073741852,17,13,13,3221225500,9,0, @@ -20,7 +20,7 @@ 0,0,0,0,0,0,0,0,0,0,0 - + @@ -28,4 +28,18 @@ + + + + + + + + + + + + + + diff --git a/examples/the-dungeon-puzzlers-lament/maps/levels/level_spikes.tmx b/examples/the-dungeon-puzzlers-lament/maps/levels/level_spikes.tmx index d50168d9..845fa321 100644 --- a/examples/the-dungeon-puzzlers-lament/maps/levels/level_spikes.tmx +++ b/examples/the-dungeon-puzzlers-lament/maps/levels/level_spikes.tmx @@ -1,12 +1,12 @@ - + - + 0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0, @@ -20,7 +20,7 @@ 0,0,0,0,0,0,0,0,0,0,0 - + @@ -37,4 +37,12 @@ + + + + + + + + diff --git a/examples/the-dungeon-puzzlers-lament/maps/levels/level_spikes2.tmx b/examples/the-dungeon-puzzlers-lament/maps/levels/level_spikes2.tmx index f1e28c2f..1f3fbde5 100644 --- a/examples/the-dungeon-puzzlers-lament/maps/levels/level_spikes2.tmx +++ b/examples/the-dungeon-puzzlers-lament/maps/levels/level_spikes2.tmx @@ -1,12 +1,12 @@ - + - + 0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0, @@ -20,7 +20,7 @@ 0,0,0,0,0,0,0,0,0,0,0 - + @@ -40,4 +40,18 @@ + + + + + + + + + + + + + + diff --git a/examples/the-dungeon-puzzlers-lament/maps/levels/level_spikes3.tmx b/examples/the-dungeon-puzzlers-lament/maps/levels/level_spikes3.tmx index e8e67c6e..fe1fefb3 100644 --- a/examples/the-dungeon-puzzlers-lament/maps/levels/level_spikes3.tmx +++ b/examples/the-dungeon-puzzlers-lament/maps/levels/level_spikes3.tmx @@ -1,12 +1,12 @@ - + - + 0,0,1,8,4,1073741872,2,7,9,0,0, 0,0,37,15,15,1073741863,15,13,3221225500,3,9, @@ -20,7 +20,7 @@ 0,0,0,0,0,19,21,22,23,27,0 - + @@ -43,4 +43,15 @@ + + + + + + + + + + + diff --git a/examples/the-dungeon-puzzlers-lament/maps/levels/level_squid1.tmx b/examples/the-dungeon-puzzlers-lament/maps/levels/level_squid1.tmx index 79dcfd30..0e062937 100644 --- a/examples/the-dungeon-puzzlers-lament/maps/levels/level_squid1.tmx +++ b/examples/the-dungeon-puzzlers-lament/maps/levels/level_squid1.tmx @@ -1,12 +1,12 @@ - + - + 0,0,0,0,1,8,2,6,9,0,0, 0,0,0,0,46,11,11,11,38,0,0, @@ -20,7 +20,7 @@ 0,0,0,0,0,19,23,27,0,0,0 - + @@ -34,4 +34,15 @@ + + + + + + + + + + + diff --git a/examples/the-dungeon-puzzlers-lament/maps/levels/level_squid2.tmx b/examples/the-dungeon-puzzlers-lament/maps/levels/level_squid2.tmx index a740e0fc..327ce03b 100644 --- a/examples/the-dungeon-puzzlers-lament/maps/levels/level_squid2.tmx +++ b/examples/the-dungeon-puzzlers-lament/maps/levels/level_squid2.tmx @@ -1,12 +1,12 @@ - + - + 0,0,0,0,0,0,0,0,0,0,0, 0,0,0,1,5,9,0,0,0,0,0, @@ -20,7 +20,7 @@ 0,0,0,0,0,0,0,0,0,0,0 - + @@ -37,4 +37,15 @@ + + + + + + + + + + + diff --git a/examples/the-dungeon-puzzlers-lament/maps/levels/level_squid_button.tmx b/examples/the-dungeon-puzzlers-lament/maps/levels/level_squid_button.tmx index a6d7a077..05481924 100644 --- a/examples/the-dungeon-puzzlers-lament/maps/levels/level_squid_button.tmx +++ b/examples/the-dungeon-puzzlers-lament/maps/levels/level_squid_button.tmx @@ -1,12 +1,12 @@ - + - + 0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,1,2,9,0,0,0, @@ -20,7 +20,7 @@ 0,0,0,0,0,0,0,0,0,0,0 - + @@ -40,4 +40,21 @@ + + + + + + + + + + + + + + + + + diff --git a/examples/the-dungeon-puzzlers-lament/maps/levels/level_squid_drop.tmx b/examples/the-dungeon-puzzlers-lament/maps/levels/level_squid_drop.tmx index 1dc5cabd..f00d08fc 100644 --- a/examples/the-dungeon-puzzlers-lament/maps/levels/level_squid_drop.tmx +++ b/examples/the-dungeon-puzzlers-lament/maps/levels/level_squid_drop.tmx @@ -1,12 +1,12 @@ - + - + 0,0,0,1,4,8,3,2,3,9,0, 0,0,0,46,11,12,14,16,14,38,0, @@ -20,7 +20,7 @@ 0,0,0,0,0,0,0,0,0,0,0 - + @@ -34,4 +34,21 @@ + + + + + + + + + + + + + + + + + diff --git a/examples/the-dungeon-puzzlers-lament/maps/levels/level_squid_force_button.tmx b/examples/the-dungeon-puzzlers-lament/maps/levels/level_squid_force_button.tmx index 918dd3c5..b962a0ca 100644 --- a/examples/the-dungeon-puzzlers-lament/maps/levels/level_squid_force_button.tmx +++ b/examples/the-dungeon-puzzlers-lament/maps/levels/level_squid_force_button.tmx @@ -1,12 +1,12 @@ - + - + 0,0,0,0,0,0,0,0,0,0,0, 0,1,7,9,0,0,0,0,0,0,0, @@ -20,7 +20,7 @@ 0,0,0,0,0,0,0,0,0,0,0 - + @@ -37,4 +37,12 @@ + + + + + + + + diff --git a/examples/the-dungeon-puzzlers-lament/maps/levels/level_squid_intro.tmx b/examples/the-dungeon-puzzlers-lament/maps/levels/level_squid_intro.tmx index f16222ce..d121b081 100644 --- a/examples/the-dungeon-puzzlers-lament/maps/levels/level_squid_intro.tmx +++ b/examples/the-dungeon-puzzlers-lament/maps/levels/level_squid_intro.tmx @@ -1,12 +1,12 @@ - + - + 0,0,0,1,8,9,0,0,0,0,0, 1,7,2,32,16,3221225500,9,0,0,0,0, @@ -20,7 +20,7 @@ 0,0,0,19,23,25,48,22,27,0,0 - + @@ -40,4 +40,12 @@ + + + + + + + + diff --git a/examples/the-dungeon-puzzlers-lament/maps/levels/level_squid_item.tmx b/examples/the-dungeon-puzzlers-lament/maps/levels/level_squid_item.tmx index 8c250cdb..d60fe025 100644 --- a/examples/the-dungeon-puzzlers-lament/maps/levels/level_squid_item.tmx +++ b/examples/the-dungeon-puzzlers-lament/maps/levels/level_squid_item.tmx @@ -1,12 +1,12 @@ - + - + 0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,1,3,7,6,9,0,0, @@ -20,7 +20,7 @@ 0,0,0,0,0,0,0,0,0,0,0 - + @@ -40,4 +40,15 @@ + + + + + + + + + + + diff --git a/examples/the-dungeon-puzzlers-lament/maps/levels/level_squidprogramming.tmx b/examples/the-dungeon-puzzlers-lament/maps/levels/level_squidprogramming.tmx index b7c12c53..c422f7d3 100644 --- a/examples/the-dungeon-puzzlers-lament/maps/levels/level_squidprogramming.tmx +++ b/examples/the-dungeon-puzzlers-lament/maps/levels/level_squidprogramming.tmx @@ -1,12 +1,12 @@ - + - + 0,1,4,3221225492,7,2147483655,3,1073741844,1073741850,2147483649,0, 0,37,2147483659,11,2147483659,2147483665,3221225486,3221225484,1073741839,3221225518,0, @@ -20,7 +20,7 @@ 19,2147483672,2147483673,1073741831,1073741832,1073741829,21,1073741826,22,22,27 - + @@ -49,4 +49,15 @@ + + + + + + + + + + + diff --git a/examples/the-dungeon-puzzlers-lament/maps/levels/level_switch.tmx b/examples/the-dungeon-puzzlers-lament/maps/levels/level_switch.tmx index 333cba05..f81b4dbb 100644 --- a/examples/the-dungeon-puzzlers-lament/maps/levels/level_switch.tmx +++ b/examples/the-dungeon-puzzlers-lament/maps/levels/level_switch.tmx @@ -1,12 +1,12 @@ - + - + 0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0, @@ -20,7 +20,7 @@ 0,0,0,0,0,0,0,0,0,0,0 - + @@ -34,4 +34,9 @@ + + + + + diff --git a/examples/the-dungeon-puzzlers-lament/maps/levels/rotator_1.tmx b/examples/the-dungeon-puzzlers-lament/maps/levels/rotator_1.tmx index 3847f552..a07675ac 100644 --- a/examples/the-dungeon-puzzlers-lament/maps/levels/rotator_1.tmx +++ b/examples/the-dungeon-puzzlers-lament/maps/levels/rotator_1.tmx @@ -1,12 +1,12 @@ - + - + 1,6,7,7,4,5,3,2,4,7,9, 37,12,14,13,12,15,12,16,14,13,47, @@ -20,7 +20,7 @@ 19,23,24,26,22,20,24,25,26,25,27 - + @@ -40,4 +40,18 @@ + + + + + + + + + + + + + + diff --git a/examples/the-dungeon-puzzlers-lament/maps/levels/rotator_2.tmx b/examples/the-dungeon-puzzlers-lament/maps/levels/rotator_2.tmx index ba90804c..4783ebeb 100644 --- a/examples/the-dungeon-puzzlers-lament/maps/levels/rotator_2.tmx +++ b/examples/the-dungeon-puzzlers-lament/maps/levels/rotator_2.tmx @@ -1,12 +1,12 @@ - + - + 0,0,0,0,0,1,6,8,5,4,9, 0,0,1,7,8,32,11,17,12,17,38, @@ -20,7 +20,7 @@ 19,26,20,21,25,20,22,24,21,24,27 - + @@ -37,4 +37,12 @@ + + + + + + + + diff --git a/examples/the-dungeon-puzzlers-lament/maps/levels/rotator_demonstration.tmx b/examples/the-dungeon-puzzlers-lament/maps/levels/rotator_demonstration.tmx index 69b1604e..896034e4 100644 --- a/examples/the-dungeon-puzzlers-lament/maps/levels/rotator_demonstration.tmx +++ b/examples/the-dungeon-puzzlers-lament/maps/levels/rotator_demonstration.tmx @@ -1,12 +1,12 @@ - + - + 0,1,8,3,9,1,7,9,0,0,0, 1,1073741852,11,11,3221225500,1073741852,13,38,0,0,0, @@ -20,7 +20,7 @@ 0,0,0,19,20,24,21,27,0,0,0 - + @@ -37,4 +37,9 @@ + + + + + diff --git a/examples/the-dungeon-puzzlers-lament/maps/levels/slime_teleporter.tmx b/examples/the-dungeon-puzzlers-lament/maps/levels/slime_teleporter.tmx index 9ef70e31..1dab8d70 100644 --- a/examples/the-dungeon-puzzlers-lament/maps/levels/slime_teleporter.tmx +++ b/examples/the-dungeon-puzzlers-lament/maps/levels/slime_teleporter.tmx @@ -1,12 +1,12 @@ - + - + 0,0,0,0,0,0,0,0,0,0,0, 0,0,0,1,6,4,3,9,0,0,0, @@ -20,7 +20,7 @@ 0,0,0,0,0,19,22,22,27,0,0 - + @@ -40,4 +40,18 @@ + + + + + + + + + + + + + + diff --git a/examples/the-dungeon-puzzlers-lament/maps/levels/squid_rock.tmx b/examples/the-dungeon-puzzlers-lament/maps/levels/squid_rock.tmx index 584de271..5c5f5ba6 100644 --- a/examples/the-dungeon-puzzlers-lament/maps/levels/squid_rock.tmx +++ b/examples/the-dungeon-puzzlers-lament/maps/levels/squid_rock.tmx @@ -1,12 +1,12 @@ - + - + 0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0, @@ -20,7 +20,7 @@ 0,0,0,0,0,0,0,0,0,0,0 - + @@ -34,4 +34,15 @@ + + + + + + + + + + + diff --git a/examples/the-dungeon-puzzlers-lament/maps/levels/squid_teleport.tmx b/examples/the-dungeon-puzzlers-lament/maps/levels/squid_teleport.tmx index 9c917b6b..5807282d 100644 --- a/examples/the-dungeon-puzzlers-lament/maps/levels/squid_teleport.tmx +++ b/examples/the-dungeon-puzzlers-lament/maps/levels/squid_teleport.tmx @@ -1,12 +1,12 @@ - + - + 0,0,0,0,0,0,0,0,0,0,0, 1,7,4,2,6,9,0,1,8,9,0, @@ -20,7 +20,7 @@ 0,0,0,0,0,0,0,0,0,0,0 - + @@ -43,4 +43,15 @@ + + + + + + + + + + + diff --git a/examples/the-dungeon-puzzlers-lament/maps/levels/teleporter_1.tmx b/examples/the-dungeon-puzzlers-lament/maps/levels/teleporter_1.tmx index 4f9c4457..1d30a67a 100644 --- a/examples/the-dungeon-puzzlers-lament/maps/levels/teleporter_1.tmx +++ b/examples/the-dungeon-puzzlers-lament/maps/levels/teleporter_1.tmx @@ -1,12 +1,12 @@ - + - + 0,0,0,0,0,0,0,0,0,0,0, 0,1,4,5,4,3,7,2,8,9,0, @@ -20,7 +20,7 @@ 0,0,0,0,0,0,0,0,0,0,0 - + @@ -31,4 +31,9 @@ + + + + + diff --git a/examples/the-dungeon-puzzlers-lament/maps/levels/teleporter_2.tmx b/examples/the-dungeon-puzzlers-lament/maps/levels/teleporter_2.tmx index c8cae9cc..f3ee9d48 100644 --- a/examples/the-dungeon-puzzlers-lament/maps/levels/teleporter_2.tmx +++ b/examples/the-dungeon-puzzlers-lament/maps/levels/teleporter_2.tmx @@ -1,12 +1,12 @@ - + - + 0,0,1,8,7,7,5,9,0,0,0, 1,6,1073741852,15,16,15,13,3221225500,9,0,0, @@ -20,7 +20,7 @@ 0,0,0,0,19,23,27,0,0,0,0 - + @@ -43,4 +43,24 @@ + + + + + + + + + + + + + + + + + + + + diff --git a/examples/the-dungeon-puzzlers-lament/src/game/simulation.rs b/examples/the-dungeon-puzzlers-lament/src/game/simulation.rs index 8d9e36bb..574fda1b 100644 --- a/examples/the-dungeon-puzzlers-lament/src/game/simulation.rs +++ b/examples/the-dungeon-puzzlers-lament/src/game/simulation.rs @@ -11,7 +11,7 @@ use crate::{ use self::{ animation::{Animation, RenderCache}, - entity::{Action, EntityMap}, + entity::{Action, EntityMap, EntityMapMaker}, }; mod animation; @@ -33,19 +33,21 @@ pub struct Simulation { impl Simulation { pub fn generate( - a: impl Iterator)>, + entities_to_add: impl Iterator)>, level: &'static Level, sfx: &mut Sfx, loader: &mut SpriteLoader, ) -> Simulation { - let mut entities = EntityMap::default(); + let mut entities = EntityMapMaker::new(); let mut animation = Animation::default(); - let mut entities_to_add: Vec<_> = a.collect(); - entities_to_add.sort_unstable_by_key(|(_, location)| location.x + location.y * 100); - for (item, location) in entities_to_add { - animation.populate(entities.add(item, location), sfx); + entities.add(item, location); + } + + let (entities, animations) = entities.to_entity_map(); + for ani in animations { + animation.populate(ani, sfx); } let mut simulation = Simulation { diff --git a/examples/the-dungeon-puzzlers-lament/src/game/simulation/entity.rs b/examples/the-dungeon-puzzlers-lament/src/game/simulation/entity.rs index 1b4d5421..6d38b2ee 100644 --- a/examples/the-dungeon-puzzlers-lament/src/game/simulation/entity.rs +++ b/examples/the-dungeon-puzzlers-lament/src/game/simulation/entity.rs @@ -18,11 +18,39 @@ use super::animation::AnimationInstruction; new_key_type! { pub struct EntityKey; } -#[derive(Default)] pub struct EntityMap { map: SlotMap, } +pub struct EntityMapMaker { + map: Vec<(crate::level::Item, Vector2D)>, +} + +impl EntityMapMaker { + pub fn new() -> Self { + Self { + map: Default::default(), + } + } + + pub fn add(&mut self, entity: crate::level::Item, location: Vector2D) { + let idx = self.map.push((entity, location)); + } + + pub fn to_entity_map(mut self) -> (EntityMap, Vec) { + self.map + .sort_unstable_by_key(|(_, location)| location.x + location.y * 100); + let mut entity_map = EntityMap { + map: Default::default(), + }; + let mut animations = Vec::new(); + for (entity, location) in self.map { + animations.push(entity_map.add(entity, location)); + } + (entity_map, animations) + } +} + #[derive(Clone, Copy, PartialEq, PartialOrd, Debug)] pub enum Outcome { Continue, @@ -1026,3 +1054,107 @@ impl From for EntityType { } } } + +#[cfg(test)] +mod tests { + + use super::*; + use agb::hash_map::HashMap; + + #[test_case] + fn check_all_puzzle_solutions_work(_gba: &mut agb::Gba) { + let number_of_levels = crate::level::Level::num_levels(); + let mut failed_levels = Vec::new(); + + #[derive(Debug)] + enum CompleteSimulationResult { + Success, + ExplicitLoss, + InputSequenceOver, + MismatchedItems(HashMap), + } + + fn check_level_has_valid_items(level: usize) -> HashMap { + let level = crate::level::Level::get_level(level); + + let mut given_items = HashMap::new(); + + for &item in level.items.iter() { + *given_items.entry(item).or_insert(0) += 1; + } + + let mut solution_items = HashMap::new(); + + for entity in level.solution.iter() { + *solution_items.entry(entity.0).or_insert(0) += 1; + } + + let mut mismatched = HashMap::new(); + + for (&item, &count) in solution_items.iter() { + if *given_items.entry(item).or_insert(0) < count { + mismatched.insert(item, ()); + } + } + + mismatched + } + + fn check_level_works(level: usize) -> CompleteSimulationResult { + let level = crate::level::Level::get_level(level); + + let mut simulator = EntityMapMaker::new(); + for entity in level.entities { + simulator.add(entity.0, entity.1); + } + for solution_entity in level.solution { + simulator.add(solution_entity.0, solution_entity.1); + } + + let (mut simulator, _) = simulator.to_entity_map(); + + for &direction in level.directions { + let (outcome, _) = simulator.tick(&level.map, Action::Direction(direction)); + match outcome { + Outcome::Continue => {} + Outcome::Loss => return CompleteSimulationResult::ExplicitLoss, + Outcome::Win => return CompleteSimulationResult::Success, + } + } + + CompleteSimulationResult::InputSequenceOver + } + + for level_idx in 0..number_of_levels { + let mismatched_items = check_level_has_valid_items(level_idx); + if !mismatched_items.is_empty() { + failed_levels.push(( + level_idx, + CompleteSimulationResult::MismatchedItems(mismatched_items), + )) + } + let outcome = check_level_works(level_idx); + match outcome { + CompleteSimulationResult::ExplicitLoss + | CompleteSimulationResult::InputSequenceOver => { + failed_levels.push((level_idx, outcome)) + } + _ => {} + } + } + + if !failed_levels.is_empty() { + agb::println!("Levels that failed were:"); + for (level, outcome) in failed_levels { + agb::println!( + "Level: {}, reason {:?}, lament: {}", + level, + outcome, + crate::level::Level::get_level(level).name + ); + } + + panic!("Level check failed"); + } + } +} diff --git a/examples/the-dungeon-puzzlers-lament/src/level.rs b/examples/the-dungeon-puzzlers-lament/src/level.rs index 81ce5489..ff779e0b 100644 --- a/examples/the-dungeon-puzzlers-lament/src/level.rs +++ b/examples/the-dungeon-puzzlers-lament/src/level.rs @@ -2,7 +2,7 @@ use agb::{display::object::Tag, fixnum::Vector2D}; use crate::{game::Direction, map::Map, resources}; -#[derive(Clone, Copy, PartialEq, Eq, Debug)] +#[derive(Clone, Copy, PartialEq, Eq, Debug, Hash)] pub enum Item { Sword, Slime, @@ -123,15 +123,19 @@ pub struct Entity(pub Item, pub Vector2D); pub struct Level { pub map: Map<'static>, pub entities: &'static [Entity], + #[cfg(test)] + pub solution: &'static [Entity], pub directions: &'static [Direction], pub items: &'static [Item], pub name: &'static str, } impl Level { + #[allow(unused_variables)] const fn new( map: Map<'static>, entities: &'static [Entity], + solution: &'static [Entity], directions: &'static [Direction], items: &'static [Item], name: &'static str, @@ -139,6 +143,8 @@ impl Level { Self { map, entities, + #[cfg(test)] + solution, directions, items, name, diff --git a/examples/the-dungeon-puzzlers-lament/src/map.rs b/examples/the-dungeon-puzzlers-lament/src/map.rs index c0d9c6a3..558d2779 100644 --- a/examples/the-dungeon-puzzlers-lament/src/map.rs +++ b/examples/the-dungeon-puzzlers-lament/src/map.rs @@ -22,7 +22,7 @@ impl<'map> Map<'map> { pub const fn get(&self, index: Vector2D) -> MapElement { let (x, y) = (index.x, index.y); - if x > self.width as i32 || y > self.height as i32 { + if x > self.width as i32 || x < 0 || y > self.height as i32 || y < 0 { MapElement::Wall } else { let position = x as usize + y as usize * self.width;