feat: include castling moves in GameRules.legalMoves
Switch legalMoves to the context-aware MoveValidator.legalTargets(ctx, from) so castling destinations are included, and simulate castle moves via withCastle when filtering for self-check. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -24,9 +24,13 @@ object GameRules:
|
|||||||
ctx.board.pieces
|
ctx.board.pieces
|
||||||
.collect { case (from, piece) if piece.color == color => from }
|
.collect { case (from, piece) if piece.color == color => from }
|
||||||
.flatMap { from =>
|
.flatMap { from =>
|
||||||
MoveValidator.legalTargets(ctx.board, from)
|
MoveValidator.legalTargets(ctx, from) // context-aware: includes castling
|
||||||
.filter { to =>
|
.filter { to =>
|
||||||
val (newBoard, _) = ctx.board.withMove(from, to)
|
val newBoard =
|
||||||
|
if MoveValidator.isCastle(ctx.board, from, to) then
|
||||||
|
ctx.board.withCastle(color, MoveValidator.castleSide(from, to))
|
||||||
|
else
|
||||||
|
ctx.board.withMove(from, to)._1
|
||||||
!isInCheck(newBoard, color)
|
!isInCheck(newBoard, color)
|
||||||
}
|
}
|
||||||
.map(to => from -> to)
|
.map(to => from -> to)
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
package de.nowchess.chess.logic
|
package de.nowchess.chess.logic
|
||||||
|
|
||||||
import de.nowchess.api.board.*
|
import de.nowchess.api.board.*
|
||||||
|
import de.nowchess.api.game.CastlingRights
|
||||||
import de.nowchess.chess.logic.GameContext
|
import de.nowchess.chess.logic.GameContext
|
||||||
import org.scalatest.funsuite.AnyFunSuite
|
import org.scalatest.funsuite.AnyFunSuite
|
||||||
import org.scalatest.matchers.should.Matchers
|
import org.scalatest.matchers.should.Matchers
|
||||||
@@ -88,3 +89,28 @@ class GameRulesTest extends AnyFunSuite with Matchers:
|
|||||||
|
|
||||||
test("gameStatus: normal starting position returns Normal"):
|
test("gameStatus: normal starting position returns Normal"):
|
||||||
GameRules.gameStatus(Board.initial, Color.White) shouldBe PositionStatus.Normal
|
GameRules.gameStatus(Board.initial, Color.White) shouldBe PositionStatus.Normal
|
||||||
|
|
||||||
|
test("legalMoves: includes castling destination when available"):
|
||||||
|
val c = GameContext(
|
||||||
|
board = board(
|
||||||
|
sq(File.E, Rank.R1) -> Piece.WhiteKing,
|
||||||
|
sq(File.H, Rank.R1) -> Piece.WhiteRook,
|
||||||
|
sq(File.H, Rank.R8) -> Piece.BlackKing
|
||||||
|
),
|
||||||
|
whiteCastling = CastlingRights.Both,
|
||||||
|
blackCastling = CastlingRights.None
|
||||||
|
)
|
||||||
|
GameRules.legalMoves(c, Color.White) should contain(sq(File.E, Rank.R1) -> sq(File.G, Rank.R1))
|
||||||
|
|
||||||
|
test("legalMoves: excludes castling when king is in check"):
|
||||||
|
val c = GameContext(
|
||||||
|
board = board(
|
||||||
|
sq(File.E, Rank.R1) -> Piece.WhiteKing,
|
||||||
|
sq(File.H, Rank.R1) -> Piece.WhiteRook,
|
||||||
|
sq(File.E, Rank.R8) -> Piece.BlackRook,
|
||||||
|
sq(File.A, Rank.R8) -> Piece.BlackKing
|
||||||
|
),
|
||||||
|
whiteCastling = CastlingRights.Both,
|
||||||
|
blackCastling = CastlingRights.None
|
||||||
|
)
|
||||||
|
GameRules.legalMoves(c, Color.White) should not contain (sq(File.E, Rank.R1) -> sq(File.G, Rank.R1))
|
||||||
|
|||||||
Reference in New Issue
Block a user