refactor(core): migrate GameState to GameContext and update FEN handling
Build & Test (NowChessSystems) TeamCity build failed
Build & Test (NowChessSystems) TeamCity build failed
This commit is contained in:
@@ -8,6 +8,7 @@ import de.nowchess.api.board.{Color, Square}
|
||||
* @param kingSide king-side castling still legally available
|
||||
* @param queenSide queen-side castling still legally available
|
||||
*/
|
||||
@deprecated("Use de.nowchess.api.board.CastlingRights via GameContext.", "NCS-22")
|
||||
final case class CastlingRights(kingSide: Boolean, queenSide: Boolean)
|
||||
|
||||
object CastlingRights:
|
||||
@@ -15,12 +16,14 @@ object CastlingRights:
|
||||
val Both: CastlingRights = CastlingRights(kingSide = true, queenSide = true)
|
||||
|
||||
/** Outcome of a finished game. */
|
||||
@deprecated("Use GameContext and derive game lifecycle from rules/engine state.", "NCS-22")
|
||||
enum GameResult:
|
||||
case WhiteWins
|
||||
case BlackWins
|
||||
case Draw
|
||||
|
||||
/** Lifecycle state of a game. */
|
||||
@deprecated("Use GameContext and engine events for lifecycle handling.", "NCS-22")
|
||||
enum GameStatus:
|
||||
case NotStarted
|
||||
case InProgress
|
||||
@@ -42,6 +45,7 @@ enum GameStatus:
|
||||
* @param fullMoveNumber increments after Black's move, starts at 1
|
||||
* @param status current lifecycle status of the game
|
||||
*/
|
||||
@deprecated("Use GameContext for runtime state; keep GameState only for legacy compatibility.", "NCS-22")
|
||||
final case class GameState(
|
||||
piecePlacement: String,
|
||||
activeColor: Color,
|
||||
|
||||
@@ -0,0 +1,63 @@
|
||||
package de.nowchess.api.game
|
||||
|
||||
import de.nowchess.api.board.{Board, CastlingRights, Color, File, Rank, Square}
|
||||
import de.nowchess.api.move.Move
|
||||
import org.scalatest.funsuite.AnyFunSuite
|
||||
import org.scalatest.matchers.should.Matchers
|
||||
|
||||
class GameContextTest extends AnyFunSuite with Matchers:
|
||||
|
||||
test("GameContext.initial has initial board"):
|
||||
GameContext.initial.board shouldBe Board.initial
|
||||
|
||||
test("GameContext.initial active color is White"):
|
||||
GameContext.initial.turn shouldBe Color.White
|
||||
|
||||
test("GameContext.initial has full castling rights"):
|
||||
GameContext.initial.castlingRights shouldBe CastlingRights.Initial
|
||||
|
||||
test("GameContext.initial en-passant square is None"):
|
||||
GameContext.initial.enPassantSquare shouldBe None
|
||||
|
||||
test("GameContext.initial half-move clock is 0"):
|
||||
GameContext.initial.halfMoveClock shouldBe 0
|
||||
|
||||
test("GameContext.initial move history is empty"):
|
||||
GameContext.initial.moves shouldBe List.empty
|
||||
|
||||
test("withBoard updates only board"):
|
||||
val square = Square(File.E, Rank.R4)
|
||||
val updatedBoard = Board.initial.updated(square, de.nowchess.api.board.Piece.WhiteQueen)
|
||||
val updated = GameContext.initial.withBoard(updatedBoard)
|
||||
updated.board shouldBe updatedBoard
|
||||
updated.turn shouldBe GameContext.initial.turn
|
||||
updated.castlingRights shouldBe GameContext.initial.castlingRights
|
||||
updated.enPassantSquare shouldBe GameContext.initial.enPassantSquare
|
||||
updated.halfMoveClock shouldBe GameContext.initial.halfMoveClock
|
||||
updated.moves shouldBe GameContext.initial.moves
|
||||
|
||||
test("withTurn updates only turn"):
|
||||
val updated = GameContext.initial.withTurn(Color.Black)
|
||||
updated.turn shouldBe Color.Black
|
||||
updated.board shouldBe GameContext.initial.board
|
||||
|
||||
test("withCastlingRights updates castling rights"):
|
||||
val rights = CastlingRights(
|
||||
whiteKingSide = true,
|
||||
whiteQueenSide = false,
|
||||
blackKingSide = false,
|
||||
blackQueenSide = true
|
||||
)
|
||||
GameContext.initial.withCastlingRights(rights).castlingRights shouldBe rights
|
||||
|
||||
test("withEnPassantSquare updates en-passant square"):
|
||||
val square = Some(Square(File.E, Rank.R3))
|
||||
GameContext.initial.withEnPassantSquare(square).enPassantSquare shouldBe square
|
||||
|
||||
test("withHalfMoveClock updates half-move clock"):
|
||||
GameContext.initial.withHalfMoveClock(17).halfMoveClock shouldBe 17
|
||||
|
||||
test("withMove appends move to history"):
|
||||
val move = Move(Square(File.E, Rank.R2), Square(File.E, Rank.R4))
|
||||
GameContext.initial.withMove(move).moves shouldBe List(move)
|
||||
|
||||
@@ -1,77 +0,0 @@
|
||||
package de.nowchess.api.game
|
||||
|
||||
import de.nowchess.api.board.Color
|
||||
import org.scalatest.funsuite.AnyFunSuite
|
||||
import org.scalatest.matchers.should.Matchers
|
||||
|
||||
class GameStateTest extends AnyFunSuite with Matchers:
|
||||
|
||||
test("CastlingRights.None has both flags false") {
|
||||
CastlingRights.None.kingSide shouldBe false
|
||||
CastlingRights.None.queenSide shouldBe false
|
||||
}
|
||||
|
||||
test("CastlingRights.Both has both flags true") {
|
||||
CastlingRights.Both.kingSide shouldBe true
|
||||
CastlingRights.Both.queenSide shouldBe true
|
||||
}
|
||||
|
||||
test("CastlingRights constructor sets fields") {
|
||||
val cr = CastlingRights(kingSide = true, queenSide = false)
|
||||
cr.kingSide shouldBe true
|
||||
cr.queenSide shouldBe false
|
||||
}
|
||||
|
||||
test("GameResult cases exist") {
|
||||
GameResult.WhiteWins shouldBe GameResult.WhiteWins
|
||||
GameResult.BlackWins shouldBe GameResult.BlackWins
|
||||
GameResult.Draw shouldBe GameResult.Draw
|
||||
}
|
||||
|
||||
test("GameStatus.NotStarted") {
|
||||
GameStatus.NotStarted shouldBe GameStatus.NotStarted
|
||||
}
|
||||
|
||||
test("GameStatus.InProgress") {
|
||||
GameStatus.InProgress shouldBe GameStatus.InProgress
|
||||
}
|
||||
|
||||
test("GameStatus.Finished carries result") {
|
||||
val status = GameStatus.Finished(GameResult.Draw)
|
||||
status shouldBe GameStatus.Finished(GameResult.Draw)
|
||||
status match
|
||||
case GameStatus.Finished(r) => r shouldBe GameResult.Draw
|
||||
case _ => fail("expected Finished")
|
||||
}
|
||||
|
||||
test("GameState.initial has standard FEN piece placement") {
|
||||
GameState.initial.piecePlacement shouldBe "rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR"
|
||||
}
|
||||
|
||||
test("GameState.initial active color is White") {
|
||||
GameState.initial.activeColor shouldBe Color.White
|
||||
}
|
||||
|
||||
test("GameState.initial white has full castling rights") {
|
||||
GameState.initial.castlingWhite shouldBe CastlingRights.Both
|
||||
}
|
||||
|
||||
test("GameState.initial black has full castling rights") {
|
||||
GameState.initial.castlingBlack shouldBe CastlingRights.Both
|
||||
}
|
||||
|
||||
test("GameState.initial en-passant target is None") {
|
||||
GameState.initial.enPassantTarget shouldBe None
|
||||
}
|
||||
|
||||
test("GameState.initial half-move clock is 0") {
|
||||
GameState.initial.halfMoveClock shouldBe 0
|
||||
}
|
||||
|
||||
test("GameState.initial full-move number is 1") {
|
||||
GameState.initial.fullMoveNumber shouldBe 1
|
||||
}
|
||||
|
||||
test("GameState.initial status is InProgress") {
|
||||
GameState.initial.status shouldBe GameStatus.InProgress
|
||||
}
|
||||
Reference in New Issue
Block a user