- Removed unused CastleSide import from PgnExporter
- Updated TerminalUI and GUIObserver to use GameContext
- Temporarily disabled GUI FEN/PGN import-export (requires full rework with GameContext)
- Deleted unused logic files and GameController per spec
Note: GameEngine still needs final refactoring to use RuleSet + GameContext.
Core architecture (api -> rule -> core) is structurally complete.
Task 6: Updated all GameEvent case classes to use context: GameContext instead of separate board/history/turn
Task 7: Deleted old logic files and restored as compatibility layer in modules/api
Task 8: Verified build - main source compilation succeeds
Changes:
- Updated Observer.scala events: all GameEvent subclasses now accept GameContext
- Restored GameHistory and HistoryMove to modules/api as compatibility types
- Restored logic files (GameRules, MoveValidator, etc.) with updated imports
- Updated GameEngine to use currentContext helper for event creation
- Updated GameController to convert CastleSide to String for HistoryMove
- Updated PgnParser/PgnExporter to work with String representation of castling
- Added modules:rule to settings.gradle.kts for dependency resolution
- All main source code compiles successfully; tests expected to need refactoring
Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com>
Replace Situation parameter with GameContext across all RuleSet methods
to align with the new game state abstraction. Updated imports to use the
api module's types (GameContext, Square, Move).
StandardRules will need to be updated in Task 3 to implement the new
interface signature and use api types instead of maichess.
Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com>
Bundles complete game state (board, turn, castling rights, en passant, halfMoveClock, moves)
with immutable builder methods for functional state transitions.
Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com>
Summary
- Implements the FIDE 50-move draw rule: a player may claim a draw if no pawn move or capture has occurred in the last
50 full moves (100 half-moves)
- Draw is not automatic — the eligible player must claim it via a TUI menu shown at the start of their turn
- halfMoveClock: Int is threaded through processMove and gameLoop; resets on pawn move, capture, or en passant;
increments on all other moves
Changes
- GameController.scala: extended MoveResult.Moved and MoveResult.MovedInCheck with newHalfMoveClock: Int; added
MoveResult.DrawClaimed; added halfMoveClock parameter to processMove and gameLoop; TUI menu shown when clock ≥ 100
- Main.scala: initial gameLoop call passes halfMoveClock = 0
- GameControllerTest.scala: updated all existing pattern matches; added 10 new tests covering clock reset, clock
increment, draw claim, and TUI menu behaviour
Test plan
- processMove: 'draw' with halfMoveClock = 100 → DrawClaimed
- processMove: 'draw' with halfMoveClock = 99 → InvalidFormat
- Pawn move / capture / en passant → clock resets to 0
- Quiet piece move → clock increments by 1
- MovedInCheck carries updated clock
- TUI menu appears when clock ≥ 100; option 1 claims draw, option 2 continues
- No TUI menu when clock < 100
- All 197 tests passing
Co-authored-by: LQ63 <lkhermann@web.de>
Reviewed-on: #9
Co-authored-by: Leon Hermann <lq@blackhole.local>
Co-committed-by: Leon Hermann <lq@blackhole.local>
- Add EnPassantCalculator to derive the en passant target square from GameHistory, detect en passant captures, and
compute the captured pawn's square
- Extend MoveValidator.legalTargets to include the en passant diagonal square in pawn legal targets
- Extend GameController.processMove to remove the captured pawn from the board when an en passant capture is played
Details
En passant is derived purely from the last HistoryMove — no new state is introduced. If the last move was a double
pawn push, the target square is the square the pawn passed through. The board mutation follows the same pattern as
castling: board.withMove moves the capturing pawn, then board.removed removes the captured pawn from its actual square
(which differs from the destination square).
Test Plan
- EnPassantCalculatorTest — 14 unit tests covering target derivation, captured square calculation, and capture
detection for both colors
- MoveValidatorTest — 5 new tests: ep target included/excluded based on history, adjacency filter, both colors, case _
branch coverage
- GameControllerTest — 2 integration tests: white and black en passant capture removes pawn from board and returns
correct captured piece
- 100% scoverage (line/branch/method) confirmed
Co-authored-by: LQ63 <lkhermann@web.de>
Reviewed-on: #8
Reviewed-by: Janis <janis-e@gmx.de>
Co-authored-by: Leon Hermann <lq@blackhole.local>
Co-committed-by: Leon Hermann <lq@blackhole.local>
## Summary
- Introduces `GameContext` wrapper (board + castling rights) threading through the entire engine pipeline
- Extends `MoveValidator` with `castlingTargets`, context-aware `legalTargets`/`isLegal` overloads, and helpers (`isCastle`, `castleSide`)
- Updates `GameRules.legalMoves` and `gameStatus` to use `GameContext`, preventing false stalemate when castling is the only legal move
- Adds castle detection and atomic execution (`withCastle`) to `GameController.processMove`, plus full rights revocation via source- and
destination-square tables
## Test Plan
- [ ] 142 tests passing, 100% statement and branch coverage on `modules/core`
- [ ] White/Black kingside (e1g1/e8g8) and queenside (e1c1/e8c8) castling moves execute correctly
- [ ] All six legality conditions enforced (rights flags, home squares, empty transit, king not in check, transit/landing squares not attacked)
- [ ] Rights revoked on king moves, own rook moves, castle moves, and enemy rook captures
- [ ] False stalemate correctly prevented when castling is the only escape
Co-authored-by: LQ63 <lkhermann@web.de>
Co-authored-by: Janis <janis.e.20@gmx.de>
Reviewed-on: #1
Reviewed-by: Janis <janis-e@gmx.de>
Co-authored-by: Leon Hermann <lq@blackhole.local>
Co-committed-by: Leon Hermann <lq@blackhole.local>
The three GameControllerTest bugs described in the entry have been fixed
by the test-writer agent; the file contained no other entries.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Add BlackKing/WhiteKing to capture board in 'legal capture returns Moved'
so the position is not treated as stalemate after the capture.
- Move WhiteKing from A3 to C3 in three MovedInCheck tests so it no
longer blocks the rook's path along file A.
- Remove Console.withOut(System.out) from withInput so it no longer
overrides the ByteArrayOutputStream installed by captureOutput.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Replace stub branches with GameRules.gameStatus dispatch in processMove
and fill in MovedInCheck/Checkmate/Stalemate cases in gameLoop.
Document 6 pre-existing test bugs in docs/unresolved.md.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>