fix: correct 50-move rule threshold to 100 half-moves (FIDE-compliant)
The halfMoveClock counts plies (half-moves). The FIDE 50-move rule requires 50 moves by each side = 100 plies, not 50. Changed both the processMove and gameLoop checks from >= 50 to >= 100, and updated all tests accordingly. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -36,7 +36,7 @@ object GameController:
|
|||||||
case "quit" | "q" =>
|
case "quit" | "q" =>
|
||||||
MoveResult.Quit
|
MoveResult.Quit
|
||||||
case "draw" =>
|
case "draw" =>
|
||||||
if halfMoveClock >= 50 then MoveResult.DrawClaimed
|
if halfMoveClock >= 100 then MoveResult.DrawClaimed
|
||||||
else MoveResult.InvalidFormat("draw")
|
else MoveResult.InvalidFormat("draw")
|
||||||
case trimmed =>
|
case trimmed =>
|
||||||
Parser.parseMove(trimmed) match
|
Parser.parseMove(trimmed) match
|
||||||
@@ -80,7 +80,7 @@ object GameController:
|
|||||||
println()
|
println()
|
||||||
print(Renderer.render(board))
|
print(Renderer.render(board))
|
||||||
val input =
|
val input =
|
||||||
if halfMoveClock >= 50 then
|
if halfMoveClock >= 100 then
|
||||||
println(s"[50-move rule] ${turn.label} may claim a draw, or continue playing.")
|
println(s"[50-move rule] ${turn.label} may claim a draw, or continue playing.")
|
||||||
println(" 1. Claim draw")
|
println(" 1. Claim draw")
|
||||||
println(" 2. Continue")
|
println(" 2. Continue")
|
||||||
|
|||||||
@@ -404,19 +404,19 @@ class GameControllerTest extends AnyFunSuite with Matchers:
|
|||||||
|
|
||||||
// ──── processMove: 50-move rule draw claim ───────────────────────────────
|
// ──── processMove: 50-move rule draw claim ───────────────────────────────
|
||||||
|
|
||||||
test("processMove: 'draw' with halfMoveClock = 50 returns DrawClaimed"):
|
test("processMove: 'draw' with halfMoveClock = 100 returns DrawClaimed"):
|
||||||
val b = Board(Map(
|
val b = Board(Map(
|
||||||
sq(File.E, Rank.R1) -> Piece.WhiteKing,
|
sq(File.E, Rank.R1) -> Piece.WhiteKing,
|
||||||
sq(File.E, Rank.R8) -> Piece.BlackKing
|
sq(File.E, Rank.R8) -> Piece.BlackKing
|
||||||
))
|
))
|
||||||
GameController.processMove(b, GameHistory.empty, Color.White, 50, "draw") shouldBe MoveResult.DrawClaimed
|
GameController.processMove(b, GameHistory.empty, Color.White, 100, "draw") shouldBe MoveResult.DrawClaimed
|
||||||
|
|
||||||
test("processMove: 'draw' with halfMoveClock = 49 returns InvalidFormat"):
|
test("processMove: 'draw' with halfMoveClock = 99 returns InvalidFormat"):
|
||||||
val b = Board(Map(
|
val b = Board(Map(
|
||||||
sq(File.E, Rank.R1) -> Piece.WhiteKing,
|
sq(File.E, Rank.R1) -> Piece.WhiteKing,
|
||||||
sq(File.E, Rank.R8) -> Piece.BlackKing
|
sq(File.E, Rank.R8) -> Piece.BlackKing
|
||||||
))
|
))
|
||||||
GameController.processMove(b, GameHistory.empty, Color.White, 49, "draw") shouldBe MoveResult.InvalidFormat("draw")
|
GameController.processMove(b, GameHistory.empty, Color.White, 99, "draw") shouldBe MoveResult.InvalidFormat("draw")
|
||||||
|
|
||||||
// ──── processMove: halfMoveClock update ──────────────────────────────────
|
// ──── processMove: halfMoveClock update ──────────────────────────────────
|
||||||
|
|
||||||
@@ -470,30 +470,30 @@ class GameControllerTest extends AnyFunSuite with Matchers:
|
|||||||
|
|
||||||
// ──── gameLoop: 50-move rule menu ────────────────────────────────────────
|
// ──── gameLoop: 50-move rule menu ────────────────────────────────────────
|
||||||
|
|
||||||
test("gameLoop: shows 50-move rule menu when halfMoveClock >= 50 and draw claimed"):
|
test("gameLoop: shows 50-move rule menu when halfMoveClock >= 100 and draw claimed"):
|
||||||
val b = Board(Map(
|
val b = Board(Map(
|
||||||
sq(File.E, Rank.R1) -> Piece.WhiteKing,
|
sq(File.E, Rank.R1) -> Piece.WhiteKing,
|
||||||
sq(File.E, Rank.R8) -> Piece.BlackKing
|
sq(File.E, Rank.R8) -> Piece.BlackKing
|
||||||
))
|
))
|
||||||
val output = captureOutput:
|
val output = captureOutput:
|
||||||
withInput("1\nquit\n"):
|
withInput("1\nquit\n"):
|
||||||
GameController.gameLoop(b, GameHistory.empty, Color.White, 50)
|
GameController.gameLoop(b, GameHistory.empty, Color.White, 100)
|
||||||
output should include("50-move rule")
|
output should include("50-move rule")
|
||||||
output should include("Draw claimed by 50-move rule.")
|
output should include("Draw claimed by 50-move rule.")
|
||||||
|
|
||||||
test("gameLoop: shows 50-move rule menu when halfMoveClock >= 50 and player continues"):
|
test("gameLoop: shows 50-move rule menu when halfMoveClock >= 100 and player continues"):
|
||||||
val b = Board(Map(
|
val b = Board(Map(
|
||||||
sq(File.E, Rank.R1) -> Piece.WhiteKing,
|
sq(File.E, Rank.R1) -> Piece.WhiteKing,
|
||||||
sq(File.E, Rank.R8) -> Piece.BlackKing
|
sq(File.E, Rank.R8) -> Piece.BlackKing
|
||||||
))
|
))
|
||||||
val output = captureOutput:
|
val output = captureOutput:
|
||||||
withInput("2\nquit\n"):
|
withInput("2\nquit\n"):
|
||||||
GameController.gameLoop(b, GameHistory.empty, Color.White, 50)
|
GameController.gameLoop(b, GameHistory.empty, Color.White, 100)
|
||||||
output should include("50-move rule")
|
output should include("50-move rule")
|
||||||
output should include("White's turn")
|
output should include("White's turn")
|
||||||
|
|
||||||
test("gameLoop: no 50-move rule menu when halfMoveClock < 50"):
|
test("gameLoop: no 50-move rule menu when halfMoveClock < 100"):
|
||||||
val output = captureOutput:
|
val output = captureOutput:
|
||||||
withInput("quit\n"):
|
withInput("quit\n"):
|
||||||
GameController.gameLoop(Board.initial, GameHistory.empty, Color.White, 49)
|
GameController.gameLoop(Board.initial, GameHistory.empty, Color.White, 99)
|
||||||
output should not include "50-move rule"
|
output should not include "50-move rule"
|
||||||
|
|||||||
Reference in New Issue
Block a user