feat: add memory structure documentation and update index (#5)
Build & Test (NowChessSystems) TeamCity build finished
Build & Test (NowChessSystems) TeamCity build finished
Reviewed-on: #5
This commit was merged in pull request #5.
This commit is contained in:
@@ -0,0 +1,9 @@
|
||||
# Memory Index
|
||||
|
||||
## Feedback
|
||||
- [feedback_keep_structure_updated.md](feedback_keep_structure_updated.md) — Update structure memory files whenever source files are added, removed, or changed
|
||||
|
||||
## Project Structure
|
||||
- [project_structure_root.md](project_structure_root.md) — Top-level layout, modules list, VERSIONS map, navigation rules (skip `build/`, `.gradle/`, `.idea/`)
|
||||
- [project_structure_api.md](project_structure_api.md) — `modules/api`: all files and types (Board, Piece, Square, GameState, Move, ApiResponse, PlayerInfo)
|
||||
- [project_structure_core.md](project_structure_core.md) — `modules/core`: all files and types (GameContext, GameRules, MoveValidator, GameController, Parser, Renderer)
|
||||
@@ -0,0 +1,16 @@
|
||||
---
|
||||
name: keep-structure-memory-updated
|
||||
description: Always update the project structure memory files when adding, removing, or changing source files
|
||||
type: feedback
|
||||
---
|
||||
|
||||
After any change that adds, removes, renames, or significantly alters a source file, update the relevant structure memory file:
|
||||
|
||||
- New/renamed/deleted file in `modules/api` → update `project_structure_api.md`
|
||||
- New/renamed/deleted file in `modules/core` → update `project_structure_core.md`
|
||||
- New module, dependency version change, or new top-level directory → update `project_structure_root.md`
|
||||
- New module added → create a new `project_structure_<module>.md` and add it to `MEMORY.md`
|
||||
|
||||
**Why:** Structure memories are the primary navigation aid. Stale entries cause wasted exploration.
|
||||
|
||||
**How to apply:** Treat the structure memory update as part of completing any implementation task — do it in the same session, not as a follow-up.
|
||||
@@ -0,0 +1,51 @@
|
||||
---
|
||||
name: module-api-structure
|
||||
description: File and type overview for the modules/api module (shared domain types)
|
||||
type: project
|
||||
---
|
||||
|
||||
# Module: `modules/api`
|
||||
|
||||
**Purpose:** Shared domain model — pure data types with no game logic. Depended on by `modules/core`.
|
||||
|
||||
**Gradle:** `id("scala")`, no `application` plugin. No Quarkus. Uses scoverage plugin.
|
||||
|
||||
**Package root:** `de.nowchess.api`
|
||||
|
||||
## Source files (`src/main/scala/de/nowchess/api/`)
|
||||
|
||||
### `board/`
|
||||
| File | Contents |
|
||||
|------|----------|
|
||||
| `Board.scala` | `opaque type Board = Map[Square, Piece]` — extensions: `pieceAt`, `withMove`, `pieces`; `Board.initial` sets up start position |
|
||||
| `Color.scala` | `enum Color { White, Black }` — `.opposite`, `.label` |
|
||||
| `Piece.scala` | `case class Piece(color, pieceType)` — convenience vals `WhitePawn`…`BlackKing` |
|
||||
| `PieceType.scala` | `enum PieceType { Pawn, Knight, Bishop, Rook, Queen, King }` — `.label` |
|
||||
| `Square.scala` | `enum File { A–H }`, `enum Rank { R1–R8 }`, `case class Square(file, rank)` — `.toString` algebraic, `Square.fromAlgebraic(s)` |
|
||||
|
||||
### `game/`
|
||||
| File | Contents |
|
||||
|------|----------|
|
||||
| `GameState.scala` | `case class CastlingRights(kingSide, queenSide)` + `.None`/`.Both`; `enum GameResult { WhiteWins, BlackWins, Draw }`; `enum GameStatus { NotStarted, InProgress, Finished(result) }`; `case class GameState(piecePlacement, activeColor, castlingWhite, castlingBlack, enPassantTarget, halfMoveClock, fullMoveNumber, status)` — FEN-compatible snapshot |
|
||||
|
||||
### `move/`
|
||||
| File | Contents |
|
||||
|------|----------|
|
||||
| `Move.scala` | `enum PromotionPiece { Knight, Bishop, Rook, Queen }`; `enum MoveType { Normal, CastleKingside, CastleQueenside, EnPassant, Promotion(piece) }`; `case class Move(from, to, moveType = Normal)` |
|
||||
|
||||
### `player/`
|
||||
| File | Contents |
|
||||
|------|----------|
|
||||
| `PlayerInfo.scala` | `opaque type PlayerId = String`; `case class PlayerInfo(id: PlayerId, displayName: String)` |
|
||||
|
||||
### `response/`
|
||||
| File | Contents |
|
||||
|------|----------|
|
||||
| `ApiResponse.scala` | `sealed trait ApiResponse[+A]` → `Success[A](data)` / `Failure(errors)`; `case class ApiError(code, message, field?)`; `case class Pagination(page, pageSize, totalItems)` + `.totalPages`; `case class PagedResponse[A](items, pagination)` |
|
||||
|
||||
## Test files (`src/test/scala/de/nowchess/api/`)
|
||||
Mirror of main structure — one `*Test.scala` per source file using `AnyFunSuite with Matchers`.
|
||||
|
||||
## Notes
|
||||
- `GameState` is FEN-style but `Board` (in `core`) is a `Map[Square,Piece]` — the two are separate representations
|
||||
- `CastlingRights` is defined here in `api`; the castling logic lives in `core`
|
||||
@@ -0,0 +1,48 @@
|
||||
---
|
||||
name: module-core-structure
|
||||
description: File and type overview for the modules/core module (TUI chess engine)
|
||||
type: project
|
||||
---
|
||||
|
||||
# Module: `modules/core`
|
||||
|
||||
**Purpose:** Standalone TUI chess application. All game logic, move validation, rendering. Depends on `modules/api`.
|
||||
|
||||
**Gradle:** `id("scala")` + `application` plugin. Main class: `de.nowchess.chess.Main`. Uses scoverage plugin.
|
||||
|
||||
**Package root:** `de.nowchess.chess`
|
||||
|
||||
## Source files (`src/main/scala/de/nowchess/chess/`)
|
||||
|
||||
### Root
|
||||
| File | Contents |
|
||||
|------|----------|
|
||||
| `Main.scala` | Entry point — prints welcome, starts `GameController.gameLoop(GameContext.initial, Color.White)` |
|
||||
|
||||
### `controller/`
|
||||
| File | Contents |
|
||||
|------|----------|
|
||||
| `GameController.scala` | `sealed trait MoveResult` ADT: `Quit`, `InvalidFormat`, `NoPiece`, `WrongColor`, `IllegalMove`, `Moved`, `MovedInCheck`, `Checkmate`, `Stalemate`; `object GameController` — `processMove(ctx, turn, raw): MoveResult` (pure), `gameLoop(ctx, turn)` (I/O loop), `applyRightsRevocation(...)` (castling rights bookkeeping) |
|
||||
| `Parser.scala` | `object Parser` — `parseMove(input): Option[(Square, Square)]` parses coordinate notation e.g. `"e2e4"` |
|
||||
|
||||
### `logic/`
|
||||
| File | Contents |
|
||||
|------|----------|
|
||||
| `GameContext.scala` | `enum CastleSide { Kingside, Queenside }`; `case class GameContext(board, whiteCastling, blackCastling)` — `.castlingFor(color)`, `.withUpdatedRights(color, rights)`; `GameContext.initial`; `extension (Board).withCastle(color, side)` moves king+rook atomically |
|
||||
| `GameRules.scala` | `enum PositionStatus { Normal, InCheck, Mated, Drawn }`; `object GameRules` — `isInCheck(board, color)`, `legalMoves(ctx, color): Set[(Square,Square)]`, `gameStatus(ctx, color): PositionStatus` |
|
||||
| `MoveValidator.scala` | `object MoveValidator` — `isLegal(board, from, to)`, `legalTargets(board, from): Set[Square]` (board-only, no castling), `legalTargets(ctx, from)` (context-aware, includes castling), `isCastle`, `castleSide`, `castlingTargets(ctx, color)` — full castling legality (empty squares, no check through transit) |
|
||||
|
||||
### `view/`
|
||||
| File | Contents |
|
||||
|------|----------|
|
||||
| `Renderer.scala` | `object Renderer` — `render(board): String` outputs ANSI-colored board with file/rank labels |
|
||||
| `PieceUnicode.scala` | `extension (Piece).unicode: String` maps each piece to its Unicode chess symbol |
|
||||
|
||||
## Test files (`src/test/scala/de/nowchess/chess/`)
|
||||
Mirror of main structure — one `*Test.scala` per source file using `AnyFunSuite with Matchers`.
|
||||
|
||||
## Key design notes
|
||||
- `MoveValidator` has two overloaded `legalTargets`: one takes `Board` (geometry only), one takes `GameContext` (adds castling)
|
||||
- `GameRules.legalMoves` filters by check — it calls `MoveValidator.legalTargets(ctx, from)` then simulates each move
|
||||
- Castling rights revocation is in `GameController.applyRightsRevocation`, triggered after every move
|
||||
- No `@QuarkusTest` — this module is a plain Scala application, not a Quarkus service
|
||||
@@ -0,0 +1,55 @@
|
||||
---
|
||||
name: project-root-structure
|
||||
description: Top-level project structure, modules list, and navigation notes for NowChessSystems
|
||||
type: project
|
||||
---
|
||||
|
||||
# NowChessSystems — Root Structure
|
||||
|
||||
## Directory layout (skip `build/`, `.gradle/`, `.idea/`)
|
||||
|
||||
```
|
||||
NowChessSystems/
|
||||
├── build.gradle.kts # Root: sonarqube plugin, VERSIONS map
|
||||
├── settings.gradle.kts # include(":modules:core", ":modules:api")
|
||||
├── gradlew / gradlew.bat
|
||||
├── CLAUDE.md # Project instructions for Claude Code
|
||||
├── .claude/
|
||||
│ ├── CLAUDE.MD # Working agreement (plan/verify/unresolved)
|
||||
│ ├── settings.json
|
||||
│ └── agents/ # architect, code-reviewer, gradle-builder, scala-implementer, test-writer
|
||||
├── docs/
|
||||
│ ├── Claude-Skills.md
|
||||
│ ├── Security.md
|
||||
│ └── unresolved.md
|
||||
├── jacoco-reporter/ # Python scripts for coverage gap reporting
|
||||
└── modules/
|
||||
├── api/ # Shared domain types (no logic)
|
||||
└── core/ # TUI chess engine + game logic
|
||||
```
|
||||
|
||||
## Modules
|
||||
|
||||
| Module | Gradle path | Purpose |
|
||||
|--------|-------------|---------|
|
||||
| `api` | `:modules:api` | Shared domain model: Board, Piece, Move, GameState, ApiResponse |
|
||||
| `core` | `:modules:core` | TUI chess app: game logic, move validation, rendering |
|
||||
|
||||
`core` depends on `api` via `implementation(project(":modules:api"))`.
|
||||
|
||||
## VERSIONS (root `build.gradle.kts`)
|
||||
|
||||
| Key | Value |
|
||||
|-----|-------|
|
||||
| `QUARKUS_SCALA3` | 1.0.0 |
|
||||
| `SCALA3` | 3.5.1 |
|
||||
| `SCALA_LIBRARY` | 2.13.18 |
|
||||
| `SCALATEST` | 3.2.19 |
|
||||
| `SCALATEST_JUNIT` | 0.1.11 |
|
||||
| `SCOVERAGE` | 2.1.1 |
|
||||
|
||||
## Navigation rules
|
||||
- **Always skip** `build/`, `.gradle/`, `.idea/` when exploring — they are generated artifacts
|
||||
- Tests use `AnyFunSuite with Matchers` (ScalaTest), not JUnit `@Test`
|
||||
- No Quarkus in current modules — Quarkus is planned for future services
|
||||
- Agent workflow: architect → scala-implementer → test-writer → gradle-builder → code-reviewer
|
||||
Reference in New Issue
Block a user