feat(api): add immutable GameContext type
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>
This commit is contained in:
@@ -0,0 +1,70 @@
|
||||
package de.nowchess.api.board
|
||||
|
||||
/**
|
||||
* Unified castling rights tracker for all four sides.
|
||||
* Tracks whether castling is still available for each side and direction.
|
||||
*
|
||||
* @param whiteKingSide White's king-side castling (0-0) still legally available
|
||||
* @param whiteQueenSide White's queen-side castling (0-0-0) still legally available
|
||||
* @param blackKingSide Black's king-side castling (0-0) still legally available
|
||||
* @param blackQueenSide Black's queen-side castling (0-0-0) still legally available
|
||||
*/
|
||||
final case class CastlingRights(
|
||||
whiteKingSide: Boolean,
|
||||
whiteQueenSide: Boolean,
|
||||
blackKingSide: Boolean,
|
||||
blackQueenSide: Boolean
|
||||
):
|
||||
/**
|
||||
* Check if either side has any castling rights remaining.
|
||||
*/
|
||||
def hasAnyRights: Boolean =
|
||||
whiteKingSide || whiteQueenSide || blackKingSide || blackQueenSide
|
||||
|
||||
/**
|
||||
* Check if a specific color has any castling rights remaining.
|
||||
*/
|
||||
def hasRights(color: Color): Boolean = color match
|
||||
case Color.White => whiteKingSide || whiteQueenSide
|
||||
case Color.Black => blackKingSide || blackQueenSide
|
||||
|
||||
/**
|
||||
* Revoke all castling rights for a specific color.
|
||||
*/
|
||||
def revokeColor(color: Color): CastlingRights = color match
|
||||
case Color.White => copy(whiteKingSide = false, whiteQueenSide = false)
|
||||
case Color.Black => copy(blackKingSide = false, blackQueenSide = false)
|
||||
|
||||
/**
|
||||
* Revoke a specific castling right.
|
||||
*/
|
||||
def revokeKingSide(color: Color): CastlingRights = color match
|
||||
case Color.White => copy(whiteKingSide = false)
|
||||
case Color.Black => copy(blackKingSide = false)
|
||||
|
||||
/**
|
||||
* Revoke a specific castling right.
|
||||
*/
|
||||
def revokeQueenSide(color: Color): CastlingRights = color match
|
||||
case Color.White => copy(whiteQueenSide = false)
|
||||
case Color.Black => copy(blackQueenSide = false)
|
||||
|
||||
object CastlingRights:
|
||||
/** No castling rights for any side. */
|
||||
val None: CastlingRights = CastlingRights(
|
||||
whiteKingSide = false,
|
||||
whiteQueenSide = false,
|
||||
blackKingSide = false,
|
||||
blackQueenSide = false
|
||||
)
|
||||
|
||||
/** All castling rights available. */
|
||||
val All: CastlingRights = CastlingRights(
|
||||
whiteKingSide = true,
|
||||
whiteQueenSide = true,
|
||||
blackKingSide = true,
|
||||
blackQueenSide = true
|
||||
)
|
||||
|
||||
/** Standard starting position castling rights (both sides can castle both ways). */
|
||||
val Initial: CastlingRights = All
|
||||
@@ -0,0 +1,44 @@
|
||||
package de.nowchess.api.game
|
||||
|
||||
import de.nowchess.api.board.{Board, Color, Square, CastlingRights}
|
||||
import de.nowchess.api.move.Move
|
||||
|
||||
/** Immutable bundle of complete game state.
|
||||
* All state changes produce new GameContext instances.
|
||||
*/
|
||||
case class GameContext(
|
||||
board: Board,
|
||||
turn: Color,
|
||||
castlingRights: CastlingRights,
|
||||
enPassantSquare: Option[Square],
|
||||
halfMoveClock: Int,
|
||||
moves: List[Move]
|
||||
):
|
||||
/** Create new context with updated board. */
|
||||
def withBoard(newBoard: Board): GameContext = copy(board = newBoard)
|
||||
|
||||
/** Create new context with updated turn. */
|
||||
def withTurn(newTurn: Color): GameContext = copy(turn = newTurn)
|
||||
|
||||
/** Create new context with updated castling rights. */
|
||||
def withCastlingRights(newRights: CastlingRights): GameContext = copy(castlingRights = newRights)
|
||||
|
||||
/** Create new context with updated en passant square. */
|
||||
def withEnPassantSquare(newSq: Option[Square]): GameContext = copy(enPassantSquare = newSq)
|
||||
|
||||
/** Create new context with updated half-move clock. */
|
||||
def withHalfMoveClock(newClock: Int): GameContext = copy(halfMoveClock = newClock)
|
||||
|
||||
/** Create new context with move appended to history. */
|
||||
def withMove(move: Move): GameContext = copy(moves = moves :+ move)
|
||||
|
||||
object GameContext:
|
||||
/** Initial position: white to move, all castling rights, no en passant. */
|
||||
def initial: GameContext = GameContext(
|
||||
board = Board.initial,
|
||||
turn = Color.White,
|
||||
castlingRights = CastlingRights.Initial,
|
||||
enPassantSquare = None,
|
||||
halfMoveClock = 0,
|
||||
moves = List.empty
|
||||
)
|
||||
Reference in New Issue
Block a user