//! Part II: what each property does when an object moves. The engine plans a move //! one step at a time and runs these responses for every step, in this order (the //! order of the wiki's movement checks: OPEN/SHUT, then PUSH, then STOP). A new //! movement property is one more response here. use crate::engine::puzzle::{Planner, Response, Step}; /// The movement responses, in the order the engine runs them. pub fn responses() -> Vec { vec![open_shut, push, stop] } /// An OPEN object stepping onto a SHUT one (or a SHUT one onto an OPEN one) /// destroys both, and that object doesn't block the step. One partner per step: /// the oldest. fn open_shut(p: &mut Planner, s: Step) -> bool { for (mine, theirs) in [("OPEN", "SHUT"), ("SHUT", "OPEN")] { if !p.has(s.mover, mine) { continue; } let partner = p.staying_at(s.to).into_iter().find(|&o| p.has(o, theirs)); if let Some(partner) = partner { p.destroy(partner); p.destroy(s.mover); return true; } } true } /// Every PUSH object on the tile ahead must step the same way, or the step fails. fn push(p: &mut Planner, s: Step) -> bool { for o in p.staying_at(s.to) { if p.has(o, "PUSH") && !p.try_move(o) { return false; } } true } /// A STOP object still on the tile ahead blocks the step. fn stop(p: &mut Planner, s: Step) -> bool { !p.staying_at(s.to).into_iter().any(|o| p.has(o, "STOP")) }