refactor: NCS-19 Currying (#18)

Summary

  - Curried candidateMoves, legalMoves, and applyMove in the RuleSet trait to separate (context) as the world being
  operated on from the computation parameter
  - Updated DefaultRules overrides and all internal call sites
  - Updated all external call sites: GameEngine, PgnParser, PgnExporter, ChessBoardView, and all affected tests

  Test plan

  - All existing tests pass (./gradlew build)
  - No behaviour changes — pure style refactoring, existing test suite is the regression guard

Co-authored-by: LQ63 <lkhermann@web.de>
Reviewed-on: #18
Reviewed-by: Janis <janis-e@gmx.de>
Co-authored-by: Leon Hermann <lq@blackhole.local>
Co-committed-by: Leon Hermann <lq@blackhole.local>
This commit is contained in:
2026-04-06 21:03:17 +02:00
committed by shahdlala66
parent b4bf447453
commit cfa4429d49
9 changed files with 59 additions and 59 deletions
@@ -30,7 +30,7 @@ object PgnExporter extends GameContextExport:
var ctx = GameContext.initial
val sanMoves = moves.map { move =>
val algebraic = moveToAlgebraic(move, ctx.board)
ctx = DefaultRules.applyMove(ctx, move)
ctx = DefaultRules.applyMove(ctx)(move)
algebraic
}
@@ -29,7 +29,7 @@ object PgnParser extends GameContextImport:
* Returns Left(error message) if validation fails or move replay encounters an issue. */
def importGameContext(input: String): Either[String, GameContext] =
validatePgn(input).flatMap { game =>
Right(game.moves.foldLeft(GameContext.initial)(DefaultRules.applyMove))
Right(game.moves.foldLeft(GameContext.initial)((ctx, move) => DefaultRules.applyMove(ctx)(move)))
}
/** Parse a complete PGN text into a PgnGame with headers and moves.
@@ -59,7 +59,7 @@ object PgnParser extends GameContextImport:
parseAlgebraicMove(token, ctx, color) match
case None => state
case Some(move) =>
val nextCtx = DefaultRules.applyMove(ctx, move)
val nextCtx = DefaultRules.applyMove(ctx)(move)
(nextCtx, color.opposite, acc :+ move)
moves
@@ -77,12 +77,12 @@ object PgnParser extends GameContextImport:
case "O-O" | "O-O+" | "O-O#" =>
val rank = if color == Color.White then Rank.R1 else Rank.R8
val move = Move(Square(File.E, rank), Square(File.G, rank), MoveType.CastleKingside)
Option.when(DefaultRules.legalMoves(ctx, Square(File.E, rank)).contains(move))(move)
Option.when(DefaultRules.legalMoves(ctx)(Square(File.E, rank)).contains(move))(move)
case "O-O-O" | "O-O-O+" | "O-O-O#" =>
val rank = if color == Color.White then Rank.R1 else Rank.R8
val move = Move(Square(File.E, rank), Square(File.C, rank), MoveType.CastleQueenside)
Option.when(DefaultRules.legalMoves(ctx, Square(File.E, rank)).contains(move))(move)
Option.when(DefaultRules.legalMoves(ctx)(Square(File.E, rank)).contains(move))(move)
case _ =>
parseRegularMove(notation, ctx, color)
@@ -176,7 +176,7 @@ object PgnParser extends GameContextImport:
parseAlgebraicMove(token, ctx, color) match
case None => Left(s"Illegal or impossible move: '$token'")
case Some(move) =>
val nextCtx = DefaultRules.applyMove(ctx, move)
val nextCtx = DefaultRules.applyMove(ctx)(move)
Right((nextCtx, color.opposite, moves :+ move))
}
}.map(_._3)