feat: I/O json export import with 100% coverage
Build & Test (NowChessSystems) TeamCity build finished
Build & Test (NowChessSystems) TeamCity build finished
- Full FEN parser tests - Json exporter with all move types covered - CastleKingside branch coverage Co-Authored-By: Claude Opus 4.6
This commit is contained in:
@@ -188,26 +188,3 @@
|
||||
* correct test board positions and captureOutput/withInput interaction ([f0481e2](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/f0481e2561b779df00925b46ee281dc36a795150))
|
||||
* update main class path in build configuration and adjust VCS directory mapping ([7b1f8b1](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/7b1f8b117623d327232a1a92a8a44d18582e0189))
|
||||
* update move validation to check for king safety ([#13](https://git.janis-eccarius.de/NowChess/NowChessSystems/issues/13)) ([e5e20c5](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/e5e20c566e368b12ca1dc59680c34e9112bf6762))
|
||||
## (2026-04-07)
|
||||
|
||||
### Features
|
||||
|
||||
* add GameRules stub with PositionStatus enum ([76d4168](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/76d4168038de23e5d6083d4e8f0504fbf31d15a3))
|
||||
* add MovedInCheck/Checkmate/Stalemate MoveResult variants (stub dispatch) ([8b7ec57](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/8b7ec57e5ea6ee1615a1883848a426dc07d26364))
|
||||
* implement GameRules with isInCheck, legalMoves, gameStatus ([94a02ff](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/94a02ff6849436d9496c70a0f16c21666dae8e4e))
|
||||
* implement legal castling ([#1](https://git.janis-eccarius.de/NowChess/NowChessSystems/issues/1)) ([00d326c](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/00d326c1ba67711fbe180f04e1100c3f01dd0254))
|
||||
* NCS-10 Implement Pawn Promotion ([#12](https://git.janis-eccarius.de/NowChess/NowChessSystems/issues/12)) ([13bfc16](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/13bfc16cfe25db78ec607db523ca6d993c13430c))
|
||||
* NCS-11 50-move rule ([#9](https://git.janis-eccarius.de/NowChess/NowChessSystems/issues/9)) ([412ed98](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/412ed986a95703a3b282276540153480ceed229d))
|
||||
* NCS-16 Core Separation via Patterns ([#10](https://git.janis-eccarius.de/NowChess/NowChessSystems/issues/10)) ([1361dfc](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/1361dfc89553b146864fb8ff3526cf12cf3f293a))
|
||||
* NCS-17 Implement basic ScalaFX UI ([#14](https://git.janis-eccarius.de/NowChess/NowChessSystems/issues/14)) ([3ff8031](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/3ff80318b4f16c59733a46498581a5c27f048287))
|
||||
* NCS-21 Write Scripts to automate certain tasks ([#15](https://git.janis-eccarius.de/NowChess/NowChessSystems/issues/15)) ([8051871](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/80518719d536a087d339fe02530825dc07f8b388))
|
||||
* NCS-6 Implementing FEN & PGN ([#7](https://git.janis-eccarius.de/NowChess/NowChessSystems/issues/7)) ([f28e69d](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/f28e69dc181416aa2f221fdc4b45c2cda5efbf07))
|
||||
* NCS-9 En passant implementation ([#8](https://git.janis-eccarius.de/NowChess/NowChessSystems/issues/8)) ([919beb3](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/919beb3b4bfa8caf2f90976a415fe9b19b7e9747))
|
||||
* wire check/checkmate/stalemate into processMove and gameLoop ([5264a22](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/5264a225418b885c5e6ea6411b96f85e38837f6c))
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* add missing kings to gameLoop capture test board ([aedd787](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/aedd787b77203c2af934751dba7b784eaf165032))
|
||||
* correct test board positions and captureOutput/withInput interaction ([f0481e2](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/f0481e2561b779df00925b46ee281dc36a795150))
|
||||
* update main class path in build configuration and adjust VCS directory mapping ([7b1f8b1](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/7b1f8b117623d327232a1a92a8a44d18582e0189))
|
||||
* update move validation to check for king safety ([#13](https://git.janis-eccarius.de/NowChess/NowChessSystems/issues/13)) ([e5e20c5](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/e5e20c566e368b12ca1dc59680c34e9112bf6762))
|
||||
|
||||
@@ -88,7 +88,7 @@ class GameEngine(
|
||||
case Some(piece) if piece.color != currentContext.turn =>
|
||||
notifyObservers(InvalidMoveEvent(currentContext, "That is not your piece."))
|
||||
case Some(piece) =>
|
||||
val legal = ruleSet.legalMoves(currentContext)(from)
|
||||
val legal = ruleSet.legalMoves(currentContext, from)
|
||||
// Find all legal moves going to `to`
|
||||
val candidates = legal.filter(_.to == to)
|
||||
candidates match
|
||||
@@ -119,7 +119,7 @@ class GameEngine(
|
||||
pendingPromotion = None
|
||||
val move = Move(pending.from, pending.to, MoveType.Promotion(piece))
|
||||
// Verify it's actually legal
|
||||
val legal = ruleSet.legalMoves(currentContext)(pending.from)
|
||||
val legal = ruleSet.legalMoves(currentContext, pending.from)
|
||||
if legal.contains(move) then
|
||||
executeMove(move)
|
||||
else
|
||||
@@ -203,7 +203,7 @@ class GameEngine(
|
||||
|
||||
private def executeMove(move: Move): Unit =
|
||||
val contextBefore = currentContext
|
||||
val nextContext = ruleSet.applyMove(currentContext)(move)
|
||||
val nextContext = ruleSet.applyMove(currentContext, move)
|
||||
val captured = computeCaptured(currentContext, move)
|
||||
|
||||
val cmd = MoveCommand(
|
||||
|
||||
+6
-6
@@ -89,8 +89,8 @@ class GameEngineIntegrationTest extends AnyFunSuite with Matchers:
|
||||
val promotionMove = Move(sq("e2"), sq("e8"), MoveType.Promotion(PromotionPiece.Queen))
|
||||
|
||||
val permissiveRules = new RuleSet:
|
||||
def candidateMoves(context: GameContext)(square: Square): List[Move] = legalMoves(context)(square)
|
||||
def legalMoves(context: GameContext)(square: Square): List[Move] =
|
||||
def candidateMoves(context: GameContext, square: Square): List[Move] = legalMoves(context, square)
|
||||
def legalMoves(context: GameContext, square: Square): List[Move] =
|
||||
if square == sq("e2") then List(promotionMove) else List.empty
|
||||
def allLegalMoves(context: GameContext): List[Move] = List(promotionMove)
|
||||
def isCheck(context: GameContext): Boolean = false
|
||||
@@ -98,7 +98,7 @@ class GameEngineIntegrationTest extends AnyFunSuite with Matchers:
|
||||
def isStalemate(context: GameContext): Boolean = false
|
||||
def isInsufficientMaterial(context: GameContext): Boolean = false
|
||||
def isFiftyMoveRule(context: GameContext): Boolean = false
|
||||
def applyMove(context: GameContext)(move: Move): GameContext = DefaultRules.applyMove(context)(move)
|
||||
def applyMove(context: GameContext, move: Move): GameContext = DefaultRules.applyMove(context, move)
|
||||
|
||||
val engine = new GameEngine(ruleSet = permissiveRules)
|
||||
val importer = new GameContextImport:
|
||||
@@ -111,15 +111,15 @@ class GameEngineIntegrationTest extends AnyFunSuite with Matchers:
|
||||
test("loadGame replay restores previous context when promotion cannot be completed"):
|
||||
val promotionMove = Move(sq("e2"), sq("e8"), MoveType.Promotion(PromotionPiece.Queen))
|
||||
val noLegalMoves = new RuleSet:
|
||||
def candidateMoves(context: GameContext)(square: Square): List[Move] = List.empty
|
||||
def legalMoves(context: GameContext)(square: Square): List[Move] = List.empty
|
||||
def candidateMoves(context: GameContext, square: Square): List[Move] = List.empty
|
||||
def legalMoves(context: GameContext, square: Square): List[Move] = List.empty
|
||||
def allLegalMoves(context: GameContext): List[Move] = List.empty
|
||||
def isCheck(context: GameContext): Boolean = false
|
||||
def isCheckmate(context: GameContext): Boolean = false
|
||||
def isStalemate(context: GameContext): Boolean = false
|
||||
def isInsufficientMaterial(context: GameContext): Boolean = false
|
||||
def isFiftyMoveRule(context: GameContext): Boolean = false
|
||||
def applyMove(context: GameContext)(move: Move): GameContext = context
|
||||
def applyMove(context: GameContext, move: Move): GameContext = context
|
||||
|
||||
val engine = new GameEngine(ruleSet = noLegalMoves)
|
||||
engine.processUserInput("e2e4")
|
||||
|
||||
@@ -153,10 +153,10 @@ class GameEnginePromotionTest extends AnyFunSuite with Matchers:
|
||||
// This makes completePromotion unable to find Move(from, to, Promotion(Queen)),
|
||||
// triggering the "Error completing promotion." branch.
|
||||
val delegatingRuleSet: RuleSet = new RuleSet:
|
||||
def candidateMoves(context: GameContext)(square: Square): List[Move] =
|
||||
DefaultRules.candidateMoves(context)(square)
|
||||
def legalMoves(context: GameContext)(square: Square): List[Move] =
|
||||
DefaultRules.legalMoves(context)(square).map { m =>
|
||||
def candidateMoves(context: GameContext, square: Square): List[Move] =
|
||||
DefaultRules.candidateMoves(context, square)
|
||||
def legalMoves(context: GameContext, square: Square): List[Move] =
|
||||
DefaultRules.legalMoves(context, square).map { m =>
|
||||
m.moveType match
|
||||
case MoveType.Promotion(_) => Move(m.from, m.to, MoveType.Normal())
|
||||
case _ => m
|
||||
@@ -173,8 +173,8 @@ class GameEnginePromotionTest extends AnyFunSuite with Matchers:
|
||||
DefaultRules.isInsufficientMaterial(context)
|
||||
def isFiftyMoveRule(context: GameContext): Boolean =
|
||||
DefaultRules.isFiftyMoveRule(context)
|
||||
def applyMove(context: GameContext)(move: Move): GameContext =
|
||||
DefaultRules.applyMove(context)(move)
|
||||
def applyMove(context: GameContext, move: Move): GameContext =
|
||||
DefaultRules.applyMove(context, move)
|
||||
|
||||
val promotionBoard = FenParser.parseBoard("8/4P3/4k3/8/8/8/8/8").get
|
||||
val initialCtx = GameContext.initial.withBoard(promotionBoard).withTurn(Color.White)
|
||||
|
||||
@@ -1,3 +1,3 @@
|
||||
MAJOR=0
|
||||
MINOR=11
|
||||
MINOR=10
|
||||
PATCH=0
|
||||
|
||||
Reference in New Issue
Block a user