Files
NowChessSystems/docs/superpowers/specs/2026-03-31-currying-public-api-design.md
T
LQ63 87806d516f docs: add currying public API design spec
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-31 13:35:13 +02:00

3.2 KiB

Currying Public API — Design Spec

Branch: feat/NCS-11 Date: 2026-03-31


Overview

Refactor the public methods of MoveValidator and GameRules to use multiple parameter groups (currying), separating (board[, history]) as the context group from the computation parameters. This is a pure style refactoring — no behaviour changes, no new tests required.


Motivation

Currying clarifies intent: (board, history) is "the world being operated on"; the remaining parameters are "what varies." It also enables partial application at call sites where board/history are fixed across a loop (e.g. isInCheck, legalMoves).


Section 1: Methods Being Curried

MoveValidator (public API only)

Before After
legalTargets(board, from) legalTargets(board)(from)
legalTargets(board, history, from) legalTargets(board, history)(from)
isLegal(board, from, to) isLegal(board)(from, to)
isLegal(board, history, from, to) isLegal(board, history)(from, to)
isCastle(board, from, to) isCastle(board)(from, to)
castlingTargets(board, history, color) castlingTargets(board, history)(color)
castleSide(from, to) unchanged — no board parameter

Private helpers (isOwnPiece, isEnemyPiece, slide, pawnTargets, knightTargets, kingTargets) are not changed.

GameRules (all public methods)

Before After
isInCheck(board, color) isInCheck(board)(color)
legalMoves(board, history, color) legalMoves(board, history)(color)
gameStatus(board, history, color) gameStatus(board, history)(color)

Section 2: Call Sites Updated

File Methods affected
modules/core/src/main/scala/de/nowchess/chess/logic/MoveValidator.scala Internal calls to legalTargets, castlingTargets, isCastle
modules/core/src/main/scala/de/nowchess/chess/logic/GameRules.scala MoveValidator.legalTargets, MoveValidator.isCastle, isInCheck
modules/core/src/main/scala/de/nowchess/chess/controller/GameController.scala MoveValidator.isLegal, MoveValidator.isCastle, GameRules.gameStatus
modules/core/src/test/scala/de/nowchess/chess/logic/MoveValidatorTest.scala legalTargets, isLegal, castlingTargets
modules/core/src/test/scala/de/nowchess/chess/logic/GameRulesTest.scala isInCheck, legalMoves, gameStatus

EnPassantCalculator, CastlingRightsCalculator, and their tests are not touched.


Section 3: Concrete Style Gain

In GameRules.isInCheck and legalMoves, board is passed to legalTargets on every loop iteration today. After currying, it is factored out as a single partial application:

// Before
board.pieces.exists { case (sq, piece) =>
  piece.color != color &&
  MoveValidator.legalTargets(board, sq).contains(kingSq)
}

// After
val targets = MoveValidator.legalTargets(board)
board.pieces.exists { case (sq, piece) =>
  piece.color != color &&
  targets(sq).contains(kingSq)
}

Section 4: Testing

Pure refactoring — no new tests. All existing tests must pass after call sites are updated. The test suite is the regression guard.