feat: undo in Module 9 and stackAt from Module 8; Lesson 8 quote matches the reference
Baba.undo() restores the level before the last step or move (board snapshot: objects in age order with ids, the id counter, and won; rules recompiled). place clears the history. SpellGrid's undo throws/panics 'not supported'. stackAt / stack_at lists a tile's kinds oldest first, on Baba and SpellGrid. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
1 parent
21fb40c6f5
commit
820b378929
27 files changed
+530
-30
No files matched your search
@@ -7,6 +7,10 @@
|
||||
//!
|
||||
//! A turn (Module 9) runs the phases of `TURN` in order: movement, parse,
|
||||
//! conversion, parse, content's hazards, the win check, parse.
|
||||
//!
|
||||
//! Undo (Module 9): before each move or turn the level saves the board (every
|
||||
//! object's id, kind and position, oldest first, and the id counter) and `won`.
|
||||
//! The rules are not saved: undo restores the board and reparses.
|
||||
|
||||
use std::collections::BTreeSet;
|
||||
|
||||
@@ -26,6 +30,16 @@ pub struct Level {
|
||||
rules: Vec<Rule>,
|
||||
active: Vec<Rule>,
|
||||
won: bool,
|
||||
/// What `undo` puts back: one entry per move or turn, the latest last (Module 9).
|
||||
history: Vec<Snapshot>,
|
||||
}
|
||||
|
||||
/// The level before a move or a turn: the whole board (its objects, oldest first,
|
||||
/// and its id counter) and `won`.
|
||||
#[derive(Debug, Clone)]
|
||||
struct Snapshot {
|
||||
board: Board,
|
||||
won: bool,
|
||||
}
|
||||
|
||||
/// The property that makes an object move when the player moves.
|
||||
@@ -53,6 +67,7 @@ impl Level {
|
||||
rules: vec![],
|
||||
active: vec![],
|
||||
won: false,
|
||||
history: vec![],
|
||||
};
|
||||
for o in &def.objects {
|
||||
level.board.place(Kind::parse(&o.kind), o.x, o.y);
|
||||
@@ -63,6 +78,7 @@ impl Level {
|
||||
|
||||
pub fn place(&mut self, kind: &str, x: i32, y: i32) -> ObjectId {
|
||||
let id = self.board.place(Kind::parse(kind), x, y);
|
||||
self.history.clear();
|
||||
self.reparse();
|
||||
id
|
||||
}
|
||||
@@ -127,12 +143,14 @@ impl Level {
|
||||
/// Move every `YOU` object one tile in `dir`, then reparse (Module 8). Movement
|
||||
/// only: no conversion, hazard or win.
|
||||
pub fn move_you(&mut self, dir: Dir) {
|
||||
self.save();
|
||||
self.movement(dir);
|
||||
self.reparse();
|
||||
}
|
||||
|
||||
/// Play one turn: the phases of `TURN`, in order.
|
||||
pub fn step(&mut self, dir: Dir) {
|
||||
self.save();
|
||||
for phase in TURN {
|
||||
match phase {
|
||||
Phase::Movement => self.movement(dir),
|
||||
@@ -144,6 +162,26 @@ impl Level {
|
||||
}
|
||||
}
|
||||
|
||||
/// Put the level back as it was before the last move or turn (Module 9), and
|
||||
/// reparse. False, and no change, if there is none; `place` forgets them all.
|
||||
pub fn undo(&mut self) -> bool {
|
||||
let Some(last) = self.history.pop() else {
|
||||
return false;
|
||||
};
|
||||
self.board = last.board;
|
||||
self.won = last.won;
|
||||
self.reparse();
|
||||
true
|
||||
}
|
||||
|
||||
fn save(&mut self) {
|
||||
let snapshot = Snapshot {
|
||||
board: self.board.clone(),
|
||||
won: self.won,
|
||||
};
|
||||
self.history.push(snapshot);
|
||||
}
|
||||
|
||||
/// The `YOU` objects move one at a time, the one furthest ahead in `dir` first
|
||||
/// (oldest first on a tie); each one's move is planned in full, then committed,
|
||||
/// before the next is planned. Every move uses the rules in force before the
|
||||
|
||||
Reference in new issue
Block a user