refactor: migrate GameRules.legalMoves signature to GameContext
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -1,6 +1,7 @@
|
||||
package de.nowchess.chess.logic
|
||||
|
||||
import de.nowchess.api.board.*
|
||||
import de.nowchess.chess.logic.GameContext
|
||||
|
||||
enum PositionStatus:
|
||||
case Normal, InCheck, Mated, Drawn
|
||||
@@ -19,13 +20,13 @@ object GameRules:
|
||||
}
|
||||
|
||||
/** All (from, to) moves for `color` that do not leave their own king in check. */
|
||||
def legalMoves(board: Board, color: Color): Set[(Square, Square)] =
|
||||
board.pieces
|
||||
def legalMoves(ctx: GameContext, color: Color): Set[(Square, Square)] =
|
||||
ctx.board.pieces
|
||||
.collect { case (from, piece) if piece.color == color => from }
|
||||
.flatMap { from =>
|
||||
MoveValidator.legalTargets(board, from)
|
||||
MoveValidator.legalTargets(ctx.board, from)
|
||||
.filter { to =>
|
||||
val (newBoard, _) = board.withMove(from, to)
|
||||
val (newBoard, _) = ctx.board.withMove(from, to)
|
||||
!isInCheck(newBoard, color)
|
||||
}
|
||||
.map(to => from -> to)
|
||||
@@ -34,7 +35,7 @@ object GameRules:
|
||||
|
||||
/** Position status for the side whose turn it is (`color`). */
|
||||
def gameStatus(board: Board, color: Color): PositionStatus =
|
||||
val moves = legalMoves(board, color)
|
||||
val moves = legalMoves(GameContext(board), color)
|
||||
val inCheck = isInCheck(board, color)
|
||||
if moves.isEmpty && inCheck then PositionStatus.Mated
|
||||
else if moves.isEmpty then PositionStatus.Drawn
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
package de.nowchess.chess.logic
|
||||
|
||||
import de.nowchess.api.board.*
|
||||
import de.nowchess.chess.logic.GameContext
|
||||
import org.scalatest.funsuite.AnyFunSuite
|
||||
import org.scalatest.matchers.should.Matchers
|
||||
|
||||
@@ -9,6 +10,9 @@ class GameRulesTest extends AnyFunSuite with Matchers:
|
||||
private def sq(f: File, r: Rank): Square = Square(f, r)
|
||||
private def board(entries: (Square, Piece)*): Board = Board(entries.toMap)
|
||||
|
||||
/** Wrap a board in a GameContext with no castling rights — for non-castling tests. */
|
||||
private def ctx(entries: (Square, Piece)*): GameContext = GameContext(Board(entries.toMap))
|
||||
|
||||
// ──── isInCheck ──────────────────────────────────────────────────────
|
||||
|
||||
test("isInCheck: king attacked by enemy rook on same rank"):
|
||||
@@ -36,22 +40,20 @@ class GameRulesTest extends AnyFunSuite with Matchers:
|
||||
test("legalMoves: move that exposes own king to rook is excluded"):
|
||||
// White King E1, White Rook E4 (pinned on E-file), Black Rook E8
|
||||
// Moving the White Rook off the E-file would expose the king
|
||||
val b = board(
|
||||
val moves = GameRules.legalMoves(ctx(
|
||||
sq(File.E, Rank.R1) -> Piece.WhiteKing,
|
||||
sq(File.E, Rank.R4) -> Piece.WhiteRook,
|
||||
sq(File.E, Rank.R8) -> Piece.BlackRook
|
||||
)
|
||||
val moves = GameRules.legalMoves(b, Color.White)
|
||||
), Color.White)
|
||||
moves should not contain (sq(File.E, Rank.R4) -> sq(File.D, Rank.R4))
|
||||
|
||||
test("legalMoves: move that blocks check is included"):
|
||||
// White King E1 in check from Black Rook E8; White Rook A5 can interpose on E5
|
||||
val b = board(
|
||||
val moves = GameRules.legalMoves(ctx(
|
||||
sq(File.E, Rank.R1) -> Piece.WhiteKing,
|
||||
sq(File.A, Rank.R5) -> Piece.WhiteRook,
|
||||
sq(File.E, Rank.R8) -> Piece.BlackRook
|
||||
)
|
||||
val moves = GameRules.legalMoves(b, Color.White)
|
||||
), Color.White)
|
||||
moves should contain(sq(File.A, Rank.R5) -> sq(File.E, Rank.R5))
|
||||
|
||||
// ──── gameStatus ──────────────────────────────────────────────────────
|
||||
|
||||
Reference in New Issue
Block a user