// Module 8: Push chains. 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_08_chain_moves_together() { let mut b = new_baba(empty_level(6, 4)); write(&mut b, &[("BABA", 0, 0), ("IS", 1, 0), ("YOU", 2, 0)]); write(&mut b, &[("ROCK", 0, 1), ("IS", 1, 1), ("PUSH", 2, 1)]); let baba = b.place("baba", 0, 3); let rocks = [ b.place("rock", 1, 3), b.place("rock", 2, 3), b.place("rock", 3, 3), ]; b.move_dir(Dir::Right); assert_eq!(b.pos_of(baba), Some((1, 3))); assert_eq!(b.pos_of(rocks[0]), Some((2, 3))); assert_eq!(b.pos_of(rocks[1]), Some((3, 3))); assert_eq!(b.pos_of(rocks[2]), Some((4, 3))); assert_eq!(b.kinds_at(0, 3), Vec::::new()); assert_eq!(b.kinds_at(4, 3), vec!["rock"]); } #[test] fn test_08_chain_into_stop_nothing_moves() { let mut b = new_baba(empty_level(6, 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, &[("WALL", 0, 2), ("IS", 1, 2), ("STOP", 2, 2)]); let baba = b.place("baba", 0, 4); let rocks = [ b.place("rock", 1, 4), b.place("rock", 2, 4), b.place("rock", 3, 4), ]; let wall = b.place("wall", 4, 4); b.move_dir(Dir::Right); assert_eq!(b.pos_of(baba), Some((0, 4))); assert_eq!(b.pos_of(rocks[0]), Some((1, 4))); assert_eq!(b.pos_of(rocks[1]), Some((2, 4))); assert_eq!(b.pos_of(rocks[2]), Some((3, 4))); assert_eq!(b.pos_of(wall), Some((4, 4))); } #[test] fn test_08_open_shut_during_push() { 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), ("PUSH", 2, 1), ("AND", 3, 1), ("OPEN", 4, 1), ], ); write( &mut b, &[ ("DOOR", 0, 2), ("IS", 1, 2), ("STOP", 2, 2), ("AND", 3, 2), ("SHUT", 4, 2), ], ); let baba = b.place("baba", 0, 4); let key = b.place("key", 1, 4); let door = b.place("door", 2, 4); b.move_dir(Dir::Right); assert_eq!(b.pos_of(key), None); assert_eq!(b.pos_of(door), None); // Inferred, not stated by a source: Baba lands on the key's former tile. assert_eq!(b.pos_of(baba), Some((1, 4))); assert_eq!(b.kinds_at(2, 4), Vec::::new()); assert_eq!(b.kinds_at(1, 4), vec!["baba"]); } #[test] fn test_08_text_pushed() { let mut b = new_baba(empty_level(4, 5)); write(&mut b, &[("BABA", 0, 0), ("IS", 1, 0), ("YOU", 2, 0)]); let baba = b.place("baba", 0, 2); let rock_text = b.place("text:ROCK", 1, 2); write(&mut b, &[("IS", 2, 3), ("PUSH", 2, 4)]); assert_eq!(b.rules(), vec!["BABA IS YOU", "TEXT IS PUSH"]); b.move_dir(Dir::Right); assert_eq!(b.pos_of(baba), Some((1, 2))); assert_eq!(b.pos_of(rock_text), Some((2, 2))); assert_eq!( b.rules(), vec!["BABA IS YOU", "ROCK IS PUSH", "TEXT IS PUSH"] ); } #[test] fn test_08_level_edge_is_stop() { let mut b = new_baba(empty_level(3, 3)); write(&mut b, &[("BABA", 0, 0), ("IS", 1, 0), ("YOU", 2, 0)]); let baba = b.place("baba", 1, 2); let flag_text = b.place("text:FLAG", 2, 2); b.move_dir(Dir::Right); assert_eq!(b.pos_of(baba), Some((1, 2))); assert_eq!(b.pos_of(flag_text), Some((2, 2))); b.move_dir(Dir::Down); assert_eq!(b.pos_of(baba), Some((1, 2))); assert_eq!(b.pos_of(flag_text), Some((2, 2))); }