feat: NCS-11 propagate half-move clock flags through GameController
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -63,7 +63,8 @@ object GameController:
|
||||
case PromotionPiece.Bishop => PieceType.Bishop
|
||||
case PromotionPiece.Knight => PieceType.Knight
|
||||
val newBoard = boardAfterMove.updated(to, Piece(turn, promotedPieceType))
|
||||
val newHistory = history.addMove(from, to, None, Some(piece))
|
||||
// Promotion is always a pawn move → clock resets
|
||||
val newHistory = history.addMove(from, to, None, Some(piece), wasPawnMove = true)
|
||||
toMoveResult(newBoard, newHistory, captured, turn)
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
@@ -91,7 +92,9 @@ object GameController:
|
||||
val capturedSq = EnPassantCalculator.capturedPawnSquare(to, turn)
|
||||
(b.removed(capturedSq), board.pieceAt(capturedSq))
|
||||
else (b, cap)
|
||||
val newHistory = history.addMove(from, to, castleOpt)
|
||||
val wasPawnMove = board.pieceAt(from).exists(_.pieceType == PieceType.Pawn)
|
||||
val wasCapture = captured.isDefined
|
||||
val newHistory = history.addMove(from, to, castleOpt, wasPawnMove = wasPawnMove, wasCapture = wasCapture)
|
||||
toMoveResult(newBoard, newHistory, captured, turn)
|
||||
|
||||
private def toMoveResult(newBoard: Board, newHistory: GameHistory, captured: Option[Piece], turn: Color): MoveResult =
|
||||
|
||||
@@ -488,3 +488,39 @@ class GameControllerTest extends AnyFunSuite with Matchers:
|
||||
PromotionPiece.Knight, Color.White
|
||||
)
|
||||
result should be (MoveResult.Stalemate)
|
||||
|
||||
// ──── half-move clock propagation ────────────────────────────────────
|
||||
|
||||
test("processMove: non-pawn non-capture increments halfMoveClock"):
|
||||
// g1f3 is a knight move — not a pawn, not a capture
|
||||
processMove(Board.initial, GameHistory.empty, Color.White, "g1f3") match
|
||||
case MoveResult.Moved(_, newHistory, _, _) =>
|
||||
newHistory.halfMoveClock shouldBe 1
|
||||
case other => fail(s"Expected Moved, got $other")
|
||||
|
||||
test("processMove: pawn move resets halfMoveClock to 0"):
|
||||
processMove(Board.initial, GameHistory.empty, Color.White, "e2e4") match
|
||||
case MoveResult.Moved(_, newHistory, _, _) =>
|
||||
newHistory.halfMoveClock shouldBe 0
|
||||
case other => fail(s"Expected Moved, got $other")
|
||||
|
||||
test("processMove: capture resets halfMoveClock to 0"):
|
||||
// White pawn on e5, Black pawn on d6 — exd6 is a capture
|
||||
val board = Board(Map(
|
||||
sq(File.E, Rank.R5) -> Piece.WhitePawn,
|
||||
sq(File.D, Rank.R6) -> Piece.BlackPawn,
|
||||
sq(File.E, Rank.R1) -> Piece.WhiteKing,
|
||||
sq(File.E, Rank.R8) -> Piece.BlackKing
|
||||
))
|
||||
val history = GameHistory(halfMoveClock = 10)
|
||||
processMove(board, history, Color.White, "e5d6") match
|
||||
case MoveResult.Moved(_, newHistory, _, _) =>
|
||||
newHistory.halfMoveClock shouldBe 0
|
||||
case other => fail(s"Expected Moved, got $other")
|
||||
|
||||
test("processMove: clock carries from previous history on non-pawn non-capture"):
|
||||
val history = GameHistory(halfMoveClock = 5)
|
||||
processMove(Board.initial, history, Color.White, "g1f3") match
|
||||
case MoveResult.Moved(_, newHistory, _, _) =>
|
||||
newHistory.halfMoveClock shouldBe 6
|
||||
case other => fail(s"Expected Moved, got $other")
|
||||
|
||||
Reference in New Issue
Block a user