docs: add currying public API design spec
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,82 @@
|
|||||||
|
# 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:
|
||||||
|
|
||||||
|
```scala
|
||||||
|
// 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.
|
||||||
Reference in New Issue
Block a user