feat: module 08 push chains

Movement planned in full, then committed: a Planner builds a plan
(moving and destroyed ids) by running content's movement responses
(OPEN/SHUT, PUSH, STOP) for every step, rolling back failed branches.
Edge of level blocks; YOU objects move furthest-ahead first; rules are
reparsed once after movement. Harness: move/move_dir(Dir), posOf,
kindsAt. Expansion Drop: PULL as one word plus one content response.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
Lucas Winther
2026-10-29 04:05:42 +01:00
co-authored by Claude Opus 5.5
parent d993457772
commit bd80cefbef
64 changed files with 6933 additions and 0 deletions
@@ -0,0 +1,29 @@
//! Part II: the rule-writing puzzle game. Objects have no behaviour of their own; every rule is
//! compiled from the text on the board, and recompiled whenever the board changes.
//!
//! Module 6: the grid, the lexer (text objects to words with grammatical roles)
//! and the parser (words to rules). The engine knows the operators `IS`, `AND`,
//! `NOT`, the meta-noun `TEXT` and the base rule `TEXT IS PUSH`. Every other word,
//! nouns included, is data handed in by content.
//!
//! Module 7: `IS NOT` in the parser, and the resolution pass (negation, then the
//! identity lock) that turns the parsed rules into the rules in force. Objects are
//! asked about through `Level::has_property`, which knows which nouns name them.
//!
//! Module 8: movement. `Level::move_you` plans each `YOU` object's move in full
//! (`Planner`), then commits it, then reparses. What a property does when something
//! moves is a `Response` that content provides; the engine runs them in order.
mod grid;
mod level;
mod movement;
mod parse;
mod resolve;
mod word;
pub use grid::{Board, Kind, LevelDef, LevelObject, Object, ObjectId};
pub use level::{Level, YOU};
pub use movement::{Dir, Plan, Planner, Response, Step};
pub use parse::{parse, Rule, BASE_RULES};
pub use resolve::resolve;
pub use word::{lex, Lexicon, Role, Selects, Token, WordDef};