Files
systemic-game-design-course/course/09-turn-pipeline/reference/rust/src/content/movement.rs
T
Lucas WintherandClaude Opus 5.5 1f3359cfe2 feat: module 09 turn pipeline
Module 9 lesson, scenarios, tests (8, both tracks), reference engines
(TURN phase list, conversion, content-registered hazards, win/lost),
WEAK Expansion Drop, harness.md M9 semantics, research notes (WEAK page,
baba-is-auto Game::MovePlayer, X IS NOT X placement reading).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-29 04:28:17 +01:00

45 lines
1.5 KiB
Rust

//! 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<Response> {
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"))
}