// Module 9: The turn pipeline. Each test matches a heading in scenarios.md. use engine::harness::*; /// An empty level `width` wide and `height` high. fn empty_level(width: i32, height: i32) -> LevelDef { LevelDef { width, height, ..Default::default() } } /// Place one text object per word: `(word, x, y)`. fn write(b: &mut Baba, words: &[(&str, i32, i32)]) { for &(word, x, y) in words { b.place(&format!("text:{word}"), x, y); } } #[test] fn test_09_lava_saved_by_reparse() { let mut b = new_baba(empty_level(6, 5)); write(&mut b, &[("BABA", 0, 0), ("IS", 1, 0), ("YOU", 2, 0)]); write(&mut b, &[("LAVA", 0, 1), ("IS", 1, 1), ("HOT", 2, 1)]); write(&mut b, &[("BABA", 4, 2), ("IS", 4, 3)]); let melt_text = b.place("text:MELT", 4, 4); let lava = b.place("lava", 4, 4); let baba = b.place("baba", 3, 4); assert!(b.has_property(baba, "MELT")); b.step(Dir::Right); assert_eq!(b.pos_of(baba), Some((4, 4))); assert_eq!(b.pos_of(melt_text), Some((5, 4))); // Inferred from the order of operations, not stated by a source: Baba survives. assert_eq!(b.pos_of(lava), Some((4, 4))); assert_eq!(b.kinds_at(4, 4), vec!["baba", "lava"]); assert!(!b.rules().contains(&"BABA IS MELT".to_string())); assert!(!b.lost()); } #[test] fn test_09_mid_turn_conversion() { let mut b = new_baba(empty_level(5, 5)); write(&mut b, &[("BABA", 0, 0), ("IS", 1, 0), ("YOU", 2, 0)]); write(&mut b, &[("BABA", 0, 2), ("IS", 1, 2)]); let rock_text = b.place("text:ROCK", 2, 3); let pusher = b.place("baba", 2, 4); let other = b.place("baba", 4, 4); b.step(Dir::Up); assert_eq!(b.pos_of(rock_text), Some((2, 2))); assert!(b.rules().contains(&"BABA IS ROCK".to_string())); assert_eq!(b.pos_of(pusher), Some((2, 3))); assert_eq!(b.pos_of(other), Some((4, 3))); assert_eq!(b.kinds_at(2, 3), vec!["rock"]); assert_eq!(b.kinds_at(4, 3), vec!["rock"]); assert_eq!(b.kinds_at(2, 4), Vec::::new()); assert_eq!(b.kinds_at(4, 4), Vec::::new()); } #[test] fn test_09_identity_lock_blocks_conversion() { let mut b = new_baba(empty_level(5, 5)); write(&mut b, &[("BABA", 0, 0), ("IS", 1, 0), ("YOU", 2, 0)]); write(&mut b, &[("BABA", 0, 1), ("IS", 1, 1), ("BABA", 2, 1)]); write(&mut b, &[("BABA", 0, 2), ("IS", 1, 2), ("ROCK", 2, 2)]); write(&mut b, &[("KEY", 0, 3), ("IS", 1, 3), ("ROCK", 2, 3)]); let baba = b.place("baba", 0, 4); let key = b.place("key", 3, 4); b.step(Dir::Right); assert_eq!(b.pos_of(baba), Some((1, 4))); assert_eq!(b.kinds_at(1, 4), vec!["baba"]); assert_eq!(b.kinds_at(3, 4), vec!["rock"]); assert_eq!(b.pos_of(key), Some((3, 4))); let active = b.active_rules(); assert!(!active.contains(&"BABA IS ROCK".to_string())); assert!(active.contains(&"BABA IS BABA".to_string())); assert!(active.contains(&"KEY IS ROCK".to_string())); } #[test] fn test_09_self_negation_deletes() { let mut b = new_baba(empty_level(5, 5)); write(&mut b, &[("BABA", 0, 0), ("IS", 1, 0), ("YOU", 2, 0)]); write( &mut b, &[("KEY", 0, 1), ("IS", 1, 1), ("NOT", 2, 1), ("KEY", 3, 1)], ); write(&mut b, &[("KEY", 0, 2), ("IS", 1, 2), ("ROCK", 2, 2)]); let baba = b.place("baba", 0, 4); let key = b.place("key", 3, 4); assert_eq!(b.pos_of(key), Some((3, 4))); b.step(Dir::Right); assert_eq!(b.pos_of(key), None); assert_eq!(b.kinds_at(3, 4), vec!["rock"]); assert_eq!(b.pos_of(baba), Some((1, 4))); } #[test] fn test_09_float_separates_hazards() { let mut b = new_baba(empty_level(4, 6)); write(&mut b, &[("BABA", 0, 0), ("IS", 1, 0), ("YOU", 2, 0)]); write(&mut b, &[("KEY", 0, 1), ("IS", 1, 1), ("YOU", 2, 1)]); write(&mut b, &[("SKULL", 0, 2), ("IS", 1, 2), ("DEFEAT", 2, 2)]); write(&mut b, &[("BABA", 0, 3), ("IS", 1, 3), ("FLOAT", 2, 3)]); let baba = b.place("baba", 0, 4); b.place("skull", 1, 4); let key = b.place("key", 0, 5); b.place("skull", 1, 5); b.step(Dir::Right); assert_eq!(b.pos_of(baba), Some((1, 4))); assert_eq!(b.kinds_at(1, 4), vec!["baba", "skull"]); assert_eq!(b.pos_of(key), None); assert_eq!(b.kinds_at(1, 5), vec!["skull"]); assert!(!b.lost()); } #[test] fn test_09_sink_destroys_both() { let mut b = new_baba(empty_level(5, 5)); write(&mut b, &[("BABA", 0, 0), ("IS", 1, 0), ("YOU", 2, 0)]); write(&mut b, &[("ROCK", 0, 1), ("IS", 1, 1), ("PUSH", 2, 1)]); write(&mut b, &[("WATER", 0, 2), ("IS", 1, 2), ("SINK", 2, 2)]); let baba = b.place("baba", 0, 4); let rock = b.place("rock", 1, 4); let water = b.place("water", 2, 4); b.step(Dir::Right); assert_eq!(b.pos_of(rock), None); assert_eq!(b.pos_of(water), None); assert_eq!(b.kinds_at(2, 4), Vec::::new()); assert_eq!(b.pos_of(baba), Some((1, 4))); } #[test] fn test_09_you_and_win() { let mut b = new_baba(empty_level(4, 4)); write(&mut b, &[("BABA", 0, 0), ("IS", 1, 0), ("YOU", 2, 0)]); write(&mut b, &[("BABA", 0, 1), ("IS", 1, 1), ("WIN", 2, 1)]); b.place("baba", 0, 3); assert!(!b.won()); b.step(Dir::Right); assert!(b.won()); assert!(!b.lost()); } #[test] fn test_09_defeat_beats_win() { let mut b = new_baba(empty_level(5, 4)); write(&mut b, &[("BABA", 0, 0), ("IS", 1, 0), ("YOU", 2, 0)]); write( &mut b, &[ ("FLAG", 0, 1), ("IS", 1, 1), ("WIN", 2, 1), ("AND", 3, 1), ("DEFEAT", 4, 1), ], ); let baba = b.place("baba", 0, 3); let flag = b.place("flag", 1, 3); b.step(Dir::Right); assert_eq!(b.pos_of(baba), None); assert!(!b.won()); assert!(b.lost()); assert_eq!(b.pos_of(flag), Some((1, 3))); }