Compare commits
46 Commits
b0141d2c89
...
ui-0.9.0
| Author | SHA1 | Date | |
|---|---|---|---|
| fd4e67d4f7 | |||
| 3cb3160731 | |||
| dbcafd2869 | |||
| 3ecb2c9d66 | |||
| 9ad11fb97a | |||
| e158b0a7f0 | |||
| f1c9df16b6 | |||
| 9d11d25b99 | |||
| 7a045d31d7 | |||
| b518c704fa | |||
| fe8e3c0539 | |||
| 1b16adcc72 | |||
| b4bc72f7e4 | |||
| 8959c3a849 | |||
| 47032378e2 | |||
| 217f14f899 | |||
| 638139602c | |||
| 8f56a82104 | |||
| 51ffd7aac9 | |||
| 1b9eb471de | |||
| 45013c87a9 | |||
| 80518719d5 | |||
| 2d6ead7e47 | |||
| 3ff80318b4 | |||
| 9fb743d135 | |||
| 412ed986a9 | |||
| 8bbeead702 | |||
| e5e20c566e | |||
| 13bfc16cfe | |||
| 85cbf95c18 | |||
| 1361dfc895 | |||
| 707c4826a4 | |||
| 919beb3b4b | |||
| ee79dc5b98 | |||
| f28e69dc18 | |||
| 5f485fed9b | |||
| f4c18d22d7 | |||
| 4d800e88eb | |||
| 2df2fdeeb9 | |||
| 9190d1e5a0 | |||
| d675966436 | |||
| b4116e9a82 | |||
| 11efb1a42d | |||
| 00d326c1ba | |||
| d0289e16f4 | |||
| 7b1f8b1176 |
@@ -1,120 +0,0 @@
|
||||
# Claude Code – Working Agreement
|
||||
|
||||
## Workflow: Plan → Write Tests → Implement → Verify
|
||||
|
||||
### 1. Plan First
|
||||
Before writing any code, produce an explicit plan:
|
||||
- Restate the requirement in your own words to confirm understanding.
|
||||
- List every file you intend to create or modify.
|
||||
- Identify risks or unknowns upfront.
|
||||
- Wait for confirmation **only** when the plan reveals an ambiguity that cannot be resolved from context. Otherwise proceed immediately.
|
||||
|
||||
### 2. Write Tests
|
||||
Before implementing, write tests that should cover the new behaviour.
|
||||
Only write tests for the new behaviour.
|
||||
|
||||
### 3. Implement
|
||||
Follow the plan. Do not add scope beyond what was agreed.
|
||||
|
||||
### 4. Verify Every Requirement
|
||||
After implementation, go through each requirement one-by-one and confirm it is satisfied:
|
||||
- Run the relevant tests (unit, integration, or build check) for every changed module.
|
||||
- If a requirement **cannot** be fulfilled, do **not** silently skip it — document it immediately (see *Unresolved Requirements* below).
|
||||
|
||||
---
|
||||
|
||||
## No Code Without Verification (Testing)
|
||||
|
||||
- Every new behaviour must be covered by at least one automated test before the task is considered done.
|
||||
- Every bug fix must be accompanied by a regression test that fails before the fix and passes after.
|
||||
- Run `./gradlew :modules:<module>:test` (or the appropriate Gradle task) and confirm a green build before marking work complete.
|
||||
- If a test cannot be written for a legitimate reason, document it in `docs/unresolved.md` with an explanation.
|
||||
|
||||
---
|
||||
|
||||
## Automatic Bug Fixing
|
||||
|
||||
- When a test or build step fails, attempt to fix the root cause immediately — do **not** ask for permission.
|
||||
- Apply the fix, re-run the verification, and continue until green.
|
||||
- If the same failure persists after **three** fix attempts, stop, log the issue in `docs/unresolved.md`, and surface a concise summary.
|
||||
|
||||
---
|
||||
|
||||
## Unresolved Requirements → `docs/unresolved.md`
|
||||
|
||||
When a requirement or bug cannot be resolved, append an entry to `docs/unresolved.md`:
|
||||
|
||||
```markdown
|
||||
## [YYYY-MM-DD] <Short title>
|
||||
|
||||
**Requirement / Bug:**
|
||||
<What was requested or what failed>
|
||||
|
||||
**Root Cause (if known):**
|
||||
<Why it cannot be resolved right now>
|
||||
|
||||
**Attempted Fixes:**
|
||||
1. <What was tried>
|
||||
2. …
|
||||
|
||||
**Suggested Next Step:**
|
||||
<What a human engineer should investigate>
|
||||
```
|
||||
|
||||
Create the file if it does not exist. Never delete existing entries.
|
||||
|
||||
---
|
||||
|
||||
## Project Structure
|
||||
|
||||
```
|
||||
. ← Repository root (multi-project Gradle setup)
|
||||
├── build.gradle.kts ← Root build file (shared plugins, dependency versions)
|
||||
├── settings.gradle.kts ← Gradle settings (declares all subprojects)
|
||||
├── modules/ ← One subdirectory per microservice
|
||||
│ └── <service>/
|
||||
│ ├── build.gradle.kts
|
||||
│ └── src/
|
||||
└── docs/ ← Architecture Decision Records, API docs, unresolved issues
|
||||
└── unresolved.md
|
||||
```
|
||||
|
||||
### Conventions
|
||||
- All microservices live under `modules/{service-name}`. Never place service code in the root.
|
||||
- Shared configuration (dependency versions, plugin setup) belongs in the **root** `build.gradle.kts` or in `buildSrc` / a version catalog.
|
||||
- `settings.gradle.kts` must include every module via `include(":modules:<service>")`.
|
||||
- Architecture decisions go in `docs/adr/` as numbered Markdown files (`ADR-001-<title>.md`).
|
||||
- API contracts live in `/docs/api/`.
|
||||
- Unit tests extend `AnyFunSuite with Matchers with JUnitSuiteLike` — no `@Test` annotations, no `: Unit` requirement
|
||||
- Integration tests use `@QuarkusTest` with JUnit 5 — `@Test` methods must be explicitly typed `: Unit`
|
||||
- Always exclude scala-library from Quarkus deps to avoid Scala 2 conflicts
|
||||
|
||||
## Coverage Conventions
|
||||
- Branch coverage must be at least 90% - unless there is a good reason not to.
|
||||
- Line coverage must be at least 95% - unless there is a good reason not to.
|
||||
- Method coverage must be at least 90% - unless there is a good reason not to.
|
||||
- To check coverage use jacoco-reporter/scoverage_coverage_gaps.py modules/{service}/build/reports/scoverageTest/scoverage.xml
|
||||
- IMPORTANT: modules/{service}/build/reports/scoverage/scoverage.xml is not used for coverage TEST calculation. Do not use it.
|
||||
|
||||
## Agent Routing Rules
|
||||
|
||||
### Use agents in PARALLEL when:
|
||||
- Tasks touch different, independent microservices
|
||||
- No shared files or state between tasks
|
||||
- Example: "implement service-user AND service-orders simultaneously"
|
||||
|
||||
### Use agents SEQUENTIALLY when:
|
||||
- Tasks have dependencies (architect → implementer → test-writer)
|
||||
- Shared API contracts are involved
|
||||
- Example: design API first, then implement, then test
|
||||
|
||||
## Quick-Reference Checklist
|
||||
|
||||
Before considering any task done, confirm:
|
||||
|
||||
- [ ] Plan was written and requirements restated
|
||||
- [ ] All planned files were created / modified
|
||||
- [ ] Automated tests cover the new behaviour
|
||||
- [ ] `./gradlew build` (or scoped task) is green
|
||||
- [ ] Each requirement has been explicitly verified
|
||||
- [ ] Any unresolved items are logged in `docs/unresolved.md`
|
||||
@@ -23,7 +23,7 @@ report findings to team-leader, who re-invokes scala-implementer for fixes.
|
||||
- `@QuarkusTest` methods (JUnit 5) must be explicitly typed `: Unit`
|
||||
|
||||
### Tests
|
||||
- Unit tests must extend `AnyFunSuite with Matchers with JUnitSuiteLike`, not plain JUnit 5
|
||||
- Unit tests must extend `AnyFunSuite with Matchers`
|
||||
- Integration tests use `@QuarkusTest` with JUnit 5 `@Test` methods
|
||||
- No raw `@Test` annotations on plain unit test classes
|
||||
|
||||
|
||||
@@ -2,9 +2,10 @@
|
||||
name: scala-implementer
|
||||
description: "Implements Scala 3 + Quarkus REST services, domain logic, and persistence"
|
||||
tools: Read, Write, Edit, Bash, Glob
|
||||
model: sonnet
|
||||
model: inherit
|
||||
color: pink
|
||||
---
|
||||
|
||||
You do not have permissions to write tests, just source code.
|
||||
You are a Scala 3 expert specialising in Quarkus microservices.
|
||||
Always read the relevant /docs/api/ file before implementing.
|
||||
|
||||
@@ -2,9 +2,10 @@
|
||||
name: test-writer
|
||||
description: "Writes QuarkusTest unit and integration tests for a service. Invoke after scala-implementer has finished."
|
||||
tools: Read, Write, Edit, Bash, Glob, Grep, WebFetch, WebSearch, NotebookEdit
|
||||
model: sonnet
|
||||
model: haiku
|
||||
color: purple
|
||||
---
|
||||
|
||||
You do not have permissions to modify the source code, just write tests.
|
||||
You write tests for Scala 3 + Quarkus services.
|
||||
|
||||
@@ -12,12 +13,11 @@ You write tests for Scala 3 + Quarkus services.
|
||||
- Unit tests: `extends AnyFunSuite with Matchers` — use `test("description") { ... }` DSL, no `@Test` annotation, no `: Unit` return type needed.
|
||||
- Integration tests: `@QuarkusTest` with JUnit 5 — `@Test` methods MUST be explicitly typed `: Unit`.
|
||||
|
||||
Target 95%+ conditional coverage.
|
||||
Target 100% conditional coverage if possible.
|
||||
|
||||
When invoked BEFORE scala-implementer (no implementation exists yet):
|
||||
Use the contract-first-test-writing skill — write failing tests from docs/api/{service}.yaml.
|
||||
|
||||
When invoked AFTER scala-implementer (implementation exists):
|
||||
Run python3 jacoco-reporter/jacoco_coverage_gaps.py modules/{service-name}/build/reports/jacoco/test/jacocoTestReport.xml --output agent
|
||||
Use the jacoco-coverage-gaps skill — close coverage gaps revealed by the report.
|
||||
To regenerate the report run the tests first.
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"enabledPlugins": {
|
||||
"superpowers@claude-plugins-official": true,
|
||||
"ui-ux-pro-max@ui-ux-pro-max-skill": true
|
||||
"superpowers@claude-plugins-official": false,
|
||||
"ui-ux-pro-max@ui-ux-pro-max-skill": false
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,203 @@
|
||||
# NowChessSystems — AI Context Map
|
||||
|
||||
> **Stack:** raw-http | none | unknown | scala
|
||||
|
||||
> 0 routes | 0 models | 0 components | 35 lib files | 0 env vars | 0 middleware
|
||||
> **Token savings:** this file is ~3.700 tokens. Without it, AI exploration would cost ~18.200 tokens. **Saves ~14.500 tokens per conversation.**
|
||||
|
||||
---
|
||||
|
||||
# Libraries
|
||||
|
||||
- `jacoco-reporter/scoverage_coverage_gaps.py`
|
||||
- function parse_scoverage_xml: (xml_path) -> tuple[dict, list[ClassGap]]
|
||||
- function format_agent: (project_stats, classes) -> str
|
||||
- function format_json: (project_stats, classes) -> str
|
||||
- function format_markdown: (project_stats, classes) -> str
|
||||
- function format_module_gaps: (module_name, classes, stmt_pct) -> str
|
||||
- function run_scan_modules: (modules_dir, package_filter, min_coverage) -> None
|
||||
- _...4 more_
|
||||
- `jacoco-reporter/test_gaps.py`
|
||||
- function parse_suite_xml: (xml_path) -> SuiteResult
|
||||
- function load_module: (module_dir, results_subdir) -> Optional[ModuleResult]
|
||||
- function format_module: (mod) -> str
|
||||
- function run: (modules_dir, results_subdir, module_filter) -> None
|
||||
- function main: () -> None
|
||||
- class TestCase
|
||||
- _...2 more_
|
||||
- `modules/api/src/main/scala/de/nowchess/api/board/Board.scala`
|
||||
- class Board
|
||||
- function apply
|
||||
- function pieceAt
|
||||
- function updated
|
||||
- function removed
|
||||
- function withMove
|
||||
- _...2 more_
|
||||
- `modules/api/src/main/scala/de/nowchess/api/board/CastlingRights.scala`
|
||||
- function hasAnyRights
|
||||
- function hasRights
|
||||
- function revokeColor
|
||||
- function revokeKingSide
|
||||
- function revokeQueenSide
|
||||
- class CastlingRights
|
||||
- `modules/api/src/main/scala/de/nowchess/api/board/Color.scala` — function opposite, function label
|
||||
- `modules/api/src/main/scala/de/nowchess/api/board/Piece.scala` — class Piece
|
||||
- `modules/api/src/main/scala/de/nowchess/api/board/PieceType.scala` — function label
|
||||
- `modules/api/src/main/scala/de/nowchess/api/board/Square.scala`
|
||||
- class Square
|
||||
- function fromAlgebraic
|
||||
- function offset
|
||||
- `modules/api/src/main/scala/de/nowchess/api/game/GameContext.scala`
|
||||
- function withBoard
|
||||
- function withTurn
|
||||
- function withCastlingRights
|
||||
- function withEnPassantSquare
|
||||
- function withHalfMoveClock
|
||||
- function withMove
|
||||
- _...2 more_
|
||||
- `modules/api/src/main/scala/de/nowchess/api/player/PlayerInfo.scala` — class PlayerId, function apply
|
||||
- `modules/api/src/main/scala/de/nowchess/api/response/ApiResponse.scala`
|
||||
- class ApiResponse
|
||||
- function error
|
||||
- function totalPages
|
||||
- `modules/core/src/main/scala/de/nowchess/chess/command/Command.scala`
|
||||
- class Command
|
||||
- function execute
|
||||
- function undo
|
||||
- function description
|
||||
- class MoveResult
|
||||
- `modules/core/src/main/scala/de/nowchess/chess/command/CommandInvoker.scala`
|
||||
- class CommandInvoker
|
||||
- function execute
|
||||
- function undo
|
||||
- function redo
|
||||
- function history
|
||||
- function getCurrentIndex
|
||||
- _...3 more_
|
||||
- `modules/core/src/main/scala/de/nowchess/chess/controller/Parser.scala` — class Parser, function parseMove
|
||||
- `modules/core/src/main/scala/de/nowchess/chess/engine/GameEngine.scala`
|
||||
- class GameEngine
|
||||
- function isPendingPromotion
|
||||
- function board
|
||||
- function turn
|
||||
- function context
|
||||
- function canUndo
|
||||
- _...10 more_
|
||||
- `modules/core/src/main/scala/de/nowchess/chess/observer/Observer.scala`
|
||||
- function context
|
||||
- class Observer
|
||||
- function onGameEvent
|
||||
- class Observable
|
||||
- function subscribe
|
||||
- function unsubscribe
|
||||
- _...1 more_
|
||||
- `modules/io/src/main/scala/de/nowchess/io/GameContextExport.scala` — class GameContextExport, function exportGameContext
|
||||
- `modules/io/src/main/scala/de/nowchess/io/GameContextImport.scala` — class GameContextImport, function importGameContext
|
||||
- `modules/io/src/main/scala/de/nowchess/io/fen/FenExporter.scala`
|
||||
- class FenExporter
|
||||
- function boardToFen
|
||||
- function gameContextToFen
|
||||
- function exportGameContext
|
||||
- `modules/io/src/main/scala/de/nowchess/io/fen/FenParser.scala`
|
||||
- class FenParser
|
||||
- function parseFen
|
||||
- function importGameContext
|
||||
- function parseBoard
|
||||
- `modules/io/src/main/scala/de/nowchess/io/fen/FenParserCombinators.scala`
|
||||
- class FenParserCombinators
|
||||
- function parseFen
|
||||
- function parseBoard
|
||||
- function importGameContext
|
||||
- `modules/io/src/main/scala/de/nowchess/io/fen/FenParserFastParse.scala`
|
||||
- class FenParserFastParse
|
||||
- function parseFen
|
||||
- function parseBoard
|
||||
- function importGameContext
|
||||
- `modules/io/src/main/scala/de/nowchess/io/fen/FenParserSupport.scala` — function buildSquares
|
||||
- `modules/io/src/main/scala/de/nowchess/io/pgn/PgnExporter.scala`
|
||||
- class PgnExporter
|
||||
- function exportGameContext
|
||||
- function exportGame
|
||||
- `modules/io/src/main/scala/de/nowchess/io/pgn/PgnParser.scala`
|
||||
- class PgnParser
|
||||
- function validatePgn
|
||||
- function importGameContext
|
||||
- function parsePgn
|
||||
- function parseAlgebraicMove
|
||||
- `modules/rule/src/main/scala/de/nowchess/rules/RuleSet.scala`
|
||||
- class RuleSet
|
||||
- function candidateMoves
|
||||
- function legalMoves
|
||||
- function allLegalMoves
|
||||
- function isCheck
|
||||
- function isCheckmate
|
||||
- _...4 more_
|
||||
- `modules/rule/src/main/scala/de/nowchess/rules/sets/DefaultRules.scala`
|
||||
- class DefaultRules
|
||||
- function loop
|
||||
- function toMoves
|
||||
- function loop
|
||||
- `modules/ui/src/main/scala/de/nowchess/ui/Main.scala` — class Main, function main
|
||||
- `modules/ui/src/main/scala/de/nowchess/ui/gui/ChessBoardView.scala`
|
||||
- class ChessBoardView
|
||||
- function updateBoard
|
||||
- function updateUndoRedoButtons
|
||||
- function showMessage
|
||||
- function showPromotionDialog
|
||||
- `modules/ui/src/main/scala/de/nowchess/ui/gui/ChessGUI.scala`
|
||||
- class ChessGUIApp
|
||||
- class ChessGUILauncher
|
||||
- function getEngine
|
||||
- function launch
|
||||
- `modules/ui/src/main/scala/de/nowchess/ui/gui/GUIObserver.scala` — class GUIObserver
|
||||
- `modules/ui/src/main/scala/de/nowchess/ui/gui/PieceSprites.scala`
|
||||
- class PieceSprites
|
||||
- function loadPieceImage
|
||||
- class SquareColors
|
||||
- `modules/ui/src/main/scala/de/nowchess/ui/terminal/TerminalUI.scala` — class TerminalUI, function start
|
||||
- `modules/ui/src/main/scala/de/nowchess/ui/utils/PieceUnicode.scala` — function unicode
|
||||
- `modules/ui/src/main/scala/de/nowchess/ui/utils/Renderer.scala` — class Renderer, function render
|
||||
|
||||
---
|
||||
|
||||
# Dependency Graph
|
||||
|
||||
## Most Imported Files (change these carefully)
|
||||
|
||||
- `modules/api/src/main/scala/de/nowchess/api/game/GameContext.scala` — imported by **28** files
|
||||
- `modules/api/src/main/scala/de/nowchess/api/board/Square.scala` — imported by **21** files
|
||||
- `modules/api/src/main/scala/de/nowchess/api/board/Color.scala` — imported by **19** files
|
||||
- `modules/api/src/main/scala/de/nowchess/api/move/Move.scala` — imported by **14** files
|
||||
- `modules/api/src/main/scala/de/nowchess/api/board/Board.scala` — imported by **13** files
|
||||
- `modules/api/src/main/scala/de/nowchess/api/board/Piece.scala` — imported by **10** files
|
||||
- `modules/api/src/main/scala/de/nowchess/api/board/PieceType.scala` — imported by **9** files
|
||||
- `modules/io/src/main/scala/de/nowchess/io/fen/FenParser.scala` — imported by **9** files
|
||||
- `modules/rule/src/main/scala/de/nowchess/rules/sets/DefaultRules.scala` — imported by **8** files
|
||||
- `modules/io/src/main/scala/de/nowchess/io/GameContextImport.scala` — imported by **7** files
|
||||
- `modules/api/src/main/scala/de/nowchess/api/board/CastlingRights.scala` — imported by **4** files
|
||||
- `modules/io/src/main/scala/de/nowchess/io/GameContextExport.scala` — imported by **4** files
|
||||
- `modules/rule/src/main/scala/de/nowchess/rules/RuleSet.scala` — imported by **4** files
|
||||
- `modules/core/src/main/scala/de/nowchess/chess/observer/Observer.scala` — imported by **4** files
|
||||
- `modules/core/src/main/scala/de/nowchess/chess/engine/GameEngine.scala` — imported by **4** files
|
||||
- `modules/io/src/main/scala/de/nowchess/io/pgn/PgnParser.scala` — imported by **2** files
|
||||
- `modules/io/src/main/scala/de/nowchess/io/pgn/PgnExporter.scala` — imported by **2** files
|
||||
- `modules/io/src/main/scala/de/nowchess/io/fen/FenExporter.scala` — imported by **2** files
|
||||
- `modules/io/src/main/scala/de/nowchess/io/fen/FenParserSupport.scala` — imported by **2** files
|
||||
- `modules/core/src/main/scala/de/nowchess/chess/controller/Parser.scala` — imported by **1** files
|
||||
|
||||
## Import Map (who imports what)
|
||||
|
||||
- `modules/api/src/main/scala/de/nowchess/api/game/GameContext.scala` ← `modules/core/src/main/scala/de/nowchess/chess/command/Command.scala`, `modules/core/src/main/scala/de/nowchess/chess/engine/GameEngine.scala`, `modules/core/src/main/scala/de/nowchess/chess/observer/Observer.scala`, `modules/core/src/test/scala/de/nowchess/chess/command/CommandInvokerBranchTest.scala`, `modules/core/src/test/scala/de/nowchess/chess/command/CommandInvokerTest.scala` +23 more
|
||||
- `modules/api/src/main/scala/de/nowchess/api/board/Square.scala` ← `modules/api/src/main/scala/de/nowchess/api/game/GameContext.scala`, `modules/api/src/main/scala/de/nowchess/api/move/Move.scala`, `modules/api/src/test/scala/de/nowchess/api/game/GameContextTest.scala`, `modules/api/src/test/scala/de/nowchess/api/move/MoveTest.scala`, `modules/core/src/main/scala/de/nowchess/chess/command/Command.scala` +16 more
|
||||
- `modules/api/src/main/scala/de/nowchess/api/board/Color.scala` ← `modules/api/src/main/scala/de/nowchess/api/game/GameContext.scala`, `modules/api/src/test/scala/de/nowchess/api/game/GameContextTest.scala`, `modules/core/src/main/scala/de/nowchess/chess/engine/GameEngine.scala`, `modules/core/src/main/scala/de/nowchess/chess/observer/Observer.scala`, `modules/core/src/test/scala/de/nowchess/chess/engine/EngineTestHelpers.scala` +14 more
|
||||
- `modules/api/src/main/scala/de/nowchess/api/move/Move.scala` ← `modules/api/src/main/scala/de/nowchess/api/game/GameContext.scala`, `modules/api/src/test/scala/de/nowchess/api/board/BoardTest.scala`, `modules/api/src/test/scala/de/nowchess/api/game/GameContextTest.scala`, `modules/core/src/main/scala/de/nowchess/chess/engine/GameEngine.scala`, `modules/core/src/test/scala/de/nowchess/chess/engine/GameEngineIntegrationTest.scala` +9 more
|
||||
- `modules/api/src/main/scala/de/nowchess/api/board/Board.scala` ← `modules/api/src/main/scala/de/nowchess/api/game/GameContext.scala`, `modules/api/src/test/scala/de/nowchess/api/game/GameContextTest.scala`, `modules/core/src/main/scala/de/nowchess/chess/engine/GameEngine.scala`, `modules/core/src/test/scala/de/nowchess/chess/engine/EngineTestHelpers.scala`, `modules/core/src/test/scala/de/nowchess/chess/engine/GameEngineGameEndingTest.scala` +8 more
|
||||
- `modules/api/src/main/scala/de/nowchess/api/board/Piece.scala` ← `modules/core/src/main/scala/de/nowchess/chess/command/Command.scala`, `modules/core/src/main/scala/de/nowchess/chess/engine/GameEngine.scala`, `modules/core/src/test/scala/de/nowchess/chess/engine/GameEnginePromotionTest.scala`, `modules/core/src/test/scala/de/nowchess/chess/engine/GameEngineScenarioTest.scala`, `modules/rule/src/test/scala/de/nowchess/rule/DefaultRulesStateTransitionsTest.scala` +5 more
|
||||
- `modules/api/src/main/scala/de/nowchess/api/board/PieceType.scala` ← `modules/core/src/main/scala/de/nowchess/chess/engine/GameEngine.scala`, `modules/core/src/test/scala/de/nowchess/chess/engine/GameEngineIntegrationTest.scala`, `modules/core/src/test/scala/de/nowchess/chess/engine/GameEnginePromotionTest.scala`, `modules/rule/src/test/scala/de/nowchess/rule/DefaultRulesStateTransitionsTest.scala`, `modules/rule/src/test/scala/de/nowchess/rule/DefaultRulesTest.scala` +4 more
|
||||
- `modules/io/src/main/scala/de/nowchess/io/fen/FenParser.scala` ← `modules/core/src/test/scala/de/nowchess/chess/engine/EngineTestHelpers.scala`, `modules/core/src/test/scala/de/nowchess/chess/engine/GameEngineLoadGameTest.scala`, `modules/core/src/test/scala/de/nowchess/chess/engine/GameEngineNotationTest.scala`, `modules/core/src/test/scala/de/nowchess/chess/engine/GameEnginePromotionTest.scala`, `modules/core/src/test/scala/de/nowchess/chess/engine/GameEngineScenarioTest.scala` +4 more
|
||||
- `modules/rule/src/main/scala/de/nowchess/rules/sets/DefaultRules.scala` ← `modules/core/src/main/scala/de/nowchess/chess/engine/GameEngine.scala`, `modules/core/src/test/scala/de/nowchess/chess/engine/EngineTestHelpers.scala`, `modules/core/src/test/scala/de/nowchess/chess/engine/GameEngineIntegrationTest.scala`, `modules/core/src/test/scala/de/nowchess/chess/engine/GameEnginePromotionTest.scala`, `modules/io/src/main/scala/de/nowchess/io/pgn/PgnExporter.scala` +3 more
|
||||
- `modules/io/src/main/scala/de/nowchess/io/GameContextImport.scala` ← `modules/core/src/main/scala/de/nowchess/chess/engine/GameEngine.scala`, `modules/core/src/test/scala/de/nowchess/chess/engine/GameEngineIntegrationTest.scala`, `modules/io/src/main/scala/de/nowchess/io/fen/FenParser.scala`, `modules/io/src/main/scala/de/nowchess/io/fen/FenParserCombinators.scala`, `modules/io/src/main/scala/de/nowchess/io/fen/FenParserFastParse.scala` +2 more
|
||||
|
||||
---
|
||||
|
||||
_Generated by [codesight](https://github.com/Houseofmvps/codesight) — see your codebase clearly_
|
||||
@@ -0,0 +1,37 @@
|
||||
# Dependency Graph
|
||||
|
||||
## Most Imported Files (change these carefully)
|
||||
|
||||
- `modules/api/src/main/scala/de/nowchess/api/game/GameContext.scala` — imported by **28** files
|
||||
- `modules/api/src/main/scala/de/nowchess/api/board/Square.scala` — imported by **21** files
|
||||
- `modules/api/src/main/scala/de/nowchess/api/board/Color.scala` — imported by **19** files
|
||||
- `modules/api/src/main/scala/de/nowchess/api/move/Move.scala` — imported by **14** files
|
||||
- `modules/api/src/main/scala/de/nowchess/api/board/Board.scala` — imported by **13** files
|
||||
- `modules/api/src/main/scala/de/nowchess/api/board/Piece.scala` — imported by **10** files
|
||||
- `modules/api/src/main/scala/de/nowchess/api/board/PieceType.scala` — imported by **9** files
|
||||
- `modules/io/src/main/scala/de/nowchess/io/fen/FenParser.scala` — imported by **9** files
|
||||
- `modules/rule/src/main/scala/de/nowchess/rules/sets/DefaultRules.scala` — imported by **8** files
|
||||
- `modules/io/src/main/scala/de/nowchess/io/GameContextImport.scala` — imported by **7** files
|
||||
- `modules/api/src/main/scala/de/nowchess/api/board/CastlingRights.scala` — imported by **4** files
|
||||
- `modules/io/src/main/scala/de/nowchess/io/GameContextExport.scala` — imported by **4** files
|
||||
- `modules/rule/src/main/scala/de/nowchess/rules/RuleSet.scala` — imported by **4** files
|
||||
- `modules/core/src/main/scala/de/nowchess/chess/observer/Observer.scala` — imported by **4** files
|
||||
- `modules/core/src/main/scala/de/nowchess/chess/engine/GameEngine.scala` — imported by **4** files
|
||||
- `modules/io/src/main/scala/de/nowchess/io/pgn/PgnParser.scala` — imported by **2** files
|
||||
- `modules/io/src/main/scala/de/nowchess/io/pgn/PgnExporter.scala` — imported by **2** files
|
||||
- `modules/io/src/main/scala/de/nowchess/io/fen/FenExporter.scala` — imported by **2** files
|
||||
- `modules/io/src/main/scala/de/nowchess/io/fen/FenParserSupport.scala` — imported by **2** files
|
||||
- `modules/core/src/main/scala/de/nowchess/chess/controller/Parser.scala` — imported by **1** files
|
||||
|
||||
## Import Map (who imports what)
|
||||
|
||||
- `modules/api/src/main/scala/de/nowchess/api/game/GameContext.scala` ← `modules/core/src/main/scala/de/nowchess/chess/command/Command.scala`, `modules/core/src/main/scala/de/nowchess/chess/engine/GameEngine.scala`, `modules/core/src/main/scala/de/nowchess/chess/observer/Observer.scala`, `modules/core/src/test/scala/de/nowchess/chess/command/CommandInvokerBranchTest.scala`, `modules/core/src/test/scala/de/nowchess/chess/command/CommandInvokerTest.scala` +23 more
|
||||
- `modules/api/src/main/scala/de/nowchess/api/board/Square.scala` ← `modules/api/src/main/scala/de/nowchess/api/game/GameContext.scala`, `modules/api/src/main/scala/de/nowchess/api/move/Move.scala`, `modules/api/src/test/scala/de/nowchess/api/game/GameContextTest.scala`, `modules/api/src/test/scala/de/nowchess/api/move/MoveTest.scala`, `modules/core/src/main/scala/de/nowchess/chess/command/Command.scala` +16 more
|
||||
- `modules/api/src/main/scala/de/nowchess/api/board/Color.scala` ← `modules/api/src/main/scala/de/nowchess/api/game/GameContext.scala`, `modules/api/src/test/scala/de/nowchess/api/game/GameContextTest.scala`, `modules/core/src/main/scala/de/nowchess/chess/engine/GameEngine.scala`, `modules/core/src/main/scala/de/nowchess/chess/observer/Observer.scala`, `modules/core/src/test/scala/de/nowchess/chess/engine/EngineTestHelpers.scala` +14 more
|
||||
- `modules/api/src/main/scala/de/nowchess/api/move/Move.scala` ← `modules/api/src/main/scala/de/nowchess/api/game/GameContext.scala`, `modules/api/src/test/scala/de/nowchess/api/board/BoardTest.scala`, `modules/api/src/test/scala/de/nowchess/api/game/GameContextTest.scala`, `modules/core/src/main/scala/de/nowchess/chess/engine/GameEngine.scala`, `modules/core/src/test/scala/de/nowchess/chess/engine/GameEngineIntegrationTest.scala` +9 more
|
||||
- `modules/api/src/main/scala/de/nowchess/api/board/Board.scala` ← `modules/api/src/main/scala/de/nowchess/api/game/GameContext.scala`, `modules/api/src/test/scala/de/nowchess/api/game/GameContextTest.scala`, `modules/core/src/main/scala/de/nowchess/chess/engine/GameEngine.scala`, `modules/core/src/test/scala/de/nowchess/chess/engine/EngineTestHelpers.scala`, `modules/core/src/test/scala/de/nowchess/chess/engine/GameEngineGameEndingTest.scala` +8 more
|
||||
- `modules/api/src/main/scala/de/nowchess/api/board/Piece.scala` ← `modules/core/src/main/scala/de/nowchess/chess/command/Command.scala`, `modules/core/src/main/scala/de/nowchess/chess/engine/GameEngine.scala`, `modules/core/src/test/scala/de/nowchess/chess/engine/GameEnginePromotionTest.scala`, `modules/core/src/test/scala/de/nowchess/chess/engine/GameEngineScenarioTest.scala`, `modules/rule/src/test/scala/de/nowchess/rule/DefaultRulesStateTransitionsTest.scala` +5 more
|
||||
- `modules/api/src/main/scala/de/nowchess/api/board/PieceType.scala` ← `modules/core/src/main/scala/de/nowchess/chess/engine/GameEngine.scala`, `modules/core/src/test/scala/de/nowchess/chess/engine/GameEngineIntegrationTest.scala`, `modules/core/src/test/scala/de/nowchess/chess/engine/GameEnginePromotionTest.scala`, `modules/rule/src/test/scala/de/nowchess/rule/DefaultRulesStateTransitionsTest.scala`, `modules/rule/src/test/scala/de/nowchess/rule/DefaultRulesTest.scala` +4 more
|
||||
- `modules/io/src/main/scala/de/nowchess/io/fen/FenParser.scala` ← `modules/core/src/test/scala/de/nowchess/chess/engine/EngineTestHelpers.scala`, `modules/core/src/test/scala/de/nowchess/chess/engine/GameEngineLoadGameTest.scala`, `modules/core/src/test/scala/de/nowchess/chess/engine/GameEngineNotationTest.scala`, `modules/core/src/test/scala/de/nowchess/chess/engine/GameEnginePromotionTest.scala`, `modules/core/src/test/scala/de/nowchess/chess/engine/GameEngineScenarioTest.scala` +4 more
|
||||
- `modules/rule/src/main/scala/de/nowchess/rules/sets/DefaultRules.scala` ← `modules/core/src/main/scala/de/nowchess/chess/engine/GameEngine.scala`, `modules/core/src/test/scala/de/nowchess/chess/engine/EngineTestHelpers.scala`, `modules/core/src/test/scala/de/nowchess/chess/engine/GameEngineIntegrationTest.scala`, `modules/core/src/test/scala/de/nowchess/chess/engine/GameEnginePromotionTest.scala`, `modules/io/src/main/scala/de/nowchess/io/pgn/PgnExporter.scala` +3 more
|
||||
- `modules/io/src/main/scala/de/nowchess/io/GameContextImport.scala` ← `modules/core/src/main/scala/de/nowchess/chess/engine/GameEngine.scala`, `modules/core/src/test/scala/de/nowchess/chess/engine/GameEngineIntegrationTest.scala`, `modules/io/src/main/scala/de/nowchess/io/fen/FenParser.scala`, `modules/io/src/main/scala/de/nowchess/io/fen/FenParserCombinators.scala`, `modules/io/src/main/scala/de/nowchess/io/fen/FenParserFastParse.scala` +2 more
|
||||
@@ -0,0 +1,150 @@
|
||||
# Libraries
|
||||
|
||||
- `jacoco-reporter/scoverage_coverage_gaps.py`
|
||||
- function parse_scoverage_xml: (xml_path) -> tuple[dict, list[ClassGap]]
|
||||
- function format_agent: (project_stats, classes) -> str
|
||||
- function format_json: (project_stats, classes) -> str
|
||||
- function format_markdown: (project_stats, classes) -> str
|
||||
- function format_module_gaps: (module_name, classes, stmt_pct) -> str
|
||||
- function run_scan_modules: (modules_dir, package_filter, min_coverage) -> None
|
||||
- _...4 more_
|
||||
- `jacoco-reporter/test_gaps.py`
|
||||
- function parse_suite_xml: (xml_path) -> SuiteResult
|
||||
- function load_module: (module_dir, results_subdir) -> Optional[ModuleResult]
|
||||
- function format_module: (mod) -> str
|
||||
- function run: (modules_dir, results_subdir, module_filter) -> None
|
||||
- function main: () -> None
|
||||
- class TestCase
|
||||
- _...2 more_
|
||||
- `modules/api/src/main/scala/de/nowchess/api/board/Board.scala`
|
||||
- class Board
|
||||
- function apply
|
||||
- function pieceAt
|
||||
- function updated
|
||||
- function removed
|
||||
- function withMove
|
||||
- _...2 more_
|
||||
- `modules/api/src/main/scala/de/nowchess/api/board/CastlingRights.scala`
|
||||
- function hasAnyRights
|
||||
- function hasRights
|
||||
- function revokeColor
|
||||
- function revokeKingSide
|
||||
- function revokeQueenSide
|
||||
- class CastlingRights
|
||||
- `modules/api/src/main/scala/de/nowchess/api/board/Color.scala` — function opposite, function label
|
||||
- `modules/api/src/main/scala/de/nowchess/api/board/Piece.scala` — class Piece
|
||||
- `modules/api/src/main/scala/de/nowchess/api/board/PieceType.scala` — function label
|
||||
- `modules/api/src/main/scala/de/nowchess/api/board/Square.scala`
|
||||
- class Square
|
||||
- function fromAlgebraic
|
||||
- function offset
|
||||
- `modules/api/src/main/scala/de/nowchess/api/game/GameContext.scala`
|
||||
- function withBoard
|
||||
- function withTurn
|
||||
- function withCastlingRights
|
||||
- function withEnPassantSquare
|
||||
- function withHalfMoveClock
|
||||
- function withMove
|
||||
- _...2 more_
|
||||
- `modules/api/src/main/scala/de/nowchess/api/player/PlayerInfo.scala` — class PlayerId, function apply
|
||||
- `modules/api/src/main/scala/de/nowchess/api/response/ApiResponse.scala`
|
||||
- class ApiResponse
|
||||
- function error
|
||||
- function totalPages
|
||||
- `modules/core/src/main/scala/de/nowchess/chess/command/Command.scala`
|
||||
- class Command
|
||||
- function execute
|
||||
- function undo
|
||||
- function description
|
||||
- class MoveResult
|
||||
- `modules/core/src/main/scala/de/nowchess/chess/command/CommandInvoker.scala`
|
||||
- class CommandInvoker
|
||||
- function execute
|
||||
- function undo
|
||||
- function redo
|
||||
- function history
|
||||
- function getCurrentIndex
|
||||
- _...3 more_
|
||||
- `modules/core/src/main/scala/de/nowchess/chess/controller/Parser.scala` — class Parser, function parseMove
|
||||
- `modules/core/src/main/scala/de/nowchess/chess/engine/GameEngine.scala`
|
||||
- class GameEngine
|
||||
- function isPendingPromotion
|
||||
- function board
|
||||
- function turn
|
||||
- function context
|
||||
- function canUndo
|
||||
- _...10 more_
|
||||
- `modules/core/src/main/scala/de/nowchess/chess/observer/Observer.scala`
|
||||
- function context
|
||||
- class Observer
|
||||
- function onGameEvent
|
||||
- class Observable
|
||||
- function subscribe
|
||||
- function unsubscribe
|
||||
- _...1 more_
|
||||
- `modules/io/src/main/scala/de/nowchess/io/GameContextExport.scala` — class GameContextExport, function exportGameContext
|
||||
- `modules/io/src/main/scala/de/nowchess/io/GameContextImport.scala` — class GameContextImport, function importGameContext
|
||||
- `modules/io/src/main/scala/de/nowchess/io/fen/FenExporter.scala`
|
||||
- class FenExporter
|
||||
- function boardToFen
|
||||
- function gameContextToFen
|
||||
- function exportGameContext
|
||||
- `modules/io/src/main/scala/de/nowchess/io/fen/FenParser.scala`
|
||||
- class FenParser
|
||||
- function parseFen
|
||||
- function importGameContext
|
||||
- function parseBoard
|
||||
- `modules/io/src/main/scala/de/nowchess/io/fen/FenParserCombinators.scala`
|
||||
- class FenParserCombinators
|
||||
- function parseFen
|
||||
- function parseBoard
|
||||
- function importGameContext
|
||||
- `modules/io/src/main/scala/de/nowchess/io/fen/FenParserFastParse.scala`
|
||||
- class FenParserFastParse
|
||||
- function parseFen
|
||||
- function parseBoard
|
||||
- function importGameContext
|
||||
- `modules/io/src/main/scala/de/nowchess/io/fen/FenParserSupport.scala` — function buildSquares
|
||||
- `modules/io/src/main/scala/de/nowchess/io/pgn/PgnExporter.scala`
|
||||
- class PgnExporter
|
||||
- function exportGameContext
|
||||
- function exportGame
|
||||
- `modules/io/src/main/scala/de/nowchess/io/pgn/PgnParser.scala`
|
||||
- class PgnParser
|
||||
- function validatePgn
|
||||
- function importGameContext
|
||||
- function parsePgn
|
||||
- function parseAlgebraicMove
|
||||
- `modules/rule/src/main/scala/de/nowchess/rules/RuleSet.scala`
|
||||
- class RuleSet
|
||||
- function candidateMoves
|
||||
- function legalMoves
|
||||
- function allLegalMoves
|
||||
- function isCheck
|
||||
- function isCheckmate
|
||||
- _...4 more_
|
||||
- `modules/rule/src/main/scala/de/nowchess/rules/sets/DefaultRules.scala`
|
||||
- class DefaultRules
|
||||
- function loop
|
||||
- function toMoves
|
||||
- function loop
|
||||
- `modules/ui/src/main/scala/de/nowchess/ui/Main.scala` — class Main, function main
|
||||
- `modules/ui/src/main/scala/de/nowchess/ui/gui/ChessBoardView.scala`
|
||||
- class ChessBoardView
|
||||
- function updateBoard
|
||||
- function updateUndoRedoButtons
|
||||
- function showMessage
|
||||
- function showPromotionDialog
|
||||
- `modules/ui/src/main/scala/de/nowchess/ui/gui/ChessGUI.scala`
|
||||
- class ChessGUIApp
|
||||
- class ChessGUILauncher
|
||||
- function getEngine
|
||||
- function launch
|
||||
- `modules/ui/src/main/scala/de/nowchess/ui/gui/GUIObserver.scala` — class GUIObserver
|
||||
- `modules/ui/src/main/scala/de/nowchess/ui/gui/PieceSprites.scala`
|
||||
- class PieceSprites
|
||||
- function loadPieceImage
|
||||
- class SquareColors
|
||||
- `modules/ui/src/main/scala/de/nowchess/ui/terminal/TerminalUI.scala` — class TerminalUI, function start
|
||||
- `modules/ui/src/main/scala/de/nowchess/ui/utils/PieceUnicode.scala` — function unicode
|
||||
- `modules/ui/src/main/scala/de/nowchess/ui/utils/Renderer.scala` — class Renderer, function render
|
||||
@@ -0,0 +1,44 @@
|
||||
# NowChessSystems — Wiki
|
||||
|
||||
_Generated 2026-04-12 — re-run `npx codesight --wiki` if the codebase has changed._
|
||||
|
||||
Structural map compiled from source code via AST. No LLM — deterministic, 200ms.
|
||||
|
||||
> **How to use safely:** These articles tell you WHERE things live and WHAT exists. They do not show full implementation logic. Always read the actual source files before implementing new features or making changes. Never infer how a function works from the wiki alone.
|
||||
|
||||
## Articles
|
||||
|
||||
- [Overview](./overview.md)
|
||||
|
||||
## Quick Stats
|
||||
|
||||
- Routes: **0**
|
||||
- Models: **0**
|
||||
- Components: **0**
|
||||
- Env vars: **0** required, **0** with defaults
|
||||
|
||||
## How to Use
|
||||
|
||||
- **New session:** read `index.md` (this file) for orientation — WHERE things are
|
||||
- **Architecture question:** read `overview.md` (~500 tokens)
|
||||
- **Domain question:** read the relevant article, then **read those source files**
|
||||
- **Database question:** read `database.md`, then read the actual schema files
|
||||
- **Before implementing anything:** read the source files listed in the article
|
||||
- **Full source context:** read `.codesight/CODESIGHT.md`
|
||||
|
||||
## What the Wiki Does Not Cover
|
||||
|
||||
These exist in your codebase but are **not** reflected in wiki articles:
|
||||
- Routes registered dynamically at runtime (loops, plugin factories, `app.use(dynamicRouter)`)
|
||||
- Internal routes from npm packages (e.g. Better Auth's built-in `/api/auth/*` endpoints)
|
||||
- WebSocket and SSE handlers
|
||||
- Raw SQL tables not declared through an ORM
|
||||
- Computed or virtual fields absent from schema declarations
|
||||
- TypeScript types that are not actual database columns
|
||||
- Routes marked `[inferred]` were detected via regex and may have lower precision
|
||||
- gRPC, tRPC, and GraphQL resolvers may be partially captured
|
||||
|
||||
When in doubt, search the source. The wiki is a starting point, not a complete inventory.
|
||||
|
||||
---
|
||||
_Last compiled: 2026-04-12 · 2 articles · [codesight](https://github.com/Houseofmvps/codesight)_
|
||||
@@ -0,0 +1,5 @@
|
||||
# Wiki Log
|
||||
|
||||
History of `npx codesight --wiki` runs. Capped at 20 entries.
|
||||
|
||||
## [2026-04-12 14:34:19] scan | 0 routes, 0 models, 0 components → 2 articles
|
||||
@@ -0,0 +1,19 @@
|
||||
# NowChessSystems — Overview
|
||||
|
||||
> **Navigation aid.** This article shows WHERE things live (routes, models, files). Read actual source files before implementing new features or making changes.
|
||||
|
||||
**NowChessSystems** is a scala project built with raw-http.
|
||||
|
||||
## High-Impact Files
|
||||
|
||||
Changes to these files have the widest blast radius across the codebase:
|
||||
|
||||
- `modules/api/src/main/scala/de/nowchess/api/game/GameContext.scala` — imported by **28** files
|
||||
- `modules/api/src/main/scala/de/nowchess/api/board/Square.scala` — imported by **21** files
|
||||
- `modules/api/src/main/scala/de/nowchess/api/board/Color.scala` — imported by **19** files
|
||||
- `modules/api/src/main/scala/de/nowchess/api/move/Move.scala` — imported by **14** files
|
||||
- `modules/api/src/main/scala/de/nowchess/api/board/Board.scala` — imported by **13** files
|
||||
- `modules/api/src/main/scala/de/nowchess/api/board/Piece.scala` — imported by **10** files
|
||||
|
||||
---
|
||||
_Back to [index.md](./index.md) · Generated 2026-04-12_
|
||||
@@ -0,0 +1,41 @@
|
||||
# Normalize text files in the repo
|
||||
* text=auto eol=lf
|
||||
|
||||
# Keep Windows command scripts in CRLF
|
||||
*.bat text eol=crlf
|
||||
*.cmd text eol=crlf
|
||||
|
||||
# Keep Unix shell scripts in LF
|
||||
*.sh text eol=lf
|
||||
|
||||
# Binary assets (no EOL normalization / textual diff)
|
||||
*.png binary
|
||||
*.jpg binary
|
||||
*.jpeg binary
|
||||
*.gif binary
|
||||
*.webp binary
|
||||
*.bmp binary
|
||||
*.ico binary
|
||||
|
||||
# ML / model / numeric artifacts
|
||||
*.bin binary
|
||||
*.pt binary
|
||||
*.pth binary
|
||||
*.onnx binary
|
||||
*.h5 binary
|
||||
*.hdf5 binary
|
||||
*.pb binary
|
||||
*.tflite binary
|
||||
*.npy binary
|
||||
*.npz binary
|
||||
*.safetensors binary
|
||||
|
||||
# Firmware / hex-like artifacts
|
||||
*.hex binary
|
||||
|
||||
# Packaged binaries
|
||||
*.jar binary
|
||||
*.zip binary
|
||||
*.7z binary
|
||||
*.gz binary
|
||||
|
||||
@@ -0,0 +1,6 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="AndroidProjectSystem">
|
||||
<option name="providerId" value="com.android.tools.idea.GradleProjectSystem" />
|
||||
</component>
|
||||
</project>
|
||||
@@ -12,6 +12,9 @@
|
||||
<option value="$PROJECT_DIR$/modules" />
|
||||
<option value="$PROJECT_DIR$/modules/api" />
|
||||
<option value="$PROJECT_DIR$/modules/core" />
|
||||
<option value="$PROJECT_DIR$/modules/io" />
|
||||
<option value="$PROJECT_DIR$/modules/rule" />
|
||||
<option value="$PROJECT_DIR$/modules/ui" />
|
||||
</set>
|
||||
</option>
|
||||
</GradleProjectSettings>
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="ExternalStorageConfigurationManager" enabled="true" />
|
||||
<component name="FrameworkDetectionExcludesConfiguration">
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
<option name="deprecationWarnings" value="true" />
|
||||
<option name="uncheckedWarnings" value="true" />
|
||||
</profile>
|
||||
<profile name="Gradle 2" modules="NowChessSystems.modules.core.main,NowChessSystems.modules.core.scoverage,NowChessSystems.modules.core.test">
|
||||
<profile name="Gradle 2" modules="NowChessSystems.modules.core.main,NowChessSystems.modules.core.scoverage,NowChessSystems.modules.core.test,NowChessSystems.modules.io.main,NowChessSystems.modules.io.scoverage,NowChessSystems.modules.io.test,NowChessSystems.modules.rule.main,NowChessSystems.modules.rule.scoverage,NowChessSystems.modules.rule.test,NowChessSystems.modules.ui.main,NowChessSystems.modules.ui.scoverage,NowChessSystems.modules.ui.test">
|
||||
<option name="deprecationWarnings" value="true" />
|
||||
<option name="uncheckedWarnings" value="true" />
|
||||
<parameters>
|
||||
|
||||
@@ -6,7 +6,17 @@
|
||||
<inspection_tool class="CommitNamingConvention" enabled="true" level="WARNING" enabled_by_default="true" />
|
||||
</profile>
|
||||
</component>
|
||||
<component name="IssueNavigationConfiguration">
|
||||
<option name="links">
|
||||
<list>
|
||||
<IssueNavigationLink>
|
||||
<option name="issueRegexp" value="(?x)\b(CORE|NCWF|BAC|FRO|K8S|ORG|NCI|NCS)-\d+\b#YouTrack" />
|
||||
<option name="linkRegexp" value="https://knockoutwhist.youtrack.cloud/issue/$0" />
|
||||
</IssueNavigationLink>
|
||||
</list>
|
||||
</option>
|
||||
</component>
|
||||
<component name="VcsDirectoryMappings">
|
||||
<mapping directory="$PROJECT_DIR$" vcs="Git" />
|
||||
<mapping directory="" vcs="Git" />
|
||||
</component>
|
||||
</project>
|
||||
@@ -0,0 +1,15 @@
|
||||
rules = [
|
||||
DisableSyntax,
|
||||
LeakingImplicitClassVal,
|
||||
NoValInForComprehension,
|
||||
ProcedureSyntax,
|
||||
]
|
||||
|
||||
DisableSyntax.noVars = true
|
||||
DisableSyntax.noThrows = true
|
||||
DisableSyntax.noNulls = true
|
||||
DisableSyntax.noReturns = true
|
||||
DisableSyntax.noAsInstanceOf = true
|
||||
DisableSyntax.noIsInstanceOf = true
|
||||
DisableSyntax.noXml = true
|
||||
DisableSyntax.noFinalize = true
|
||||
@@ -0,0 +1,8 @@
|
||||
version = 3.8.1
|
||||
runner.dialect = scala3
|
||||
maxColumn = 120
|
||||
indent.main = 2
|
||||
align.preset = more
|
||||
trailingCommas = always
|
||||
rewrite.rules = [SortImports, RedundantBraces]
|
||||
rewrite.scala3.convertToNewSyntax = true
|
||||
@@ -0,0 +1,21 @@
|
||||
# Project Context
|
||||
|
||||
This is a scala project using raw-http.
|
||||
|
||||
Middleware includes: custom.
|
||||
|
||||
High-impact files (most imported, changes here affect many other files):
|
||||
- modules/api/src/main/scala/de/nowchess/api/game/GameContext.scala (imported by 50 files)
|
||||
- modules/api/src/main/scala/de/nowchess/api/board/Square.scala (imported by 33 files)
|
||||
- modules/api/src/main/scala/de/nowchess/api/board/Color.scala (imported by 30 files)
|
||||
- modules/api/src/main/scala/de/nowchess/api/move/Move.scala (imported by 29 files)
|
||||
- modules/api/src/main/scala/de/nowchess/api/board/Board.scala (imported by 19 files)
|
||||
- modules/api/src/main/scala/de/nowchess/api/board/PieceType.scala (imported by 18 files)
|
||||
- modules/rule/src/main/scala/de/nowchess/rules/sets/DefaultRules.scala (imported by 17 files)
|
||||
- modules/api/src/main/scala/de/nowchess/api/board/Piece.scala (imported by 15 files)
|
||||
|
||||
Required environment variables (no defaults):
|
||||
- STOCKFISH_PATH (modules/bot/python/nnue.py)
|
||||
|
||||
Read .codesight/wiki/index.md for orientation (WHERE things live). Then read actual source files before implementing. Wiki articles are navigation aids, not implementation guides.
|
||||
Read .codesight/CODESIGHT.md for the complete AI context map including all routes, schema, components, libraries, config, middleware, and dependency graph.
|
||||
@@ -0,0 +1,7 @@
|
||||
YOU CAN:
|
||||
- Edit and use the asset in any commercial or non commercial project
|
||||
- Use the asset in any commercial or non commercial project
|
||||
|
||||
YOU CAN'T:
|
||||
- Resell or distribute the asset to others
|
||||
- Edit and resell the asset to others - - Credits required using This link: https://fatman200.itch.io/
|
||||
|
After Width: | Height: | Size: 28 KiB |
|
After Width: | Height: | Size: 31 KiB |
|
After Width: | Height: | Size: 3.3 KiB |
|
After Width: | Height: | Size: 907 B |
|
After Width: | Height: | Size: 919 B |
|
After Width: | Height: | Size: 818 B |
|
After Width: | Height: | Size: 1.2 KiB |
|
After Width: | Height: | Size: 1.6 KiB |
|
After Width: | Height: | Size: 161 B |
|
After Width: | Height: | Size: 188 B |
|
After Width: | Height: | Size: 188 B |
|
After Width: | Height: | Size: 237 B |
|
After Width: | Height: | Size: 243 B |
|
After Width: | Height: | Size: 264 B |
|
After Width: | Height: | Size: 244 B |
|
After Width: | Height: | Size: 240 B |
|
After Width: | Height: | Size: 232 B |
|
After Width: | Height: | Size: 287 B |
|
After Width: | Height: | Size: 211 B |
|
After Width: | Height: | Size: 238 B |
|
After Width: | Height: | Size: 227 B |
|
After Width: | Height: | Size: 267 B |
|
After Width: | Height: | Size: 300 B |
|
After Width: | Height: | Size: 218 B |
|
After Width: | Height: | Size: 244 B |
|
After Width: | Height: | Size: 245 B |
|
After Width: | Height: | Size: 229 B |
|
After Width: | Height: | Size: 286 B |
|
After Width: | Height: | Size: 245 B |
|
After Width: | Height: | Size: 266 B |
|
After Width: | Height: | Size: 297 B |
|
After Width: | Height: | Size: 258 B |
|
After Width: | Height: | Size: 263 B |
|
After Width: | Height: | Size: 313 B |
|
After Width: | Height: | Size: 251 B |
|
After Width: | Height: | Size: 275 B |
|
After Width: | Height: | Size: 305 B |
|
After Width: | Height: | Size: 281 B |
|
After Width: | Height: | Size: 280 B |
@@ -1,58 +1,95 @@
|
||||
# CLAUDE.md
|
||||
# Now-Chess
|
||||
|
||||
This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
|
||||
Scala 3.5.1 · Gradle 9
|
||||
|
||||
## Build & Test Commands
|
||||
## Commands
|
||||
|
||||
```bash
|
||||
# Build everything
|
||||
./gradlew build
|
||||
|
||||
# Build a single module
|
||||
./gradlew :modules:<service>:build
|
||||
|
||||
# Run tests for a single module
|
||||
./gradlew :modules:<service>:test
|
||||
|
||||
# Run a specific test class
|
||||
./gradlew :modules:<service>:test --tests "de.nowchess.<service>.<ClassName>"
|
||||
```
|
||||
./clean # Clear build dirs — only when necessary
|
||||
./compile # Compile all modules — always run
|
||||
./test # Run all tests
|
||||
./coverage # Check coverage
|
||||
```
|
||||
Try to stick to these commands for consistency.
|
||||
|
||||
The only current module is `core` (`modules/core`).
|
||||
## Modules
|
||||
|
||||
## Architecture
|
||||
| Module | Role | Depends on |
|
||||
|--------|------|-----------|
|
||||
| `api` | Model / shared types | (none) |
|
||||
| `core` | Primary business logic | api, rule |
|
||||
| `rule` | Game rules | api |
|
||||
| `io` | Export formats | api, core |
|
||||
| `ui` | Entrypoint & UI | core, io |
|
||||
|
||||
**NowChessSystems** is a chess platform built as a Scala 3 + Quarkus microservice system.
|
||||
## Style
|
||||
|
||||
- Multi-module Gradle project; every service lives under `modules/{service-name}`.
|
||||
- Shared dependency versions live in the root `build.gradle.kts` under `extra["VERSIONS"]`.
|
||||
- Each module reads versions via `rootProject.extra["VERSIONS"] as Map<String, String>`.
|
||||
- `settings.gradle.kts` must `include(":modules:<service>")` for every module.
|
||||
- Use immutable data and pure functions.
|
||||
- Keep functions under 30 lines. If you need "and" to describe it, split it.
|
||||
- Keep cyclomatic complexity under 15.
|
||||
- Avoid comments. Let names carry intent; comment only non-obvious algorithms.
|
||||
- Scan for duplicated logic before finishing. Extract it.
|
||||
- Follow default Sonar style for Scala.
|
||||
- Use `Option` or `Either` for fallible operations; avoid exceptions for control flow.
|
||||
- Naming: types are PascalCase, functions/values are camelCase.
|
||||
|
||||
### Stack (ADR-001)
|
||||
| Layer | Technology |
|
||||
|---|---|
|
||||
| Language | Scala 3.5.x |
|
||||
| Backend framework | Quarkus + `quarkus-scala3` extension |
|
||||
| Persistence | Hibernate / Jakarta Persistence |
|
||||
| Frontend (TBD) | Vite; React/Angular/Vue under evaluation |
|
||||
| TUI | Lanterna |
|
||||
| Container orchestration | Kubernetes + ArgoCD + Kargo |
|
||||
## Code Quality
|
||||
|
||||
### Key Scala 3 / Quarkus Rules
|
||||
- Use `given`/`using`, not `implicit` (no Scala 2 idioms).
|
||||
- Use `Option`/`Either`/`Try`, never `null` or `.get`.
|
||||
- Jakarta annotations only (`jakarta.*`), never `javax.*`.
|
||||
- Use reactive types (`Uni`, `Multi`) for I/O; no blocking calls on the event loop.
|
||||
- **Always exclude `org.scala-lang:scala-library` from Quarkus BOM** to avoid Scala 2 conflicts.
|
||||
- **Unit tests use `extends AnyFunSuite with Matchers with JUnitSuiteLike`** — ScalaTest DSL, no `@Test` annotations needed.
|
||||
- **Integration tests use `@QuarkusTest` with JUnit 5** — explicit `: Unit` return type still required on `@Test` methods.
|
||||
- **Coverage:** 100% condition coverage required in `api`, `core`, `rule`, `io` (mandatory); `ui` exempt.
|
||||
|
||||
### Agent Workflow (for new services)
|
||||
1. **architect** → writes OpenAPI contract to `docs/api/{service}.yaml` and ADR to `docs/adr/`.
|
||||
2. **scala-implementer** → reads contract, implements service under `modules/{service}/`.
|
||||
3. **test-writer** → writes `@QuarkusTest` integration tests and `AnyFunSuite with Matchers with JUnitSuiteLike` unit tests.
|
||||
4. **gradle-builder** → resolves any build/dependency issues.
|
||||
5. **code-reviewer** → reviews; reports findings back without self-fixing.
|
||||
### Linters
|
||||
|
||||
Detailed working agreement (plan/verify/unresolved workflow) is in `.claude/CLAUDE.MD`.
|
||||
- **scalafmt** — enforces formatting; run `./gradlew spotlessScalaCheck` to check and `./gradlew spotlessScalaApply` to refactor.
|
||||
- **scalafix** — enforces style and detects unused imports/code; run `./gradlew scalafix` to apply rules.
|
||||
|
||||
## Architecture Decisions
|
||||
|
||||
- **Immutable state as primary model:** GameContext (api) holds board, history, player state — immutable, passed through the system. Each move creates a new GameContext, enabling undo/redo without side effects.
|
||||
- **Observer pattern for UI decoupling:** GameEngine publishes move/state events; CommandInvoker queues moves; UI listens to events, not polling. GameEngine never imports UI code.
|
||||
- **RuleSet trait encapsulates rules:** Move generation, check, castling, en passant all in RuleSet impl. GameEngine calls rules as a black box; rules don't know about the rest of core.
|
||||
|
||||
## Rules
|
||||
|
||||
- **Tests are the spec.** Never modify tests to pass; modify requirements or code. Update tests only if requirements change.
|
||||
- Never read build folders. Ask permission if needed.
|
||||
- Keep this file up to date with any important decisions or conventions.
|
||||
|
||||
---
|
||||
|
||||
## Instructions for Claude Code
|
||||
|
||||
### Two-Step Rule (mandatory)
|
||||
**Step 1 — Orient:** Use wiki articles to find WHERE things live.
|
||||
**Step 2 — Verify:** Read the actual source files listed in the wiki article BEFORE writing any code.
|
||||
|
||||
Wiki articles are structural summaries extracted by AST. They show routes, models, and file locations.
|
||||
They do NOT show full function logic, middleware internals, or dynamic runtime behavior.
|
||||
**Never write or modify code based solely on wiki content — always read source files first.**
|
||||
|
||||
Read in order at session start:
|
||||
1. `.codesight/wiki/index.md` — orientation map (~200 tokens)
|
||||
2. `.codesight/wiki/overview.md` — architecture overview (~500 tokens)
|
||||
3. Domain article (e.g. `.codesight/wiki/auth.md`) → check "Source Files" section → read those files
|
||||
4. `.codesight/CODESIGHT.md` — full context map for deep exploration
|
||||
|
||||
Routes marked `[inferred]` in wiki articles were detected via regex — verify against source before trusting.
|
||||
If any source file shows ⚠ in the wiki, re-run `codesight --wiki` before proceeding.
|
||||
|
||||
Or use the codesight MCP server for on-demand queries:
|
||||
- `codesight_get_wiki_article` — read a specific wiki article by name
|
||||
- `codesight_get_wiki_index` — get the wiki index
|
||||
- `codesight_get_summary` — quick project overview
|
||||
- `codesight_get_routes --prefix /api/users` — filtered routes
|
||||
- `codesight_get_blast_radius --file src/lib/db.ts` — impact analysis before changes
|
||||
- `codesight_get_schema --model users` — specific model details
|
||||
|
||||
Only open specific files after consulting codesight context. This saves ~16.893 tokens per conversation.
|
||||
|
||||
## graphify
|
||||
|
||||
This project has a graphify knowledge graph at graphify-out/.
|
||||
|
||||
Rules:
|
||||
- Before answering architecture or codebase questions, read graphify-out/GRAPH_REPORT.md for god nodes and community structure
|
||||
- If graphify-out/wiki/index.md exists, navigate it instead of reading raw files
|
||||
- After modifying code files in this session, run `python3 -c "from graphify.watch import _rebuild_code; from pathlib import Path; _rebuild_code(Path('.'))"` to keep the graph current
|
||||
|
||||
@@ -1,5 +1,8 @@
|
||||
plugins {
|
||||
id("org.sonarqube") version "7.2.3.7755"
|
||||
id("org.scoverage") version "8.1" apply false
|
||||
id("com.diffplug.spotless") version "8.4.0" apply false
|
||||
id("io.github.cosmicsilence.scalafix") version "0.2.6" apply false
|
||||
}
|
||||
|
||||
group = "de.nowchess"
|
||||
@@ -28,7 +31,38 @@ val versions = mapOf(
|
||||
"SCALA_LIBRARY" to "2.13.18",
|
||||
"SCALATEST" to "3.2.19",
|
||||
"SCALATEST_JUNIT" to "0.1.11",
|
||||
"SCOVERAGE" to "2.1.1"
|
||||
"SCOVERAGE" to "2.1.1",
|
||||
"SCALAFX" to "21.0.0-R32",
|
||||
"JAVAFX" to "21.0.1",
|
||||
"JUNIT_BOM" to "5.13.4",
|
||||
"SCALA_PARSER_COMBINATORS" to "2.4.0",
|
||||
"FASTPARSE" to "3.0.2",
|
||||
"JACKSON" to "2.17.2",
|
||||
"JACKSON_SCALA" to "2.17.2"
|
||||
)
|
||||
extra["VERSIONS"] = versions
|
||||
|
||||
subprojects {
|
||||
apply(plugin = "com.diffplug.spotless")
|
||||
|
||||
pluginManager.withPlugin("scala") {
|
||||
configure<com.diffplug.gradle.spotless.SpotlessExtension> {
|
||||
scala {
|
||||
scalafmt().configFile(rootProject.file(".scalafmt.conf"))
|
||||
}
|
||||
}
|
||||
|
||||
apply(plugin = "io.github.cosmicsilence.scalafix")
|
||||
configure<io.github.cosmicsilence.scalafix.ScalafixExtension> {
|
||||
configFile.set(rootProject.file(".scalafix.conf"))
|
||||
}
|
||||
|
||||
// Disable SemanticDB config for the scoverage source set — it sets -sourceroot to
|
||||
// the root project dir, which conflicts with scoverage's own -sourceroot and causes
|
||||
// reportTestScoverage to fail with "No source root found".
|
||||
tasks.matching { it.name in setOf("configSemanticDBScoverage", "checkScalafixScoverage", "checkScalafixTest") }.configureEach {
|
||||
enabled = false
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,4 @@
|
||||
#! /usr/bin/env bash
|
||||
set -euo pipefail
|
||||
|
||||
./gradlew classes
|
||||
@@ -0,0 +1,10 @@
|
||||
#! /usr/bin/env bash
|
||||
set -euo pipefail
|
||||
|
||||
./gradlew test
|
||||
|
||||
if [ "$#" -eq 0 ]; then
|
||||
PYTHONUTF8=1 python3 jacoco-reporter/scoverage_coverage_gaps.py
|
||||
else
|
||||
PYTHONUTF8=1 python3 jacoco-reporter/scoverage_coverage_gaps.py "modules/$1/build/reports/scoverageTest/scoverage.xml"
|
||||
fi
|
||||
@@ -1,43 +0,0 @@
|
||||
# ADR-001: Technology Stack Selection
|
||||
|
||||
## Status
|
||||
Accepted
|
||||
|
||||
## Context
|
||||
The "NowChessSystems" project requires a modern, scalable,
|
||||
and maintainable technology stack to support web-based interfaces.
|
||||
The system is designed as a microservice architecture to allow for independent scaling and development of various components (e.g., engine, matchmaking, user management).
|
||||
|
||||
## Decision
|
||||
We have decided to use the following technologies for the core system:
|
||||
|
||||
### Backend
|
||||
- **Language:** [Scala 3](https://scala-lang.org/) for its powerful type system, functional programming capabilities, and seamless JVM integration.
|
||||
- **Framework:** [Quarkus](https://quarkus.io/) with the `io.quarkiverse.scala:quarkus-scala3` extension to leverage GraalVM native compilation and fast startup times.
|
||||
- **Persistence:** [Hibernate](https://hibernate.org/) and [Jakarta Persistence](https://jakarta.ee/specifications/persistence/) for standard-based ORM.
|
||||
|
||||
### Frontend
|
||||
- **Build Tool:** [Vite](https://vitejs.dev/) for a fast development experience.
|
||||
- **Framework:** TBD (Evaluation between React, Angular, and Vue).
|
||||
- **Terminal UI:** [Lanterna](https://github.com/mabe02/lanterna) for a text-based user interface (TUI).
|
||||
|
||||
### DevOps & Infrastructure
|
||||
- **Orchestration:** [Kubernetes](https://kubernetes.io/) for container orchestration.
|
||||
- **GitOps & Delivery:** [ArgoCD](https://argoproj.github.io/cd/) for continuous delivery and [Kargo](https://kargo.io/) for multi-stage lifecycle management.
|
||||
|
||||
### AI-Assisted Development
|
||||
- [Claude Code Pro](https://claude.ai/) and [Claude Agent Teams](https://claude.ai/team) for coding and reviews.
|
||||
- [Google Stitch](https://stitch.google.com/) (Free) for UI design and prototyping.
|
||||
|
||||
## Consequences
|
||||
|
||||
### Positive
|
||||
- **High Performance:** Quarkus and GraalVM enable low memory footprint and fast startup.
|
||||
- **Developer Productivity:** Scala 3 and AI tools provide a high-level, expressive environment.
|
||||
- **Robustness:** Kubernetes and ArgoCD ensure reliable deployment and scaling.
|
||||
- **Accessibility:** Offering both a TUI and a web interface caters to different user preferences.
|
||||
|
||||
### Negative / Risks
|
||||
- **Complexity:** Managing a microservices architecture with Kubernetes adds operational overhead.
|
||||
- **Learning Curve:** Scala 3 and the specific Quarkus-Scala integration may require training for new developers.
|
||||
- **Consistency:** Maintaining parity between the TUI and Web frontend functionality.
|
||||
@@ -1,86 +0,0 @@
|
||||
# ADR-002: Shared-Models Library (`modules/api`)
|
||||
|
||||
## Status
|
||||
Accepted
|
||||
|
||||
## Context
|
||||
|
||||
NowChessSystems is a microservice platform. As soon as two or more services need to
|
||||
exchange data — whether through REST, messaging, or internal function calls — they must
|
||||
agree on common data types. Without a shared home for those types, the same case class
|
||||
(e.g. `Square`, `Move`, `GameState`) is duplicated in every module, diverges over time,
|
||||
and causes silent serialisation mismatches at runtime.
|
||||
|
||||
The `core` module currently owns the chess engine logic. Future modules (matchmaking,
|
||||
game history, user management, notation export, etc.) will all need to refer to the
|
||||
same chess domain vocabulary. A cross-cutting place to hold that vocabulary is therefore
|
||||
required before any second service is built.
|
||||
|
||||
## Decision
|
||||
|
||||
We introduce `modules/api` as a **shared-models library**: a plain Scala 3 library
|
||||
(no Quarkus, no Jakarta, no persistence) that contains only:
|
||||
|
||||
- Pure Scala 3 data types: `case class`, `sealed trait`, and `enum` definitions
|
||||
- Value objects that model the chess domain (pieces, colors, squares, moves, game state)
|
||||
- Cross-service API envelope types (`ApiResponse[A]`, `ApiError`, `Pagination`)
|
||||
- Minimal player/user identity stubs (IDs and display names only)
|
||||
|
||||
Every service module that needs these types declares:
|
||||
|
||||
```kotlin
|
||||
implementation(project(":modules:api"))
|
||||
```
|
||||
|
||||
in its own `build.gradle.kts`. The `modules/api` module itself carries no runtime
|
||||
dependencies beyond the Scala 3 standard library.
|
||||
|
||||
### Package layout
|
||||
|
||||
```
|
||||
de.nowchess.api
|
||||
├── board – Color, PieceType, Piece, File, Rank, Square
|
||||
├── game – CastlingRights, GameState, GameResult, GameStatus
|
||||
├── move – MoveType, Move, PromotionPiece
|
||||
├── player – PlayerId, PlayerInfo
|
||||
└── response – ApiResponse, ApiError, Pagination
|
||||
```
|
||||
|
||||
## What belongs in `modules/api`
|
||||
|
||||
| Belongs | Does NOT belong |
|
||||
|---|---|
|
||||
| `case class`, `sealed trait`, `enum` for chess domain | Quarkus `@ApplicationScoped` beans |
|
||||
| API envelope types (`ApiResponse`, `ApiError`) | Jakarta Persistence entities (`@Entity`) |
|
||||
| Player identity stubs (ID + display name) | REST resource classes |
|
||||
| FEN/board-state representation types | Business logic, engine algorithms |
|
||||
| Pure type aliases and value objects | Database queries or repositories |
|
||||
|
||||
The rule of thumb: if a type carries a framework annotation or requires I/O to produce,
|
||||
it does not belong in `modules/api`.
|
||||
|
||||
## How other modules depend on it
|
||||
|
||||
1. `modules/api` is a regular Gradle subproject already declared in `settings.gradle.kts`.
|
||||
2. Consuming modules add `implementation(project(":modules:api"))` — nothing else.
|
||||
3. Because `modules/api` has no Quarkus BOM, consuming modules must not re-export Quarkus
|
||||
transitive dependencies through it.
|
||||
4. If a future module needs JSON serialisation, it adds its own JSON library (e.g.
|
||||
`circe`, `jsoniter-scala`) as a dependency and derives codecs for the shared types
|
||||
there — codec derivation stays out of `modules/api`.
|
||||
|
||||
## Consequences
|
||||
|
||||
### Positive
|
||||
- Single source of truth for all chess domain vocabulary.
|
||||
- Adding a new microservice requires only one `implementation(project(":modules:api"))`
|
||||
line — no copy-paste of types.
|
||||
- The library is fast to compile (no framework processing) and cheap to test in isolation.
|
||||
- Enforces a strict boundary: if a type needs a framework annotation it is forced into the
|
||||
correct service module.
|
||||
|
||||
### Negative / Risks
|
||||
- Any breaking change to a shared type (rename, field removal) is a cross-cutting change
|
||||
that touches every consuming module simultaneously.
|
||||
- Developers must resist the temptation to add convenience methods or logic to these
|
||||
types; discipline is required to keep the library pure.
|
||||
@@ -0,0 +1,776 @@
|
||||
openapi: 3.0.3
|
||||
info:
|
||||
title: NowChess API
|
||||
description: |
|
||||
REST API for the NowChess application. Designed to feel familiar to users
|
||||
of the [lichess API](https://lichess.org/api).
|
||||
|
||||
## Authentication
|
||||
Most endpoints require a Bearer token:
|
||||
```
|
||||
Authorization: Bearer <token>
|
||||
```
|
||||
Authentication is reserved for future implementation — endpoints are currently
|
||||
open unless noted otherwise.
|
||||
|
||||
## Move notation
|
||||
Moves are expressed in **UCI notation**: `{from}{to}[promotion]`
|
||||
- Normal move: `e2e4`
|
||||
- Capture: `d5e6`
|
||||
- Promotion: `e7e8q` (q=queen, r=rook, b=bishop, n=knight)
|
||||
- Castling: `e1g1` (kingside white), `e1c1` (queenside white)
|
||||
|
||||
## Streaming
|
||||
Endpoints that support streaming return **NDJSON** (newline-delimited JSON).
|
||||
Request them with:
|
||||
```
|
||||
Accept: application/x-ndjson
|
||||
```
|
||||
Each line of the response is a complete JSON object. Empty lines are
|
||||
keep-alive heartbeats.
|
||||
|
||||
## Rate limiting
|
||||
Requests that exceed the rate limit receive `429 Too Many Requests`.
|
||||
Honour the `Retry-After` response header and wait before retrying.
|
||||
version: 1.0.0
|
||||
contact:
|
||||
name: NowChess
|
||||
license:
|
||||
name: MIT
|
||||
|
||||
servers:
|
||||
- url: http://localhost:8080
|
||||
description: Local development server
|
||||
|
||||
tags:
|
||||
- name: game
|
||||
description: Create and manage chess games
|
||||
- name: move
|
||||
description: Make moves and navigate game history
|
||||
- name: draw
|
||||
description: Draw offers and claims
|
||||
- name: import
|
||||
description: Load a game from FEN or PGN
|
||||
- name: export
|
||||
description: Export a game as FEN or PGN
|
||||
|
||||
paths:
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# Game lifecycle
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
/api/board/game:
|
||||
post:
|
||||
operationId: createGame
|
||||
tags: [game]
|
||||
summary: Create a new game
|
||||
description: |
|
||||
Creates a new chess game starting from the initial position.
|
||||
Returns the full game state including the generated `gameId`.
|
||||
security:
|
||||
- bearerAuth: []
|
||||
requestBody:
|
||||
required: false
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: '#/components/schemas/CreateGameRequest'
|
||||
responses:
|
||||
'201':
|
||||
description: Game created
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: '#/components/schemas/GameFull'
|
||||
'400':
|
||||
$ref: '#/components/responses/BadRequest'
|
||||
'401':
|
||||
$ref: '#/components/responses/Unauthorized'
|
||||
'429':
|
||||
$ref: '#/components/responses/TooManyRequests'
|
||||
|
||||
/api/board/game/{gameId}:
|
||||
get:
|
||||
operationId: getGame
|
||||
tags: [game]
|
||||
summary: Get game state
|
||||
description: Returns the full current state of a game.
|
||||
security:
|
||||
- bearerAuth: []
|
||||
parameters:
|
||||
- $ref: '#/components/parameters/gameId'
|
||||
responses:
|
||||
'200':
|
||||
description: Current game state
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: '#/components/schemas/GameFull'
|
||||
'404':
|
||||
$ref: '#/components/responses/NotFound'
|
||||
'429':
|
||||
$ref: '#/components/responses/TooManyRequests'
|
||||
|
||||
/api/board/game/{gameId}/stream:
|
||||
get:
|
||||
operationId: streamGame
|
||||
tags: [game]
|
||||
summary: Stream game events
|
||||
description: |
|
||||
Opens a persistent NDJSON stream for a game. The first object sent is
|
||||
a `gameFull` event containing the complete game state. Subsequent
|
||||
objects are `gameState` events sent whenever the game changes (move
|
||||
made, draw offered, game over, etc.).
|
||||
|
||||
Empty lines are heartbeats to keep the connection alive.
|
||||
|
||||
Connect with:
|
||||
```
|
||||
Accept: application/x-ndjson
|
||||
```
|
||||
security:
|
||||
- bearerAuth: []
|
||||
parameters:
|
||||
- $ref: '#/components/parameters/gameId'
|
||||
responses:
|
||||
'200':
|
||||
description: NDJSON event stream
|
||||
content:
|
||||
application/x-ndjson:
|
||||
schema:
|
||||
oneOf:
|
||||
- $ref: '#/components/schemas/GameFullEvent'
|
||||
- $ref: '#/components/schemas/GameStateEvent'
|
||||
- $ref: '#/components/schemas/ErrorEvent'
|
||||
'404':
|
||||
$ref: '#/components/responses/NotFound'
|
||||
'429':
|
||||
$ref: '#/components/responses/TooManyRequests'
|
||||
|
||||
/api/board/game/{gameId}/resign:
|
||||
post:
|
||||
operationId: resignGame
|
||||
tags: [game]
|
||||
summary: Resign the game
|
||||
description: The active player resigns. The game ends immediately.
|
||||
security:
|
||||
- bearerAuth: []
|
||||
parameters:
|
||||
- $ref: '#/components/parameters/gameId'
|
||||
responses:
|
||||
'200':
|
||||
description: Resignation accepted
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: '#/components/schemas/OkResponse'
|
||||
'400':
|
||||
$ref: '#/components/responses/BadRequest'
|
||||
'404':
|
||||
$ref: '#/components/responses/NotFound'
|
||||
'429':
|
||||
$ref: '#/components/responses/TooManyRequests'
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# Move-making
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
/api/board/game/{gameId}/move/{uci}:
|
||||
post:
|
||||
operationId: makeMove
|
||||
tags: [move]
|
||||
summary: Make a move
|
||||
description: |
|
||||
Submit a move in UCI notation. The move must be legal for the side
|
||||
currently to move.
|
||||
|
||||
For promotion moves include the target piece as the fifth character:
|
||||
`e7e8q`, `a2a1r`, etc.
|
||||
|
||||
If the move results in a pawn reaching the back rank and no promotion
|
||||
character is supplied, the game enters `promotionPending` status and
|
||||
the move is not yet applied — resubmit with the promotion character.
|
||||
security:
|
||||
- bearerAuth: []
|
||||
parameters:
|
||||
- $ref: '#/components/parameters/gameId'
|
||||
- name: uci
|
||||
in: path
|
||||
required: true
|
||||
description: Move in UCI notation (e.g. `e2e4`, `e7e8q`)
|
||||
schema:
|
||||
type: string
|
||||
pattern: '^[a-h][1-8][a-h][1-8][qrbn]?$'
|
||||
example: e2e4
|
||||
responses:
|
||||
'200':
|
||||
description: Move applied — returns updated game state
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: '#/components/schemas/GameState'
|
||||
'400':
|
||||
$ref: '#/components/responses/BadRequest'
|
||||
'404':
|
||||
$ref: '#/components/responses/NotFound'
|
||||
'429':
|
||||
$ref: '#/components/responses/TooManyRequests'
|
||||
|
||||
/api/board/game/{gameId}/moves:
|
||||
get:
|
||||
operationId: getLegalMoves
|
||||
tags: [move]
|
||||
summary: Get legal moves
|
||||
description: |
|
||||
Returns all legal moves for the side currently to move.
|
||||
Optionally filter to moves originating from a single square.
|
||||
security:
|
||||
- bearerAuth: []
|
||||
parameters:
|
||||
- $ref: '#/components/parameters/gameId'
|
||||
- name: square
|
||||
in: query
|
||||
required: false
|
||||
description: Filter to moves from this square (e.g. `e2`)
|
||||
schema:
|
||||
type: string
|
||||
pattern: '^[a-h][1-8]$'
|
||||
example: e2
|
||||
responses:
|
||||
'200':
|
||||
description: List of legal moves
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: '#/components/schemas/LegalMovesResponse'
|
||||
'404':
|
||||
$ref: '#/components/responses/NotFound'
|
||||
'429':
|
||||
$ref: '#/components/responses/TooManyRequests'
|
||||
|
||||
/api/board/game/{gameId}/undo:
|
||||
post:
|
||||
operationId: undoMove
|
||||
tags: [move]
|
||||
summary: Undo the last move
|
||||
description: Reverts the most recent move. Returns the updated game state.
|
||||
security:
|
||||
- bearerAuth: []
|
||||
parameters:
|
||||
- $ref: '#/components/parameters/gameId'
|
||||
responses:
|
||||
'200':
|
||||
description: Move undone
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: '#/components/schemas/GameState'
|
||||
'400':
|
||||
description: No moves to undo
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: '#/components/schemas/ApiError'
|
||||
'404':
|
||||
$ref: '#/components/responses/NotFound'
|
||||
'429':
|
||||
$ref: '#/components/responses/TooManyRequests'
|
||||
|
||||
/api/board/game/{gameId}/redo:
|
||||
post:
|
||||
operationId: redoMove
|
||||
tags: [move]
|
||||
summary: Redo a previously undone move
|
||||
description: Re-applies the next move in the undo stack. Returns the updated game state.
|
||||
security:
|
||||
- bearerAuth: []
|
||||
parameters:
|
||||
- $ref: '#/components/parameters/gameId'
|
||||
responses:
|
||||
'200':
|
||||
description: Move redone
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: '#/components/schemas/GameState'
|
||||
'400':
|
||||
description: No moves to redo
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: '#/components/schemas/ApiError'
|
||||
'404':
|
||||
$ref: '#/components/responses/NotFound'
|
||||
'429':
|
||||
$ref: '#/components/responses/TooManyRequests'
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# Draw handling
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
/api/board/game/{gameId}/draw/{action}:
|
||||
post:
|
||||
operationId: drawAction
|
||||
tags: [draw]
|
||||
summary: Offer, accept, decline, or claim a draw
|
||||
description: |
|
||||
Perform a draw-related action:
|
||||
|
||||
| Action | Description |
|
||||
|-----------|-------------|
|
||||
| `offer` | Offer a draw to the opponent |
|
||||
| `accept` | Accept the opponent's draw offer |
|
||||
| `decline` | Decline the opponent's draw offer |
|
||||
| `claim` | Claim a draw under the fifty-move rule (only valid when `status` is `fiftyMoveAvailable`) |
|
||||
security:
|
||||
- bearerAuth: []
|
||||
parameters:
|
||||
- $ref: '#/components/parameters/gameId'
|
||||
- name: action
|
||||
in: path
|
||||
required: true
|
||||
schema:
|
||||
type: string
|
||||
enum: [offer, accept, decline, claim]
|
||||
responses:
|
||||
'200':
|
||||
description: Action accepted
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: '#/components/schemas/OkResponse'
|
||||
'400':
|
||||
$ref: '#/components/responses/BadRequest'
|
||||
'404':
|
||||
$ref: '#/components/responses/NotFound'
|
||||
'429':
|
||||
$ref: '#/components/responses/TooManyRequests'
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# Import
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
/api/board/game/import/fen:
|
||||
post:
|
||||
operationId: importFen
|
||||
tags: [import]
|
||||
summary: Load a position from FEN
|
||||
description: |
|
||||
Creates a new game from a FEN string. The game starts at the position
|
||||
described by the FEN; move history prior to that position is not
|
||||
available.
|
||||
security:
|
||||
- bearerAuth: []
|
||||
requestBody:
|
||||
required: true
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: '#/components/schemas/ImportFenRequest'
|
||||
responses:
|
||||
'201':
|
||||
description: Game created from FEN
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: '#/components/schemas/GameFull'
|
||||
'400':
|
||||
$ref: '#/components/responses/BadRequest'
|
||||
'429':
|
||||
$ref: '#/components/responses/TooManyRequests'
|
||||
|
||||
/api/board/game/import/pgn:
|
||||
post:
|
||||
operationId: importPgn
|
||||
tags: [import]
|
||||
summary: Load a game from PGN
|
||||
description: |
|
||||
Creates a new game by replaying all moves in a PGN string. The game
|
||||
starts at the position after the final move in the PGN; undo is
|
||||
available for every replayed move.
|
||||
security:
|
||||
- bearerAuth: []
|
||||
requestBody:
|
||||
required: true
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: '#/components/schemas/ImportPgnRequest'
|
||||
responses:
|
||||
'201':
|
||||
description: Game created from PGN
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: '#/components/schemas/GameFull'
|
||||
'400':
|
||||
$ref: '#/components/responses/BadRequest'
|
||||
'429':
|
||||
$ref: '#/components/responses/TooManyRequests'
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# Export
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
/api/board/game/{gameId}/export/fen:
|
||||
get:
|
||||
operationId: exportFen
|
||||
tags: [export]
|
||||
summary: Export current position as FEN
|
||||
description: Returns the FEN string representing the current board position.
|
||||
security:
|
||||
- bearerAuth: []
|
||||
parameters:
|
||||
- $ref: '#/components/parameters/gameId'
|
||||
responses:
|
||||
'200':
|
||||
description: FEN string
|
||||
content:
|
||||
text/plain:
|
||||
schema:
|
||||
type: string
|
||||
example: rnbqkbnr/pppppppp/8/8/4P3/8/PPPP1PPP/RNBQKBNR b KQkq e3 0 1
|
||||
'404':
|
||||
$ref: '#/components/responses/NotFound'
|
||||
'429':
|
||||
$ref: '#/components/responses/TooManyRequests'
|
||||
|
||||
/api/board/game/{gameId}/export/pgn:
|
||||
get:
|
||||
operationId: exportPgn
|
||||
tags: [export]
|
||||
summary: Export game as PGN
|
||||
description: Returns the full PGN for the game including headers and move text.
|
||||
security:
|
||||
- bearerAuth: []
|
||||
parameters:
|
||||
- $ref: '#/components/parameters/gameId'
|
||||
responses:
|
||||
'200':
|
||||
description: PGN text
|
||||
content:
|
||||
application/x-chess-pgn:
|
||||
schema:
|
||||
type: string
|
||||
example: |
|
||||
[Event "NowChess game"]
|
||||
[White "Player1"]
|
||||
[Black "Player2"]
|
||||
[Result "*"]
|
||||
|
||||
1. e4 e5 2. Nf3 *
|
||||
'404':
|
||||
$ref: '#/components/responses/NotFound'
|
||||
'429':
|
||||
$ref: '#/components/responses/TooManyRequests'
|
||||
|
||||
# =============================================================================
|
||||
# Components
|
||||
# =============================================================================
|
||||
|
||||
components:
|
||||
|
||||
securitySchemes:
|
||||
bearerAuth:
|
||||
type: http
|
||||
scheme: bearer
|
||||
description: 'Personal access token — `Authorization: Bearer <token>`'
|
||||
|
||||
parameters:
|
||||
gameId:
|
||||
name: gameId
|
||||
in: path
|
||||
required: true
|
||||
description: 8-character alphanumeric game ID (e.g. `Qa7FJNk2`)
|
||||
schema:
|
||||
type: string
|
||||
pattern: '^[A-Za-z0-9]{8}$'
|
||||
example: Qa7FJNk2
|
||||
|
||||
responses:
|
||||
BadRequest:
|
||||
description: Invalid input
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: '#/components/schemas/ApiError'
|
||||
Unauthorized:
|
||||
description: Missing or invalid authentication token
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: '#/components/schemas/ApiError'
|
||||
NotFound:
|
||||
description: Game not found
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: '#/components/schemas/ApiError'
|
||||
TooManyRequests:
|
||||
description: Rate limit exceeded — see `Retry-After` header
|
||||
headers:
|
||||
Retry-After:
|
||||
description: Seconds to wait before retrying
|
||||
schema:
|
||||
type: integer
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: '#/components/schemas/ApiError'
|
||||
|
||||
schemas:
|
||||
|
||||
# -------------------------------------------------------------------------
|
||||
# Requests
|
||||
# -------------------------------------------------------------------------
|
||||
|
||||
CreateGameRequest:
|
||||
type: object
|
||||
description: Parameters for creating a new game. All fields are optional.
|
||||
properties:
|
||||
white:
|
||||
$ref: '#/components/schemas/PlayerInfo'
|
||||
black:
|
||||
$ref: '#/components/schemas/PlayerInfo'
|
||||
|
||||
ImportFenRequest:
|
||||
type: object
|
||||
required: [fen]
|
||||
properties:
|
||||
fen:
|
||||
type: string
|
||||
description: Complete FEN string (6 fields)
|
||||
example: rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR w KQkq - 0 1
|
||||
white:
|
||||
$ref: '#/components/schemas/PlayerInfo'
|
||||
black:
|
||||
$ref: '#/components/schemas/PlayerInfo'
|
||||
|
||||
ImportPgnRequest:
|
||||
type: object
|
||||
required: [pgn]
|
||||
properties:
|
||||
pgn:
|
||||
type: string
|
||||
description: PGN text (headers and move list)
|
||||
example: "1. e4 e5 2. Nf3 Nc6 *"
|
||||
|
||||
# -------------------------------------------------------------------------
|
||||
# Game state
|
||||
# -------------------------------------------------------------------------
|
||||
|
||||
GameFull:
|
||||
type: object
|
||||
description: Complete game information including players and current state.
|
||||
required: [gameId, white, black, state]
|
||||
properties:
|
||||
gameId:
|
||||
type: string
|
||||
description: Unique 8-character game identifier
|
||||
example: Qa7FJNk2
|
||||
white:
|
||||
$ref: '#/components/schemas/PlayerInfo'
|
||||
black:
|
||||
$ref: '#/components/schemas/PlayerInfo'
|
||||
state:
|
||||
$ref: '#/components/schemas/GameState'
|
||||
|
||||
GameState:
|
||||
type: object
|
||||
description: |
|
||||
The current game state. Included in `GameFull` and returned by move
|
||||
endpoints and stream events.
|
||||
required: [fen, pgn, turn, status, moves, undoAvailable, redoAvailable]
|
||||
properties:
|
||||
fen:
|
||||
type: string
|
||||
description: FEN string for the current position
|
||||
example: rnbqkbnr/pppppppp/8/8/4P3/8/PPPP1PPP/RNBQKBNR b KQkq e3 0 1
|
||||
pgn:
|
||||
type: string
|
||||
description: PGN move text for the full game so far
|
||||
example: "1. e4"
|
||||
turn:
|
||||
type: string
|
||||
enum: [white, black]
|
||||
description: The side to move
|
||||
status:
|
||||
$ref: '#/components/schemas/GameStatus'
|
||||
winner:
|
||||
type: string
|
||||
enum: [white, black]
|
||||
description: Set when `status` is `checkmate` or `resign`
|
||||
nullable: true
|
||||
moves:
|
||||
type: array
|
||||
description: All moves played so far, in UCI notation
|
||||
items:
|
||||
type: string
|
||||
example: [e2e4, e7e5, g1f3]
|
||||
undoAvailable:
|
||||
type: boolean
|
||||
description: Whether `POST /undo` is currently valid
|
||||
redoAvailable:
|
||||
type: boolean
|
||||
description: Whether `POST /redo` is currently valid
|
||||
|
||||
GameStatus:
|
||||
type: string
|
||||
description: |
|
||||
Current game status:
|
||||
|
||||
| Value | Meaning |
|
||||
|-------|---------|
|
||||
| `started` | Game in progress, no special condition |
|
||||
| `check` | Side to move is in check |
|
||||
| `checkmate` | Side to move is checkmated — game over |
|
||||
| `stalemate` | Side to move has no legal moves, not in check — game over (draw) |
|
||||
| `resign` | A player resigned — game over |
|
||||
| `draw` | Draw agreed or claimed — game over |
|
||||
| `drawOffered` | Waiting for the opponent to accept or decline a draw offer |
|
||||
| `fiftyMoveAvailable` | Fifty-move rule threshold reached; active player may claim draw |
|
||||
| `promotionPending` | A pawn reached the back rank; awaiting promotion piece selection |
|
||||
| `insufficientMaterial` | Neither side has enough pieces to deliver checkmate — game over (draw) |
|
||||
enum:
|
||||
- started
|
||||
- check
|
||||
- checkmate
|
||||
- stalemate
|
||||
- resign
|
||||
- draw
|
||||
- drawOffered
|
||||
- fiftyMoveAvailable
|
||||
- promotionPending
|
||||
- insufficientMaterial
|
||||
|
||||
# -------------------------------------------------------------------------
|
||||
# Moves
|
||||
# -------------------------------------------------------------------------
|
||||
|
||||
LegalMovesResponse:
|
||||
type: object
|
||||
required: [moves]
|
||||
properties:
|
||||
moves:
|
||||
type: array
|
||||
items:
|
||||
$ref: '#/components/schemas/LegalMove'
|
||||
|
||||
LegalMove:
|
||||
type: object
|
||||
required: [from, to, uci, moveType]
|
||||
properties:
|
||||
from:
|
||||
type: string
|
||||
description: Origin square in algebraic notation
|
||||
example: e2
|
||||
to:
|
||||
type: string
|
||||
description: Destination square in algebraic notation
|
||||
example: e4
|
||||
uci:
|
||||
type: string
|
||||
description: Full move in UCI notation
|
||||
example: e2e4
|
||||
moveType:
|
||||
$ref: '#/components/schemas/MoveType'
|
||||
promotion:
|
||||
type: string
|
||||
enum: [queen, rook, bishop, knight]
|
||||
description: Target piece for promotion moves
|
||||
nullable: true
|
||||
|
||||
MoveType:
|
||||
type: string
|
||||
description: Classification of the move
|
||||
enum:
|
||||
- normal
|
||||
- capture
|
||||
- castleKingside
|
||||
- castleQueenside
|
||||
- enPassant
|
||||
- promotion
|
||||
|
||||
# -------------------------------------------------------------------------
|
||||
# Streaming events
|
||||
# -------------------------------------------------------------------------
|
||||
|
||||
GameFullEvent:
|
||||
type: object
|
||||
description: |
|
||||
First event on a game stream. Contains the complete game snapshot.
|
||||
required: [type, game]
|
||||
properties:
|
||||
type:
|
||||
type: string
|
||||
enum: [gameFull]
|
||||
game:
|
||||
$ref: '#/components/schemas/GameFull'
|
||||
|
||||
GameStateEvent:
|
||||
type: object
|
||||
description: |
|
||||
Emitted on a game stream whenever the game state changes (move played,
|
||||
draw offered, game over, etc.).
|
||||
required: [type, state]
|
||||
properties:
|
||||
type:
|
||||
type: string
|
||||
enum: [gameState]
|
||||
state:
|
||||
$ref: '#/components/schemas/GameState'
|
||||
|
||||
ErrorEvent:
|
||||
type: object
|
||||
description: Emitted on a game stream when an error occurs.
|
||||
required: [type, error]
|
||||
properties:
|
||||
type:
|
||||
type: string
|
||||
enum: [error]
|
||||
error:
|
||||
$ref: '#/components/schemas/ApiError'
|
||||
|
||||
# -------------------------------------------------------------------------
|
||||
# Shared types
|
||||
# -------------------------------------------------------------------------
|
||||
|
||||
PlayerInfo:
|
||||
type: object
|
||||
required: [id, displayName]
|
||||
properties:
|
||||
id:
|
||||
type: string
|
||||
description: Unique player identifier
|
||||
example: player1
|
||||
displayName:
|
||||
type: string
|
||||
description: Human-readable display name
|
||||
example: Alice
|
||||
|
||||
OkResponse:
|
||||
type: object
|
||||
required: [ok]
|
||||
properties:
|
||||
ok:
|
||||
type: boolean
|
||||
enum: [true]
|
||||
|
||||
ApiError:
|
||||
type: object
|
||||
required: [code, message]
|
||||
properties:
|
||||
code:
|
||||
type: string
|
||||
description: Machine-readable error code
|
||||
example: INVALID_MOVE
|
||||
message:
|
||||
type: string
|
||||
description: Human-readable error description
|
||||
example: e2e5 is not a legal move
|
||||
field:
|
||||
type: string
|
||||
description: Request field that caused the error, if applicable
|
||||
example: uci
|
||||
nullable: true
|
||||
@@ -1,244 +0,0 @@
|
||||
# ScalaTest + Scoverage Migration Implementation Plan
|
||||
|
||||
> **For agentic workers:** REQUIRED SUB-SKILL: Use superpowers:subagent-driven-development (recommended) or superpowers:executing-plans to implement this plan task-by-task. Steps use checkbox (`- [ ]`) syntax for tracking.
|
||||
|
||||
**Goal:** Replace JaCoCo with Scoverage and add ScalaTest (with its JUnit 5 bridge) as the test library across all modules.
|
||||
|
||||
**Architecture:** Three build files are modified — the root for shared dependency versions, and each module for plugins, dependencies, and task wiring. No source files are created. The Scoverage Gradle plugin is applied per-module with its version hardcoded inline (Gradle resolves `plugins {}` before `rootProject.extra` is available).
|
||||
|
||||
**Tech Stack:** Scala 3, Gradle (Kotlin DSL), ScalaTest 3.2.19, scalatestplus-junit-5-11 3.2.19.1, Scoverage Gradle plugin 8.1.
|
||||
|
||||
---
|
||||
|
||||
## File Map
|
||||
|
||||
| File | Change |
|
||||
|---|---|
|
||||
| `build.gradle.kts` (root) | Add `SCALATEST` and `SCALATESTPLUS_JUNIT5` version entries |
|
||||
| `modules/core/build.gradle.kts` | Replace `jacoco` with `org.scoverage`; swap JUnit deps for ScalaTest; merge two `tasks.test {}` blocks |
|
||||
| `modules/api/build.gradle.kts` | Same as core; also add missing `useJUnitPlatform()` |
|
||||
|
||||
---
|
||||
|
||||
### Task 1: Add ScalaTest version entries to root build
|
||||
|
||||
**Files:**
|
||||
- Modify: `build.gradle.kts` (root)
|
||||
|
||||
- [ ] **Step 1: Add version entries**
|
||||
|
||||
Open `build.gradle.kts` at the root. The `versions` map currently looks like:
|
||||
|
||||
```kotlin
|
||||
val versions = mapOf(
|
||||
"QUARKUS_SCALA3" to "1.0.0",
|
||||
"SCALA3" to "3.5.1",
|
||||
"SCALA_LIBRARY" to "2.13.18"
|
||||
)
|
||||
```
|
||||
|
||||
Add two entries so it becomes:
|
||||
|
||||
```kotlin
|
||||
val versions = mapOf(
|
||||
"QUARKUS_SCALA3" to "1.0.0",
|
||||
"SCALA3" to "3.5.1",
|
||||
"SCALA_LIBRARY" to "2.13.18",
|
||||
"SCALATEST" to "3.2.19",
|
||||
"SCALATESTPLUS_JUNIT5" to "3.2.19.1"
|
||||
)
|
||||
```
|
||||
|
||||
- [ ] **Step 2: Verify the root build file parses**
|
||||
|
||||
```bash
|
||||
./gradlew help --quiet
|
||||
```
|
||||
|
||||
Expected: exits 0 with no errors.
|
||||
|
||||
- [ ] **Step 3: Commit**
|
||||
|
||||
```bash
|
||||
git add build.gradle.kts
|
||||
git commit -m "build: add ScalaTest version entries to root versions map"
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### Task 2: Migrate `modules/core` to ScalaTest + Scoverage
|
||||
|
||||
**Files:**
|
||||
- Modify: `modules/core/build.gradle.kts`
|
||||
|
||||
- [ ] **Step 1: Replace the `jacoco` plugin with `org.scoverage`**
|
||||
|
||||
In the `plugins {}` block, replace:
|
||||
```kotlin
|
||||
jacoco
|
||||
```
|
||||
with:
|
||||
```kotlin
|
||||
id("org.scoverage") version "8.1"
|
||||
```
|
||||
|
||||
The full plugins block should be:
|
||||
```kotlin
|
||||
plugins {
|
||||
id("scala")
|
||||
id("org.scoverage") version "8.1"
|
||||
application
|
||||
}
|
||||
```
|
||||
|
||||
- [ ] **Step 2: Swap JUnit dependencies for ScalaTest**
|
||||
|
||||
In the `dependencies {}` block, remove:
|
||||
```kotlin
|
||||
testImplementation(platform("org.junit:junit-bom:5.10.0"))
|
||||
testImplementation("org.junit.jupiter:junit-jupiter")
|
||||
testRuntimeOnly("org.junit.platform:junit-platform-launcher")
|
||||
```
|
||||
|
||||
Add in their place:
|
||||
```kotlin
|
||||
testImplementation("org.scalatest:scalatest_3:${versions["SCALATEST"]!!}")
|
||||
testImplementation("org.scalatestplus:junit-5-11_3:${versions["SCALATESTPLUS_JUNIT5"]!!}")
|
||||
```
|
||||
|
||||
- [ ] **Step 3: Merge the two `tasks.test {}` blocks and replace jacoco wiring**
|
||||
|
||||
The file currently has two separate `tasks.test {}` blocks and a `tasks.jacocoTestReport {}` block. Delete all three. Add the following single merged block **after** the `dependencies {}` block:
|
||||
|
||||
```kotlin
|
||||
tasks.test {
|
||||
useJUnitPlatform()
|
||||
finalizedBy(tasks.reportScoverage)
|
||||
}
|
||||
tasks.reportScoverage {
|
||||
dependsOn(tasks.test)
|
||||
}
|
||||
```
|
||||
|
||||
- [ ] **Step 4: Run the tests**
|
||||
|
||||
```bash
|
||||
./gradlew :modules:core:test
|
||||
```
|
||||
|
||||
Expected: BUILD SUCCESSFUL. (Zero tests is fine — there are no test files yet. The build must not fail with dependency resolution or plugin errors.)
|
||||
|
||||
- [ ] **Step 5: Run the coverage report**
|
||||
|
||||
```bash
|
||||
./gradlew :modules:core:reportScoverage
|
||||
```
|
||||
|
||||
Expected: BUILD SUCCESSFUL. A report is generated under `modules/core/build/reports/scoverage/`.
|
||||
|
||||
- [ ] **Step 6: Commit**
|
||||
|
||||
```bash
|
||||
git add modules/core/build.gradle.kts
|
||||
git commit -m "build(core): replace JaCoCo with Scoverage, add ScalaTest dependencies"
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### Task 3: Migrate `modules/api` to ScalaTest + Scoverage
|
||||
|
||||
**Files:**
|
||||
- Modify: `modules/api/build.gradle.kts`
|
||||
|
||||
- [ ] **Step 1: Replace the `jacoco` plugin with `org.scoverage`**
|
||||
|
||||
In the `plugins {}` block, replace:
|
||||
```kotlin
|
||||
jacoco
|
||||
```
|
||||
with:
|
||||
```kotlin
|
||||
id("org.scoverage") version "8.1"
|
||||
```
|
||||
|
||||
The full plugins block should be:
|
||||
```kotlin
|
||||
plugins {
|
||||
id("scala")
|
||||
id("org.scoverage") version "8.1"
|
||||
}
|
||||
```
|
||||
|
||||
- [ ] **Step 2: Swap JUnit dependencies for ScalaTest**
|
||||
|
||||
In the `dependencies {}` block, remove:
|
||||
```kotlin
|
||||
testImplementation(platform("org.junit:junit-bom:5.10.0"))
|
||||
testImplementation("org.junit.jupiter:junit-jupiter")
|
||||
testRuntimeOnly("org.junit.platform:junit-platform-launcher")
|
||||
```
|
||||
|
||||
Add in their place:
|
||||
```kotlin
|
||||
testImplementation("org.scalatest:scalatest_3:${versions["SCALATEST"]!!}")
|
||||
testImplementation("org.scalatestplus:junit-5-11_3:${versions["SCALATESTPLUS_JUNIT5"]!!}")
|
||||
```
|
||||
|
||||
- [ ] **Step 3: Merge the two `tasks.test {}` blocks and replace jacoco wiring**
|
||||
|
||||
The `modules/api` file also has two `tasks.test {}` blocks and a `jacocoTestReport` block. Delete all three. Add the following merged block **after** the `dependencies {}` block:
|
||||
|
||||
```kotlin
|
||||
tasks.test {
|
||||
useJUnitPlatform()
|
||||
finalizedBy(tasks.reportScoverage)
|
||||
}
|
||||
tasks.reportScoverage {
|
||||
dependsOn(tasks.test)
|
||||
}
|
||||
```
|
||||
|
||||
> Note: `modules/api` did not previously have `useJUnitPlatform()` — it is being **added** here, not preserved.
|
||||
|
||||
- [ ] **Step 4: Run the tests**
|
||||
|
||||
```bash
|
||||
./gradlew :modules:api:test
|
||||
```
|
||||
|
||||
Expected: BUILD SUCCESSFUL.
|
||||
|
||||
- [ ] **Step 5: Run the coverage report**
|
||||
|
||||
```bash
|
||||
./gradlew :modules:api:reportScoverage
|
||||
```
|
||||
|
||||
Expected: BUILD SUCCESSFUL. A report is generated under `modules/api/build/reports/scoverage/`.
|
||||
|
||||
- [ ] **Step 6: Commit**
|
||||
|
||||
```bash
|
||||
git add modules/api/build.gradle.kts
|
||||
git commit -m "build(api): replace JaCoCo with Scoverage, add ScalaTest dependencies"
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### Task 4: Full build verification
|
||||
|
||||
- [ ] **Step 1: Run the full build**
|
||||
|
||||
```bash
|
||||
./gradlew build
|
||||
```
|
||||
|
||||
Expected: BUILD SUCCESSFUL with no errors across all modules.
|
||||
|
||||
- [ ] **Step 2: Confirm no JaCoCo references remain**
|
||||
|
||||
```bash
|
||||
grep -r "jacoco\|jacocoTestReport" --include="*.kts" .
|
||||
```
|
||||
|
||||
Expected: no output (zero matches).
|
||||
@@ -1,579 +0,0 @@
|
||||
# Chess Check / Checkmate / Stalemate Implementation Plan
|
||||
|
||||
> **For agentic workers:** REQUIRED SUB-SKILL: Use superpowers:subagent-driven-development (recommended) or superpowers:executing-plans to implement this plan task-by-task. Steps use checkbox (`- [ ]`) syntax for tracking.
|
||||
|
||||
**Goal:** Add check detection, checkmate (win by opponent having no legal reply while in check), and stalemate (draw by opponent having no legal reply while not in check) to the chess game loop.
|
||||
|
||||
**Architecture:** A new `GameRules` object owns all check-aware logic; the existing `MoveValidator` keeps its geometric-only contract unchanged. `GameController.processMove` calls `GameRules.gameStatus` after each move and returns new `MoveResult` variants (`MovedInCheck`, `Checkmate`, `Stalemate`). Terminal states reset the board.
|
||||
|
||||
**Tech Stack:** Scala 3.5, ScalaTest (`AnyFunSuite with Matchers`), Gradle (`:modules:core:test`)
|
||||
|
||||
---
|
||||
|
||||
## File Map
|
||||
|
||||
| File | Action | Responsibility |
|
||||
|---|---|---|
|
||||
| `modules/core/src/main/scala/de/nowchess/chess/logic/GameRules.scala` | **Create** | `isInCheck`, `legalMoves`, `gameStatus`, `PositionStatus` enum |
|
||||
| `modules/core/src/test/scala/de/nowchess/chess/logic/GameRulesTest.scala` | **Create** | Unit tests for all three `GameRules` methods |
|
||||
| `modules/core/src/main/scala/de/nowchess/chess/controller/GameController.scala` | **Modify** | Add `MovedInCheck`/`Checkmate`/`Stalemate` to `MoveResult`; wire `processMove` and `gameLoop` |
|
||||
| `modules/core/src/test/scala/de/nowchess/chess/controller/GameControllerTest.scala` | **Modify** | Add `processMove` and `gameLoop` tests for the three new results |
|
||||
|
||||
---
|
||||
|
||||
## Task 1: Create `GameRules` stub
|
||||
|
||||
**Files:**
|
||||
- Create: `modules/core/src/main/scala/de/nowchess/chess/logic/GameRules.scala`
|
||||
|
||||
- [ ] **Step 1: Create the stub file**
|
||||
|
||||
```scala
|
||||
package de.nowchess.chess.logic
|
||||
|
||||
import de.nowchess.api.board.*
|
||||
|
||||
enum PositionStatus:
|
||||
case Normal, InCheck, Mated, Drawn
|
||||
|
||||
object GameRules:
|
||||
|
||||
/** True if `color`'s king is under attack on this board. */
|
||||
def isInCheck(board: Board, color: Color): Boolean = false
|
||||
|
||||
/** All (from, to) moves for `color` that do not leave their own king in check. */
|
||||
def legalMoves(board: Board, color: Color): Set[(Square, Square)] = Set.empty
|
||||
|
||||
/** Position status for the side whose turn it is (`color`). */
|
||||
def gameStatus(board: Board, color: Color): PositionStatus = PositionStatus.Normal
|
||||
```
|
||||
|
||||
- [ ] **Step 2: Verify the project compiles**
|
||||
|
||||
```bash
|
||||
./gradlew :modules:core:compileScala
|
||||
```
|
||||
|
||||
Expected: `BUILD SUCCESSFUL`
|
||||
|
||||
- [ ] **Step 3: Commit**
|
||||
|
||||
```bash
|
||||
git add modules/core/src/main/scala/de/nowchess/chess/logic/GameRules.scala
|
||||
git commit -m "feat: add GameRules stub with PositionStatus enum"
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Task 2: Write `GameRulesTest` (all tests must fail)
|
||||
|
||||
**Files:**
|
||||
- Create: `modules/core/src/test/scala/de/nowchess/chess/logic/GameRulesTest.scala`
|
||||
|
||||
- [ ] **Step 1: Create the test file**
|
||||
|
||||
```scala
|
||||
package de.nowchess.chess.logic
|
||||
|
||||
import de.nowchess.api.board.*
|
||||
import org.scalatest.funsuite.AnyFunSuite
|
||||
import org.scalatest.matchers.should.Matchers
|
||||
|
||||
class GameRulesTest extends AnyFunSuite with Matchers:
|
||||
|
||||
private def sq(f: File, r: Rank): Square = Square(f, r)
|
||||
private def board(entries: (Square, Piece)*): Board = Board(entries.toMap)
|
||||
|
||||
// ──── isInCheck ──────────────────────────────────────────────────────
|
||||
|
||||
test("isInCheck: king attacked by enemy rook on same rank"):
|
||||
// White King E1, Black Rook A1 — rook slides along rank 1 to E1
|
||||
val b = board(
|
||||
sq(File.E, Rank.R1) -> Piece.WhiteKing,
|
||||
sq(File.A, Rank.R1) -> Piece.BlackRook
|
||||
)
|
||||
GameRules.isInCheck(b, Color.White) shouldBe true
|
||||
|
||||
test("isInCheck: king not attacked"):
|
||||
// Black Rook A3 does not cover E1
|
||||
val b = board(
|
||||
sq(File.E, Rank.R1) -> Piece.WhiteKing,
|
||||
sq(File.A, Rank.R3) -> Piece.BlackRook
|
||||
)
|
||||
GameRules.isInCheck(b, Color.White) shouldBe false
|
||||
|
||||
test("isInCheck: no king on board returns false"):
|
||||
val b = board(sq(File.A, Rank.R1) -> Piece.BlackRook)
|
||||
GameRules.isInCheck(b, Color.White) shouldBe false
|
||||
|
||||
// ──── legalMoves ─────────────────────────────────────────────────────
|
||||
|
||||
test("legalMoves: move that exposes own king to rook is excluded"):
|
||||
// White King E1, White Rook E4 (pinned on E-file), Black Rook E8
|
||||
// Moving the White Rook off the E-file would expose the king
|
||||
val b = board(
|
||||
sq(File.E, Rank.R1) -> Piece.WhiteKing,
|
||||
sq(File.E, Rank.R4) -> Piece.WhiteRook,
|
||||
sq(File.E, Rank.R8) -> Piece.BlackRook
|
||||
)
|
||||
val moves = GameRules.legalMoves(b, Color.White)
|
||||
moves should not contain (sq(File.E, Rank.R4) -> sq(File.D, Rank.R4))
|
||||
|
||||
test("legalMoves: move that blocks check is included"):
|
||||
// White King E1 in check from Black Rook E8; White Rook A5 can interpose on E5
|
||||
val b = board(
|
||||
sq(File.E, Rank.R1) -> Piece.WhiteKing,
|
||||
sq(File.A, Rank.R5) -> Piece.WhiteRook,
|
||||
sq(File.E, Rank.R8) -> Piece.BlackRook
|
||||
)
|
||||
val moves = GameRules.legalMoves(b, Color.White)
|
||||
moves should contain(sq(File.A, Rank.R5) -> sq(File.E, Rank.R5))
|
||||
|
||||
// ──── gameStatus ──────────────────────────────────────────────────────
|
||||
|
||||
test("gameStatus: checkmate returns Mated"):
|
||||
// White Qh8, Ka6; Black Ka8
|
||||
// Qh8 attacks Ka8 along rank 8; all escape squares covered (spec-verified position)
|
||||
val b = board(
|
||||
sq(File.H, Rank.R8) -> Piece.WhiteQueen,
|
||||
sq(File.A, Rank.R6) -> Piece.WhiteKing,
|
||||
sq(File.A, Rank.R8) -> Piece.BlackKing
|
||||
)
|
||||
GameRules.gameStatus(b, Color.Black) shouldBe PositionStatus.Mated
|
||||
|
||||
test("gameStatus: stalemate returns Drawn"):
|
||||
// White Qb6, Kc6; Black Ka8
|
||||
// Black king has no legal moves and is not in check (spec-verified position)
|
||||
val b = board(
|
||||
sq(File.B, Rank.R6) -> Piece.WhiteQueen,
|
||||
sq(File.C, Rank.R6) -> Piece.WhiteKing,
|
||||
sq(File.A, Rank.R8) -> Piece.BlackKing
|
||||
)
|
||||
GameRules.gameStatus(b, Color.Black) shouldBe PositionStatus.Drawn
|
||||
|
||||
test("gameStatus: king in check with legal escape returns InCheck"):
|
||||
// White Ra8 attacks Black Ke8 along rank 8; king can escape to d7, e7, f7
|
||||
val b = board(
|
||||
sq(File.A, Rank.R8) -> Piece.WhiteRook,
|
||||
sq(File.E, Rank.R8) -> Piece.BlackKing
|
||||
)
|
||||
GameRules.gameStatus(b, Color.Black) shouldBe PositionStatus.InCheck
|
||||
|
||||
test("gameStatus: normal starting position returns Normal"):
|
||||
GameRules.gameStatus(Board.initial, Color.White) shouldBe PositionStatus.Normal
|
||||
```
|
||||
|
||||
- [ ] **Step 2: Run the tests and confirm they all fail**
|
||||
|
||||
```bash
|
||||
./gradlew :modules:core:test --tests "de.nowchess.chess.logic.GameRulesTest"
|
||||
```
|
||||
|
||||
Expected: all 8 tests FAIL (stubs always return `false` / `Set.empty` / `Normal`)
|
||||
|
||||
- [ ] **Step 3: Commit**
|
||||
|
||||
```bash
|
||||
git add modules/core/src/test/scala/de/nowchess/chess/logic/GameRulesTest.scala
|
||||
git commit -m "test: add failing GameRulesTest for check/checkmate/stalemate"
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Task 3: Implement `GameRules`
|
||||
|
||||
**Files:**
|
||||
- Modify: `modules/core/src/main/scala/de/nowchess/chess/logic/GameRules.scala`
|
||||
|
||||
- [ ] **Step 1: Replace the stub bodies with real implementations**
|
||||
|
||||
```scala
|
||||
package de.nowchess.chess.logic
|
||||
|
||||
import de.nowchess.api.board.*
|
||||
|
||||
enum PositionStatus:
|
||||
case Normal, InCheck, Mated, Drawn
|
||||
|
||||
object GameRules:
|
||||
|
||||
def isInCheck(board: Board, color: Color): Boolean =
|
||||
board.pieces
|
||||
.collectFirst { case (sq, Piece(`color`, PieceType.King)) => sq }
|
||||
.exists { kingSq =>
|
||||
board.pieces.exists { case (sq, piece) =>
|
||||
piece.color != color &&
|
||||
MoveValidator.legalTargets(board, sq).contains(kingSq)
|
||||
}
|
||||
}
|
||||
|
||||
def legalMoves(board: Board, color: Color): Set[(Square, Square)] =
|
||||
board.pieces
|
||||
.collect { case (from, piece) if piece.color == color => from }
|
||||
.flatMap { from =>
|
||||
MoveValidator.legalTargets(board, from)
|
||||
.filter { to =>
|
||||
val (newBoard, _) = board.withMove(from, to)
|
||||
!isInCheck(newBoard, color)
|
||||
}
|
||||
.map(to => from -> to)
|
||||
}
|
||||
.toSet
|
||||
|
||||
def gameStatus(board: Board, color: Color): PositionStatus =
|
||||
val moves = legalMoves(board, color)
|
||||
val inCheck = isInCheck(board, color)
|
||||
if moves.isEmpty && inCheck then PositionStatus.Mated
|
||||
else if moves.isEmpty then PositionStatus.Drawn
|
||||
else if inCheck then PositionStatus.InCheck
|
||||
else PositionStatus.Normal
|
||||
```
|
||||
|
||||
- [ ] **Step 2: Run the GameRules tests and confirm they all pass**
|
||||
|
||||
```bash
|
||||
./gradlew :modules:core:test --tests "de.nowchess.chess.logic.GameRulesTest"
|
||||
```
|
||||
|
||||
Expected: all 8 tests PASS
|
||||
|
||||
- [ ] **Step 3: Run the full test suite to make sure nothing regressed**
|
||||
|
||||
```bash
|
||||
./gradlew :modules:core:test
|
||||
```
|
||||
|
||||
Expected: `BUILD SUCCESSFUL`, all existing tests still pass
|
||||
|
||||
- [ ] **Step 4: Commit**
|
||||
|
||||
```bash
|
||||
git add modules/core/src/main/scala/de/nowchess/chess/logic/GameRules.scala
|
||||
git commit -m "feat: implement GameRules with isInCheck, legalMoves, gameStatus"
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Task 4: Add new `MoveResult` variants and stub `processMove`
|
||||
|
||||
**Files:**
|
||||
- Modify: `modules/core/src/main/scala/de/nowchess/chess/controller/GameController.scala`
|
||||
|
||||
- [ ] **Step 1: Add three new variants to `MoveResult` and import `GameRules`**
|
||||
|
||||
In `GameController.scala`, update the `MoveResult` object and `processMove`. The new variants go after `Moved`. The import of `GameRules`/`PositionStatus` is added at the top. The stub `processMove` calls `GameRules.gameStatus` but always maps to `Moved` — this makes it compile while the new tests will fail:
|
||||
|
||||
```scala
|
||||
package de.nowchess.chess.controller
|
||||
|
||||
import scala.io.StdIn
|
||||
import de.nowchess.api.board.{Board, Color, Piece}
|
||||
import de.nowchess.chess.logic.{MoveValidator, GameRules, PositionStatus}
|
||||
import de.nowchess.chess.view.Renderer
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// Result ADT returned by the pure processMove function
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
sealed trait MoveResult
|
||||
object MoveResult:
|
||||
case object Quit extends MoveResult
|
||||
case class InvalidFormat(raw: String) extends MoveResult
|
||||
case object NoPiece extends MoveResult
|
||||
case object WrongColor extends MoveResult
|
||||
case object IllegalMove extends MoveResult
|
||||
case class Moved(newBoard: Board, captured: Option[Piece], newTurn: Color) extends MoveResult
|
||||
case class MovedInCheck(newBoard: Board, captured: Option[Piece], newTurn: Color) extends MoveResult
|
||||
case class Checkmate(winner: Color) extends MoveResult
|
||||
case object Stalemate extends MoveResult
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// Controller
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
object GameController:
|
||||
|
||||
def processMove(board: Board, turn: Color, raw: String): MoveResult =
|
||||
raw.trim match
|
||||
case "quit" | "q" =>
|
||||
MoveResult.Quit
|
||||
case trimmed =>
|
||||
Parser.parseMove(trimmed) match
|
||||
case None =>
|
||||
MoveResult.InvalidFormat(trimmed)
|
||||
case Some((from, to)) =>
|
||||
board.pieceAt(from) match
|
||||
case None =>
|
||||
MoveResult.NoPiece
|
||||
case Some(piece) if piece.color != turn =>
|
||||
MoveResult.WrongColor
|
||||
case Some(_) =>
|
||||
if !MoveValidator.isLegal(board, from, to) then
|
||||
MoveResult.IllegalMove
|
||||
else
|
||||
val (newBoard, captured) = board.withMove(from, to)
|
||||
MoveResult.Moved(newBoard, captured, turn.opposite) // stub — Task 6 will fix
|
||||
|
||||
def gameLoop(board: Board, turn: Color): Unit =
|
||||
println()
|
||||
print(Renderer.render(board))
|
||||
println(s"${turn.label}'s turn. Enter move: ")
|
||||
val input = Option(StdIn.readLine()).getOrElse("quit").trim
|
||||
processMove(board, turn, input) match
|
||||
case MoveResult.Quit =>
|
||||
println("Game over. Goodbye!")
|
||||
case MoveResult.InvalidFormat(raw) =>
|
||||
println(s"Invalid move format '$raw'. Use coordinate notation, e.g. e2e4.")
|
||||
gameLoop(board, turn)
|
||||
case MoveResult.NoPiece =>
|
||||
println(s"No piece on ${Parser.parseMove(input).map(_._1).fold("?")(_.toString)}.")
|
||||
gameLoop(board, turn)
|
||||
case MoveResult.WrongColor =>
|
||||
println(s"That is not your piece.")
|
||||
gameLoop(board, turn)
|
||||
case MoveResult.IllegalMove =>
|
||||
println(s"Illegal move.")
|
||||
gameLoop(board, turn)
|
||||
case MoveResult.Moved(newBoard, captured, newTurn) =>
|
||||
val prevTurn = newTurn.opposite
|
||||
captured.foreach: cap =>
|
||||
val toSq = Parser.parseMove(input).map(_._2).fold("?")(_.toString)
|
||||
println(s"${prevTurn.label} captures ${cap.color.label} ${cap.pieceType.label} on $toSq")
|
||||
gameLoop(newBoard, newTurn)
|
||||
case MoveResult.MovedInCheck(newBoard, captured, newTurn) => // stub — Task 6
|
||||
gameLoop(newBoard, newTurn)
|
||||
case MoveResult.Checkmate(winner) => // stub — Task 6
|
||||
gameLoop(Board.initial, Color.White)
|
||||
case MoveResult.Stalemate => // stub — Task 6
|
||||
gameLoop(Board.initial, Color.White)
|
||||
```
|
||||
|
||||
- [ ] **Step 2: Confirm everything still compiles and existing tests pass**
|
||||
|
||||
```bash
|
||||
./gradlew :modules:core:test
|
||||
```
|
||||
|
||||
Expected: `BUILD SUCCESSFUL` — existing tests still pass, no compilation errors
|
||||
|
||||
- [ ] **Step 3: Commit**
|
||||
|
||||
```bash
|
||||
git add modules/core/src/main/scala/de/nowchess/chess/controller/GameController.scala
|
||||
git commit -m "feat: add MovedInCheck/Checkmate/Stalemate MoveResult variants (stub dispatch)"
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Task 5: Write new `GameControllerTest` cases (all must fail)
|
||||
|
||||
**Files:**
|
||||
- Modify: `modules/core/src/test/scala/de/nowchess/chess/controller/GameControllerTest.scala`
|
||||
|
||||
- [ ] **Step 1: Append the following tests to the existing file**
|
||||
|
||||
Add after the last existing test (the `gameLoop: capture` test). Add the `captureOutput` helper alongside `withInput`:
|
||||
|
||||
```scala
|
||||
// ──── helpers ────────────────────────────────────────────────────────
|
||||
|
||||
private def captureOutput(block: => Unit): String =
|
||||
val out = java.io.ByteArrayOutputStream()
|
||||
scala.Console.withOut(out)(block)
|
||||
out.toString("UTF-8")
|
||||
|
||||
// ──── processMove: check / checkmate / stalemate ─────────────────────
|
||||
|
||||
test("processMove: legal move that delivers check returns MovedInCheck"):
|
||||
// White Ra1, Ka3; Black Kh8 — White plays Ra1-Ra8, putting Kh8 in check
|
||||
// (Ra8 attacks along rank 8: b8..h8; king escapes to g7/g8/h7 — InCheck, not Mated)
|
||||
val b = Board(Map(
|
||||
sq(File.A, Rank.R1) -> Piece.WhiteRook,
|
||||
sq(File.A, Rank.R3) -> Piece.WhiteKing,
|
||||
sq(File.H, Rank.R8) -> Piece.BlackKing
|
||||
))
|
||||
GameController.processMove(b, Color.White, "a1a8") match
|
||||
case MoveResult.MovedInCheck(_, _, newTurn) => newTurn shouldBe Color.Black
|
||||
case other => fail(s"Expected MovedInCheck, got $other")
|
||||
|
||||
test("processMove: legal move that results in checkmate returns Checkmate"):
|
||||
// White Qa1, Ka6; Black Ka8 — White plays Qa1-Qh8 (diagonal a1-h8)
|
||||
// After Qh8: White Qh8 + Ka6 vs Black Ka8 = checkmate (spec-verified)
|
||||
// Note: Qa1 does NOT currently attack Ka8 (path along file A is blocked by Ka6)
|
||||
val b = Board(Map(
|
||||
sq(File.A, Rank.R1) -> Piece.WhiteQueen,
|
||||
sq(File.A, Rank.R6) -> Piece.WhiteKing,
|
||||
sq(File.A, Rank.R8) -> Piece.BlackKing
|
||||
))
|
||||
GameController.processMove(b, Color.White, "a1h8") match
|
||||
case MoveResult.Checkmate(winner) => winner shouldBe Color.White
|
||||
case other => fail(s"Expected Checkmate(White), got $other")
|
||||
|
||||
test("processMove: legal move that results in stalemate returns Stalemate"):
|
||||
// White Qb1, Kc6; Black Ka8 — White plays Qb1-Qb6
|
||||
// After Qb6: White Qb6 + Kc6 vs Black Ka8 = stalemate (spec-verified)
|
||||
val b = Board(Map(
|
||||
sq(File.B, Rank.R1) -> Piece.WhiteQueen,
|
||||
sq(File.C, Rank.R6) -> Piece.WhiteKing,
|
||||
sq(File.A, Rank.R8) -> Piece.BlackKing
|
||||
))
|
||||
GameController.processMove(b, Color.White, "b1b6") match
|
||||
case MoveResult.Stalemate => succeed
|
||||
case other => fail(s"Expected Stalemate, got $other")
|
||||
|
||||
// ──── gameLoop: check / checkmate / stalemate ─────────────────────────
|
||||
|
||||
test("gameLoop: checkmate prints winner message and resets to new game"):
|
||||
// Same position as checkmate processMove test above; after Qa1-Qh8 game resets
|
||||
// Second move "quit" exits the new game cleanly
|
||||
val b = Board(Map(
|
||||
sq(File.A, Rank.R1) -> Piece.WhiteQueen,
|
||||
sq(File.A, Rank.R6) -> Piece.WhiteKing,
|
||||
sq(File.A, Rank.R8) -> Piece.BlackKing
|
||||
))
|
||||
val output = captureOutput:
|
||||
withInput("a1h8\nquit\n"):
|
||||
GameController.gameLoop(b, Color.White)
|
||||
output should include("Checkmate! White wins.")
|
||||
|
||||
test("gameLoop: stalemate prints draw message and resets to new game"):
|
||||
val b = Board(Map(
|
||||
sq(File.B, Rank.R1) -> Piece.WhiteQueen,
|
||||
sq(File.C, Rank.R6) -> Piece.WhiteKing,
|
||||
sq(File.A, Rank.R8) -> Piece.BlackKing
|
||||
))
|
||||
val output = captureOutput:
|
||||
withInput("b1b6\nquit\n"):
|
||||
GameController.gameLoop(b, Color.White)
|
||||
output should include("Stalemate! The game is a draw.")
|
||||
|
||||
test("gameLoop: MovedInCheck without capture prints check message"):
|
||||
val b = Board(Map(
|
||||
sq(File.A, Rank.R1) -> Piece.WhiteRook,
|
||||
sq(File.A, Rank.R3) -> Piece.WhiteKing,
|
||||
sq(File.H, Rank.R8) -> Piece.BlackKing
|
||||
))
|
||||
val output = captureOutput:
|
||||
withInput("a1a8\nquit\n"):
|
||||
GameController.gameLoop(b, Color.White)
|
||||
output should include("Black is in check!")
|
||||
|
||||
test("gameLoop: MovedInCheck with capture prints both capture and check message"):
|
||||
// White Rook A1 captures Black Pawn on A8, putting Black King (H8) in check
|
||||
// Ra8 attacks rank 8 → Black Kh8 is in check; king can escape to g7/g8/h7
|
||||
val b = Board(Map(
|
||||
sq(File.A, Rank.R1) -> Piece.WhiteRook,
|
||||
sq(File.A, Rank.R3) -> Piece.WhiteKing,
|
||||
sq(File.A, Rank.R8) -> Piece.BlackPawn,
|
||||
sq(File.H, Rank.R8) -> Piece.BlackKing
|
||||
))
|
||||
val output = captureOutput:
|
||||
withInput("a1a8\nquit\n"):
|
||||
GameController.gameLoop(b, Color.White)
|
||||
output should include("captures")
|
||||
output should include("Black is in check!")
|
||||
```
|
||||
|
||||
- [ ] **Step 2: Run only the new tests and confirm they fail**
|
||||
|
||||
```bash
|
||||
./gradlew :modules:core:test --tests "de.nowchess.chess.controller.GameControllerTest"
|
||||
```
|
||||
|
||||
Expected: the 7 new tests FAIL; the existing 17 tests PASS
|
||||
|
||||
- [ ] **Step 3: Commit**
|
||||
|
||||
```bash
|
||||
git add modules/core/src/test/scala/de/nowchess/chess/controller/GameControllerTest.scala
|
||||
git commit -m "test: add failing GameControllerTest cases for check/checkmate/stalemate"
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Task 6: Implement `processMove` dispatch and `gameLoop` branches
|
||||
|
||||
**Files:**
|
||||
- Modify: `modules/core/src/main/scala/de/nowchess/chess/controller/GameController.scala`
|
||||
|
||||
- [ ] **Step 1: Replace the stub `processMove` else-branch and the three stub `gameLoop` cases**
|
||||
|
||||
Replace only the `else` branch inside `processMove` (keep everything else identical):
|
||||
|
||||
```scala
|
||||
else
|
||||
val (newBoard, captured) = board.withMove(from, to)
|
||||
GameRules.gameStatus(newBoard, turn.opposite) match
|
||||
case PositionStatus.Normal => MoveResult.Moved(newBoard, captured, turn.opposite)
|
||||
case PositionStatus.InCheck => MoveResult.MovedInCheck(newBoard, captured, turn.opposite)
|
||||
case PositionStatus.Mated => MoveResult.Checkmate(turn)
|
||||
case PositionStatus.Drawn => MoveResult.Stalemate
|
||||
```
|
||||
|
||||
Replace the three stub `gameLoop` cases:
|
||||
|
||||
```scala
|
||||
case MoveResult.MovedInCheck(newBoard, captured, newTurn) =>
|
||||
val prevTurn = newTurn.opposite
|
||||
captured.foreach: cap =>
|
||||
val toSq = Parser.parseMove(input).map(_._2).fold("?")(_.toString)
|
||||
println(s"${prevTurn.label} captures ${cap.color.label} ${cap.pieceType.label} on $toSq")
|
||||
println(s"${newTurn.label} is in check!")
|
||||
gameLoop(newBoard, newTurn)
|
||||
case MoveResult.Checkmate(winner) =>
|
||||
println(s"Checkmate! ${winner.label} wins.")
|
||||
gameLoop(Board.initial, Color.White)
|
||||
case MoveResult.Stalemate =>
|
||||
println("Stalemate! The game is a draw.")
|
||||
gameLoop(Board.initial, Color.White)
|
||||
```
|
||||
|
||||
- [ ] **Step 2: Run all controller tests**
|
||||
|
||||
```bash
|
||||
./gradlew :modules:core:test --tests "de.nowchess.chess.controller.GameControllerTest"
|
||||
```
|
||||
|
||||
Expected: all 24 tests PASS
|
||||
|
||||
- [ ] **Step 3: Run the full test suite**
|
||||
|
||||
```bash
|
||||
./gradlew :modules:core:test
|
||||
```
|
||||
|
||||
Expected: `BUILD SUCCESSFUL`, all tests pass
|
||||
|
||||
- [ ] **Step 4: Commit**
|
||||
|
||||
```bash
|
||||
git add modules/core/src/main/scala/de/nowchess/chess/controller/GameController.scala
|
||||
git commit -m "feat: wire check/checkmate/stalemate into processMove and gameLoop"
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Task 7: Coverage check and final verification
|
||||
|
||||
- [ ] **Step 1: Run the full build with coverage**
|
||||
|
||||
```bash
|
||||
./gradlew :modules:core:test
|
||||
```
|
||||
|
||||
Expected: `BUILD SUCCESSFUL`
|
||||
|
||||
- [ ] **Step 2: Check coverage gaps**
|
||||
|
||||
```bash
|
||||
python jacoco-reporter/scoverage_coverage_gaps.py modules/core/build/reports/scoverageTest/scoverage.xml
|
||||
```
|
||||
|
||||
Review output. If any newly added method falls below the thresholds from `CLAUDE.md` (branch ≥ 90%, line ≥ 95%, method ≥ 90%), add targeted tests to close the gaps before considering the task done.
|
||||
|
||||
- [ ] **Step 3: Commit coverage fixes (if any)**
|
||||
|
||||
```bash
|
||||
git add -p
|
||||
git commit -m "test: improve coverage for GameRules and GameController"
|
||||
```
|
||||
@@ -1,85 +0,0 @@
|
||||
# Design: Add ScalaTest + Replace JaCoCo with Scoverage
|
||||
|
||||
**Date:** 2026-03-22
|
||||
**Status:** Approved
|
||||
|
||||
## Summary
|
||||
|
||||
Replace the current JUnit-only test setup and JaCoCo coverage with ScalaTest (via its JUnit 5 bridge) and Scoverage across both `modules/core` and `modules/api`.
|
||||
|
||||
## Motivation
|
||||
|
||||
- The CLAUDE.md working agreement prescribes `AnyFunSuite with Matchers with JUnitSuiteLike` as the unit test style, which requires ScalaTest.
|
||||
- Scoverage is the standard Scala code coverage tool and understands Scala semantics; JaCoCo's JVM bytecode instrumentation is less accurate for Scala code.
|
||||
|
||||
## Scope
|
||||
|
||||
Two modules are affected: `modules/core` and `modules/api`. The root `build.gradle.kts` is updated for shared dependency versions only.
|
||||
|
||||
## Changes
|
||||
|
||||
### Root `build.gradle.kts`
|
||||
|
||||
Add to the `versions` map (dependency versions only — plugin version is hardcoded per module, see note below):
|
||||
- `SCALATEST` → `3.2.19`
|
||||
- `SCALATESTPLUS_JUNIT5` → `3.2.19.1`
|
||||
|
||||
> **Note on plugin versioning:** Gradle resolves the `plugins {}` block before `rootProject.extra` is available, so the Scoverage plugin version (`8.1`) must be declared inline in each module's `plugins {}` block. It cannot be read from the root versions map.
|
||||
|
||||
### `modules/core/build.gradle.kts` and `modules/api/build.gradle.kts`
|
||||
|
||||
Both modules require the same set of changes. Both currently have **two separate `tasks.test {}` blocks** that must be merged into one.
|
||||
|
||||
**Plugins block:**
|
||||
- Remove `jacoco`
|
||||
- Add `id("org.scoverage") version "8.1"`
|
||||
|
||||
**Dependencies block:**
|
||||
- Remove `testImplementation(platform("org.junit:junit-bom:5.10.0"))`
|
||||
- Remove `testImplementation("org.junit.jupiter:junit-jupiter")`
|
||||
- Remove `testRuntimeOnly("org.junit.platform:junit-platform-launcher")`
|
||||
- Add `testImplementation("org.scalatest:scalatest_3:${versions["SCALATEST"]!!}")`
|
||||
- Add `testImplementation("org.scalatestplus:junit-5-11_3:${versions["SCALATESTPLUS_JUNIT5"]!!}")`
|
||||
|
||||
**Task wiring — merge both `tasks.test {}` blocks into one and replace jacoco wiring:**
|
||||
|
||||
Both `modules/core` and `modules/api` currently have two `tasks.test {}` blocks. Delete both and replace with the following single merged block placed **after** the `dependencies {}` block (conventional position):
|
||||
|
||||
```kotlin
|
||||
tasks.test {
|
||||
useJUnitPlatform() // required — scalatestplus JUnit 5 bridge relies on this
|
||||
finalizedBy(tasks.reportScoverage)
|
||||
}
|
||||
tasks.reportScoverage {
|
||||
dependsOn(tasks.test)
|
||||
}
|
||||
```
|
||||
|
||||
> Note: `modules/api` does not currently have `useJUnitPlatform()` — it must be **added** (not just kept) in the merged block.
|
||||
|
||||
Remove the `jacocoTestReport` task block entirely from both modules.
|
||||
|
||||
**Task name confirmation:** The Scoverage Gradle plugin 8.1 registers `reportScoverage` as the HTML report task.
|
||||
|
||||
## Versions
|
||||
|
||||
| Artifact | Version | Notes |
|
||||
|---|---|---|
|
||||
| `org.scalatest:scalatest_3` | 3.2.19 | Core ScalaTest for Scala 3 |
|
||||
| `org.scalatestplus:junit-5-11_3` | 3.2.19.1 | JUnit 5.11 runner bridge; `.1` = build 1 |
|
||||
| Scoverage Gradle plugin | 8.1 | Hardcoded inline in `plugins {}` block |
|
||||
|
||||
## Testing the Change
|
||||
|
||||
After applying:
|
||||
1. `./gradlew :modules:core:test` and `./gradlew :modules:api:test` must pass (green, even with zero test files).
|
||||
2. `./gradlew :modules:core:reportScoverage` must produce a coverage report.
|
||||
3. `./gradlew build` must be fully green.
|
||||
|
||||
## Files Modified
|
||||
|
||||
- `build.gradle.kts` (root) — add two version entries
|
||||
- `modules/core/build.gradle.kts` — plugin, deps, merge two `tasks.test` blocks, replace jacoco wiring
|
||||
- `modules/api/build.gradle.kts` — plugin, deps, merge two `tasks.test` blocks, add `useJUnitPlatform()`, replace jacoco wiring
|
||||
|
||||
No new source files are created.
|
||||
@@ -1,169 +0,0 @@
|
||||
# Chess Check / Checkmate / Stalemate — Design Spec
|
||||
|
||||
**Date:** 2026-03-23
|
||||
**Status:** Approved
|
||||
|
||||
---
|
||||
|
||||
## Scope
|
||||
|
||||
Implement check detection, checkmate (win condition), and stalemate (draw) on top of the existing normal-move rules. En passant, castling, and pawn promotion are **out of scope** for this iteration.
|
||||
|
||||
---
|
||||
|
||||
## Architecture
|
||||
|
||||
### New: `GameRules` object
|
||||
|
||||
**File:** `modules/core/src/main/scala/de/nowchess/chess/logic/GameRules.scala`
|
||||
|
||||
Owns all check-aware game logic. `MoveValidator` retains its documented geometric-only contract ("ignoring check/pin").
|
||||
|
||||
```
|
||||
GameRules
|
||||
isInCheck(board, color): Boolean
|
||||
legalMoves(board, color): Set[(Square, Square)]
|
||||
gameStatus(board, color): PositionStatus
|
||||
```
|
||||
|
||||
#### `isInCheck(board, color)`
|
||||
|
||||
Finds the king square for `color` by scanning `board.pieces` for a `Piece(color, PieceType.King)`. If no king is found (constructed/test boards), returns `false`.
|
||||
|
||||
Then checks whether any enemy piece's `MoveValidator.legalTargets` contains that square. This works correctly for all piece types, including the king: `kingTargets` returns the squares the king can move to, which are identical to the squares the king attacks, so using `legalTargets` for attack detection is correct by design.
|
||||
|
||||
Returns `true` if the king square is covered by at least one enemy piece.
|
||||
|
||||
|
||||
#### `legalMoves(board, color)`
|
||||
|
||||
1. Filter `board.pieces` to entries where `piece.color == color`.
|
||||
2. For each such `(from, piece)`, call `MoveValidator.legalTargets(board, from)` to get geometric candidates.
|
||||
3. For each candidate `to`, apply `board.withMove(from, to)` to get `newBoard`.
|
||||
4. Keep only moves where `isInCheck(newBoard, color)` is `false` (i.e., the move does not leave own king in check).
|
||||
5. Return the full set of `(from, to)` pairs that survive this filter.
|
||||
|
||||
#### `gameStatus(board, color)`
|
||||
|
||||
Returns a `PositionStatus` enum value based on `legalMoves(board, color)` and `isInCheck(board, color)`:
|
||||
|
||||
- `Mated` — `legalMoves` is empty **and** king is in check → the side to move has been checkmated
|
||||
- `Drawn` — `legalMoves` is empty **and** king is **not** in check → stalemate (draw)
|
||||
- `InCheck` — `legalMoves` is non-empty **and** king is in check → game continues under check
|
||||
- `Normal` — otherwise
|
||||
|
||||
#### Local `PositionStatus` enum
|
||||
|
||||
Defined in `GameRules.scala`. Names are intentionally distinct from `MoveResult` variants to avoid unqualified-name collisions in `GameController.scala`:
|
||||
|
||||
```scala
|
||||
enum PositionStatus:
|
||||
case Normal, InCheck, Mated, Drawn
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### Modified: `MoveResult` (in `GameController.scala`)
|
||||
|
||||
Three new variants; existing variants are unchanged:
|
||||
|
||||
| Variant | When used |
|
||||
|---|---|
|
||||
| `MovedInCheck(newBoard, captured, newTurn)` | Move was legal; opponent is now in check but has legal replies |
|
||||
| `Checkmate(winner: Color)` | Move was legal; opponent is `Mated` → `winner` is the side that just moved |
|
||||
| `Stalemate` | Move was legal; opponent is `Drawn` (no legal reply, not in check) |
|
||||
|
||||
`Moved` continues to be used when `gameStatus` returns `Normal`.
|
||||
|
||||
---
|
||||
|
||||
### Modified: `GameController.processMove`
|
||||
|
||||
After computing `(newBoard, captured)` from `board.withMove`:
|
||||
|
||||
1. Call `GameRules.gameStatus(newBoard, newTurn)`.
|
||||
2. Map to the appropriate `MoveResult`:
|
||||
|
||||
```
|
||||
PositionStatus.Normal → Moved(newBoard, captured, newTurn)
|
||||
PositionStatus.InCheck → MovedInCheck(newBoard, captured, newTurn)
|
||||
PositionStatus.Mated → Checkmate(turn) // turn = the side that just moved
|
||||
PositionStatus.Drawn → Stalemate
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### Modified: `GameController.gameLoop`
|
||||
|
||||
**New terminal branches** (both print a message then restart):
|
||||
|
||||
- `Checkmate(winner)` → print `"Checkmate! {winner.label} wins."`, then recurse with `(Board.initial, Color.White)`
|
||||
- `Stalemate` → print `"Stalemate! The game is a draw."`, then recurse with `(Board.initial, Color.White)`
|
||||
|
||||
**New non-terminal branch:**
|
||||
|
||||
- `MovedInCheck(newBoard, captured, newTurn)` → print the same optional capture message as `Moved` (when `captured.isDefined`), then print `"{newTurn.label} is in check!"`, then recurse with `(newBoard, newTurn)`
|
||||
|
||||
**Restart vs. exit:** Checkmate and stalemate restart the game automatically (no prompt). This is intentionally asymmetric with `Quit`, which exits. `Quit` is an explicit user request to stop; Checkmate/Stalemate are natural game endings that should roll into a new game.
|
||||
|
||||
---
|
||||
|
||||
## Test Strategy
|
||||
|
||||
All tests are unit tests extending `AnyFunSuite with Matchers with JUnitSuiteLike`.
|
||||
|
||||
### `GameRulesTest` — new file
|
||||
|
||||
| Scenario | Method | Expected |
|
||||
|---|---|---|
|
||||
| King attacked by enemy rook on same rank | `isInCheck` | `true` |
|
||||
| King not attacked (only own pieces nearby) | `isInCheck` | `false` |
|
||||
| No king on board (constructed board) | `isInCheck` | `false` |
|
||||
| Move that exposes own king to rook is excluded | `legalMoves` | does not contain that move |
|
||||
| Move that blocks check is included | `legalMoves` | contains the blocking move |
|
||||
| Checkmate: White Qh8, Ka6; Black Ka8 — Black king is in check (Qh8 along rank 8), cannot escape to a7 (Ka6), b7 (Ka6), or b8 (Qh8) | `gameStatus` | `Mated` |
|
||||
| Stalemate: White Qb6, Kc6; Black Ka8 — Black king has no legal moves (a7/b7/b8 all controlled by Qb6), not in check | `gameStatus` | `Drawn` |
|
||||
| King in check with at least one escape square | `gameStatus` | `InCheck` |
|
||||
| Normal midgame position, not in check, has moves | `gameStatus` | `Normal` |
|
||||
|
||||
### `GameControllerTest` additions — new `processMove` cases
|
||||
|
||||
| Scenario | Expected `MoveResult` |
|
||||
|---|---|
|
||||
| Move leaves opponent in check (has escape) | `MovedInCheck` |
|
||||
| Move results in checkmate | `Checkmate(winner)` where winner is the side that moved |
|
||||
| Move results in stalemate | `Stalemate` |
|
||||
|
||||
### `GameControllerTest` additions — new `gameLoop` cases
|
||||
|
||||
| Scenario | Expected output / behavior |
|
||||
|---|---|
|
||||
| `gameLoop` receives `Checkmate(White)` | Prints "Checkmate! White wins." and continues (new game) |
|
||||
| `gameLoop` receives `Stalemate` | Prints "Stalemate! The game is a draw." and continues (new game) |
|
||||
| `gameLoop` receives `MovedInCheck` with a capture | Prints capture message AND check message |
|
||||
| `gameLoop` receives `MovedInCheck` without a capture | Prints check message only |
|
||||
|
||||
---
|
||||
|
||||
## Development Workflow (TDD)
|
||||
|
||||
1. Create `GameRules.scala` with empty/stub method bodies that compile but return placeholder values (`false`, `Set.empty`, `PositionStatus.Normal`).
|
||||
2. Write all `GameRulesTest` tests — they should **fail**.
|
||||
3. Implement `GameRules` logic until `GameRulesTest` is green.
|
||||
4. Add new `MoveResult` variants to `GameController.scala`; update `processMove` to call `GameRules.gameStatus` (stub the match arms initially).
|
||||
5. Write new `GameControllerTest` cases — they should **fail**.
|
||||
6. Implement `processMove` match arms and `gameLoop` new branches until all tests pass.
|
||||
7. Run `./gradlew :modules:core:test` — full green build required.
|
||||
|
||||
---
|
||||
|
||||
## Files Changed
|
||||
|
||||
| File | Change |
|
||||
|---|---|
|
||||
| `modules/core/src/main/scala/de/nowchess/chess/logic/GameRules.scala` | New |
|
||||
| `modules/core/src/test/scala/de/nowchess/chess/logic/GameRulesTest.scala` | New |
|
||||
| `modules/core/src/main/scala/de/nowchess/chess/controller/GameController.scala` | Add `MoveResult` variants; update `processMove` and `gameLoop` |
|
||||
| `modules/core/src/test/scala/de/nowchess/chess/controller/GameControllerTest.scala` | Add new test cases |
|
||||
|
||||
No changes to `modules/api` or `MoveValidator`.
|
||||
@@ -1,584 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<verification-metadata xmlns="https://schema.gradle.org/dependency-verification" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="https://schema.gradle.org/dependency-verification https://schema.gradle.org/dependency-verification/dependency-verification-1.3.xsd">
|
||||
<configuration>
|
||||
<verify-metadata>true</verify-metadata>
|
||||
<verify-signatures>true</verify-signatures>
|
||||
<ignored-keys>
|
||||
<ignored-key id="01D9B9C7952C4A1F" reason="Key couldn't be downloaded from any key server"/>
|
||||
<ignored-key id="1B6E3BDDD4415872" reason="Key couldn't be downloaded from any key server"/>
|
||||
<ignored-key id="29967E804D85663F" reason="Key couldn't be downloaded from any key server"/>
|
||||
<ignored-key id="41CB98F33B06146E" reason="Key couldn't be downloaded from any key server"/>
|
||||
<ignored-key id="60BE32B1404779E5" reason="Key couldn't be downloaded from any key server"/>
|
||||
<ignored-key id="63BB5E152DFF95F0" reason="Key couldn't be downloaded from any key server"/>
|
||||
<ignored-key id="7090AF43A5E10D0B" reason="Key couldn't be downloaded from any key server"/>
|
||||
<ignored-key id="7DC3076FE22D4F88" reason="Key couldn't be downloaded from any key server"/>
|
||||
<ignored-key id="84E913A8E3A748C0" reason="Key couldn't be downloaded from any key server"/>
|
||||
<ignored-key id="85911F425EC61B51" reason="Key couldn't be downloaded from any key server"/>
|
||||
<ignored-key id="9AEE152CDCCEBFCB" reason="Key couldn't be downloaded from any key server"/>
|
||||
<ignored-key id="9DAADC1C9FCC82D0" reason="Key couldn't be downloaded from any key server"/>
|
||||
<ignored-key id="BCF4173966770193" reason="Key couldn't be downloaded from any key server"/>
|
||||
<ignored-key id="BFFA420097F49C8A" reason="Key couldn't be downloaded from any key server"/>
|
||||
<ignored-key id="C03EF1D7D692BCFF" reason="Key couldn't be downloaded from any key server"/>
|
||||
<ignored-key id="C2952540150670BE" reason="Key couldn't be downloaded from any key server"/>
|
||||
<ignored-key id="D364ABAA39A47320" reason="Key couldn't be downloaded from any key server"/>
|
||||
<ignored-key id="DCD5181297A43D24" reason="Key couldn't be downloaded from any key server"/>
|
||||
<ignored-key id="ED2378CD09A08CDE" reason="Key couldn't be downloaded from any key server"/>
|
||||
<ignored-key id="F42E87F9665015C9" reason="Key couldn't be downloaded from any key server"/>
|
||||
</ignored-keys>
|
||||
<trusted-keys>
|
||||
<trusted-key id="0181A4828FA27B6BE6F1F5A68611CD28F472E006" group="org.jline"/>
|
||||
<trusted-key id="073F7A9345756F3B40CDB99E6C70A3B7599C5736" group="org.jline"/>
|
||||
<trusted-key id="120D6F34E627ED3A772EBBFE55C7E5E701832382" group="org.yaml" name="snakeyaml" version="2.0"/>
|
||||
<trusted-key id="1FA868A348719E88B6D0DE24C03EF1D7D692BCFF" group="org.scala-lang"/>
|
||||
<trusted-key id="23D4275AC69688098AF3997BA6C4333204634502" group="org.scoverage"/>
|
||||
<trusted-key id="28118C070CB22A0175A2E8D43D12CA2AC19F3181" group="^com[.]fasterxml($|([.].*))" regex="true"/>
|
||||
<trusted-key id="2A5E8B338438CAC7033F9D8FB8A045C0A6EC398E" group="org.scala-lang"/>
|
||||
<trusted-key id="2BE67AC00D699E04E840B7FE29967E804D85663F" group="com.eed3si9n"/>
|
||||
<trusted-key id="2DB4F1EF0FA761ECC4EA935C86FDC7E2A11262CB">
|
||||
<trusting group="commons-codec"/>
|
||||
<trusting group="commons-io"/>
|
||||
<trusting group="org.apache.commons"/>
|
||||
</trusted-key>
|
||||
<trusted-key id="2E3A1AFFE42B5F53AF19F780BCF4173966770193" group="org.jetbrains" name="annotations" version="15.0"/>
|
||||
<trusted-key id="3F3633D644494880818AD64601D9B9C7952C4A1F" group="org.scala-lang.modules" name="scala-asm" version="9.6.0-scala-1"/>
|
||||
<trusted-key id="4008F9DFF7DBC968F35F9E712642156411CCE8B3" group="com.vladsch.flexmark"/>
|
||||
<trusted-key id="50B670A8DE1F3CD89583895241CB98F33B06146E">
|
||||
<trusting group="nl.big-o"/>
|
||||
<trusting group="ua.co.k"/>
|
||||
</trusted-key>
|
||||
<trusted-key id="58DF461CAAC5F4E5FB2BE32CBFFA420097F49C8A" group="com.lmax" name="disruptor" version="3.4.2"/>
|
||||
<trusted-key id="600D21219963F228200A72375365A8A69292AF1A" group="org.scala-lang.modules" name="scala-xml_3" version="2.1.0"/>
|
||||
<trusted-key id="624B96CEB9896889C97B258F7DC3076FE22D4F88" group="org.nibor.autolink" name="autolink" version="0.6.0"/>
|
||||
<trusted-key id="6766B3EC6ECC2FFD5F899F7C63BB5E152DFF95F0">
|
||||
<trusting group="org.scalactic"/>
|
||||
<trusting group="org.scalatest"/>
|
||||
</trusted-key>
|
||||
<trusted-key id="6E601AC418304FD7DCB373CA3D30EF3598565988" group="org.scoverage"/>
|
||||
<trusted-key id="7B121B76A7ED6CE6E60AD51784E913A8E3A748C0" group="org.bouncycastle" name="bcprov-jdk18on" version="1.83"/>
|
||||
<trusted-key id="7CEAC05AFEB808AD75C2097D60BE32B1404779E5" group="co.helmethair" name="scalatest-junit-runner" version="0.1.11"/>
|
||||
<trusted-key id="84789D24DF77A32433CE1F079EB80E92EB2135B1" group="org.apache" name="apache" version="35"/>
|
||||
<trusted-key id="8A10792983023D5D14C93B488D7F1BEC1E2ECAE7" group="^com[.]fasterxml[.]jackson($|([.].*))" regex="true"/>
|
||||
<trusted-key id="9D0A56AAA0D60E0C0C7DCCC0B4C70893B62BABE8" group="^org[.]apache[.]logging($|([.].*))" regex="true"/>
|
||||
<trusted-key id="A7D8BE3D575D6C5040E889331B6E3BDDD4415872" group="net.openhft"/>
|
||||
<trusted-key id="ACF39CCDED38E2C6F0898BF28F7F6C0451967B84" group="org.scala-lang" name="scala3-library_3"/>
|
||||
<trusted-key id="B9611F878B0CE6D92145157FA6ED77BB4C0EAE26" group="org.scoverage" name="gradle-scoverage" version="8.1"/>
|
||||
<trusted-key id="C44A68FD10FF456C91E2757D18088D07854014B3" group="org.scala-lang.modules" name="scala-parallel-collections_2.13" version="0.2.0"/>
|
||||
<trusted-key id="C7BE5BCC9FEC15518CFDA882B0F3710FA64900E7" group="com.google.code.gson"/>
|
||||
<trusted-key id="CD5464315F0B98C77E6E8ECD9DAADC1C9FCC82D0" group="commons-io" name="commons-io" version="2.6"/>
|
||||
<trusted-key id="D1436C0DBACEA48702AF97C363F1DD7753B8B315" group="^org[.]sonarsource($|([.].*))" regex="true"/>
|
||||
<trusted-key id="D477D51812E692011DB11E66A6EA2E2BF22E0543" group="io.github.java-diff-utils"/>
|
||||
<trusted-key id="D54A395B5CF3F86EB45F6E426B1B008864323B92" group="org.antlr"/>
|
||||
<trusted-key id="DBE61B6BA51DFCAEDED256477090AF43A5E10D0B" group="org.scala-lang.modules" name="scala-parser-combinators_2.13" version="1.1.2"/>
|
||||
<trusted-key id="DC98224C6421A7A5BB87F346ED2378CD09A08CDE" group="org.fusesource.jansi" name="jansi" version="2.4.0"/>
|
||||
<trusted-key id="EA313384CA0EBA950EA017E937890E298D9A2BFA">
|
||||
<trusting group="com.eed3si9n"/>
|
||||
<trusting group="^org[.]scala-sbt($|([.].*))" regex="true"/>
|
||||
</trusted-key>
|
||||
<trusted-key id="EE2CFEB6A2AECF44C781C5C3DCD5181297A43D24" group="com.swoval" name="file-tree-views" version="2.1.12"/>
|
||||
<trusted-key id="F3184BCD55F4D016E30D4C9BF42E87F9665015C9" group="org.jsoup" name="jsoup" version="1.17.2"/>
|
||||
<trusted-key id="F3D9FF1EE50634CC57D1E380C2952540150670BE" group="org.scala-lang.modules"/>
|
||||
<trusted-key id="FA7929F83AD44C4590F6CC6815C71C0A4E0B8EDD" group="net.java.dev.jna" name="jna" version="5.14.0"/>
|
||||
</trusted-keys>
|
||||
</configuration>
|
||||
<components>
|
||||
<component group="co.helmethair" name="scalatest-junit-runner" version="0.1.11">
|
||||
<artifact name="scalatest-junit-runner-0.1.11.jar">
|
||||
<sha256 value="d2528b296efc33c8aef2175ea7da9cb41252eddfe24b62a29b7ec7fbe5f664d7" origin="Generated by Gradle" reason="A key couldn't be downloaded"/>
|
||||
</artifact>
|
||||
<artifact name="scalatest-junit-runner-0.1.11.module">
|
||||
<sha256 value="673aedd69783976df2c0a15c55f6bf12870a3edf05b3e13921752fa81c02195b" origin="Generated by Gradle" reason="A key couldn't be downloaded"/>
|
||||
</artifact>
|
||||
</component>
|
||||
<component group="com.eed3si9n" name="shaded-scalajson_2.13" version="1.0.0-M4">
|
||||
<artifact name="shaded-scalajson_2.13-1.0.0-M4.jar">
|
||||
<sha256 value="7b6b6d85727bd8abab940b559de8e32aa5081add29f7531c855bb0761ae8de67" origin="Generated by Gradle" reason="A key couldn't be downloaded"/>
|
||||
</artifact>
|
||||
<artifact name="shaded-scalajson_2.13-1.0.0-M4.pom">
|
||||
<sha256 value="256d22f6d5634dc4be9358c6ab692d81e511d468c3e7836db2833a3ed88a84f8" origin="Generated by Gradle" reason="A key couldn't be downloaded"/>
|
||||
</artifact>
|
||||
</component>
|
||||
<component group="com.eed3si9n" name="sjson-new-core_2.13" version="0.9.0">
|
||||
<artifact name="sjson-new-core_2.13-0.9.0.pom">
|
||||
<sha256 value="185df6fb71d7d900e960277896adb790b36ba65d299ff29f27060ab3d65323ee" origin="Generated by Gradle" reason="A key couldn't be downloaded"/>
|
||||
</artifact>
|
||||
</component>
|
||||
<component group="com.google.errorprone" name="error_prone_annotations" version="2.41.0">
|
||||
<artifact name="error_prone_annotations-2.41.0.jar">
|
||||
<sha256 value="a56e782b5b50811ac204073a355a21d915a2107fce13ec711331ad036f660fcc" origin="Generated by Gradle" reason="A key couldn't be downloaded"/>
|
||||
</artifact>
|
||||
<artifact name="error_prone_annotations-2.41.0.pom">
|
||||
<sha256 value="a151df1e2e0b48618d8b06a180748a29b3abb39b1b2396f6a1c879a727488c6e" origin="Generated by Gradle" reason="A key couldn't be downloaded"/>
|
||||
</artifact>
|
||||
</component>
|
||||
<component group="com.google.errorprone" name="error_prone_parent" version="2.41.0">
|
||||
<artifact name="error_prone_parent-2.41.0.pom">
|
||||
<sha256 value="c538388d760a5c1c98dcf06f6ed3cfe5f11a651827db5cbd2ed8288c795cad42" origin="Generated by Gradle" reason="A key couldn't be downloaded"/>
|
||||
</artifact>
|
||||
</component>
|
||||
<component group="com.lmax" name="disruptor" version="3.4.2">
|
||||
<artifact name="disruptor-3.4.2.jar">
|
||||
<sha256 value="f412ecbb235c2460b45e63584109723dea8d94b819c78c9bfc38f50cba8546c0" origin="Generated by Gradle" reason="A key couldn't be downloaded"/>
|
||||
</artifact>
|
||||
<artifact name="disruptor-3.4.2.pom">
|
||||
<sha256 value="7311e5e261ca62f259b2d14e6d6f1ce375a64718731a730fd7cec0228d50f5da" origin="Generated by Gradle" reason="A key couldn't be downloaded"/>
|
||||
</artifact>
|
||||
</component>
|
||||
<component group="com.swoval" name="file-tree-views" version="2.1.12">
|
||||
<artifact name="file-tree-views-2.1.12.jar">
|
||||
<sha256 value="fd7373889b7a92cf3e97db36c920ba272aec158a9387b3259fca9f2dfaeda914" origin="Generated by Gradle" reason="A key couldn't be downloaded"/>
|
||||
</artifact>
|
||||
<artifact name="file-tree-views-2.1.12.pom">
|
||||
<sha256 value="edd270dc776d1d85dd300e415cff9e0609757d7afeb223a6b187bad5b0abe746" origin="Generated by Gradle" reason="A key couldn't be downloaded"/>
|
||||
</artifact>
|
||||
</component>
|
||||
<component group="commons-io" name="commons-io" version="2.6">
|
||||
<artifact name="commons-io-2.6.jar">
|
||||
<sha256 value="f877d304660ac2a142f3865badfc971dec7ed73c747c7f8d5d2f5139ca736513" origin="Generated by Gradle" reason="A key couldn't be downloaded"/>
|
||||
</artifact>
|
||||
<artifact name="commons-io-2.6.pom">
|
||||
<sha256 value="0c23863893a2291f5a7afdbd8d15923b3948afd87e563fa341cdcf6eae338a60" origin="Generated by Gradle" reason="A key couldn't be downloaded"/>
|
||||
</artifact>
|
||||
</component>
|
||||
<component group="io.github.hakky54" name="ayza" version="10.0.2">
|
||||
<artifact name="ayza-10.0.2.jar">
|
||||
<sha256 value="9aa06304993aff5677dba769c677e578364f5793cbaf1569b2b5f39b71119a7b" origin="Generated by Gradle" reason="A key couldn't be downloaded"/>
|
||||
</artifact>
|
||||
<artifact name="ayza-10.0.2.pom">
|
||||
<sha256 value="441136232173d5eb533feffc96daa0353f8f0cb695033ca9631ecc8e68ddd335" origin="Generated by Gradle" reason="A key couldn't be downloaded"/>
|
||||
</artifact>
|
||||
</component>
|
||||
<component group="io.github.hakky54" name="ayza-bom" version="10.0.2">
|
||||
<artifact name="ayza-bom-10.0.2.pom">
|
||||
<sha256 value="817c3e174101e3d843bae65a13130dad8e1b93396e1355b5ad676941045d8dd2" origin="Generated by Gradle" reason="A key couldn't be downloaded"/>
|
||||
</artifact>
|
||||
</component>
|
||||
<component group="io.github.hakky54" name="ayza-parent" version="10.0.2">
|
||||
<artifact name="ayza-parent-10.0.2.pom">
|
||||
<sha256 value="f021993e03a484a8bd1d06dc6c7f2a6007a92ac1102bd5ddac9be13059df1cdf" origin="Generated by Gradle" reason="A key couldn't be downloaded"/>
|
||||
</artifact>
|
||||
</component>
|
||||
<component group="io.github.hakky54" name="sude" version="2.0.2">
|
||||
<artifact name="sude-2.0.2.jar">
|
||||
<sha256 value="f88e3d031dbbd2fea1b98481df0646a25b8d63d92796d6f30f907d5187595b39" origin="Generated by Gradle" reason="A key couldn't be downloaded"/>
|
||||
</artifact>
|
||||
<artifact name="sude-2.0.2.pom">
|
||||
<sha256 value="c38a30206ea8b95811805348ecb79cb3d3517df835ba10c660d395ec76181441" origin="Generated by Gradle" reason="A key couldn't be downloaded"/>
|
||||
</artifact>
|
||||
</component>
|
||||
<component group="net.openhft" name="java-parent-pom" version="1.1.28">
|
||||
<artifact name="java-parent-pom-1.1.28.pom">
|
||||
<sha256 value="02199c347a9d2b9e6f5dbf8e13d4c34e8febfab90c9b81fba13a16e8208809bf" origin="Generated by Gradle" reason="A key couldn't be downloaded"/>
|
||||
</artifact>
|
||||
</component>
|
||||
<component group="net.openhft" name="root-parent-pom" version="1.2.12">
|
||||
<artifact name="root-parent-pom-1.2.12.pom">
|
||||
<sha256 value="31802b4c86422d91ac5337dad705113535ca986f7cd7bc239701b9f9df967ccf" origin="Generated by Gradle" reason="A key couldn't be downloaded"/>
|
||||
</artifact>
|
||||
</component>
|
||||
<component group="net.openhft" name="zero-allocation-hashing" version="0.16">
|
||||
<artifact name="zero-allocation-hashing-0.16.jar">
|
||||
<sha256 value="3bc39c640cc8314575de4ebcb1a0bca540516d3c60d49f8de7d638b09868553d" origin="Generated by Gradle" reason="A key couldn't be downloaded"/>
|
||||
</artifact>
|
||||
<artifact name="zero-allocation-hashing-0.16.pom">
|
||||
<sha256 value="0949496963193655f81afb9dba28743444dd2a23a6f4933638a6991cfd728fc6" origin="Generated by Gradle" reason="A key couldn't be downloaded"/>
|
||||
</artifact>
|
||||
</component>
|
||||
<component group="nl.big-o" name="liqp" version="0.8.2">
|
||||
<artifact name="liqp-0.8.2.jar">
|
||||
<sha256 value="a948c26558e31fb445b5f1a2561c4518136a5d74046e4ab12bfb6010f6b0cc5b" origin="Generated by Gradle" reason="A key couldn't be downloaded"/>
|
||||
</artifact>
|
||||
<artifact name="liqp-0.8.2.pom">
|
||||
<sha256 value="846da39098c20be8631523c62928e4dd2b4cf7686d428678aae50060eef009b8" origin="Generated by Gradle" reason="A key couldn't be downloaded"/>
|
||||
</artifact>
|
||||
</component>
|
||||
<component group="org.apache" name="apache" version="18">
|
||||
<artifact name="apache-18.pom">
|
||||
<pgp value="190D5A957FF22273E601F7A7C92C5FEC70161C62"/>
|
||||
</artifact>
|
||||
</component>
|
||||
<component group="org.apache" name="apache" version="23">
|
||||
<artifact name="apache-23.pom">
|
||||
<pgp value="FA77DCFEF2EE6EB2DEBEDD2C012579464D01C06A"/>
|
||||
</artifact>
|
||||
</component>
|
||||
<component group="org.apache" name="apache" version="35">
|
||||
<artifact name="apache-35.pom">
|
||||
<sha256 value="ea297dcd114136e8b8e8b630230d52a76c2fc69f6c5db25d672b1857000728b8" origin="Generated by Gradle"/>
|
||||
</artifact>
|
||||
</component>
|
||||
<component group="org.apache.commons" name="commons-parent" version="42">
|
||||
<artifact name="commons-parent-42.pom">
|
||||
<pgp value="CE8075A251547BEE249BC151A2115AE15F6B8B72"/>
|
||||
</artifact>
|
||||
</component>
|
||||
<component group="org.apache.commons" name="commons-parent" version="85">
|
||||
<artifact name="commons-parent-85.pom">
|
||||
<sha256 value="d189ff2c0027e96bb65d31e6f227ed2af966169b36af1e973dd5ba08926dc7b5" origin="Generated by Gradle"/>
|
||||
</artifact>
|
||||
</component>
|
||||
<component group="org.apiguardian" name="apiguardian-api" version="1.1.2">
|
||||
<artifact name="apiguardian-api-1.1.2.jar">
|
||||
<sha256 value="b509448ac506d607319f182537f0b35d71007582ec741832a1f111e5b5b70b38" origin="Generated by Gradle" reason="A key couldn't be downloaded"/>
|
||||
</artifact>
|
||||
<artifact name="apiguardian-api-1.1.2.module">
|
||||
<sha256 value="e08028131375b357d1d28734e9a4fb4216da84b240641cb3ef7e7c7d628223fc" origin="Generated by Gradle" reason="A key couldn't be downloaded"/>
|
||||
</artifact>
|
||||
</component>
|
||||
<component group="org.bouncycastle" name="bcprov-jdk18on" version="1.83">
|
||||
<artifact name="bcprov-jdk18on-1.83.jar">
|
||||
<sha256 value="82cf3a2af766c3bc874f6d36b9f20a8b99a8f09762dc776e8a227a45d8daaafb" origin="Generated by Gradle" reason="A key couldn't be downloaded"/>
|
||||
</artifact>
|
||||
<artifact name="bcprov-jdk18on-1.83.pom">
|
||||
<sha256 value="c87cf06f5aac4656380f1d441b2459fbe066ec812b29469bd0b3fcb8bb20574a" origin="Generated by Gradle" reason="A key couldn't be downloaded"/>
|
||||
</artifact>
|
||||
</component>
|
||||
<component group="org.fusesource" name="fusesource-pom" version="1.12">
|
||||
<artifact name="fusesource-pom-1.12.pom">
|
||||
<sha256 value="c40d960daadcef7b01c1b1c6657afbac4fffb5e53168f8fcb0b28b84e6fdcca1" origin="Generated by Gradle" reason="Artifact is not signed"/>
|
||||
</artifact>
|
||||
</component>
|
||||
<component group="org.fusesource.jansi" name="jansi" version="2.4.0">
|
||||
<artifact name="jansi-2.4.0.jar">
|
||||
<sha256 value="6cd91991323dd7b2fb28ca93d7ac12af5a86a2f53279e2b35827b30313fd0b9f" origin="Generated by Gradle" reason="A key couldn't be downloaded"/>
|
||||
</artifact>
|
||||
<artifact name="jansi-2.4.0.pom">
|
||||
<sha256 value="ac40a9f2d0c1ee631fc3b08ef8e2f0bd14ba22011ca76ff1bcf65fb569eadf35" origin="Generated by Gradle" reason="A key couldn't be downloaded"/>
|
||||
</artifact>
|
||||
</component>
|
||||
<component group="org.jetbrains" name="annotations" version="15.0">
|
||||
<artifact name="annotations-15.0.jar">
|
||||
<sha256 value="d74599cef2b363fdb3cdd3198515aca090e3ea3e98b2ba473c6e46f114dab272" origin="Generated by Gradle" reason="A key couldn't be downloaded"/>
|
||||
</artifact>
|
||||
<artifact name="annotations-15.0.pom">
|
||||
<sha256 value="6726678ac07b481b5e35d3aeefce526b95fd18ede33d0d85cb1c688bcdf0e840" origin="Generated by Gradle" reason="A key couldn't be downloaded"/>
|
||||
</artifact>
|
||||
</component>
|
||||
<component group="org.jsoup" name="jsoup" version="1.17.2">
|
||||
<artifact name="jsoup-1.17.2.jar">
|
||||
<sha256 value="f60b33b38e9d7ac93eaaa68a6c70f706bb99036494b2e2add2bfee11d09ac6f5" origin="Generated by Gradle" reason="A key couldn't be downloaded"/>
|
||||
</artifact>
|
||||
<artifact name="jsoup-1.17.2.pom">
|
||||
<sha256 value="7a349d217790c3730be308ced1ea9ee32c4e74f72058e83c2b60e5a28954dd0d" origin="Generated by Gradle" reason="A key couldn't be downloaded"/>
|
||||
</artifact>
|
||||
</component>
|
||||
<component group="org.junit" name="junit-bom" version="5.13.1">
|
||||
<artifact name="junit-bom-5.13.1.module">
|
||||
<sha256 value="33c07ab9724790a6e5859ba07d69117ac530439724545a81c4179e3272c75de8" origin="Generated by Gradle" reason="A key couldn't be downloaded"/>
|
||||
</artifact>
|
||||
<artifact name="junit-bom-5.13.1.pom">
|
||||
<sha256 value="fa68451ea830572ed43ffe51d75b6a05f7a5e665a602a51f49d6be02063a65f3" origin="Generated by Gradle"/>
|
||||
</artifact>
|
||||
</component>
|
||||
<component group="org.junit" name="junit-bom" version="5.13.4">
|
||||
<artifact name="junit-bom-5.13.4.module">
|
||||
<sha256 value="e959288fde1b1b050d9bc082fc786789128da5d2853091468fca504104bdf400" origin="Generated by Gradle" reason="A key couldn't be downloaded"/>
|
||||
</artifact>
|
||||
<artifact name="junit-bom-5.13.4.pom">
|
||||
<sha256 value="d7a08a99b2502f0bb68cd4e1f984f0bf69324aaa208bd0f73366c03fc3548a42" origin="Generated by Gradle" reason="A key couldn't be downloaded"/>
|
||||
</artifact>
|
||||
</component>
|
||||
<component group="org.junit" name="junit-bom" version="5.14.1">
|
||||
<artifact name="junit-bom-5.14.1.module">
|
||||
<sha256 value="278acb11ccc9998694224386f96fb4941a22edb42cb446c92e0f1f33014b6b48" origin="Generated by Gradle" reason="A key couldn't be downloaded"/>
|
||||
</artifact>
|
||||
<artifact name="junit-bom-5.14.1.pom">
|
||||
<sha256 value="01b01dfa366550b40ac5760548a7d728b6109d17c451e83864d1e5e0ce862c94" origin="Generated by Gradle" reason="A key couldn't be downloaded"/>
|
||||
</artifact>
|
||||
</component>
|
||||
<component group="org.junit.jupiter" name="junit-jupiter" version="5.13.4">
|
||||
<artifact name="junit-jupiter-5.13.4.jar">
|
||||
<sha256 value="b960f79217dd01c863031b678f07df4730bbf1eac650c74ad6b0c61faad78379" origin="Generated by Gradle" reason="A key couldn't be downloaded"/>
|
||||
</artifact>
|
||||
<artifact name="junit-jupiter-5.13.4.module">
|
||||
<sha256 value="46946227c2967d1659e955f53d34ec8731811d4af401c2ac7d646f793c78e1f9" origin="Generated by Gradle" reason="A key couldn't be downloaded"/>
|
||||
</artifact>
|
||||
</component>
|
||||
<component group="org.junit.jupiter" name="junit-jupiter-api" version="5.13.4">
|
||||
<artifact name="junit-jupiter-api-5.13.4.jar">
|
||||
<sha256 value="d1bb81abfd9e03418306b4e6a3390c8db52c58372e749c2980ac29f0c08278f1" origin="Generated by Gradle" reason="A key couldn't be downloaded"/>
|
||||
</artifact>
|
||||
<artifact name="junit-jupiter-api-5.13.4.module">
|
||||
<sha256 value="fe464d37f5c810a805ff319198165cac33c2558e2261021d8f312a825a48671f" origin="Generated by Gradle" reason="A key couldn't be downloaded"/>
|
||||
</artifact>
|
||||
</component>
|
||||
<component group="org.junit.jupiter" name="junit-jupiter-engine" version="5.13.4">
|
||||
<artifact name="junit-jupiter-engine-5.13.4.jar">
|
||||
<sha256 value="027404a92fe618b72465792a257951495c503a7d5751e2791e0f51c87f67f5bc" origin="Generated by Gradle" reason="A key couldn't be downloaded"/>
|
||||
</artifact>
|
||||
<artifact name="junit-jupiter-engine-5.13.4.module">
|
||||
<sha256 value="ceeee6d0034a738135bd9f3820cfe089c6569163c623ba8e3e9b44f7208fd21a" origin="Generated by Gradle" reason="A key couldn't be downloaded"/>
|
||||
</artifact>
|
||||
</component>
|
||||
<component group="org.junit.jupiter" name="junit-jupiter-params" version="5.13.4">
|
||||
<artifact name="junit-jupiter-params-5.13.4.jar">
|
||||
<sha256 value="3a8c6365716dbb698c0d49a05456c1e1ad05c406613c550f9dd50037872efc41" origin="Generated by Gradle" reason="A key couldn't be downloaded"/>
|
||||
</artifact>
|
||||
<artifact name="junit-jupiter-params-5.13.4.module">
|
||||
<sha256 value="fc366fbe607999afc8cf02b9dca95d1e02a06b0ce872a45605a9d968c246f4b4" origin="Generated by Gradle" reason="A key couldn't be downloaded"/>
|
||||
</artifact>
|
||||
</component>
|
||||
<component group="org.junit.platform" name="junit-platform-commons" version="1.13.4">
|
||||
<artifact name="junit-platform-commons-1.13.4.jar">
|
||||
<sha256 value="1c25ca641ebaae44ff3ad21ca1b2ef68d0dd84bfeb07c4805ba7840899b77408" origin="Generated by Gradle" reason="A key couldn't be downloaded"/>
|
||||
</artifact>
|
||||
<artifact name="junit-platform-commons-1.13.4.module">
|
||||
<sha256 value="1a7a2de7c798995fb97b244d6ef9e99c3a5799b57a0fbacd68496ba7ee8159d7" origin="Generated by Gradle" reason="A key couldn't be downloaded"/>
|
||||
</artifact>
|
||||
</component>
|
||||
<component group="org.junit.platform" name="junit-platform-engine" version="1.13.4">
|
||||
<artifact name="junit-platform-engine-1.13.4.jar">
|
||||
<sha256 value="390c5f77b84283a64b644f88251b397e0b0debb80bdcc50f899881aecff43a5a" origin="Generated by Gradle" reason="A key couldn't be downloaded"/>
|
||||
</artifact>
|
||||
<artifact name="junit-platform-engine-1.13.4.module">
|
||||
<sha256 value="35e4fd68ebf314e62660148936436b39ae105d355beaac1aa54eb91c2066ca77" origin="Generated by Gradle" reason="A key couldn't be downloaded"/>
|
||||
</artifact>
|
||||
</component>
|
||||
<component group="org.junit.platform" name="junit-platform-launcher" version="1.13.4">
|
||||
<artifact name="junit-platform-launcher-1.13.4.jar">
|
||||
<sha256 value="0b0beaeb6880a31149641d2d848b863712885469670c12099586d7f798522564" origin="Generated by Gradle" reason="A key couldn't be downloaded"/>
|
||||
</artifact>
|
||||
<artifact name="junit-platform-launcher-1.13.4.module">
|
||||
<sha256 value="115f77455740e0c3c5398bcdd841c8aa699c2d8002b1100f2ae7a643d9405928" origin="Generated by Gradle" reason="A key couldn't be downloaded"/>
|
||||
</artifact>
|
||||
</component>
|
||||
<component group="org.nibor.autolink" name="autolink" version="0.6.0">
|
||||
<artifact name="autolink-0.6.0.jar">
|
||||
<sha256 value="a80be030f6386f18111cad9161c0b6983157352a1b59a59e6002172f0d321c04" origin="Generated by Gradle" reason="A key couldn't be downloaded"/>
|
||||
</artifact>
|
||||
<artifact name="autolink-0.6.0.pom">
|
||||
<sha256 value="916755647a34ccb367e11834d28380198c834adfcf660e0d983e375b8f5c28f2" origin="Generated by Gradle" reason="A key couldn't be downloaded"/>
|
||||
</artifact>
|
||||
</component>
|
||||
<component group="org.opentest4j" name="opentest4j" version="1.3.0">
|
||||
<artifact name="opentest4j-1.3.0.jar">
|
||||
<sha256 value="48e2df636cab6563ced64dcdff8abb2355627cb236ef0bf37598682ddf742f1b" origin="Generated by Gradle" reason="A key couldn't be downloaded"/>
|
||||
</artifact>
|
||||
<artifact name="opentest4j-1.3.0.module">
|
||||
<sha256 value="48bf1d6c8b5dc94f74652bd17900f654deb714350248cf5e8fca27b9090c8e0d" origin="Generated by Gradle" reason="A key couldn't be downloaded"/>
|
||||
</artifact>
|
||||
</component>
|
||||
<component group="org.scala-lang" name="scala-compiler" version="2.13.15">
|
||||
<artifact name="scala-compiler-2.13.15.jar">
|
||||
<sha256 value="4c200cd193c082bec14a2a2dffe6a1ba5f8130b1b27c79ee54c936dfcafc8ed9" origin="Generated by Gradle" reason="A key couldn't be downloaded"/>
|
||||
</artifact>
|
||||
<artifact name="scala-compiler-2.13.15.pom">
|
||||
<sha256 value="6ae13081e950a55545e53e7e6f9bf6754ed0ec17af331772ae8fae4fb406f697" origin="Generated by Gradle" reason="A key couldn't be downloaded"/>
|
||||
</artifact>
|
||||
</component>
|
||||
<component group="org.scala-lang" name="scala-library" version="2.13.14">
|
||||
<artifact name="scala-library-2.13.14.jar">
|
||||
<sha256 value="43e0ca1583df1966eaf02f0fbddcfb3784b995dd06bfc907209347758ce4b7e3" origin="Generated by Gradle" reason="A key couldn't be downloaded"/>
|
||||
</artifact>
|
||||
<artifact name="scala-library-2.13.14.pom">
|
||||
<sha256 value="cee86c6df5653aaf55403666902fcbb0aaaf400eb2cffb27f09ca5d75ec703bc" origin="Generated by Gradle" reason="A key couldn't be downloaded"/>
|
||||
</artifact>
|
||||
</component>
|
||||
<component group="org.scala-lang" name="scala-library" version="2.13.15">
|
||||
<artifact name="scala-library-2.13.15.jar">
|
||||
<sha256 value="8e4dbc3becf70d59c787118f6ad06fab6790136a0699cd6412bc9da3d336944e" origin="Generated by Gradle" reason="A key couldn't be downloaded"/>
|
||||
</artifact>
|
||||
<artifact name="scala-library-2.13.15.pom">
|
||||
<sha256 value="f81d6f32917a0e931daa6559a8500be1c62ff8c6c82db071dcdbebf60bbd4786" origin="Generated by Gradle" reason="A key couldn't be downloaded"/>
|
||||
</artifact>
|
||||
</component>
|
||||
<component group="org.scala-lang" name="scala-library" version="2.13.16">
|
||||
<artifact name="scala-library-2.13.16.jar">
|
||||
<sha256 value="1ebb2b6f9e4eb4022497c19b1e1e825019c08514f962aaac197145f88ed730f1" origin="Generated by Gradle" reason="A key couldn't be downloaded"/>
|
||||
</artifact>
|
||||
<artifact name="scala-library-2.13.16.pom">
|
||||
<sha256 value="b25b72ba96eb30934868d86d307298d24d3ac154d362e7a4eeb37ba51ba86853" origin="Generated by Gradle" reason="A key couldn't be downloaded"/>
|
||||
</artifact>
|
||||
</component>
|
||||
<component group="org.scala-lang" name="scala-reflect" version="2.13.15">
|
||||
<artifact name="scala-reflect-2.13.15.jar">
|
||||
<sha256 value="78d0cc350e1ee42d87c6e11cf5b0dc7bf0b70829c00aa38f27bfb019d439dc11" origin="Generated by Gradle" reason="A key couldn't be downloaded"/>
|
||||
</artifact>
|
||||
<artifact name="scala-reflect-2.13.15.pom">
|
||||
<sha256 value="aa9cac59324824e5e73dc3456fd3c3ab5f504df63d2f1ddb6413783abb1cecd6" origin="Generated by Gradle" reason="A key couldn't be downloaded"/>
|
||||
</artifact>
|
||||
</component>
|
||||
<component group="org.scala-lang.modules" name="scala-asm" version="9.6.0-scala-1">
|
||||
<artifact name="scala-asm-9.6.0-scala-1.jar">
|
||||
<sha256 value="bf16f8b69e89cadab550bce266a052780af7f1eb29dd1c04c3bd014113752c12" origin="Generated by Gradle" reason="A key couldn't be downloaded"/>
|
||||
</artifact>
|
||||
<artifact name="scala-asm-9.6.0-scala-1.pom">
|
||||
<sha256 value="48bb35622e019293c52c850a528e7bf1c1ba798562ed7829a0b30b37fd38251d" origin="Generated by Gradle" reason="A key couldn't be downloaded"/>
|
||||
</artifact>
|
||||
</component>
|
||||
<component group="org.scala-lang.modules" name="scala-parser-combinators_2.13" version="1.1.2">
|
||||
<artifact name="scala-parser-combinators_2.13-1.1.2.jar">
|
||||
<sha256 value="5c285b72e6dc0a98e99ae0a1ceeb4027dab9adfa441844046bd3f19e0efdcb54" origin="Generated by Gradle" reason="A key couldn't be downloaded"/>
|
||||
</artifact>
|
||||
<artifact name="scala-parser-combinators_2.13-1.1.2.pom">
|
||||
<sha256 value="5c856fefc046a88de0118ac5e45cddf638975fa980c007d242633276f7266f02" origin="Generated by Gradle" reason="A key couldn't be downloaded"/>
|
||||
</artifact>
|
||||
</component>
|
||||
<component group="org.scala-lang.modules" name="scala-xml_2.13" version="2.3.0">
|
||||
<artifact name="scala-xml_2.13-2.3.0.jar">
|
||||
<sha256 value="4b4d6698c74bff84a105102bbf58390980dc7bb8c40bdea4bc727040b3f966bd" origin="Generated by Gradle" reason="A key couldn't be downloaded"/>
|
||||
</artifact>
|
||||
<artifact name="scala-xml_2.13-2.3.0.pom">
|
||||
<sha256 value="9e52b1e093853e146b0b75605af98543219193cad4ea50d07b94465f4afa815c" origin="Generated by Gradle" reason="A key couldn't be downloaded"/>
|
||||
</artifact>
|
||||
</component>
|
||||
<component group="org.scala-lang.modules" name="scala-xml_3" version="2.3.0">
|
||||
<artifact name="scala-xml_3-2.3.0.jar">
|
||||
<sha256 value="3220723238102107ab83182468e5dbe351b081a0601386710ef46c81a95d38d0" origin="Generated by Gradle" reason="A key couldn't be downloaded"/>
|
||||
</artifact>
|
||||
<artifact name="scala-xml_3-2.3.0.pom">
|
||||
<sha256 value="b83f69d158032e9a83781a0c0a0f99fa8b929411f7198703734a1213c37f095f" origin="Generated by Gradle" reason="A key couldn't be downloaded"/>
|
||||
</artifact>
|
||||
</component>
|
||||
<component group="org.scalactic" name="scalactic_3" version="3.2.19">
|
||||
<artifact name="scalactic_3-3.2.19.jar">
|
||||
<sha256 value="26ef71a6d0993301d28d9693bada18ff81b373336b70368fcff01ed4eb4b958e" origin="Generated by Gradle" reason="A key couldn't be downloaded"/>
|
||||
</artifact>
|
||||
<artifact name="scalactic_3-3.2.19.pom">
|
||||
<sha256 value="af2e7bff0e0e7dfbb175b9f109917307d4cde9c56bed23893cfbe6a336780024" origin="Generated by Gradle" reason="A key couldn't be downloaded"/>
|
||||
</artifact>
|
||||
</component>
|
||||
<component group="org.scalatest" name="scalatest-compatible" version="3.2.19">
|
||||
<artifact name="scalatest-compatible-3.2.19.jar">
|
||||
<sha256 value="5dc6b8fa5396fe9e1a7c2b72df174a8eb3e92770cdc3e70636d3eba673cd0da3" origin="Generated by Gradle" reason="A key couldn't be downloaded"/>
|
||||
</artifact>
|
||||
<artifact name="scalatest-compatible-3.2.19.pom">
|
||||
<sha256 value="e7f309922cb6d072bd6098674e72e948c2738c0ac7470a63e20bd15614daa3c0" origin="Generated by Gradle" reason="A key couldn't be downloaded"/>
|
||||
</artifact>
|
||||
</component>
|
||||
<component group="org.scalatest" name="scalatest-core_3" version="3.2.19">
|
||||
<artifact name="scalatest-core_3-3.2.19.jar">
|
||||
<sha256 value="f6e3d38c2034a9cab7313f644d8a933bf1b5241ff35002cc76916a427a826223" origin="Generated by Gradle" reason="A key couldn't be downloaded"/>
|
||||
</artifact>
|
||||
<artifact name="scalatest-core_3-3.2.19.pom">
|
||||
<sha256 value="069655a6db966a255690c5d9048d4e799c17026055d60d76869e0103da9c1fdb" origin="Generated by Gradle" reason="A key couldn't be downloaded"/>
|
||||
</artifact>
|
||||
</component>
|
||||
<component group="org.scalatest" name="scalatest-diagrams_3" version="3.2.19">
|
||||
<artifact name="scalatest-diagrams_3-3.2.19.jar">
|
||||
<sha256 value="835acf8ec2cb0d39beb1052ee2139029fdac28d172fc867db89ff49d640b255e" origin="Generated by Gradle" reason="A key couldn't be downloaded"/>
|
||||
</artifact>
|
||||
<artifact name="scalatest-diagrams_3-3.2.19.pom">
|
||||
<sha256 value="cbc5724b8607cbc9d3852c5bde9c09c9d29e86ac3a5c396bf112c757cdf048f2" origin="Generated by Gradle" reason="A key couldn't be downloaded"/>
|
||||
</artifact>
|
||||
</component>
|
||||
<component group="org.scalatest" name="scalatest-featurespec_3" version="3.2.19">
|
||||
<artifact name="scalatest-featurespec_3-3.2.19.jar">
|
||||
<sha256 value="3d49deeede2cd01578e037065862d7734afd3a6330c35dc3c4906f53f57302db" origin="Generated by Gradle" reason="A key couldn't be downloaded"/>
|
||||
</artifact>
|
||||
<artifact name="scalatest-featurespec_3-3.2.19.pom">
|
||||
<sha256 value="589b5d533e9080491301c175e510422e98de22c6f92364a4c0dc598a0664ed83" origin="Generated by Gradle" reason="A key couldn't be downloaded"/>
|
||||
</artifact>
|
||||
</component>
|
||||
<component group="org.scalatest" name="scalatest-flatspec_3" version="3.2.19">
|
||||
<artifact name="scalatest-flatspec_3-3.2.19.jar">
|
||||
<sha256 value="85a6fb2285f20445615c6780a498c3bca99e4c2aad32fab6f74202bdc61e56a9" origin="Generated by Gradle" reason="A key couldn't be downloaded"/>
|
||||
</artifact>
|
||||
<artifact name="scalatest-flatspec_3-3.2.19.pom">
|
||||
<sha256 value="d5bcba3b01fdb316c9608a397b8af6f60fd4ffe83ee73479ef9b7acc4cf5a770" origin="Generated by Gradle" reason="A key couldn't be downloaded"/>
|
||||
</artifact>
|
||||
</component>
|
||||
<component group="org.scalatest" name="scalatest-freespec_3" version="3.2.19">
|
||||
<artifact name="scalatest-freespec_3-3.2.19.jar">
|
||||
<sha256 value="ebc8573874766368316366495dcdfe0cca6d8082dc9cc08b5a2fd0834cdaecc0" origin="Generated by Gradle" reason="A key couldn't be downloaded"/>
|
||||
</artifact>
|
||||
<artifact name="scalatest-freespec_3-3.2.19.pom">
|
||||
<sha256 value="0b64ca3b958c2cc35eff6a082b4654e87b6b20aaf47afd2377c2d830da8d857b" origin="Generated by Gradle" reason="A key couldn't be downloaded"/>
|
||||
</artifact>
|
||||
</component>
|
||||
<component group="org.scalatest" name="scalatest-funspec_3" version="3.2.19">
|
||||
<artifact name="scalatest-funspec_3-3.2.19.jar">
|
||||
<sha256 value="872b6889fac777aa813d21fb5f1e89710407785a61eb18a570142b6be10389a7" origin="Generated by Gradle" reason="A key couldn't be downloaded"/>
|
||||
</artifact>
|
||||
<artifact name="scalatest-funspec_3-3.2.19.pom">
|
||||
<sha256 value="25bafeabb74f734eb36ddee6f178c631a65346019d41285844d9ef2895ee2bc1" origin="Generated by Gradle" reason="A key couldn't be downloaded"/>
|
||||
</artifact>
|
||||
</component>
|
||||
<component group="org.scalatest" name="scalatest-funsuite_3" version="3.2.19">
|
||||
<artifact name="scalatest-funsuite_3-3.2.19.jar">
|
||||
<sha256 value="42129cc156bd8978d9a438abd57001fc42ababf18f6178cbee91d0a9489334e0" origin="Generated by Gradle" reason="A key couldn't be downloaded"/>
|
||||
</artifact>
|
||||
<artifact name="scalatest-funsuite_3-3.2.19.pom">
|
||||
<sha256 value="4045d7402436a35bb87baf447427598892f77280a356c5b670352426e4293478" origin="Generated by Gradle" reason="A key couldn't be downloaded"/>
|
||||
</artifact>
|
||||
</component>
|
||||
<component group="org.scalatest" name="scalatest-matchers-core_3" version="3.2.19">
|
||||
<artifact name="scalatest-matchers-core_3-3.2.19.jar">
|
||||
<sha256 value="723fecdf0ea4542947ef5174068c4e05cd2145a3dcb6ffc797079368c94a187e" origin="Generated by Gradle" reason="A key couldn't be downloaded"/>
|
||||
</artifact>
|
||||
<artifact name="scalatest-matchers-core_3-3.2.19.pom">
|
||||
<sha256 value="8b1f6a246ff1914f44550f3f98a95293a06b1d3cf9e505f7be1a8fe901620016" origin="Generated by Gradle" reason="A key couldn't be downloaded"/>
|
||||
</artifact>
|
||||
</component>
|
||||
<component group="org.scalatest" name="scalatest-mustmatchers_3" version="3.2.19">
|
||||
<artifact name="scalatest-mustmatchers_3-3.2.19.jar">
|
||||
<sha256 value="837f76b73ff299fb6748ba0aff4eb7c9d9c00252741ad2bc15af3998d2e0558c" origin="Generated by Gradle" reason="A key couldn't be downloaded"/>
|
||||
</artifact>
|
||||
<artifact name="scalatest-mustmatchers_3-3.2.19.pom">
|
||||
<sha256 value="16bff93b9c86d1c43ab945c111167081e80c1968ca541e670b33f2cfe6b35b9e" origin="Generated by Gradle" reason="A key couldn't be downloaded"/>
|
||||
</artifact>
|
||||
</component>
|
||||
<component group="org.scalatest" name="scalatest-propspec_3" version="3.2.19">
|
||||
<artifact name="scalatest-propspec_3-3.2.19.jar">
|
||||
<sha256 value="6b033e73f3a53717a32a0d4d35ae2021a0afe8a028c42da62fb937932934bce3" origin="Generated by Gradle" reason="A key couldn't be downloaded"/>
|
||||
</artifact>
|
||||
<artifact name="scalatest-propspec_3-3.2.19.pom">
|
||||
<sha256 value="fc65de4813534fa43a6de25dc09e76eb51dcc4b507c3fda79242c1851dc2d326" origin="Generated by Gradle" reason="A key couldn't be downloaded"/>
|
||||
</artifact>
|
||||
</component>
|
||||
<component group="org.scalatest" name="scalatest-refspec_3" version="3.2.19">
|
||||
<artifact name="scalatest-refspec_3-3.2.19.jar">
|
||||
<sha256 value="827b78a65c25a1dc4af747a7711e24c785fae92c39600fd357a7d486fcce2e7a" origin="Generated by Gradle" reason="A key couldn't be downloaded"/>
|
||||
</artifact>
|
||||
<artifact name="scalatest-refspec_3-3.2.19.pom">
|
||||
<sha256 value="16b9e907ccff48dc7d331bad1a6239dbcb89babdb5c969f99c322a5f7923073a" origin="Generated by Gradle" reason="A key couldn't be downloaded"/>
|
||||
</artifact>
|
||||
</component>
|
||||
<component group="org.scalatest" name="scalatest-shouldmatchers_3" version="3.2.19">
|
||||
<artifact name="scalatest-shouldmatchers_3-3.2.19.jar">
|
||||
<sha256 value="76ddce37f710ea96bdb3eebcb4bb0a0125fc70fb2ebaa7cc74c9bd28284b6a23" origin="Generated by Gradle" reason="A key couldn't be downloaded"/>
|
||||
</artifact>
|
||||
<artifact name="scalatest-shouldmatchers_3-3.2.19.pom">
|
||||
<sha256 value="826ebb218593a34770e1c77834cfe0bb6315fabc8b32406c8d6dbb8b26a05a75" origin="Generated by Gradle" reason="A key couldn't be downloaded"/>
|
||||
</artifact>
|
||||
</component>
|
||||
<component group="org.scalatest" name="scalatest-wordspec_3" version="3.2.19">
|
||||
<artifact name="scalatest-wordspec_3-3.2.19.jar">
|
||||
<sha256 value="c6acce0958b086cb857c4da6107f903b6166a46dfa251f54d3a0869212e229c7" origin="Generated by Gradle" reason="A key couldn't be downloaded"/>
|
||||
</artifact>
|
||||
<artifact name="scalatest-wordspec_3-3.2.19.pom">
|
||||
<sha256 value="aec178b094f2176c1ad340be467184176065a3ba04cde4c187947cf750f643de" origin="Generated by Gradle" reason="A key couldn't be downloaded"/>
|
||||
</artifact>
|
||||
</component>
|
||||
<component group="org.scalatest" name="scalatest_3" version="3.2.19">
|
||||
<artifact name="scalatest_3-3.2.19.jar">
|
||||
<sha256 value="cd886ba42615fe0d730dd57197e6ee53eeb062cfd0b4d8c5d9757c977c0fdcf8" origin="Generated by Gradle" reason="A key couldn't be downloaded"/>
|
||||
</artifact>
|
||||
<artifact name="scalatest_3-3.2.19.pom">
|
||||
<sha256 value="b26fcbf4ff2cdbda2654d3da86e7ad7e6fde16ccc46a81ec40247e068ae9326f" origin="Generated by Gradle" reason="A key couldn't be downloaded"/>
|
||||
</artifact>
|
||||
</component>
|
||||
<component group="org.scoverage" name="org.scoverage.gradle.plugin" version="8.1">
|
||||
<artifact name="org.scoverage.gradle.plugin-8.1.pom">
|
||||
<sha256 value="099b26b0039c24fd4026aabcf0c191fc160bb7881d9e988b7ab480d0d16f85c5" origin="Generated by Gradle" reason="Artifact is not signed"/>
|
||||
</artifact>
|
||||
</component>
|
||||
<component group="org.sonarqube" name="org.sonarqube.gradle.plugin" version="7.2.3.7755">
|
||||
<artifact name="org.sonarqube.gradle.plugin-7.2.3.7755.pom">
|
||||
<sha256 value="7b9a2bfb6b7929f789dd2c729569ba7cba5fc8572bd8e9a72c64279da299f0e8" origin="Generated by Gradle" reason="Artifact is not signed"/>
|
||||
</artifact>
|
||||
</component>
|
||||
<component group="org.sonatype.oss" name="oss-parent" version="9">
|
||||
<artifact name="oss-parent-9.pom">
|
||||
<pgp value="44FBDBBC1A00FE414F1C1873586654072EAD6677"/>
|
||||
</artifact>
|
||||
</component>
|
||||
<component group="ua.co.k" name="strftime4j" version="1.0.5">
|
||||
<artifact name="strftime4j-1.0.5.jar">
|
||||
<sha256 value="8ee3be181a1d3871d2b14e1e145cbc48918abbbf3596268fdd4b3d7292b07fc9" origin="Generated by Gradle" reason="A key couldn't be downloaded"/>
|
||||
</artifact>
|
||||
<artifact name="strftime4j-1.0.5.pom">
|
||||
<sha256 value="df50d06823a4f87c3fd739ebd1718f09bc126bb8206dfde8c477b3a816edf500" origin="Generated by Gradle" reason="A key couldn't be downloaded"/>
|
||||
</artifact>
|
||||
</component>
|
||||
</components>
|
||||
</verification-metadata>
|
||||
@@ -0,0 +1,396 @@
|
||||
{
|
||||
"nodes": [
|
||||
{
|
||||
"id": "claude_md_project_instructions",
|
||||
"label": "Now-Chess Project Instructions (CLAUDE.md)",
|
||||
"file_type": "document",
|
||||
"source_file": "CLAUDE.md",
|
||||
"source_location": null,
|
||||
"source_url": null,
|
||||
"captured_at": null,
|
||||
"author": null,
|
||||
"contributor": null
|
||||
},
|
||||
{
|
||||
"id": "agents_md_config",
|
||||
"label": "Agents Configuration (AGENTS.md)",
|
||||
"file_type": "document",
|
||||
"source_file": "AGENTS.md",
|
||||
"source_location": null,
|
||||
"source_url": null,
|
||||
"captured_at": null,
|
||||
"author": null,
|
||||
"contributor": null
|
||||
},
|
||||
{
|
||||
"id": "api_changelog",
|
||||
"label": "API Module Changelog",
|
||||
"file_type": "document",
|
||||
"source_file": "modules/api/CHANGELOG.md",
|
||||
"source_location": null,
|
||||
"source_url": null,
|
||||
"captured_at": null,
|
||||
"author": null,
|
||||
"contributor": null
|
||||
},
|
||||
{
|
||||
"id": "ui_changelog",
|
||||
"label": "UI Module Changelog",
|
||||
"file_type": "document",
|
||||
"source_file": "modules/ui/CHANGELOG.md",
|
||||
"source_location": null,
|
||||
"source_url": null,
|
||||
"captured_at": null,
|
||||
"author": null,
|
||||
"contributor": null
|
||||
},
|
||||
{
|
||||
"id": "rule_changelog",
|
||||
"label": "Rule Module Changelog",
|
||||
"file_type": "document",
|
||||
"source_file": "modules/rule/CHANGELOG.md",
|
||||
"source_location": null,
|
||||
"source_url": null,
|
||||
"captured_at": null,
|
||||
"author": null,
|
||||
"contributor": null
|
||||
},
|
||||
{
|
||||
"id": "io_changelog",
|
||||
"label": "IO Module Changelog",
|
||||
"file_type": "document",
|
||||
"source_file": "modules/io/CHANGELOG.md",
|
||||
"source_location": null,
|
||||
"source_url": null,
|
||||
"captured_at": null,
|
||||
"author": null,
|
||||
"contributor": null
|
||||
},
|
||||
{
|
||||
"id": "core_changelog",
|
||||
"label": "Core Module Changelog",
|
||||
"file_type": "document",
|
||||
"source_file": "modules/core/CHANGELOG.md",
|
||||
"source_location": null,
|
||||
"source_url": null,
|
||||
"captured_at": null,
|
||||
"author": null,
|
||||
"contributor": null
|
||||
},
|
||||
{
|
||||
"id": "bot_python_readme",
|
||||
"label": "Bot Python Module README",
|
||||
"file_type": "document",
|
||||
"source_file": "modules/bot/python/README.md",
|
||||
"source_location": null,
|
||||
"source_url": null,
|
||||
"captured_at": null,
|
||||
"author": null,
|
||||
"contributor": null
|
||||
},
|
||||
{
|
||||
"id": "bot_python_requirements",
|
||||
"label": "Bot Python Requirements",
|
||||
"file_type": "document",
|
||||
"source_file": "modules/bot/python/requirements.txt",
|
||||
"source_location": null,
|
||||
"source_url": null,
|
||||
"captured_at": null,
|
||||
"author": null,
|
||||
"contributor": null
|
||||
},
|
||||
{
|
||||
"id": "bot_python_positions",
|
||||
"label": "Bot Python Positions Dataset",
|
||||
"file_type": "document",
|
||||
"source_file": "modules/bot/python/data/positions.txt",
|
||||
"source_location": null,
|
||||
"source_url": null,
|
||||
"captured_at": null,
|
||||
"author": null,
|
||||
"contributor": null
|
||||
},
|
||||
{
|
||||
"id": "security_doc",
|
||||
"label": "Security Documentation",
|
||||
"file_type": "document",
|
||||
"source_file": "docs/Security.md",
|
||||
"source_location": null,
|
||||
"source_url": null,
|
||||
"captured_at": null,
|
||||
"author": null,
|
||||
"contributor": null
|
||||
},
|
||||
{
|
||||
"id": "claude_skills_doc",
|
||||
"label": "Claude Skills Documentation",
|
||||
"file_type": "document",
|
||||
"source_file": "docs/Claude-Skills.md",
|
||||
"source_location": null,
|
||||
"source_url": null,
|
||||
"captured_at": null,
|
||||
"author": null,
|
||||
"contributor": null
|
||||
},
|
||||
{
|
||||
"id": "idea_doc",
|
||||
"label": "Idea Documentation",
|
||||
"file_type": "document",
|
||||
"source_file": "docs/idea.md",
|
||||
"source_location": null,
|
||||
"source_url": null,
|
||||
"captured_at": null,
|
||||
"author": null,
|
||||
"contributor": null
|
||||
},
|
||||
{
|
||||
"id": "arabian_chess_license",
|
||||
"label": "Arabian Chess License",
|
||||
"file_type": "document",
|
||||
"source_file": "ARABIAN CHESS/license.txt",
|
||||
"source_location": null,
|
||||
"source_url": null,
|
||||
"captured_at": null,
|
||||
"author": null,
|
||||
"contributor": null
|
||||
},
|
||||
{
|
||||
"id": "ui_board_sprite_black",
|
||||
"label": "UI Board Square Black Sprite",
|
||||
"file_type": "image",
|
||||
"source_file": "modules/ui/src/main/resources/sprites/board/board_square_black.png",
|
||||
"source_location": null,
|
||||
"source_url": null,
|
||||
"captured_at": null,
|
||||
"author": null,
|
||||
"contributor": null
|
||||
},
|
||||
{
|
||||
"id": "ui_board_sprite_white",
|
||||
"label": "UI Board Square White Sprite",
|
||||
"file_type": "image",
|
||||
"source_file": "modules/ui/src/main/resources/sprites/board/board_square_white.png",
|
||||
"source_location": null,
|
||||
"source_url": null,
|
||||
"captured_at": null,
|
||||
"author": null,
|
||||
"contributor": null
|
||||
},
|
||||
{
|
||||
"id": "ui_board_sprite_bottom",
|
||||
"label": "UI Board Bottom Sprite",
|
||||
"file_type": "image",
|
||||
"source_file": "modules/ui/src/main/resources/sprites/board/board_bottom.png",
|
||||
"source_location": null,
|
||||
"source_url": null,
|
||||
"captured_at": null,
|
||||
"author": null,
|
||||
"contributor": null
|
||||
},
|
||||
{
|
||||
"id": "ui_piece_sprite_black_rook",
|
||||
"label": "UI Black Rook Piece Sprite",
|
||||
"file_type": "image",
|
||||
"source_file": "modules/ui/src/main/resources/sprites/pieces/black_rook.png",
|
||||
"source_location": null,
|
||||
"source_url": null,
|
||||
"captured_at": null,
|
||||
"author": null,
|
||||
"contributor": null
|
||||
},
|
||||
{
|
||||
"id": "ui_piece_sprite_white_pawn",
|
||||
"label": "UI White Pawn Piece Sprite",
|
||||
"file_type": "image",
|
||||
"source_file": "modules/ui/src/main/resources/sprites/pieces/white_pawn.png",
|
||||
"source_location": null,
|
||||
"source_url": null,
|
||||
"captured_at": null,
|
||||
"author": null,
|
||||
"contributor": null
|
||||
},
|
||||
{
|
||||
"id": "ui_piece_sprite_white_knight",
|
||||
"label": "UI White Knight Piece Sprite",
|
||||
"file_type": "image",
|
||||
"source_file": "modules/ui/src/main/resources/sprites/pieces/white_knight.png",
|
||||
"source_location": null,
|
||||
"source_url": null,
|
||||
"captured_at": null,
|
||||
"author": null,
|
||||
"contributor": null
|
||||
},
|
||||
{
|
||||
"id": "ui_piece_sprite_black_knight",
|
||||
"label": "UI Black Knight Piece Sprite",
|
||||
"file_type": "image",
|
||||
"source_file": "modules/ui/src/main/resources/sprites/pieces/black_knight.png",
|
||||
"source_location": null,
|
||||
"source_url": null,
|
||||
"captured_at": null,
|
||||
"author": null,
|
||||
"contributor": null
|
||||
}
|
||||
],
|
||||
"edges": [
|
||||
{
|
||||
"source": "claude_md_project_instructions",
|
||||
"target": "agents_md_config",
|
||||
"relation": "references",
|
||||
"confidence": "EXTRACTED",
|
||||
"confidence_score": 1.0,
|
||||
"source_file": "CLAUDE.md",
|
||||
"source_location": null,
|
||||
"weight": 1.0
|
||||
},
|
||||
{
|
||||
"source": "bot_python_readme",
|
||||
"target": "bot_python_requirements",
|
||||
"relation": "references",
|
||||
"confidence": "INFERRED",
|
||||
"confidence_score": 0.85,
|
||||
"source_file": "modules/bot/python/README.md",
|
||||
"source_location": null,
|
||||
"weight": 1.0
|
||||
},
|
||||
{
|
||||
"source": "bot_python_readme",
|
||||
"target": "bot_python_positions",
|
||||
"relation": "references",
|
||||
"confidence": "INFERRED",
|
||||
"confidence_score": 0.8,
|
||||
"source_file": "modules/bot/python/README.md",
|
||||
"source_location": null,
|
||||
"weight": 1.0
|
||||
},
|
||||
{
|
||||
"source": "ui_changelog",
|
||||
"target": "ui_board_sprite_black",
|
||||
"relation": "references",
|
||||
"confidence": "INFERRED",
|
||||
"confidence_score": 0.75,
|
||||
"source_file": "modules/ui/CHANGELOG.md",
|
||||
"source_location": null,
|
||||
"weight": 1.0
|
||||
},
|
||||
{
|
||||
"source": "ui_changelog",
|
||||
"target": "ui_board_sprite_white",
|
||||
"relation": "references",
|
||||
"confidence": "INFERRED",
|
||||
"confidence_score": 0.75,
|
||||
"source_file": "modules/ui/CHANGELOG.md",
|
||||
"source_location": null,
|
||||
"weight": 1.0
|
||||
},
|
||||
{
|
||||
"source": "ui_changelog",
|
||||
"target": "ui_piece_sprite_black_rook",
|
||||
"relation": "references",
|
||||
"confidence": "INFERRED",
|
||||
"confidence_score": 0.75,
|
||||
"source_file": "modules/ui/CHANGELOG.md",
|
||||
"source_location": null,
|
||||
"weight": 1.0
|
||||
},
|
||||
{
|
||||
"source": "ui_changelog",
|
||||
"target": "ui_piece_sprite_white_pawn",
|
||||
"relation": "references",
|
||||
"confidence": "INFERRED",
|
||||
"confidence_score": 0.75,
|
||||
"source_file": "modules/ui/CHANGELOG.md",
|
||||
"source_location": null,
|
||||
"weight": 1.0
|
||||
},
|
||||
{
|
||||
"source": "ui_changelog",
|
||||
"target": "ui_piece_sprite_white_knight",
|
||||
"relation": "references",
|
||||
"confidence": "INFERRED",
|
||||
"confidence_score": 0.75,
|
||||
"source_file": "modules/ui/CHANGELOG.md",
|
||||
"source_location": null,
|
||||
"weight": 1.0
|
||||
},
|
||||
{
|
||||
"source": "ui_changelog",
|
||||
"target": "ui_piece_sprite_black_knight",
|
||||
"relation": "references",
|
||||
"confidence": "INFERRED",
|
||||
"confidence_score": 0.75,
|
||||
"source_file": "modules/ui/CHANGELOG.md",
|
||||
"source_location": null,
|
||||
"weight": 1.0
|
||||
},
|
||||
{
|
||||
"source": "ui_changelog",
|
||||
"target": "ui_board_sprite_bottom",
|
||||
"relation": "references",
|
||||
"confidence": "INFERRED",
|
||||
"confidence_score": 0.75,
|
||||
"source_file": "modules/ui/CHANGELOG.md",
|
||||
"source_location": null,
|
||||
"weight": 1.0
|
||||
},
|
||||
{
|
||||
"source": "claude_skills_doc",
|
||||
"target": "agents_md_config",
|
||||
"relation": "references",
|
||||
"confidence": "INFERRED",
|
||||
"confidence_score": 0.7,
|
||||
"source_file": "docs/Claude-Skills.md",
|
||||
"source_location": null,
|
||||
"weight": 1.0
|
||||
}
|
||||
],
|
||||
"hyperedges": [
|
||||
{
|
||||
"id": "module_changelogs",
|
||||
"label": "Module Changelog Documentation",
|
||||
"nodes": [
|
||||
"api_changelog",
|
||||
"ui_changelog",
|
||||
"rule_changelog",
|
||||
"io_changelog",
|
||||
"core_changelog"
|
||||
],
|
||||
"relation": "form",
|
||||
"confidence": "EXTRACTED",
|
||||
"confidence_score": 1.0,
|
||||
"source_file": "modules"
|
||||
},
|
||||
{
|
||||
"id": "ui_sprite_assets",
|
||||
"label": "UI Sprite Asset Collection",
|
||||
"nodes": [
|
||||
"ui_board_sprite_black",
|
||||
"ui_board_sprite_white",
|
||||
"ui_board_sprite_bottom",
|
||||
"ui_piece_sprite_black_rook",
|
||||
"ui_piece_sprite_white_pawn",
|
||||
"ui_piece_sprite_white_knight",
|
||||
"ui_piece_sprite_black_knight"
|
||||
],
|
||||
"relation": "participate_in",
|
||||
"confidence": "EXTRACTED",
|
||||
"confidence_score": 1.0,
|
||||
"source_file": "modules/ui/src/main/resources/sprites"
|
||||
},
|
||||
{
|
||||
"id": "bot_python_components",
|
||||
"label": "Bot Python Implementation Components",
|
||||
"nodes": [
|
||||
"bot_python_readme",
|
||||
"bot_python_requirements",
|
||||
"bot_python_positions"
|
||||
],
|
||||
"relation": "participate_in",
|
||||
"confidence": "EXTRACTED",
|
||||
"confidence_score": 1.0,
|
||||
"source_file": "modules/bot/python"
|
||||
}
|
||||
],
|
||||
"input_tokens": 0,
|
||||
"output_tokens": 0
|
||||
}
|
||||
@@ -0,0 +1 @@
|
||||
/usr/bin/python
|
||||
@@ -0,0 +1,413 @@
|
||||
# Graph Report - . (2026-04-12)
|
||||
|
||||
## Corpus Check
|
||||
- 78 files · ~273,497 words
|
||||
- Verdict: corpus is large enough that graph structure adds value.
|
||||
|
||||
## Summary
|
||||
- 480 nodes · 549 edges · 74 communities detected
|
||||
- Extraction: 100% EXTRACTED · 0% INFERRED · 0% AMBIGUOUS
|
||||
- Token cost: 0 input · 0 output
|
||||
|
||||
## God Nodes (most connected - your core abstractions)
|
||||
1. `DefaultRules` - 35 edges
|
||||
2. `GameEngine` - 29 edges
|
||||
3. `ChessBoardView` - 17 edges
|
||||
4. `FenParserFastParse` - 17 edges
|
||||
5. `FenParserCombinators` - 16 edges
|
||||
6. `PgnParser` - 14 edges
|
||||
7. `FenParser` - 9 edges
|
||||
8. `CommandInvoker` - 9 edges
|
||||
9. `GameContext` - 8 edges
|
||||
10. `FenExporter` - 7 edges
|
||||
|
||||
## Surprising Connections (you probably didn't know these)
|
||||
- None detected - all connections are within the same source files.
|
||||
|
||||
## Communities
|
||||
|
||||
### Community 0 - "Community 0"
|
||||
Cohesion: 0.11
|
||||
Nodes (2): CastlingMove, DefaultRules
|
||||
|
||||
### Community 1 - "Community 1"
|
||||
Cohesion: 0.09
|
||||
Nodes (17): ClassGap, _compact_ranges(), _find_scoverage_xml(), format_agent(), format_json(), format_markdown(), format_module_gaps(), main() (+9 more)
|
||||
|
||||
### Community 2 - "Community 2"
|
||||
Cohesion: 0.11
|
||||
Nodes (2): GameEngine, PendingPromotion
|
||||
|
||||
### Community 3 - "Community 3"
|
||||
Cohesion: 0.09
|
||||
Nodes (4): FenParserCombinators, EmptyToken, FenParserSupport, PieceToken
|
||||
|
||||
### Community 4 - "Community 4"
|
||||
Cohesion: 0.14
|
||||
Nodes (9): format_module(), load_module(), main(), ModuleResult, parse_suite_xml(), run(), SuiteResult, TestCase (+1 more)
|
||||
|
||||
### Community 5 - "Community 5"
|
||||
Cohesion: 0.2
|
||||
Nodes (1): ChessBoardView
|
||||
|
||||
### Community 6 - "Community 6"
|
||||
Cohesion: 0.15
|
||||
Nodes (1): FenParserFastParse
|
||||
|
||||
### Community 7 - "Community 7"
|
||||
Cohesion: 0.12
|
||||
Nodes (7): InvalidFormat, InvalidMove, MoveCommand, MoveResult, QuitCommand, ResetCommand, Successful
|
||||
|
||||
### Community 8 - "Community 8"
|
||||
Cohesion: 0.12
|
||||
Nodes (12): BoardResetEvent, CheckDetectedEvent, CheckmateEvent, DrawClaimedEvent, FiftyMoveRuleAvailableEvent, InvalidMoveEvent, MoveExecutedEvent, MoveRedoneEvent (+4 more)
|
||||
|
||||
### Community 9 - "Community 9"
|
||||
Cohesion: 0.26
|
||||
Nodes (2): PgnGame, PgnParser
|
||||
|
||||
### Community 10 - "Community 10"
|
||||
Cohesion: 0.15
|
||||
Nodes (3): candidateMoves(), GameEngineIntegrationTest, legalMoves()
|
||||
|
||||
### Community 11 - "Community 11"
|
||||
Cohesion: 0.14
|
||||
Nodes (1): GameEnginePromotionTest
|
||||
|
||||
### Community 12 - "Community 12"
|
||||
Cohesion: 0.15
|
||||
Nodes (2): EngineTestHelpers, MockObserver
|
||||
|
||||
### Community 13 - "Community 13"
|
||||
Cohesion: 0.17
|
||||
Nodes (3): CommandInvokerBranchTest, ConditionalFailCommand, FailingCommand
|
||||
|
||||
### Community 14 - "Community 14"
|
||||
Cohesion: 0.36
|
||||
Nodes (1): FenParser
|
||||
|
||||
### Community 15 - "Community 15"
|
||||
Cohesion: 0.22
|
||||
Nodes (1): CommandInvoker
|
||||
|
||||
### Community 16 - "Community 16"
|
||||
Cohesion: 0.31
|
||||
Nodes (5): applyMove(), Board, removed(), updated(), withMove()
|
||||
|
||||
### Community 17 - "Community 17"
|
||||
Cohesion: 0.22
|
||||
Nodes (1): GameContext
|
||||
|
||||
### Community 18 - "Community 18"
|
||||
Cohesion: 0.25
|
||||
Nodes (6): ApiError, ApiResponse, Failure, PagedResponse, Pagination, Success
|
||||
|
||||
### Community 19 - "Community 19"
|
||||
Cohesion: 0.43
|
||||
Nodes (1): FenExporter
|
||||
|
||||
### Community 20 - "Community 20"
|
||||
Cohesion: 0.29
|
||||
Nodes (1): CastlingRights
|
||||
|
||||
### Community 21 - "Community 21"
|
||||
Cohesion: 0.4
|
||||
Nodes (2): ChessGUIApp, ChessGUILauncher
|
||||
|
||||
### Community 22 - "Community 22"
|
||||
Cohesion: 0.5
|
||||
Nodes (2): offset(), Square
|
||||
|
||||
### Community 23 - "Community 23"
|
||||
Cohesion: 0.4
|
||||
Nodes (2): PlayerId, PlayerInfo
|
||||
|
||||
### Community 24 - "Community 24"
|
||||
Cohesion: 0.5
|
||||
Nodes (2): PieceSprites, SquareColors
|
||||
|
||||
### Community 25 - "Community 25"
|
||||
Cohesion: 0.6
|
||||
Nodes (1): TerminalUI
|
||||
|
||||
### Community 26 - "Community 26"
|
||||
Cohesion: 0.6
|
||||
Nodes (1): PgnExporter
|
||||
|
||||
### Community 27 - "Community 27"
|
||||
Cohesion: 0.67
|
||||
Nodes (1): GUIObserver
|
||||
|
||||
### Community 28 - "Community 28"
|
||||
Cohesion: 0.5
|
||||
Nodes (1): DefaultRulesStateTransitionsTest
|
||||
|
||||
### Community 29 - "Community 29"
|
||||
Cohesion: 0.5
|
||||
Nodes (2): EndingMockObserver, GameEngineGameEndingTest
|
||||
|
||||
### Community 30 - "Community 30"
|
||||
Cohesion: 0.5
|
||||
Nodes (2): GameEngineLoadGameTest, MockObserver
|
||||
|
||||
### Community 31 - "Community 31"
|
||||
Cohesion: 0.5
|
||||
Nodes (1): CommandInvokerTest
|
||||
|
||||
### Community 32 - "Community 32"
|
||||
Cohesion: 0.67
|
||||
Nodes (1): Parser
|
||||
|
||||
### Community 33 - "Community 33"
|
||||
Cohesion: 0.67
|
||||
Nodes (0):
|
||||
|
||||
### Community 34 - "Community 34"
|
||||
Cohesion: 0.67
|
||||
Nodes (1): Main
|
||||
|
||||
### Community 35 - "Community 35"
|
||||
Cohesion: 0.67
|
||||
Nodes (1): Renderer
|
||||
|
||||
### Community 36 - "Community 36"
|
||||
Cohesion: 0.67
|
||||
Nodes (1): PgnExporterTest
|
||||
|
||||
### Community 37 - "Community 37"
|
||||
Cohesion: 0.67
|
||||
Nodes (1): FenExporterTest
|
||||
|
||||
### Community 38 - "Community 38"
|
||||
Cohesion: 0.67
|
||||
Nodes (1): GameEngineNotationTest
|
||||
|
||||
### Community 39 - "Community 39"
|
||||
Cohesion: 0.67
|
||||
Nodes (1): MoveCommandTest
|
||||
|
||||
### Community 40 - "Community 40"
|
||||
Cohesion: 1.0
|
||||
Nodes (1): PieceTest
|
||||
|
||||
### Community 41 - "Community 41"
|
||||
Cohesion: 1.0
|
||||
Nodes (1): PieceTypeTest
|
||||
|
||||
### Community 42 - "Community 42"
|
||||
Cohesion: 1.0
|
||||
Nodes (1): SquareTest
|
||||
|
||||
### Community 43 - "Community 43"
|
||||
Cohesion: 1.0
|
||||
Nodes (1): CastlingRightsTest
|
||||
|
||||
### Community 44 - "Community 44"
|
||||
Cohesion: 1.0
|
||||
Nodes (1): BoardTest
|
||||
|
||||
### Community 45 - "Community 45"
|
||||
Cohesion: 1.0
|
||||
Nodes (1): ColorTest
|
||||
|
||||
### Community 46 - "Community 46"
|
||||
Cohesion: 1.0
|
||||
Nodes (1): MoveTest
|
||||
|
||||
### Community 47 - "Community 47"
|
||||
Cohesion: 1.0
|
||||
Nodes (1): GameContextTest
|
||||
|
||||
### Community 48 - "Community 48"
|
||||
Cohesion: 1.0
|
||||
Nodes (1): ApiResponseTest
|
||||
|
||||
### Community 49 - "Community 49"
|
||||
Cohesion: 1.0
|
||||
Nodes (1): PlayerInfoTest
|
||||
|
||||
### Community 50 - "Community 50"
|
||||
Cohesion: 1.0
|
||||
Nodes (0):
|
||||
|
||||
### Community 51 - "Community 51"
|
||||
Cohesion: 1.0
|
||||
Nodes (1): Piece
|
||||
|
||||
### Community 52 - "Community 52"
|
||||
Cohesion: 1.0
|
||||
Nodes (1): Move
|
||||
|
||||
### Community 53 - "Community 53"
|
||||
Cohesion: 1.0
|
||||
Nodes (1): RendererAndUnicodeTest
|
||||
|
||||
### Community 54 - "Community 54"
|
||||
Cohesion: 1.0
|
||||
Nodes (0):
|
||||
|
||||
### Community 55 - "Community 55"
|
||||
Cohesion: 1.0
|
||||
Nodes (1): DefaultRulesTest
|
||||
|
||||
### Community 56 - "Community 56"
|
||||
Cohesion: 1.0
|
||||
Nodes (1): PgnParserTest
|
||||
|
||||
### Community 57 - "Community 57"
|
||||
Cohesion: 1.0
|
||||
Nodes (1): PgnValidatorTest
|
||||
|
||||
### Community 58 - "Community 58"
|
||||
Cohesion: 1.0
|
||||
Nodes (1): FenParserCombinatorsTest
|
||||
|
||||
### Community 59 - "Community 59"
|
||||
Cohesion: 1.0
|
||||
Nodes (1): FenParserTest
|
||||
|
||||
### Community 60 - "Community 60"
|
||||
Cohesion: 1.0
|
||||
Nodes (1): FenParserFastParseTest
|
||||
|
||||
### Community 61 - "Community 61"
|
||||
Cohesion: 1.0
|
||||
Nodes (1): ParserTest
|
||||
|
||||
### Community 62 - "Community 62"
|
||||
Cohesion: 1.0
|
||||
Nodes (1): GameEngineOutcomesTest
|
||||
|
||||
### Community 63 - "Community 63"
|
||||
Cohesion: 1.0
|
||||
Nodes (1): GameEngineSpecialMovesTest
|
||||
|
||||
### Community 64 - "Community 64"
|
||||
Cohesion: 1.0
|
||||
Nodes (1): GameEngineScenarioTest
|
||||
|
||||
### Community 65 - "Community 65"
|
||||
Cohesion: 1.0
|
||||
Nodes (1): CommandTest
|
||||
|
||||
### Community 66 - "Community 66"
|
||||
Cohesion: 1.0
|
||||
Nodes (0):
|
||||
|
||||
### Community 67 - "Community 67"
|
||||
Cohesion: 1.0
|
||||
Nodes (0):
|
||||
|
||||
### Community 68 - "Community 68"
|
||||
Cohesion: 1.0
|
||||
Nodes (0):
|
||||
|
||||
### Community 69 - "Community 69"
|
||||
Cohesion: 1.0
|
||||
Nodes (0):
|
||||
|
||||
### Community 70 - "Community 70"
|
||||
Cohesion: 1.0
|
||||
Nodes (0):
|
||||
|
||||
### Community 71 - "Community 71"
|
||||
Cohesion: 1.0
|
||||
Nodes (1): Strip the package prefix from the full method path.
|
||||
|
||||
### Community 72 - "Community 72"
|
||||
Cohesion: 1.0
|
||||
Nodes (1): Lines that are branch points and have at least one uncovered branch statement.
|
||||
|
||||
### Community 73 - "Community 73"
|
||||
Cohesion: 1.0
|
||||
Nodes (0):
|
||||
|
||||
## Knowledge Gaps
|
||||
- **55 isolated node(s):** `PieceTest`, `PieceTypeTest`, `SquareTest`, `CastlingRightsTest`, `BoardTest` (+50 more)
|
||||
These have ≤1 connection - possible missing edges or undocumented components.
|
||||
- **Thin community `Community 40`** (2 nodes): `PieceTest.scala`, `PieceTest`
|
||||
Too small to be a meaningful cluster - may be noise or needs more connections extracted.
|
||||
- **Thin community `Community 41`** (2 nodes): `PieceTypeTest.scala`, `PieceTypeTest`
|
||||
Too small to be a meaningful cluster - may be noise or needs more connections extracted.
|
||||
- **Thin community `Community 42`** (2 nodes): `SquareTest.scala`, `SquareTest`
|
||||
Too small to be a meaningful cluster - may be noise or needs more connections extracted.
|
||||
- **Thin community `Community 43`** (2 nodes): `CastlingRightsTest.scala`, `CastlingRightsTest`
|
||||
Too small to be a meaningful cluster - may be noise or needs more connections extracted.
|
||||
- **Thin community `Community 44`** (2 nodes): `BoardTest.scala`, `BoardTest`
|
||||
Too small to be a meaningful cluster - may be noise or needs more connections extracted.
|
||||
- **Thin community `Community 45`** (2 nodes): `ColorTest.scala`, `ColorTest`
|
||||
Too small to be a meaningful cluster - may be noise or needs more connections extracted.
|
||||
- **Thin community `Community 46`** (2 nodes): `MoveTest.scala`, `MoveTest`
|
||||
Too small to be a meaningful cluster - may be noise or needs more connections extracted.
|
||||
- **Thin community `Community 47`** (2 nodes): `GameContextTest.scala`, `GameContextTest`
|
||||
Too small to be a meaningful cluster - may be noise or needs more connections extracted.
|
||||
- **Thin community `Community 48`** (2 nodes): `ApiResponseTest.scala`, `ApiResponseTest`
|
||||
Too small to be a meaningful cluster - may be noise or needs more connections extracted.
|
||||
- **Thin community `Community 49`** (2 nodes): `PlayerInfoTest.scala`, `PlayerInfoTest`
|
||||
Too small to be a meaningful cluster - may be noise or needs more connections extracted.
|
||||
- **Thin community `Community 50`** (2 nodes): `PieceType.scala`, `label()`
|
||||
Too small to be a meaningful cluster - may be noise or needs more connections extracted.
|
||||
- **Thin community `Community 51`** (2 nodes): `Piece.scala`, `Piece`
|
||||
Too small to be a meaningful cluster - may be noise or needs more connections extracted.
|
||||
- **Thin community `Community 52`** (2 nodes): `Move.scala`, `Move`
|
||||
Too small to be a meaningful cluster - may be noise or needs more connections extracted.
|
||||
- **Thin community `Community 53`** (2 nodes): `RendererAndUnicodeTest.scala`, `RendererAndUnicodeTest`
|
||||
Too small to be a meaningful cluster - may be noise or needs more connections extracted.
|
||||
- **Thin community `Community 54`** (2 nodes): `PieceUnicode.scala`, `unicode()`
|
||||
Too small to be a meaningful cluster - may be noise or needs more connections extracted.
|
||||
- **Thin community `Community 55`** (2 nodes): `DefaultRulesTest.scala`, `DefaultRulesTest`
|
||||
Too small to be a meaningful cluster - may be noise or needs more connections extracted.
|
||||
- **Thin community `Community 56`** (2 nodes): `PgnParserTest.scala`, `PgnParserTest`
|
||||
Too small to be a meaningful cluster - may be noise or needs more connections extracted.
|
||||
- **Thin community `Community 57`** (2 nodes): `PgnValidatorTest.scala`, `PgnValidatorTest`
|
||||
Too small to be a meaningful cluster - may be noise or needs more connections extracted.
|
||||
- **Thin community `Community 58`** (2 nodes): `FenParserCombinatorsTest.scala`, `FenParserCombinatorsTest`
|
||||
Too small to be a meaningful cluster - may be noise or needs more connections extracted.
|
||||
- **Thin community `Community 59`** (2 nodes): `FenParserTest.scala`, `FenParserTest`
|
||||
Too small to be a meaningful cluster - may be noise or needs more connections extracted.
|
||||
- **Thin community `Community 60`** (2 nodes): `FenParserFastParseTest.scala`, `FenParserFastParseTest`
|
||||
Too small to be a meaningful cluster - may be noise or needs more connections extracted.
|
||||
- **Thin community `Community 61`** (2 nodes): `ParserTest.scala`, `ParserTest`
|
||||
Too small to be a meaningful cluster - may be noise or needs more connections extracted.
|
||||
- **Thin community `Community 62`** (2 nodes): `GameEngineOutcomesTest.scala`, `GameEngineOutcomesTest`
|
||||
Too small to be a meaningful cluster - may be noise or needs more connections extracted.
|
||||
- **Thin community `Community 63`** (2 nodes): `GameEngineSpecialMovesTest.scala`, `GameEngineSpecialMovesTest`
|
||||
Too small to be a meaningful cluster - may be noise or needs more connections extracted.
|
||||
- **Thin community `Community 64`** (2 nodes): `GameEngineScenarioTest.scala`, `GameEngineScenarioTest`
|
||||
Too small to be a meaningful cluster - may be noise or needs more connections extracted.
|
||||
- **Thin community `Community 65`** (2 nodes): `CommandTest.scala`, `CommandTest`
|
||||
Too small to be a meaningful cluster - may be noise or needs more connections extracted.
|
||||
- **Thin community `Community 66`** (1 nodes): `build.gradle.kts`
|
||||
Too small to be a meaningful cluster - may be noise or needs more connections extracted.
|
||||
- **Thin community `Community 67`** (1 nodes): `settings.gradle.kts`
|
||||
Too small to be a meaningful cluster - may be noise or needs more connections extracted.
|
||||
- **Thin community `Community 68`** (1 nodes): `RuleSet.scala`
|
||||
Too small to be a meaningful cluster - may be noise or needs more connections extracted.
|
||||
- **Thin community `Community 69`** (1 nodes): `GameContextImport.scala`
|
||||
Too small to be a meaningful cluster - may be noise or needs more connections extracted.
|
||||
- **Thin community `Community 70`** (1 nodes): `GameContextExport.scala`
|
||||
Too small to be a meaningful cluster - may be noise or needs more connections extracted.
|
||||
- **Thin community `Community 71`** (1 nodes): `Strip the package prefix from the full method path.`
|
||||
Too small to be a meaningful cluster - may be noise or needs more connections extracted.
|
||||
- **Thin community `Community 72`** (1 nodes): `Lines that are branch points and have at least one uncovered branch statement.`
|
||||
Too small to be a meaningful cluster - may be noise or needs more connections extracted.
|
||||
- **Thin community `Community 73`** (1 nodes): `test_counter.py`
|
||||
Too small to be a meaningful cluster - may be noise or needs more connections extracted.
|
||||
|
||||
## Suggested Questions
|
||||
_Questions this graph is uniquely positioned to answer:_
|
||||
|
||||
- **Why does `FenParserFastParse` connect `Community 6` to `Community 3`?**
|
||||
_High betweenness centrality (0.004) - this node is a cross-community bridge._
|
||||
- **What connects `PieceTest`, `PieceTypeTest`, `SquareTest` to the rest of the system?**
|
||||
_55 weakly-connected nodes found - possible documentation gaps or missing edges._
|
||||
- **Should `Community 0` be split into smaller, more focused modules?**
|
||||
_Cohesion score 0.11 - nodes in this community are weakly interconnected._
|
||||
- **Should `Community 1` be split into smaller, more focused modules?**
|
||||
_Cohesion score 0.09 - nodes in this community are weakly interconnected._
|
||||
- **Should `Community 2` be split into smaller, more focused modules?**
|
||||
_Cohesion score 0.11 - nodes in this community are weakly interconnected._
|
||||
- **Should `Community 3` be split into smaller, more focused modules?**
|
||||
_Cohesion score 0.09 - nodes in this community are weakly interconnected._
|
||||
- **Should `Community 4` be split into smaller, more focused modules?**
|
||||
_Cohesion score 0.14 - nodes in this community are weakly interconnected._
|
||||
@@ -0,0 +1 @@
|
||||
{"nodes": [{"id": "commandinvokertest", "label": "CommandInvokerTest.scala", "file_type": "code", "source_file": "modules/core/src/test/scala/de/nowchess/chess/command/CommandInvokerTest.scala", "source_location": "L1"}, {"id": "commandinvokertest_commandinvokertest", "label": "CommandInvokerTest", "file_type": "code", "source_file": "modules/core/src/test/scala/de/nowchess/chess/command/CommandInvokerTest.scala", "source_location": "L8"}, {"id": "commandinvokertest_commandinvokertest_sq", "label": ".sq()", "file_type": "code", "source_file": "modules/core/src/test/scala/de/nowchess/chess/command/CommandInvokerTest.scala", "source_location": "L10"}, {"id": "commandinvokertest_commandinvokertest_createmovecommand", "label": ".createMoveCommand()", "file_type": "code", "source_file": "modules/core/src/test/scala/de/nowchess/chess/command/CommandInvokerTest.scala", "source_location": "L12"}], "edges": [{"source": "commandinvokertest", "target": "de", "relation": "imports", "confidence": "EXTRACTED", "source_file": "modules/core/src/test/scala/de/nowchess/chess/command/CommandInvokerTest.scala", "source_location": "L3", "weight": 1.0}, {"source": "commandinvokertest", "target": "de", "relation": "imports", "confidence": "EXTRACTED", "source_file": "modules/core/src/test/scala/de/nowchess/chess/command/CommandInvokerTest.scala", "source_location": "L4", "weight": 1.0}, {"source": "commandinvokertest", "target": "org", "relation": "imports", "confidence": "EXTRACTED", "source_file": "modules/core/src/test/scala/de/nowchess/chess/command/CommandInvokerTest.scala", "source_location": "L5", "weight": 1.0}, {"source": "commandinvokertest", "target": "org", "relation": "imports", "confidence": "EXTRACTED", "source_file": "modules/core/src/test/scala/de/nowchess/chess/command/CommandInvokerTest.scala", "source_location": "L6", "weight": 1.0}, {"source": "commandinvokertest", "target": "commandinvokertest_commandinvokertest", "relation": "contains", "confidence": "EXTRACTED", "source_file": "modules/core/src/test/scala/de/nowchess/chess/command/CommandInvokerTest.scala", "source_location": "L8", "weight": 1.0}, {"source": "commandinvokertest_commandinvokertest", "target": "commandinvokertest_commandinvokertest_sq", "relation": "method", "confidence": "EXTRACTED", "source_file": "modules/core/src/test/scala/de/nowchess/chess/command/CommandInvokerTest.scala", "source_location": "L10", "weight": 1.0}, {"source": "commandinvokertest_commandinvokertest", "target": "commandinvokertest_commandinvokertest_createmovecommand", "relation": "method", "confidence": "EXTRACTED", "source_file": "modules/core/src/test/scala/de/nowchess/chess/command/CommandInvokerTest.scala", "source_location": "L12", "weight": 1.0}]}
|
||||
@@ -0,0 +1 @@
|
||||
{"nodes": [{"id": "build_gradle", "label": "build.gradle.kts", "file_type": "code", "source_file": "modules/ui/build.gradle.kts", "source_location": "L1"}], "edges": []}
|
||||
@@ -0,0 +1 @@
|
||||
{"nodes": [{"id": "nnuebot", "label": "NNUEBot.scala", "file_type": "code", "source_file": "modules/bot/src/main/scala/de/nowchess/bot/bots/NNUEBot.scala", "source_location": "L1"}, {"id": "nnuebot_nnuebot", "label": "NNUEBot", "file_type": "code", "source_file": "modules/bot/src/main/scala/de/nowchess/bot/bots/NNUEBot.scala", "source_location": "L12"}, {"id": "nnuebot_nnuebot_nextmove", "label": ".nextMove()", "file_type": "code", "source_file": "modules/bot/src/main/scala/de/nowchess/bot/bots/NNUEBot.scala", "source_location": "L23"}], "edges": [{"source": "nnuebot", "target": "de", "relation": "imports", "confidence": "EXTRACTED", "source_file": "modules/bot/src/main/scala/de/nowchess/bot/bots/NNUEBot.scala", "source_location": "L3", "weight": 1.0}, {"source": "nnuebot", "target": "de", "relation": "imports", "confidence": "EXTRACTED", "source_file": "modules/bot/src/main/scala/de/nowchess/bot/bots/NNUEBot.scala", "source_location": "L4", "weight": 1.0}, {"source": "nnuebot", "target": "de", "relation": "imports", "confidence": "EXTRACTED", "source_file": "modules/bot/src/main/scala/de/nowchess/bot/bots/NNUEBot.scala", "source_location": "L5", "weight": 1.0}, {"source": "nnuebot", "target": "de", "relation": "imports", "confidence": "EXTRACTED", "source_file": "modules/bot/src/main/scala/de/nowchess/bot/bots/NNUEBot.scala", "source_location": "L6", "weight": 1.0}, {"source": "nnuebot", "target": "de", "relation": "imports", "confidence": "EXTRACTED", "source_file": "modules/bot/src/main/scala/de/nowchess/bot/bots/NNUEBot.scala", "source_location": "L7", "weight": 1.0}, {"source": "nnuebot", "target": "de", "relation": "imports", "confidence": "EXTRACTED", "source_file": "modules/bot/src/main/scala/de/nowchess/bot/bots/NNUEBot.scala", "source_location": "L8", "weight": 1.0}, {"source": "nnuebot", "target": "de", "relation": "imports", "confidence": "EXTRACTED", "source_file": "modules/bot/src/main/scala/de/nowchess/bot/bots/NNUEBot.scala", "source_location": "L9", "weight": 1.0}, {"source": "nnuebot", "target": "de", "relation": "imports", "confidence": "EXTRACTED", "source_file": "modules/bot/src/main/scala/de/nowchess/bot/bots/NNUEBot.scala", "source_location": "L10", "weight": 1.0}, {"source": "nnuebot", "target": "nnuebot_nnuebot", "relation": "contains", "confidence": "EXTRACTED", "source_file": "modules/bot/src/main/scala/de/nowchess/bot/bots/NNUEBot.scala", "source_location": "L12", "weight": 1.0}, {"source": "nnuebot_nnuebot", "target": "nnuebot_nnuebot_nextmove", "relation": "method", "confidence": "EXTRACTED", "source_file": "modules/bot/src/main/scala/de/nowchess/bot/bots/NNUEBot.scala", "source_location": "L23", "weight": 1.0}]}
|
||||
@@ -0,0 +1 @@
|
||||
{"nodes": [{"id": "pgnexporter", "label": "PgnExporter.scala", "file_type": "code", "source_file": "modules/io/src/main/scala/de/nowchess/io/pgn/PgnExporter.scala", "source_location": "L1"}, {"id": "pgnexporter_pgnexporter", "label": "PgnExporter", "file_type": "code", "source_file": "modules/io/src/main/scala/de/nowchess/io/pgn/PgnExporter.scala", "source_location": "L9"}, {"id": "pgnexporter_pgnexporter_exportgamecontext", "label": ".exportGameContext()", "file_type": "code", "source_file": "modules/io/src/main/scala/de/nowchess/io/pgn/PgnExporter.scala", "source_location": "L12"}, {"id": "pgnexporter_pgnexporter_exportgame", "label": ".exportGame()", "file_type": "code", "source_file": "modules/io/src/main/scala/de/nowchess/io/pgn/PgnExporter.scala", "source_location": "L23"}, {"id": "pgnexporter_pgnexporter_movetoalgebraic", "label": ".moveToAlgebraic()", "file_type": "code", "source_file": "modules/io/src/main/scala/de/nowchess/io/pgn/PgnExporter.scala", "source_location": "L53"}], "edges": [{"source": "pgnexporter", "target": "de", "relation": "imports", "confidence": "EXTRACTED", "source_file": "modules/io/src/main/scala/de/nowchess/io/pgn/PgnExporter.scala", "source_location": "L3", "weight": 1.0}, {"source": "pgnexporter", "target": "de", "relation": "imports", "confidence": "EXTRACTED", "source_file": "modules/io/src/main/scala/de/nowchess/io/pgn/PgnExporter.scala", "source_location": "L4", "weight": 1.0}, {"source": "pgnexporter", "target": "de", "relation": "imports", "confidence": "EXTRACTED", "source_file": "modules/io/src/main/scala/de/nowchess/io/pgn/PgnExporter.scala", "source_location": "L5", "weight": 1.0}, {"source": "pgnexporter", "target": "de", "relation": "imports", "confidence": "EXTRACTED", "source_file": "modules/io/src/main/scala/de/nowchess/io/pgn/PgnExporter.scala", "source_location": "L6", "weight": 1.0}, {"source": "pgnexporter", "target": "de", "relation": "imports", "confidence": "EXTRACTED", "source_file": "modules/io/src/main/scala/de/nowchess/io/pgn/PgnExporter.scala", "source_location": "L7", "weight": 1.0}, {"source": "pgnexporter", "target": "pgnexporter_pgnexporter", "relation": "contains", "confidence": "EXTRACTED", "source_file": "modules/io/src/main/scala/de/nowchess/io/pgn/PgnExporter.scala", "source_location": "L9", "weight": 1.0}, {"source": "pgnexporter_pgnexporter", "target": "pgnexporter_pgnexporter_exportgamecontext", "relation": "method", "confidence": "EXTRACTED", "source_file": "modules/io/src/main/scala/de/nowchess/io/pgn/PgnExporter.scala", "source_location": "L12", "weight": 1.0}, {"source": "pgnexporter_pgnexporter", "target": "pgnexporter_pgnexporter_exportgame", "relation": "method", "confidence": "EXTRACTED", "source_file": "modules/io/src/main/scala/de/nowchess/io/pgn/PgnExporter.scala", "source_location": "L23", "weight": 1.0}, {"source": "pgnexporter_pgnexporter", "target": "pgnexporter_pgnexporter_movetoalgebraic", "relation": "method", "confidence": "EXTRACTED", "source_file": "modules/io/src/main/scala/de/nowchess/io/pgn/PgnExporter.scala", "source_location": "L53", "weight": 1.0}, {"source": "pgnexporter_pgnexporter_exportgamecontext", "target": "pgnexporter_pgnexporter_exportgame", "relation": "calls", "confidence": "EXTRACTED", "source_file": "modules/io/src/main/scala/de/nowchess/io/pgn/PgnExporter.scala", "source_location": "L20", "weight": 1.0}, {"source": "pgnexporter_pgnexporter_exportgame", "target": "pgnexporter_pgnexporter_movetoalgebraic", "relation": "calls", "confidence": "EXTRACTED", "source_file": "modules/io/src/main/scala/de/nowchess/io/pgn/PgnExporter.scala", "source_location": "L32", "weight": 1.0}]}
|
||||
@@ -0,0 +1 @@
|
||||
{"nodes": [{"id": "piece", "label": "Piece.scala", "file_type": "code", "source_file": "modules/api/src/main/scala/de/nowchess/api/board/Piece.scala", "source_location": "L1"}, {"id": "piece_piece", "label": "Piece", "file_type": "code", "source_file": "modules/api/src/main/scala/de/nowchess/api/board/Piece.scala", "source_location": "L4"}], "edges": [{"source": "piece", "target": "piece_piece", "relation": "contains", "confidence": "EXTRACTED", "source_file": "modules/api/src/main/scala/de/nowchess/api/board/Piece.scala", "source_location": "L4", "weight": 1.0}, {"source": "piece", "target": "piece_piece", "relation": "contains", "confidence": "EXTRACTED", "source_file": "modules/api/src/main/scala/de/nowchess/api/board/Piece.scala", "source_location": "L6", "weight": 1.0}]}
|
||||
@@ -0,0 +1 @@
|
||||
{"nodes": [{"id": "commandinvoker", "label": "CommandInvoker.scala", "file_type": "code", "source_file": "modules/core/src/main/scala/de/nowchess/chess/command/CommandInvoker.scala", "source_location": "L1"}, {"id": "commandinvoker_commandinvoker", "label": "CommandInvoker", "file_type": "code", "source_file": "modules/core/src/main/scala/de/nowchess/chess/command/CommandInvoker.scala", "source_location": "L4"}, {"id": "commandinvoker_commandinvoker_execute", "label": ".execute()", "file_type": "code", "source_file": "modules/core/src/main/scala/de/nowchess/chess/command/CommandInvoker.scala", "source_location": "L11"}, {"id": "commandinvoker_commandinvoker_undo", "label": ".undo()", "file_type": "code", "source_file": "modules/core/src/main/scala/de/nowchess/chess/command/CommandInvoker.scala", "source_location": "L24"}, {"id": "commandinvoker_commandinvoker_redo", "label": ".redo()", "file_type": "code", "source_file": "modules/core/src/main/scala/de/nowchess/chess/command/CommandInvoker.scala", "source_location": "L37"}, {"id": "commandinvoker_commandinvoker_history", "label": ".history()", "file_type": "code", "source_file": "modules/core/src/main/scala/de/nowchess/chess/command/CommandInvoker.scala", "source_location": "L50"}, {"id": "commandinvoker_commandinvoker_getcurrentindex", "label": ".getCurrentIndex()", "file_type": "code", "source_file": "modules/core/src/main/scala/de/nowchess/chess/command/CommandInvoker.scala", "source_location": "L55"}, {"id": "commandinvoker_commandinvoker_clear", "label": ".clear()", "file_type": "code", "source_file": "modules/core/src/main/scala/de/nowchess/chess/command/CommandInvoker.scala", "source_location": "L60"}, {"id": "commandinvoker_commandinvoker_canundo", "label": ".canUndo()", "file_type": "code", "source_file": "modules/core/src/main/scala/de/nowchess/chess/command/CommandInvoker.scala", "source_location": "L66"}, {"id": "commandinvoker_commandinvoker_canredo", "label": ".canRedo()", "file_type": "code", "source_file": "modules/core/src/main/scala/de/nowchess/chess/command/CommandInvoker.scala", "source_location": "L71"}], "edges": [{"source": "commandinvoker", "target": "commandinvoker_commandinvoker", "relation": "contains", "confidence": "EXTRACTED", "source_file": "modules/core/src/main/scala/de/nowchess/chess/command/CommandInvoker.scala", "source_location": "L4", "weight": 1.0}, {"source": "commandinvoker_commandinvoker", "target": "commandinvoker_commandinvoker_execute", "relation": "method", "confidence": "EXTRACTED", "source_file": "modules/core/src/main/scala/de/nowchess/chess/command/CommandInvoker.scala", "source_location": "L11", "weight": 1.0}, {"source": "commandinvoker_commandinvoker", "target": "commandinvoker_commandinvoker_undo", "relation": "method", "confidence": "EXTRACTED", "source_file": "modules/core/src/main/scala/de/nowchess/chess/command/CommandInvoker.scala", "source_location": "L24", "weight": 1.0}, {"source": "commandinvoker_commandinvoker", "target": "commandinvoker_commandinvoker_redo", "relation": "method", "confidence": "EXTRACTED", "source_file": "modules/core/src/main/scala/de/nowchess/chess/command/CommandInvoker.scala", "source_location": "L37", "weight": 1.0}, {"source": "commandinvoker_commandinvoker", "target": "commandinvoker_commandinvoker_history", "relation": "method", "confidence": "EXTRACTED", "source_file": "modules/core/src/main/scala/de/nowchess/chess/command/CommandInvoker.scala", "source_location": "L50", "weight": 1.0}, {"source": "commandinvoker_commandinvoker", "target": "commandinvoker_commandinvoker_getcurrentindex", "relation": "method", "confidence": "EXTRACTED", "source_file": "modules/core/src/main/scala/de/nowchess/chess/command/CommandInvoker.scala", "source_location": "L55", "weight": 1.0}, {"source": "commandinvoker_commandinvoker", "target": "commandinvoker_commandinvoker_clear", "relation": "method", "confidence": "EXTRACTED", "source_file": "modules/core/src/main/scala/de/nowchess/chess/command/CommandInvoker.scala", "source_location": "L60", "weight": 1.0}, {"source": "commandinvoker_commandinvoker", "target": "commandinvoker_commandinvoker_canundo", "relation": "method", "confidence": "EXTRACTED", "source_file": "modules/core/src/main/scala/de/nowchess/chess/command/CommandInvoker.scala", "source_location": "L66", "weight": 1.0}, {"source": "commandinvoker_commandinvoker", "target": "commandinvoker_commandinvoker_canredo", "relation": "method", "confidence": "EXTRACTED", "source_file": "modules/core/src/main/scala/de/nowchess/chess/command/CommandInvoker.scala", "source_location": "L71", "weight": 1.0}, {"source": "commandinvoker_commandinvoker_redo", "target": "commandinvoker_commandinvoker_execute", "relation": "calls", "confidence": "EXTRACTED", "source_file": "modules/core/src/main/scala/de/nowchess/chess/command/CommandInvoker.scala", "source_location": "L40", "weight": 1.0}]}
|
||||
@@ -0,0 +1 @@
|
||||
{"nodes": [{"id": "squaretest", "label": "SquareTest.scala", "file_type": "code", "source_file": "modules/api/src/test/scala/de/nowchess/api/board/SquareTest.scala", "source_location": "L1"}, {"id": "squaretest_squaretest", "label": "SquareTest", "file_type": "code", "source_file": "modules/api/src/test/scala/de/nowchess/api/board/SquareTest.scala", "source_location": "L6"}], "edges": [{"source": "squaretest", "target": "org", "relation": "imports", "confidence": "EXTRACTED", "source_file": "modules/api/src/test/scala/de/nowchess/api/board/SquareTest.scala", "source_location": "L3", "weight": 1.0}, {"source": "squaretest", "target": "org", "relation": "imports", "confidence": "EXTRACTED", "source_file": "modules/api/src/test/scala/de/nowchess/api/board/SquareTest.scala", "source_location": "L4", "weight": 1.0}, {"source": "squaretest", "target": "squaretest_squaretest", "relation": "contains", "confidence": "EXTRACTED", "source_file": "modules/api/src/test/scala/de/nowchess/api/board/SquareTest.scala", "source_location": "L6", "weight": 1.0}]}
|
||||
@@ -0,0 +1 @@
|
||||
{"nodes": [{"id": "guiobserver", "label": "GUIObserver.scala", "file_type": "code", "source_file": "modules/ui/src/main/scala/de/nowchess/ui/gui/GUIObserver.scala", "source_location": "L1"}, {"id": "guiobserver_guiobserver", "label": "GUIObserver", "file_type": "code", "source_file": "modules/ui/src/main/scala/de/nowchess/ui/gui/GUIObserver.scala", "source_location": "L13"}, {"id": "guiobserver_guiobserver_ongameevent", "label": ".onGameEvent()", "file_type": "code", "source_file": "modules/ui/src/main/scala/de/nowchess/ui/gui/GUIObserver.scala", "source_location": "L15"}, {"id": "guiobserver_guiobserver_showalert", "label": ".showAlert()", "file_type": "code", "source_file": "modules/ui/src/main/scala/de/nowchess/ui/gui/GUIObserver.scala", "source_location": "L73"}], "edges": [{"source": "guiobserver", "target": "scalafx", "relation": "imports", "confidence": "EXTRACTED", "source_file": "modules/ui/src/main/scala/de/nowchess/ui/gui/GUIObserver.scala", "source_location": "L3", "weight": 1.0}, {"source": "guiobserver", "target": "scalafx", "relation": "imports", "confidence": "EXTRACTED", "source_file": "modules/ui/src/main/scala/de/nowchess/ui/gui/GUIObserver.scala", "source_location": "L4", "weight": 1.0}, {"source": "guiobserver", "target": "scalafx", "relation": "imports", "confidence": "EXTRACTED", "source_file": "modules/ui/src/main/scala/de/nowchess/ui/gui/GUIObserver.scala", "source_location": "L5", "weight": 1.0}, {"source": "guiobserver", "target": "de", "relation": "imports", "confidence": "EXTRACTED", "source_file": "modules/ui/src/main/scala/de/nowchess/ui/gui/GUIObserver.scala", "source_location": "L6", "weight": 1.0}, {"source": "guiobserver", "target": "de", "relation": "imports", "confidence": "EXTRACTED", "source_file": "modules/ui/src/main/scala/de/nowchess/ui/gui/GUIObserver.scala", "source_location": "L7", "weight": 1.0}, {"source": "guiobserver", "target": "guiobserver_guiobserver", "relation": "contains", "confidence": "EXTRACTED", "source_file": "modules/ui/src/main/scala/de/nowchess/ui/gui/GUIObserver.scala", "source_location": "L13", "weight": 1.0}, {"source": "guiobserver_guiobserver", "target": "guiobserver_guiobserver_ongameevent", "relation": "method", "confidence": "EXTRACTED", "source_file": "modules/ui/src/main/scala/de/nowchess/ui/gui/GUIObserver.scala", "source_location": "L15", "weight": 1.0}, {"source": "guiobserver_guiobserver", "target": "guiobserver_guiobserver_showalert", "relation": "method", "confidence": "EXTRACTED", "source_file": "modules/ui/src/main/scala/de/nowchess/ui/gui/GUIObserver.scala", "source_location": "L73", "weight": 1.0}, {"source": "guiobserver_guiobserver_ongameevent", "target": "guiobserver_guiobserver_showalert", "relation": "calls", "confidence": "EXTRACTED", "source_file": "modules/ui/src/main/scala/de/nowchess/ui/gui/GUIObserver.scala", "source_location": "L31", "weight": 1.0}]}
|
||||
@@ -0,0 +1 @@
|
||||
{"nodes": [{"id": "gamecontextexport", "label": "GameContextExport.scala", "file_type": "code", "source_file": "modules/io/src/main/scala/de/nowchess/io/GameContextExport.scala", "source_location": "L1"}], "edges": [{"source": "gamecontextexport", "target": "de", "relation": "imports", "confidence": "EXTRACTED", "source_file": "modules/io/src/main/scala/de/nowchess/io/GameContextExport.scala", "source_location": "L3", "weight": 1.0}]}
|
||||
@@ -0,0 +1 @@
|
||||
{"nodes": [{"id": "apiresponsetest", "label": "ApiResponseTest.scala", "file_type": "code", "source_file": "modules/api/src/test/scala/de/nowchess/api/response/ApiResponseTest.scala", "source_location": "L1"}, {"id": "apiresponsetest_apiresponsetest", "label": "ApiResponseTest", "file_type": "code", "source_file": "modules/api/src/test/scala/de/nowchess/api/response/ApiResponseTest.scala", "source_location": "L6"}], "edges": [{"source": "apiresponsetest", "target": "org", "relation": "imports", "confidence": "EXTRACTED", "source_file": "modules/api/src/test/scala/de/nowchess/api/response/ApiResponseTest.scala", "source_location": "L3", "weight": 1.0}, {"source": "apiresponsetest", "target": "org", "relation": "imports", "confidence": "EXTRACTED", "source_file": "modules/api/src/test/scala/de/nowchess/api/response/ApiResponseTest.scala", "source_location": "L4", "weight": 1.0}, {"source": "apiresponsetest", "target": "apiresponsetest_apiresponsetest", "relation": "contains", "confidence": "EXTRACTED", "source_file": "modules/api/src/test/scala/de/nowchess/api/response/ApiResponseTest.scala", "source_location": "L6", "weight": 1.0}]}
|
||||
@@ -0,0 +1 @@
|
||||
{"nodes": [{"id": "gameenginewithbottest", "label": "GameEngineWithBotTest.scala", "file_type": "code", "source_file": "modules/core/src/test/scala/de/nowchess/chess/engine/GameEngineWithBotTest.scala", "source_location": "L1"}, {"id": "gameenginewithbottest_gameenginewithbottest", "label": "GameEngineWithBotTest", "file_type": "code", "source_file": "modules/core/src/test/scala/de/nowchess/chess/engine/GameEngineWithBotTest.scala", "source_location": "L14"}, {"id": "gameenginewithbottest_ongameevent", "label": "onGameEvent()", "file_type": "code", "source_file": "modules/core/src/test/scala/de/nowchess/chess/engine/GameEngineWithBotTest.scala", "source_location": "L29"}], "edges": [{"source": "gameenginewithbottest", "target": "de", "relation": "imports", "confidence": "EXTRACTED", "source_file": "modules/core/src/test/scala/de/nowchess/chess/engine/GameEngineWithBotTest.scala", "source_location": "L3", "weight": 1.0}, {"source": "gameenginewithbottest", "target": "de", "relation": "imports", "confidence": "EXTRACTED", "source_file": "modules/core/src/test/scala/de/nowchess/chess/engine/GameEngineWithBotTest.scala", "source_location": "L4", "weight": 1.0}, {"source": "gameenginewithbottest", "target": "de", "relation": "imports", "confidence": "EXTRACTED", "source_file": "modules/core/src/test/scala/de/nowchess/chess/engine/GameEngineWithBotTest.scala", "source_location": "L5", "weight": 1.0}, {"source": "gameenginewithbottest", "target": "de", "relation": "imports", "confidence": "EXTRACTED", "source_file": "modules/core/src/test/scala/de/nowchess/chess/engine/GameEngineWithBotTest.scala", "source_location": "L6", "weight": 1.0}, {"source": "gameenginewithbottest", "target": "de", "relation": "imports", "confidence": "EXTRACTED", "source_file": "modules/core/src/test/scala/de/nowchess/chess/engine/GameEngineWithBotTest.scala", "source_location": "L7", "weight": 1.0}, {"source": "gameenginewithbottest", "target": "de", "relation": "imports", "confidence": "EXTRACTED", "source_file": "modules/core/src/test/scala/de/nowchess/chess/engine/GameEngineWithBotTest.scala", "source_location": "L8", "weight": 1.0}, {"source": "gameenginewithbottest", "target": "org", "relation": "imports", "confidence": "EXTRACTED", "source_file": "modules/core/src/test/scala/de/nowchess/chess/engine/GameEngineWithBotTest.scala", "source_location": "L9", "weight": 1.0}, {"source": "gameenginewithbottest", "target": "org", "relation": "imports", "confidence": "EXTRACTED", "source_file": "modules/core/src/test/scala/de/nowchess/chess/engine/GameEngineWithBotTest.scala", "source_location": "L10", "weight": 1.0}, {"source": "gameenginewithbottest", "target": "scala", "relation": "imports", "confidence": "EXTRACTED", "source_file": "modules/core/src/test/scala/de/nowchess/chess/engine/GameEngineWithBotTest.scala", "source_location": "L11", "weight": 1.0}, {"source": "gameenginewithbottest", "target": "scala", "relation": "imports", "confidence": "EXTRACTED", "source_file": "modules/core/src/test/scala/de/nowchess/chess/engine/GameEngineWithBotTest.scala", "source_location": "L12", "weight": 1.0}, {"source": "gameenginewithbottest", "target": "gameenginewithbottest_gameenginewithbottest", "relation": "contains", "confidence": "EXTRACTED", "source_file": "modules/core/src/test/scala/de/nowchess/chess/engine/GameEngineWithBotTest.scala", "source_location": "L14", "weight": 1.0}, {"source": "gameenginewithbottest", "target": "gameenginewithbottest_ongameevent", "relation": "contains", "confidence": "EXTRACTED", "source_file": "modules/core/src/test/scala/de/nowchess/chess/engine/GameEngineWithBotTest.scala", "source_location": "L29", "weight": 1.0}, {"source": "gameenginewithbottest", "target": "gameenginewithbottest_ongameevent", "relation": "contains", "confidence": "EXTRACTED", "source_file": "modules/core/src/test/scala/de/nowchess/chess/engine/GameEngineWithBotTest.scala", "source_location": "L75", "weight": 1.0}, {"source": "gameenginewithbottest", "target": "gameenginewithbottest_ongameevent", "relation": "contains", "confidence": "EXTRACTED", "source_file": "modules/core/src/test/scala/de/nowchess/chess/engine/GameEngineWithBotTest.scala", "source_location": "L99", "weight": 1.0}]}
|
||||
@@ -0,0 +1 @@
|
||||
{"nodes": [{"id": "botdifficultytest", "label": "BotDifficultyTest.scala", "file_type": "code", "source_file": "modules/bot/src/test/scala/de/nowchess/bot/BotDifficultyTest.scala", "source_location": "L1"}, {"id": "botdifficultytest_botdifficultytest", "label": "BotDifficultyTest", "file_type": "code", "source_file": "modules/bot/src/test/scala/de/nowchess/bot/BotDifficultyTest.scala", "source_location": "L6"}], "edges": [{"source": "botdifficultytest", "target": "org", "relation": "imports", "confidence": "EXTRACTED", "source_file": "modules/bot/src/test/scala/de/nowchess/bot/BotDifficultyTest.scala", "source_location": "L3", "weight": 1.0}, {"source": "botdifficultytest", "target": "org", "relation": "imports", "confidence": "EXTRACTED", "source_file": "modules/bot/src/test/scala/de/nowchess/bot/BotDifficultyTest.scala", "source_location": "L4", "weight": 1.0}, {"source": "botdifficultytest", "target": "botdifficultytest_botdifficultytest", "relation": "contains", "confidence": "EXTRACTED", "source_file": "modules/bot/src/test/scala/de/nowchess/bot/BotDifficultyTest.scala", "source_location": "L6", "weight": 1.0}]}
|
||||
@@ -0,0 +1 @@
|
||||
{"nodes": [{"id": "gameengineloadgametest", "label": "GameEngineLoadGameTest.scala", "file_type": "code", "source_file": "modules/core/src/test/scala/de/nowchess/chess/engine/GameEngineLoadGameTest.scala", "source_location": "L1"}, {"id": "gameengineloadgametest_gameengineloadgametest", "label": "GameEngineLoadGameTest", "file_type": "code", "source_file": "modules/core/src/test/scala/de/nowchess/chess/engine/GameEngineLoadGameTest.scala", "source_location": "L14"}, {"id": "gameengineloadgametest_mockobserver", "label": "MockObserver", "file_type": "code", "source_file": "modules/core/src/test/scala/de/nowchess/chess/engine/GameEngineLoadGameTest.scala", "source_location": "L40"}, {"id": "gameengineloadgametest_mockobserver_ongameevent", "label": ".onGameEvent()", "file_type": "code", "source_file": "modules/core/src/test/scala/de/nowchess/chess/engine/GameEngineLoadGameTest.scala", "source_location": "L42"}], "edges": [{"source": "gameengineloadgametest", "target": "scala", "relation": "imports", "confidence": "EXTRACTED", "source_file": "modules/core/src/test/scala/de/nowchess/chess/engine/GameEngineLoadGameTest.scala", "source_location": "L3", "weight": 1.0}, {"source": "gameengineloadgametest", "target": "de", "relation": "imports", "confidence": "EXTRACTED", "source_file": "modules/core/src/test/scala/de/nowchess/chess/engine/GameEngineLoadGameTest.scala", "source_location": "L4", "weight": 1.0}, {"source": "gameengineloadgametest", "target": "de", "relation": "imports", "confidence": "EXTRACTED", "source_file": "modules/core/src/test/scala/de/nowchess/chess/engine/GameEngineLoadGameTest.scala", "source_location": "L5", "weight": 1.0}, {"source": "gameengineloadgametest", "target": "de", "relation": "imports", "confidence": "EXTRACTED", "source_file": "modules/core/src/test/scala/de/nowchess/chess/engine/GameEngineLoadGameTest.scala", "source_location": "L6", "weight": 1.0}, {"source": "gameengineloadgametest", "target": "de", "relation": "imports", "confidence": "EXTRACTED", "source_file": "modules/core/src/test/scala/de/nowchess/chess/engine/GameEngineLoadGameTest.scala", "source_location": "L7", "weight": 1.0}, {"source": "gameengineloadgametest", "target": "de", "relation": "imports", "confidence": "EXTRACTED", "source_file": "modules/core/src/test/scala/de/nowchess/chess/engine/GameEngineLoadGameTest.scala", "source_location": "L8", "weight": 1.0}, {"source": "gameengineloadgametest", "target": "de", "relation": "imports", "confidence": "EXTRACTED", "source_file": "modules/core/src/test/scala/de/nowchess/chess/engine/GameEngineLoadGameTest.scala", "source_location": "L9", "weight": 1.0}, {"source": "gameengineloadgametest", "target": "de", "relation": "imports", "confidence": "EXTRACTED", "source_file": "modules/core/src/test/scala/de/nowchess/chess/engine/GameEngineLoadGameTest.scala", "source_location": "L10", "weight": 1.0}, {"source": "gameengineloadgametest", "target": "org", "relation": "imports", "confidence": "EXTRACTED", "source_file": "modules/core/src/test/scala/de/nowchess/chess/engine/GameEngineLoadGameTest.scala", "source_location": "L11", "weight": 1.0}, {"source": "gameengineloadgametest", "target": "org", "relation": "imports", "confidence": "EXTRACTED", "source_file": "modules/core/src/test/scala/de/nowchess/chess/engine/GameEngineLoadGameTest.scala", "source_location": "L12", "weight": 1.0}, {"source": "gameengineloadgametest", "target": "gameengineloadgametest_gameengineloadgametest", "relation": "contains", "confidence": "EXTRACTED", "source_file": "modules/core/src/test/scala/de/nowchess/chess/engine/GameEngineLoadGameTest.scala", "source_location": "L14", "weight": 1.0}, {"source": "gameengineloadgametest", "target": "gameengineloadgametest_mockobserver", "relation": "contains", "confidence": "EXTRACTED", "source_file": "modules/core/src/test/scala/de/nowchess/chess/engine/GameEngineLoadGameTest.scala", "source_location": "L40", "weight": 1.0}, {"source": "gameengineloadgametest_mockobserver", "target": "gameengineloadgametest_mockobserver_ongameevent", "relation": "method", "confidence": "EXTRACTED", "source_file": "modules/core/src/test/scala/de/nowchess/chess/engine/GameEngineLoadGameTest.scala", "source_location": "L42", "weight": 1.0}]}
|
||||
@@ -0,0 +1 @@
|
||||
{"nodes": [{"id": "gamecontextimport", "label": "GameContextImport.scala", "file_type": "code", "source_file": "modules/io/src/main/scala/de/nowchess/io/GameContextImport.scala", "source_location": "L1"}], "edges": [{"source": "gamecontextimport", "target": "de", "relation": "imports", "confidence": "EXTRACTED", "source_file": "modules/io/src/main/scala/de/nowchess/io/GameContextImport.scala", "source_location": "L3", "weight": 1.0}]}
|
||||
@@ -0,0 +1 @@
|
||||
{"nodes": [{"id": "settings_gradle", "label": "settings.gradle.kts", "file_type": "code", "source_file": "settings.gradle.kts", "source_location": "L1"}], "edges": []}
|
||||