harden engine rules, position invariants, and undo history

- make Position represent only valid board squares and use checked offsets
- make move endpoints fallible and remove unchecked coordinate arithmetic
- validate moves against generated legal moves, including mandatory capture
- track pending multi-captures and restrict continuation to the same piece
- derive pending state after undo/redo and preserve redo on invalid moves
- fix circular buffer wraparound, mixed iteration, and element drops
- adapt GTK and WASM to fallible endpoints and apply errors
- add rule, promotion, chain, history, and coordinate regression tests
This commit is contained in:
2026-10-19 19:43:05 +00:00
parent 5ab62eaabc
commit dc0ad17a95
8 changed files with 750 additions and 461 deletions
+7 -3
View File
@@ -433,7 +433,9 @@ fn create_game_window(
let am = available_moves.borrow();
if !am.is_empty() {
for mv in am.iter() {
let end_pos = mv.get_end_position();
let Some(end_pos) = mv.get_end_position() else {
continue;
};
let screen_position = match current_player {
Player::White => (8 - 1 - end_pos.row(), end_pos.col()),
Player::Red => (end_pos.row(), 8 - 1 - end_pos.col()),
@@ -519,10 +521,12 @@ fn create_game_window(
if !am.is_empty() {
if let Ok(pos) = position {
for mv in am.into_iter() {
if mv.get_end_position() == pos {
if mv.get_end_position() == Some(pos) {
let mut rd_app = rd.borrow_mut();
// println!("Applied move: {:?}", mv);
rd_app.apply_move(mv).unwrap();
if rd_app.apply_move(mv).is_err() {
continue;
}
// let game_copy = rd_app.game().clone();
// thread::spawn(move || {
// if let (Some(mv), analyzed_moves) =