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 <[email protected]>
52 lines
2.1 KiB
Rust
52 lines
2.1 KiB
Rust
//! Content: the cards and the Baba Is You words. Only this directory (and the card data in `cards/`) may name
|
||
//! specific cards, or specific Baba Is You nouns.
|
||
//!
|
||
//! From Module 5 every card is a JSON file in `cards/` at the crate root, in the
|
||
//! course's card format (`course/schema/card.schema.json`). The functions that
|
||
//! were card effects in Modules 2–4 are gone: the engine interprets the data.
|
||
//! `start-module` copies the course's card files into `cards/`; add your own there.
|
||
|
||
use std::path::Path;
|
||
use std::sync::OnceLock;
|
||
|
||
use crate::engine::CardDef;
|
||
|
||
mod movement;
|
||
pub use movement::responses as movement;
|
||
|
||
/// Every card in `cards/`, in file-name order. Read once per test run.
|
||
pub fn cards() -> Vec<CardDef> {
|
||
static CARDS: OnceLock<Vec<CardDef>> = OnceLock::new();
|
||
CARDS
|
||
.get_or_init(|| load_dir(&Path::new(env!("CARGO_MANIFEST_DIR")).join("cards")))
|
||
.clone()
|
||
}
|
||
|
||
/// Parse every `.json` file in `dir` as a card definition.
|
||
pub fn load_dir(dir: &Path) -> Vec<CardDef> {
|
||
let entries = std::fs::read_dir(dir)
|
||
.unwrap_or_else(|e| panic!("cannot read card directory {}: {e}", dir.display()));
|
||
let mut paths: Vec<_> = entries
|
||
.map(|entry| entry.expect("card directory entry").path())
|
||
.filter(|p| p.extension().and_then(|x| x.to_str()) == Some("json"))
|
||
.collect();
|
||
paths.sort();
|
||
paths
|
||
.iter()
|
||
.map(|path| {
|
||
let text = std::fs::read_to_string(path)
|
||
.unwrap_or_else(|e| panic!("cannot read {}: {e}", path.display()));
|
||
serde_json::from_str(&text)
|
||
.unwrap_or_else(|e| panic!("{} is not a valid card: {e}", path.display()))
|
||
})
|
||
.collect()
|
||
}
|
||
|
||
/// Part II: the words of Baba Is You the parser can read, besides the engine's own
|
||
/// (`IS`, `AND`, `NOT`, `TEXT`). Nouns and properties are data: a new word is one
|
||
/// more entry in `words.json` in this directory.
|
||
pub fn words() -> Vec<crate::engine::puzzle::WordDef> {
|
||
serde_json::from_str(include_str!("words.json"))
|
||
.expect("src/content/words.json is not a word list")
|
||
}
|