feat: NCS-14 implemented insufficient moves rule (#30)
Build & Test (NowChessSystems) TeamCity build finished

Reviewed-on: #30
Co-authored-by: Janis <janis.e.20@gmx.de>
Co-committed-by: Janis <janis.e.20@gmx.de>
This commit was merged in pull request #30.
This commit is contained in:
2026-04-14 21:17:56 +02:00
committed by Janis
parent ec2ab2f365
commit b0399a4e48
160 changed files with 414 additions and 12042 deletions
@@ -2,7 +2,7 @@ package de.nowchess.chess.engine
import de.nowchess.api.board.{Board, Color, Piece, PieceType, Square}
import de.nowchess.api.move.{Move, MoveType, PromotionPiece}
import de.nowchess.api.game.GameContext
import de.nowchess.api.game.{DrawReason, GameContext, GameResult}
import de.nowchess.chess.controller.Parser
import de.nowchess.chess.observer.*
import de.nowchess.chess.command.{CommandInvoker, MoveCommand, MoveResult}
@@ -60,8 +60,9 @@ class GameEngine(
case "draw" =>
if currentContext.halfMoveClock >= 100 then
currentContext = currentContext.withResult(Some(GameResult.Draw(DrawReason.FiftyMoveRule)))
invoker.clear()
notifyObservers(DrawClaimedEvent(currentContext))
notifyObservers(DrawEvent(currentContext, DrawReason.FiftyMoveRule))
else
notifyObservers(
InvalidMoveEvent(
@@ -222,13 +223,17 @@ class GameEngine(
if ruleSet.isCheckmate(currentContext) then
val winner = currentContext.turn.opposite
currentContext = currentContext.withResult(Some(GameResult.Win(winner)))
notifyObservers(CheckmateEvent(currentContext, winner))
invoker.clear()
currentContext = GameContext.initial
else if ruleSet.isStalemate(currentContext) then
notifyObservers(StalemateEvent(currentContext))
currentContext = currentContext.withResult(Some(GameResult.Draw(DrawReason.Stalemate)))
notifyObservers(DrawEvent(currentContext, DrawReason.Stalemate))
invoker.clear()
else if ruleSet.isInsufficientMaterial(currentContext) then
currentContext = currentContext.withResult(Some(GameResult.Draw(DrawReason.InsufficientMaterial)))
notifyObservers(DrawEvent(currentContext, DrawReason.InsufficientMaterial))
invoker.clear()
currentContext = GameContext.initial
else if ruleSet.isCheck(currentContext) then notifyObservers(CheckDetectedEvent(currentContext))
if currentContext.halfMoveClock >= 100 then notifyObservers(FiftyMoveRuleAvailableEvent(currentContext))
@@ -1,7 +1,7 @@
package de.nowchess.chess.observer
import de.nowchess.api.board.{Color, Square}
import de.nowchess.api.game.GameContext
import de.nowchess.api.game.{DrawReason, GameContext}
/** Base trait for all game state events. Events are immutable snapshots of game state changes.
*/
@@ -27,9 +27,10 @@ case class CheckmateEvent(
winner: Color,
) extends GameEvent
/** Fired when the game reaches stalemate. */
case class StalemateEvent(
/** Fired when the game ends in a draw. */
case class DrawEvent(
context: GameContext,
reason: DrawReason,
) extends GameEvent
/** Fired when a move is invalid. */
@@ -55,11 +56,6 @@ case class FiftyMoveRuleAvailableEvent(
context: GameContext,
) extends GameEvent
/** Fired when a player successfully claims a draw under the 50-move rule. */
case class DrawClaimedEvent(
context: GameContext,
) extends GameEvent
/** Fired when a move is undone, carrying PGN notation of the reversed move. */
case class MoveUndoneEvent(
context: GameContext,