feat: Implement threefold repetition detection and update game rules
Build & Test (NowChessSystems) TeamCity build failed
Build & Test (NowChessSystems) TeamCity build failed
This commit is contained in:
@@ -45,6 +45,3 @@ graphify-out/
|
||||
.DS_Store
|
||||
/jacoco-reporter/.venv/
|
||||
/.claude/settings.local.json
|
||||
/modules/bot/python/.venv/
|
||||
/modules/bot/python/positions.txt
|
||||
/modules/bot/python/training_data.jsonl
|
||||
|
||||
@@ -1,9 +0,0 @@
|
||||
Build a Scala 3 chess engine with these files: CoreTypes.scala, BitboardUtils.scala, MagicBitboards.scala, AttackTables.scala, GameState.scala, MoveGenerator.scala, ZobristHash.scala, AlphaBetaSearch.scala, Evaluation.scala, UciEngine.scala.
|
||||
|
||||
Requirements:
|
||||
|
||||
Use bitboards and magic bitboards for sliding pieces.
|
||||
Implement negamax alpha-beta search with transposition table, quiescence search, and MVV-LVA move ordering.
|
||||
Maintain Zobrist hashing for positions.
|
||||
Separate concerns: move generation, evaluation, search, and UCI handling.
|
||||
Produce a functional, efficient UCI engine in idiomatic Scala 3.
|
||||
@@ -1,923 +0,0 @@
|
||||
# Graph Report - . (2026-04-13)
|
||||
|
||||
## Corpus Check
|
||||
- 132 files · ~24,046,508 words
|
||||
- Verdict: corpus is large enough that graph structure adds value.
|
||||
|
||||
## Summary
|
||||
- 899 nodes · 1116 edges · 146 communities detected
|
||||
- Extraction: 100% EXTRACTED · 0% INFERRED · 0% AMBIGUOUS
|
||||
- Token cost: 0 input · 0 output
|
||||
|
||||
## Community Hubs (Navigation)
|
||||
- [[_COMMUNITY_Community 0|Community 0]]
|
||||
- [[_COMMUNITY_Community 1|Community 1]]
|
||||
- [[_COMMUNITY_Community 2|Community 2]]
|
||||
- [[_COMMUNITY_Community 3|Community 3]]
|
||||
- [[_COMMUNITY_Community 4|Community 4]]
|
||||
- [[_COMMUNITY_Community 5|Community 5]]
|
||||
- [[_COMMUNITY_Community 6|Community 6]]
|
||||
- [[_COMMUNITY_Community 7|Community 7]]
|
||||
- [[_COMMUNITY_Community 8|Community 8]]
|
||||
- [[_COMMUNITY_Community 9|Community 9]]
|
||||
- [[_COMMUNITY_Community 10|Community 10]]
|
||||
- [[_COMMUNITY_Community 11|Community 11]]
|
||||
- [[_COMMUNITY_Community 12|Community 12]]
|
||||
- [[_COMMUNITY_Community 13|Community 13]]
|
||||
- [[_COMMUNITY_Community 14|Community 14]]
|
||||
- [[_COMMUNITY_Community 15|Community 15]]
|
||||
- [[_COMMUNITY_Community 16|Community 16]]
|
||||
- [[_COMMUNITY_Community 17|Community 17]]
|
||||
- [[_COMMUNITY_Community 18|Community 18]]
|
||||
- [[_COMMUNITY_Community 19|Community 19]]
|
||||
- [[_COMMUNITY_Community 20|Community 20]]
|
||||
- [[_COMMUNITY_Community 21|Community 21]]
|
||||
- [[_COMMUNITY_Community 22|Community 22]]
|
||||
- [[_COMMUNITY_Community 23|Community 23]]
|
||||
- [[_COMMUNITY_Community 24|Community 24]]
|
||||
- [[_COMMUNITY_Community 25|Community 25]]
|
||||
- [[_COMMUNITY_Community 26|Community 26]]
|
||||
- [[_COMMUNITY_Community 27|Community 27]]
|
||||
- [[_COMMUNITY_Community 28|Community 28]]
|
||||
- [[_COMMUNITY_Community 29|Community 29]]
|
||||
- [[_COMMUNITY_Community 30|Community 30]]
|
||||
- [[_COMMUNITY_Community 31|Community 31]]
|
||||
- [[_COMMUNITY_Community 32|Community 32]]
|
||||
- [[_COMMUNITY_Community 33|Community 33]]
|
||||
- [[_COMMUNITY_Community 34|Community 34]]
|
||||
- [[_COMMUNITY_Community 35|Community 35]]
|
||||
- [[_COMMUNITY_Community 36|Community 36]]
|
||||
- [[_COMMUNITY_Community 37|Community 37]]
|
||||
- [[_COMMUNITY_Community 38|Community 38]]
|
||||
- [[_COMMUNITY_Community 39|Community 39]]
|
||||
- [[_COMMUNITY_Community 40|Community 40]]
|
||||
- [[_COMMUNITY_Community 41|Community 41]]
|
||||
- [[_COMMUNITY_Community 42|Community 42]]
|
||||
- [[_COMMUNITY_Community 43|Community 43]]
|
||||
- [[_COMMUNITY_Community 44|Community 44]]
|
||||
- [[_COMMUNITY_Community 45|Community 45]]
|
||||
- [[_COMMUNITY_Community 46|Community 46]]
|
||||
- [[_COMMUNITY_Community 47|Community 47]]
|
||||
- [[_COMMUNITY_Community 48|Community 48]]
|
||||
- [[_COMMUNITY_Community 49|Community 49]]
|
||||
- [[_COMMUNITY_Community 50|Community 50]]
|
||||
- [[_COMMUNITY_Community 51|Community 51]]
|
||||
- [[_COMMUNITY_Community 52|Community 52]]
|
||||
- [[_COMMUNITY_Community 53|Community 53]]
|
||||
- [[_COMMUNITY_Community 54|Community 54]]
|
||||
- [[_COMMUNITY_Community 55|Community 55]]
|
||||
- [[_COMMUNITY_Community 56|Community 56]]
|
||||
- [[_COMMUNITY_Community 57|Community 57]]
|
||||
- [[_COMMUNITY_Community 58|Community 58]]
|
||||
- [[_COMMUNITY_Community 59|Community 59]]
|
||||
- [[_COMMUNITY_Community 60|Community 60]]
|
||||
- [[_COMMUNITY_Community 61|Community 61]]
|
||||
- [[_COMMUNITY_Community 62|Community 62]]
|
||||
- [[_COMMUNITY_Community 63|Community 63]]
|
||||
- [[_COMMUNITY_Community 64|Community 64]]
|
||||
- [[_COMMUNITY_Community 65|Community 65]]
|
||||
- [[_COMMUNITY_Community 66|Community 66]]
|
||||
- [[_COMMUNITY_Community 67|Community 67]]
|
||||
- [[_COMMUNITY_Community 68|Community 68]]
|
||||
- [[_COMMUNITY_Community 69|Community 69]]
|
||||
- [[_COMMUNITY_Community 70|Community 70]]
|
||||
- [[_COMMUNITY_Community 71|Community 71]]
|
||||
- [[_COMMUNITY_Community 72|Community 72]]
|
||||
- [[_COMMUNITY_Community 73|Community 73]]
|
||||
- [[_COMMUNITY_Community 74|Community 74]]
|
||||
- [[_COMMUNITY_Community 75|Community 75]]
|
||||
- [[_COMMUNITY_Community 76|Community 76]]
|
||||
- [[_COMMUNITY_Community 77|Community 77]]
|
||||
- [[_COMMUNITY_Community 78|Community 78]]
|
||||
- [[_COMMUNITY_Community 79|Community 79]]
|
||||
- [[_COMMUNITY_Community 80|Community 80]]
|
||||
- [[_COMMUNITY_Community 81|Community 81]]
|
||||
- [[_COMMUNITY_Community 82|Community 82]]
|
||||
- [[_COMMUNITY_Community 83|Community 83]]
|
||||
- [[_COMMUNITY_Community 84|Community 84]]
|
||||
- [[_COMMUNITY_Community 85|Community 85]]
|
||||
- [[_COMMUNITY_Community 86|Community 86]]
|
||||
- [[_COMMUNITY_Community 87|Community 87]]
|
||||
- [[_COMMUNITY_Community 88|Community 88]]
|
||||
- [[_COMMUNITY_Community 89|Community 89]]
|
||||
- [[_COMMUNITY_Community 90|Community 90]]
|
||||
- [[_COMMUNITY_Community 91|Community 91]]
|
||||
- [[_COMMUNITY_Community 92|Community 92]]
|
||||
- [[_COMMUNITY_Community 93|Community 93]]
|
||||
- [[_COMMUNITY_Community 94|Community 94]]
|
||||
- [[_COMMUNITY_Community 95|Community 95]]
|
||||
- [[_COMMUNITY_Community 96|Community 96]]
|
||||
- [[_COMMUNITY_Community 97|Community 97]]
|
||||
- [[_COMMUNITY_Community 98|Community 98]]
|
||||
- [[_COMMUNITY_Community 99|Community 99]]
|
||||
- [[_COMMUNITY_Community 100|Community 100]]
|
||||
- [[_COMMUNITY_Community 101|Community 101]]
|
||||
- [[_COMMUNITY_Community 102|Community 102]]
|
||||
- [[_COMMUNITY_Community 103|Community 103]]
|
||||
- [[_COMMUNITY_Community 104|Community 104]]
|
||||
- [[_COMMUNITY_Community 105|Community 105]]
|
||||
- [[_COMMUNITY_Community 106|Community 106]]
|
||||
- [[_COMMUNITY_Community 107|Community 107]]
|
||||
- [[_COMMUNITY_Community 108|Community 108]]
|
||||
- [[_COMMUNITY_Community 109|Community 109]]
|
||||
- [[_COMMUNITY_Community 110|Community 110]]
|
||||
- [[_COMMUNITY_Community 111|Community 111]]
|
||||
- [[_COMMUNITY_Community 112|Community 112]]
|
||||
- [[_COMMUNITY_Community 113|Community 113]]
|
||||
- [[_COMMUNITY_Community 114|Community 114]]
|
||||
- [[_COMMUNITY_Community 115|Community 115]]
|
||||
- [[_COMMUNITY_Community 116|Community 116]]
|
||||
- [[_COMMUNITY_Community 117|Community 117]]
|
||||
- [[_COMMUNITY_Community 118|Community 118]]
|
||||
- [[_COMMUNITY_Community 119|Community 119]]
|
||||
- [[_COMMUNITY_Community 120|Community 120]]
|
||||
- [[_COMMUNITY_Community 121|Community 121]]
|
||||
- [[_COMMUNITY_Community 122|Community 122]]
|
||||
- [[_COMMUNITY_Community 123|Community 123]]
|
||||
- [[_COMMUNITY_Community 124|Community 124]]
|
||||
- [[_COMMUNITY_Community 125|Community 125]]
|
||||
- [[_COMMUNITY_Community 126|Community 126]]
|
||||
- [[_COMMUNITY_Community 127|Community 127]]
|
||||
- [[_COMMUNITY_Community 128|Community 128]]
|
||||
- [[_COMMUNITY_Community 129|Community 129]]
|
||||
- [[_COMMUNITY_Community 130|Community 130]]
|
||||
- [[_COMMUNITY_Community 131|Community 131]]
|
||||
- [[_COMMUNITY_Community 132|Community 132]]
|
||||
- [[_COMMUNITY_Community 133|Community 133]]
|
||||
- [[_COMMUNITY_Community 134|Community 134]]
|
||||
- [[_COMMUNITY_Community 135|Community 135]]
|
||||
- [[_COMMUNITY_Community 136|Community 136]]
|
||||
- [[_COMMUNITY_Community 137|Community 137]]
|
||||
- [[_COMMUNITY_Community 138|Community 138]]
|
||||
- [[_COMMUNITY_Community 139|Community 139]]
|
||||
- [[_COMMUNITY_Community 140|Community 140]]
|
||||
- [[_COMMUNITY_Community 141|Community 141]]
|
||||
- [[_COMMUNITY_Community 142|Community 142]]
|
||||
- [[_COMMUNITY_Community 143|Community 143]]
|
||||
- [[_COMMUNITY_Community 144|Community 144]]
|
||||
- [[_COMMUNITY_Community 145|Community 145]]
|
||||
|
||||
## God Nodes (most connected - your core abstractions)
|
||||
1. `DefaultRules` - 35 edges
|
||||
2. `GameEngine` - 34 edges
|
||||
3. `NNUE` - 23 edges
|
||||
4. `EvaluationClassic` - 21 edges
|
||||
5. `MoveOrdering` - 21 edges
|
||||
6. `ChessBoardView` - 19 edges
|
||||
7. `FenParserFastParse` - 17 edges
|
||||
8. `FenParserCombinators` - 16 edges
|
||||
9. `PgnParser` - 14 edges
|
||||
10. `JsonExporter` - 13 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.1
|
||||
Nodes (2): GameEngine, PendingPromotion
|
||||
|
||||
### Community 2 - "Community 2"
|
||||
Cohesion: 0.09
|
||||
Nodes (17): ClassGap, _compact_ranges(), _find_scoverage_xml(), format_agent(), format_json(), format_markdown(), format_module_gaps(), main() (+9 more)
|
||||
|
||||
### Community 3 - "Community 3"
|
||||
Cohesion: 0.13
|
||||
Nodes (30): burst_train_interactive(), create_dataset_interactive(), datasets_menu(), delete_dataset_interactive(), export_interactive(), extend_dataset_interactive(), get_data_dir(), get_weights_dir() (+22 more)
|
||||
|
||||
### Community 4 - "Community 4"
|
||||
Cohesion: 0.14
|
||||
Nodes (2): MoveOrdering, OrderingContext
|
||||
|
||||
### Community 5 - "Community 5"
|
||||
Cohesion: 0.11
|
||||
Nodes (21): Dataset, burst_train(), fen_to_features(), find_next_version(), NNUE, NNUEDataset, Find the next version number for model versioning. Looks for nnue_weights_v, Save training metadata alongside the weights file. Args: weights_fi (+13 more)
|
||||
|
||||
### Community 6 - "Community 6"
|
||||
Cohesion: 0.23
|
||||
Nodes (1): NNUE
|
||||
|
||||
### Community 7 - "Community 7"
|
||||
Cohesion: 0.19
|
||||
Nodes (1): EvaluationClassic
|
||||
|
||||
### Community 8 - "Community 8"
|
||||
Cohesion: 0.15
|
||||
Nodes (20): create_dataset(), delete_dataset(), extend_dataset(), get_dataset_labeled_path(), get_datasets_dir(), list_datasets(), load_dataset_metadata(), next_dataset_version() (+12 more)
|
||||
|
||||
### Community 9 - "Community 9"
|
||||
Cohesion: 0.14
|
||||
Nodes (9): format_module(), load_module(), main(), ModuleResult, parse_suite_xml(), run(), SuiteResult, TestCase (+1 more)
|
||||
|
||||
### Community 10 - "Community 10"
|
||||
Cohesion: 0.18
|
||||
Nodes (1): ChessBoardView
|
||||
|
||||
### Community 11 - "Community 11"
|
||||
Cohesion: 0.14
|
||||
Nodes (1): FenParserFastParse
|
||||
|
||||
### Community 12 - "Community 12"
|
||||
Cohesion: 0.12
|
||||
Nodes (7): InvalidFormat, InvalidMove, MoveCommand, MoveResult, QuitCommand, ResetCommand, Successful
|
||||
|
||||
### Community 13 - "Community 13"
|
||||
Cohesion: 0.12
|
||||
Nodes (12): BoardResetEvent, CheckDetectedEvent, CheckmateEvent, DrawClaimedEvent, FiftyMoveRuleAvailableEvent, InvalidMoveEvent, MoveExecutedEvent, MoveRedoneEvent (+4 more)
|
||||
|
||||
### Community 14 - "Community 14"
|
||||
Cohesion: 0.13
|
||||
Nodes (1): FenParserCombinators
|
||||
|
||||
### Community 15 - "Community 15"
|
||||
Cohesion: 0.26
|
||||
Nodes (2): PgnGame, PgnParser
|
||||
|
||||
### Community 16 - "Community 16"
|
||||
Cohesion: 0.15
|
||||
Nodes (3): candidateMoves(), GameEngineIntegrationTest, legalMoves()
|
||||
|
||||
### Community 17 - "Community 17"
|
||||
Cohesion: 0.14
|
||||
Nodes (3): CommandInvokerBranchTest, ConditionalFailCommand, FailingCommand
|
||||
|
||||
### Community 18 - "Community 18"
|
||||
Cohesion: 0.14
|
||||
Nodes (1): GameEnginePromotionTest
|
||||
|
||||
### Community 19 - "Community 19"
|
||||
Cohesion: 0.25
|
||||
Nodes (1): JsonExporter
|
||||
|
||||
### Community 20 - "Community 20"
|
||||
Cohesion: 0.21
|
||||
Nodes (12): download_and_extract_puzzle_db(), extract_puzzle_positions(), extract_tactical_only(), interactive_merge_positions(), load_positions_from_file(), merge_positions(), Load positions from a text file (one FEN per line)., Merge two position sets and write to file. (+4 more)
|
||||
|
||||
### Community 21 - "Community 21"
|
||||
Cohesion: 0.24
|
||||
Nodes (1): AlphaBetaSearch
|
||||
|
||||
### Community 22 - "Community 22"
|
||||
Cohesion: 0.15
|
||||
Nodes (2): EngineTestHelpers, MockObserver
|
||||
|
||||
### Community 23 - "Community 23"
|
||||
Cohesion: 0.33
|
||||
Nodes (1): ZobristHash
|
||||
|
||||
### Community 24 - "Community 24"
|
||||
Cohesion: 0.18
|
||||
Nodes (1): AlphaBetaSearchTest
|
||||
|
||||
### Community 25 - "Community 25"
|
||||
Cohesion: 0.18
|
||||
Nodes (1): ClassicalBotTest
|
||||
|
||||
### Community 26 - "Community 26"
|
||||
Cohesion: 0.33
|
||||
Nodes (2): BookEntry, PolyglotBook
|
||||
|
||||
### Community 27 - "Community 27"
|
||||
Cohesion: 0.22
|
||||
Nodes (1): CommandInvoker
|
||||
|
||||
### Community 28 - "Community 28"
|
||||
Cohesion: 0.36
|
||||
Nodes (1): FenParser
|
||||
|
||||
### Community 29 - "Community 29"
|
||||
Cohesion: 0.31
|
||||
Nodes (1): JsonParser
|
||||
|
||||
### Community 30 - "Community 30"
|
||||
Cohesion: 0.31
|
||||
Nodes (5): applyMove(), Board, removed(), updated(), withMove()
|
||||
|
||||
### Community 31 - "Community 31"
|
||||
Cohesion: 0.22
|
||||
Nodes (1): GameContext
|
||||
|
||||
### Community 32 - "Community 32"
|
||||
Cohesion: 0.25
|
||||
Nodes (6): ApiError, ApiResponse, Failure, PagedResponse, Pagination, Success
|
||||
|
||||
### Community 33 - "Community 33"
|
||||
Cohesion: 0.39
|
||||
Nodes (1): NbaiLoader
|
||||
|
||||
### Community 34 - "Community 34"
|
||||
Cohesion: 0.22
|
||||
Nodes (8): JsonCapturedPieces, JsonCastlingRights, JsonGameRecord, JsonGameState, JsonMetadata, JsonMove, JsonMoveType, JsonPiece
|
||||
|
||||
### Community 35 - "Community 35"
|
||||
Cohesion: 0.46
|
||||
Nodes (1): NbaiWriter
|
||||
|
||||
### Community 36 - "Community 36"
|
||||
Cohesion: 0.43
|
||||
Nodes (1): FenExporter
|
||||
|
||||
### Community 37 - "Community 37"
|
||||
Cohesion: 0.29
|
||||
Nodes (1): CastlingRights
|
||||
|
||||
### Community 38 - "Community 38"
|
||||
Cohesion: 0.33
|
||||
Nodes (6): _evaluate_fen_batch(), label_positions_with_stockfish(), normalize_evaluation(), Normalize centipawn evaluation to a bounded range. Args: cp_value:, Worker function to evaluate a batch of FENs with Stockfish threading. Args:, Read positions and label them with Stockfish evaluations. Args: pos
|
||||
|
||||
### Community 39 - "Community 39"
|
||||
Cohesion: 0.29
|
||||
Nodes (1): EvaluationNNUE
|
||||
|
||||
### Community 40 - "Community 40"
|
||||
Cohesion: 0.29
|
||||
Nodes (4): LayerDescriptor, LayerWeights, NbaiMetadata, NbaiModel
|
||||
|
||||
### Community 41 - "Community 41"
|
||||
Cohesion: 0.53
|
||||
Nodes (5): export_to_nbai(), _infer_layers(), Derive layer descriptors from state_dict weight shapes. Assumes layers name, _read_sidecar(), _write_floats()
|
||||
|
||||
### Community 42 - "Community 42"
|
||||
Cohesion: 0.53
|
||||
Nodes (1): NbaiMigrator
|
||||
|
||||
### Community 43 - "Community 43"
|
||||
Cohesion: 0.33
|
||||
Nodes (2): TranspositionTable, TTEntry
|
||||
|
||||
### Community 44 - "Community 44"
|
||||
Cohesion: 0.53
|
||||
Nodes (1): PolyglotHash
|
||||
|
||||
### Community 45 - "Community 45"
|
||||
Cohesion: 0.4
|
||||
Nodes (2): ChessGUIApp, ChessGUILauncher
|
||||
|
||||
### Community 46 - "Community 46"
|
||||
Cohesion: 0.5
|
||||
Nodes (2): offset(), Square
|
||||
|
||||
### Community 47 - "Community 47"
|
||||
Cohesion: 0.4
|
||||
Nodes (2): PlayerId, PlayerInfo
|
||||
|
||||
### Community 48 - "Community 48"
|
||||
Cohesion: 0.4
|
||||
Nodes (4): play_random_game_and_collect_positions(), Generate games for one worker. Returns: list of FENs generated by t, Generate positions using multiprocessing with multiple workers. Args:, _worker_generate_games()
|
||||
|
||||
### Community 49 - "Community 49"
|
||||
Cohesion: 0.4
|
||||
Nodes (0):
|
||||
|
||||
### Community 50 - "Community 50"
|
||||
Cohesion: 0.6
|
||||
Nodes (1): NNUEBot
|
||||
|
||||
### Community 51 - "Community 51"
|
||||
Cohesion: 0.4
|
||||
Nodes (3): EmptyToken, FenParserSupport, PieceToken
|
||||
|
||||
### Community 52 - "Community 52"
|
||||
Cohesion: 0.6
|
||||
Nodes (1): PgnExporter
|
||||
|
||||
### Community 53 - "Community 53"
|
||||
Cohesion: 0.5
|
||||
Nodes (2): PieceSprites, SquareColors
|
||||
|
||||
### Community 54 - "Community 54"
|
||||
Cohesion: 0.6
|
||||
Nodes (1): TerminalUI
|
||||
|
||||
### Community 55 - "Community 55"
|
||||
Cohesion: 0.5
|
||||
Nodes (1): BotController
|
||||
|
||||
### Community 56 - "Community 56"
|
||||
Cohesion: 0.67
|
||||
Nodes (1): HybridBot
|
||||
|
||||
### Community 57 - "Community 57"
|
||||
Cohesion: 0.67
|
||||
Nodes (1): Parser
|
||||
|
||||
### Community 58 - "Community 58"
|
||||
Cohesion: 0.5
|
||||
Nodes (1): CommandInvokerTest
|
||||
|
||||
### Community 59 - "Community 59"
|
||||
Cohesion: 0.5
|
||||
Nodes (2): EndingMockObserver, GameEngineGameEndingTest
|
||||
|
||||
### Community 60 - "Community 60"
|
||||
Cohesion: 0.5
|
||||
Nodes (2): GameEngineLoadGameTest, MockObserver
|
||||
|
||||
### Community 61 - "Community 61"
|
||||
Cohesion: 0.5
|
||||
Nodes (1): FileSystemGameService
|
||||
|
||||
### Community 62 - "Community 62"
|
||||
Cohesion: 0.5
|
||||
Nodes (1): DefaultRulesStateTransitionsTest
|
||||
|
||||
### Community 63 - "Community 63"
|
||||
Cohesion: 0.67
|
||||
Nodes (1): GUIObserver
|
||||
|
||||
### Community 64 - "Community 64"
|
||||
Cohesion: 0.67
|
||||
Nodes (0):
|
||||
|
||||
### Community 65 - "Community 65"
|
||||
Cohesion: 0.67
|
||||
Nodes (1): ClassicalBot
|
||||
|
||||
### Community 66 - "Community 66"
|
||||
Cohesion: 0.67
|
||||
Nodes (2): BotParticipant, Human
|
||||
|
||||
### Community 67 - "Community 67"
|
||||
Cohesion: 0.67
|
||||
Nodes (1): MoveCommandTest
|
||||
|
||||
### Community 68 - "Community 68"
|
||||
Cohesion: 0.67
|
||||
Nodes (1): GameEngineNotationTest
|
||||
|
||||
### Community 69 - "Community 69"
|
||||
Cohesion: 0.67
|
||||
Nodes (1): GameEngineWithBotTest
|
||||
|
||||
### Community 70 - "Community 70"
|
||||
Cohesion: 0.67
|
||||
Nodes (1): GameFileServiceSuite
|
||||
|
||||
### Community 71 - "Community 71"
|
||||
Cohesion: 0.67
|
||||
Nodes (1): FenExporterTest
|
||||
|
||||
### Community 72 - "Community 72"
|
||||
Cohesion: 0.67
|
||||
Nodes (1): PgnExporterTest
|
||||
|
||||
### Community 73 - "Community 73"
|
||||
Cohesion: 0.67
|
||||
Nodes (1): Main
|
||||
|
||||
### Community 74 - "Community 74"
|
||||
Cohesion: 0.67
|
||||
Nodes (1): Renderer
|
||||
|
||||
### Community 75 - "Community 75"
|
||||
Cohesion: 1.0
|
||||
Nodes (1): Piece
|
||||
|
||||
### Community 76 - "Community 76"
|
||||
Cohesion: 1.0
|
||||
Nodes (0):
|
||||
|
||||
### Community 77 - "Community 77"
|
||||
Cohesion: 1.0
|
||||
Nodes (1): Move
|
||||
|
||||
### Community 78 - "Community 78"
|
||||
Cohesion: 1.0
|
||||
Nodes (1): BoardTest
|
||||
|
||||
### Community 79 - "Community 79"
|
||||
Cohesion: 1.0
|
||||
Nodes (1): CastlingRightsTest
|
||||
|
||||
### Community 80 - "Community 80"
|
||||
Cohesion: 1.0
|
||||
Nodes (1): ColorTest
|
||||
|
||||
### Community 81 - "Community 81"
|
||||
Cohesion: 1.0
|
||||
Nodes (1): PieceTest
|
||||
|
||||
### Community 82 - "Community 82"
|
||||
Cohesion: 1.0
|
||||
Nodes (1): PieceTypeTest
|
||||
|
||||
### Community 83 - "Community 83"
|
||||
Cohesion: 1.0
|
||||
Nodes (1): SquareTest
|
||||
|
||||
### Community 84 - "Community 84"
|
||||
Cohesion: 1.0
|
||||
Nodes (1): GameContextTest
|
||||
|
||||
### Community 85 - "Community 85"
|
||||
Cohesion: 1.0
|
||||
Nodes (1): MoveTest
|
||||
|
||||
### Community 86 - "Community 86"
|
||||
Cohesion: 1.0
|
||||
Nodes (1): PlayerInfoTest
|
||||
|
||||
### Community 87 - "Community 87"
|
||||
Cohesion: 1.0
|
||||
Nodes (1): ApiResponseTest
|
||||
|
||||
### Community 88 - "Community 88"
|
||||
Cohesion: 1.0
|
||||
Nodes (1): Config
|
||||
|
||||
### Community 89 - "Community 89"
|
||||
Cohesion: 1.0
|
||||
Nodes (1): BotControllerTest
|
||||
|
||||
### Community 90 - "Community 90"
|
||||
Cohesion: 1.0
|
||||
Nodes (1): BotDifficultyTest
|
||||
|
||||
### Community 91 - "Community 91"
|
||||
Cohesion: 1.0
|
||||
Nodes (1): EvaluationTest
|
||||
|
||||
### Community 92 - "Community 92"
|
||||
Cohesion: 1.0
|
||||
Nodes (1): MoveOrderingTest
|
||||
|
||||
### Community 93 - "Community 93"
|
||||
Cohesion: 1.0
|
||||
Nodes (1): PolyglotBookTest
|
||||
|
||||
### Community 94 - "Community 94"
|
||||
Cohesion: 1.0
|
||||
Nodes (1): PolyglotHashTest
|
||||
|
||||
### Community 95 - "Community 95"
|
||||
Cohesion: 1.0
|
||||
Nodes (1): TranspositionTableTest
|
||||
|
||||
### Community 96 - "Community 96"
|
||||
Cohesion: 1.0
|
||||
Nodes (1): ZobristHashTest
|
||||
|
||||
### Community 97 - "Community 97"
|
||||
Cohesion: 1.0
|
||||
Nodes (1): CommandTest
|
||||
|
||||
### Community 98 - "Community 98"
|
||||
Cohesion: 1.0
|
||||
Nodes (1): ParserTest
|
||||
|
||||
### Community 99 - "Community 99"
|
||||
Cohesion: 1.0
|
||||
Nodes (1): GameEngineOutcomesTest
|
||||
|
||||
### Community 100 - "Community 100"
|
||||
Cohesion: 1.0
|
||||
Nodes (1): GameEngineScenarioTest
|
||||
|
||||
### Community 101 - "Community 101"
|
||||
Cohesion: 1.0
|
||||
Nodes (1): GameEngineSpecialMovesTest
|
||||
|
||||
### Community 102 - "Community 102"
|
||||
Cohesion: 1.0
|
||||
Nodes (1): FenParserCombinatorsTest
|
||||
|
||||
### Community 103 - "Community 103"
|
||||
Cohesion: 1.0
|
||||
Nodes (1): FenParserFastParseTest
|
||||
|
||||
### Community 104 - "Community 104"
|
||||
Cohesion: 1.0
|
||||
Nodes (1): FenParserTest
|
||||
|
||||
### Community 105 - "Community 105"
|
||||
Cohesion: 1.0
|
||||
Nodes (1): JsonExporterBranchCoverageSuite
|
||||
|
||||
### Community 106 - "Community 106"
|
||||
Cohesion: 1.0
|
||||
Nodes (1): JsonExporterSuite
|
||||
|
||||
### Community 107 - "Community 107"
|
||||
Cohesion: 1.0
|
||||
Nodes (1): JsonModelExtraTestSuite
|
||||
|
||||
### Community 108 - "Community 108"
|
||||
Cohesion: 1.0
|
||||
Nodes (1): JsonParserEdgeCasesSuite
|
||||
|
||||
### Community 109 - "Community 109"
|
||||
Cohesion: 1.0
|
||||
Nodes (1): JsonParserErrorHandlingSuite
|
||||
|
||||
### Community 110 - "Community 110"
|
||||
Cohesion: 1.0
|
||||
Nodes (1): JsonParserMoveTypeSuite
|
||||
|
||||
### Community 111 - "Community 111"
|
||||
Cohesion: 1.0
|
||||
Nodes (1): JsonParserSuite
|
||||
|
||||
### Community 112 - "Community 112"
|
||||
Cohesion: 1.0
|
||||
Nodes (1): PgnParserTest
|
||||
|
||||
### Community 113 - "Community 113"
|
||||
Cohesion: 1.0
|
||||
Nodes (1): PgnValidatorTest
|
||||
|
||||
### Community 114 - "Community 114"
|
||||
Cohesion: 1.0
|
||||
Nodes (1): DefaultRulesTest
|
||||
|
||||
### Community 115 - "Community 115"
|
||||
Cohesion: 1.0
|
||||
Nodes (0):
|
||||
|
||||
### Community 116 - "Community 116"
|
||||
Cohesion: 1.0
|
||||
Nodes (1): RendererAndUnicodeTest
|
||||
|
||||
### Community 117 - "Community 117"
|
||||
Cohesion: 1.0
|
||||
Nodes (0):
|
||||
|
||||
### Community 118 - "Community 118"
|
||||
Cohesion: 1.0
|
||||
Nodes (0):
|
||||
|
||||
### Community 119 - "Community 119"
|
||||
Cohesion: 1.0
|
||||
Nodes (1): Strip the package prefix from the full method path.
|
||||
|
||||
### Community 120 - "Community 120"
|
||||
Cohesion: 1.0
|
||||
Nodes (1): Lines that are branch points and have at least one uncovered branch statement.
|
||||
|
||||
### Community 121 - "Community 121"
|
||||
Cohesion: 1.0
|
||||
Nodes (0):
|
||||
|
||||
### Community 122 - "Community 122"
|
||||
Cohesion: 1.0
|
||||
Nodes (0):
|
||||
|
||||
### Community 123 - "Community 123"
|
||||
Cohesion: 1.0
|
||||
Nodes (0):
|
||||
|
||||
### Community 124 - "Community 124"
|
||||
Cohesion: 1.0
|
||||
Nodes (0):
|
||||
|
||||
### Community 125 - "Community 125"
|
||||
Cohesion: 1.0
|
||||
Nodes (0):
|
||||
|
||||
### Community 126 - "Community 126"
|
||||
Cohesion: 1.0
|
||||
Nodes (0):
|
||||
|
||||
### Community 127 - "Community 127"
|
||||
Cohesion: 1.0
|
||||
Nodes (0):
|
||||
|
||||
### Community 128 - "Community 128"
|
||||
Cohesion: 1.0
|
||||
Nodes (0):
|
||||
|
||||
### Community 129 - "Community 129"
|
||||
Cohesion: 1.0
|
||||
Nodes (0):
|
||||
|
||||
### Community 130 - "Community 130"
|
||||
Cohesion: 1.0
|
||||
Nodes (0):
|
||||
|
||||
### Community 131 - "Community 131"
|
||||
Cohesion: 1.0
|
||||
Nodes (0):
|
||||
|
||||
### Community 132 - "Community 132"
|
||||
Cohesion: 1.0
|
||||
Nodes (0):
|
||||
|
||||
### Community 133 - "Community 133"
|
||||
Cohesion: 1.0
|
||||
Nodes (0):
|
||||
|
||||
### Community 134 - "Community 134"
|
||||
Cohesion: 1.0
|
||||
Nodes (1): Get/create data directory.
|
||||
|
||||
### Community 135 - "Community 135"
|
||||
Cohesion: 1.0
|
||||
Nodes (1): Get/create data directory.
|
||||
|
||||
### Community 136 - "Community 136"
|
||||
Cohesion: 1.0
|
||||
Nodes (1): Get/create weights directory.
|
||||
|
||||
### Community 137 - "Community 137"
|
||||
Cohesion: 1.0
|
||||
Nodes (1): List available checkpoint versions.
|
||||
|
||||
### Community 138 - "Community 138"
|
||||
Cohesion: 1.0
|
||||
Nodes (1): Display application header.
|
||||
|
||||
### Community 139 - "Community 139"
|
||||
Cohesion: 1.0
|
||||
Nodes (1): Display available checkpoints in a table.
|
||||
|
||||
### Community 140 - "Community 140"
|
||||
Cohesion: 1.0
|
||||
Nodes (1): Display and handle main menu.
|
||||
|
||||
### Community 141 - "Community 141"
|
||||
Cohesion: 1.0
|
||||
Nodes (1): Interactive training menu.
|
||||
|
||||
### Community 142 - "Community 142"
|
||||
Cohesion: 1.0
|
||||
Nodes (1): Interactive burst training menu.
|
||||
|
||||
### Community 143 - "Community 143"
|
||||
Cohesion: 1.0
|
||||
Nodes (1): Interactive export menu.
|
||||
|
||||
### Community 144 - "Community 144"
|
||||
Cohesion: 1.0
|
||||
Nodes (1): Interactive tactical positions extraction and merge menu.
|
||||
|
||||
### Community 145 - "Community 145"
|
||||
Cohesion: 1.0
|
||||
Nodes (1): Load PyTorch weights and export as binary file.
|
||||
|
||||
## Knowledge Gaps
|
||||
- **147 isolated node(s):** `Strip the package prefix from the full method path.`, `Lines that are branch points and have at least one uncovered branch statement.`, `[1,2,3,5,7,8,9] → '1-3, 5, 7-9`, `Compact agent format — optimised for low token count. Emits only actionable`, `Return the first scoverage.xml found inside *module_dir*, or None.` (+142 more)
|
||||
These have ≤1 connection - possible missing edges or undocumented components.
|
||||
- **Thin community `Community 75`** (2 nodes): `Piece.scala`, `Piece`
|
||||
Too small to be a meaningful cluster - may be noise or needs more connections extracted.
|
||||
- **Thin community `Community 76`** (2 nodes): `PieceType.scala`, `label()`
|
||||
Too small to be a meaningful cluster - may be noise or needs more connections extracted.
|
||||
- **Thin community `Community 77`** (2 nodes): `Move.scala`, `Move`
|
||||
Too small to be a meaningful cluster - may be noise or needs more connections extracted.
|
||||
- **Thin community `Community 78`** (2 nodes): `BoardTest`, `BoardTest.scala`
|
||||
Too small to be a meaningful cluster - may be noise or needs more connections extracted.
|
||||
- **Thin community `Community 79`** (2 nodes): `CastlingRightsTest`, `CastlingRightsTest.scala`
|
||||
Too small to be a meaningful cluster - may be noise or needs more connections extracted.
|
||||
- **Thin community `Community 80`** (2 nodes): `ColorTest`, `ColorTest.scala`
|
||||
Too small to be a meaningful cluster - may be noise or needs more connections extracted.
|
||||
- **Thin community `Community 81`** (2 nodes): `PieceTest.scala`, `PieceTest`
|
||||
Too small to be a meaningful cluster - may be noise or needs more connections extracted.
|
||||
- **Thin community `Community 82`** (2 nodes): `PieceTypeTest.scala`, `PieceTypeTest`
|
||||
Too small to be a meaningful cluster - may be noise or needs more connections extracted.
|
||||
- **Thin community `Community 83`** (2 nodes): `SquareTest.scala`, `SquareTest`
|
||||
Too small to be a meaningful cluster - may be noise or needs more connections extracted.
|
||||
- **Thin community `Community 84`** (2 nodes): `GameContextTest`, `GameContextTest.scala`
|
||||
Too small to be a meaningful cluster - may be noise or needs more connections extracted.
|
||||
- **Thin community `Community 85`** (2 nodes): `MoveTest.scala`, `MoveTest`
|
||||
Too small to be a meaningful cluster - may be noise or needs more connections extracted.
|
||||
- **Thin community `Community 86`** (2 nodes): `PlayerInfoTest.scala`, `PlayerInfoTest`
|
||||
Too small to be a meaningful cluster - may be noise or needs more connections extracted.
|
||||
- **Thin community `Community 87`** (2 nodes): `ApiResponseTest`, `ApiResponseTest.scala`
|
||||
Too small to be a meaningful cluster - may be noise or needs more connections extracted.
|
||||
- **Thin community `Community 88`** (2 nodes): `Config`, `Config.scala`
|
||||
Too small to be a meaningful cluster - may be noise or needs more connections extracted.
|
||||
- **Thin community `Community 89`** (2 nodes): `BotControllerTest`, `BotControllerTest.scala`
|
||||
Too small to be a meaningful cluster - may be noise or needs more connections extracted.
|
||||
- **Thin community `Community 90`** (2 nodes): `BotDifficultyTest`, `BotDifficultyTest.scala`
|
||||
Too small to be a meaningful cluster - may be noise or needs more connections extracted.
|
||||
- **Thin community `Community 91`** (2 nodes): `EvaluationTest`, `EvaluationTest.scala`
|
||||
Too small to be a meaningful cluster - may be noise or needs more connections extracted.
|
||||
- **Thin community `Community 92`** (2 nodes): `MoveOrderingTest.scala`, `MoveOrderingTest`
|
||||
Too small to be a meaningful cluster - may be noise or needs more connections extracted.
|
||||
- **Thin community `Community 93`** (2 nodes): `PolyglotBookTest.scala`, `PolyglotBookTest`
|
||||
Too small to be a meaningful cluster - may be noise or needs more connections extracted.
|
||||
- **Thin community `Community 94`** (2 nodes): `PolyglotHashTest.scala`, `PolyglotHashTest`
|
||||
Too small to be a meaningful cluster - may be noise or needs more connections extracted.
|
||||
- **Thin community `Community 95`** (2 nodes): `TranspositionTableTest.scala`, `TranspositionTableTest`
|
||||
Too small to be a meaningful cluster - may be noise or needs more connections extracted.
|
||||
- **Thin community `Community 96`** (2 nodes): `ZobristHashTest.scala`, `ZobristHashTest`
|
||||
Too small to be a meaningful cluster - may be noise or needs more connections extracted.
|
||||
- **Thin community `Community 97`** (2 nodes): `CommandTest`, `CommandTest.scala`
|
||||
Too small to be a meaningful cluster - may be noise or needs more connections extracted.
|
||||
- **Thin community `Community 98`** (2 nodes): `ParserTest.scala`, `ParserTest`
|
||||
Too small to be a meaningful cluster - may be noise or needs more connections extracted.
|
||||
- **Thin community `Community 99`** (2 nodes): `GameEngineOutcomesTest`, `GameEngineOutcomesTest.scala`
|
||||
Too small to be a meaningful cluster - may be noise or needs more connections extracted.
|
||||
- **Thin community `Community 100`** (2 nodes): `GameEngineScenarioTest`, `GameEngineScenarioTest.scala`
|
||||
Too small to be a meaningful cluster - may be noise or needs more connections extracted.
|
||||
- **Thin community `Community 101`** (2 nodes): `GameEngineSpecialMovesTest`, `GameEngineSpecialMovesTest.scala`
|
||||
Too small to be a meaningful cluster - may be noise or needs more connections extracted.
|
||||
- **Thin community `Community 102`** (2 nodes): `FenParserCombinatorsTest`, `FenParserCombinatorsTest.scala`
|
||||
Too small to be a meaningful cluster - may be noise or needs more connections extracted.
|
||||
- **Thin community `Community 103`** (2 nodes): `FenParserFastParseTest`, `FenParserFastParseTest.scala`
|
||||
Too small to be a meaningful cluster - may be noise or needs more connections extracted.
|
||||
- **Thin community `Community 104`** (2 nodes): `FenParserTest`, `FenParserTest.scala`
|
||||
Too small to be a meaningful cluster - may be noise or needs more connections extracted.
|
||||
- **Thin community `Community 105`** (2 nodes): `JsonExporterBranchCoverageSuite`, `JsonExporterBranchCoverageSuite.scala`
|
||||
Too small to be a meaningful cluster - may be noise or needs more connections extracted.
|
||||
- **Thin community `Community 106`** (2 nodes): `JsonExporterSuite`, `JsonExporterSuite.scala`
|
||||
Too small to be a meaningful cluster - may be noise or needs more connections extracted.
|
||||
- **Thin community `Community 107`** (2 nodes): `JsonModelExtraTestSuite`, `JsonModelExtraTestSuite.scala`
|
||||
Too small to be a meaningful cluster - may be noise or needs more connections extracted.
|
||||
- **Thin community `Community 108`** (2 nodes): `JsonParserEdgeCasesSuite`, `JsonParserEdgeCasesSuite.scala`
|
||||
Too small to be a meaningful cluster - may be noise or needs more connections extracted.
|
||||
- **Thin community `Community 109`** (2 nodes): `JsonParserErrorHandlingSuite`, `JsonParserErrorHandlingSuite.scala`
|
||||
Too small to be a meaningful cluster - may be noise or needs more connections extracted.
|
||||
- **Thin community `Community 110`** (2 nodes): `JsonParserMoveTypeSuite`, `JsonParserMoveTypeSuite.scala`
|
||||
Too small to be a meaningful cluster - may be noise or needs more connections extracted.
|
||||
- **Thin community `Community 111`** (2 nodes): `JsonParserSuite`, `JsonParserSuite.scala`
|
||||
Too small to be a meaningful cluster - may be noise or needs more connections extracted.
|
||||
- **Thin community `Community 112`** (2 nodes): `PgnParserTest.scala`, `PgnParserTest`
|
||||
Too small to be a meaningful cluster - may be noise or needs more connections extracted.
|
||||
- **Thin community `Community 113`** (2 nodes): `PgnValidatorTest.scala`, `PgnValidatorTest`
|
||||
Too small to be a meaningful cluster - may be noise or needs more connections extracted.
|
||||
- **Thin community `Community 114`** (2 nodes): `DefaultRulesTest`, `DefaultRulesTest.scala`
|
||||
Too small to be a meaningful cluster - may be noise or needs more connections extracted.
|
||||
- **Thin community `Community 115`** (2 nodes): `PieceUnicode.scala`, `unicode()`
|
||||
Too small to be a meaningful cluster - may be noise or needs more connections extracted.
|
||||
- **Thin community `Community 116`** (2 nodes): `RendererAndUnicodeTest.scala`, `RendererAndUnicodeTest`
|
||||
Too small to be a meaningful cluster - may be noise or needs more connections extracted.
|
||||
- **Thin community `Community 117`** (1 nodes): `build.gradle.kts`
|
||||
Too small to be a meaningful cluster - may be noise or needs more connections extracted.
|
||||
- **Thin community `Community 118`** (1 nodes): `settings.gradle.kts`
|
||||
Too small to be a meaningful cluster - may be noise or needs more connections extracted.
|
||||
- **Thin community `Community 119`** (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 120`** (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 121`** (1 nodes): `test_counter.py`
|
||||
Too small to be a meaningful cluster - may be noise or needs more connections extracted.
|
||||
- **Thin community `Community 122`** (1 nodes): `build.gradle.kts`
|
||||
Too small to be a meaningful cluster - may be noise or needs more connections extracted.
|
||||
- **Thin community `Community 123`** (1 nodes): `build.gradle.kts`
|
||||
Too small to be a meaningful cluster - may be noise or needs more connections extracted.
|
||||
- **Thin community `Community 124`** (1 nodes): `start.ps1`
|
||||
Too small to be a meaningful cluster - may be noise or needs more connections extracted.
|
||||
- **Thin community `Community 125`** (1 nodes): `Bot.scala`
|
||||
Too small to be a meaningful cluster - may be noise or needs more connections extracted.
|
||||
- **Thin community `Community 126`** (1 nodes): `BotDifficulty.scala`
|
||||
Too small to be a meaningful cluster - may be noise or needs more connections extracted.
|
||||
- **Thin community `Community 127`** (1 nodes): `build.gradle.kts`
|
||||
Too small to be a meaningful cluster - may be noise or needs more connections extracted.
|
||||
- **Thin community `Community 128`** (1 nodes): `build.gradle.kts`
|
||||
Too small to be a meaningful cluster - may be noise or needs more connections extracted.
|
||||
- **Thin community `Community 129`** (1 nodes): `GameContextExport.scala`
|
||||
Too small to be a meaningful cluster - may be noise or needs more connections extracted.
|
||||
- **Thin community `Community 130`** (1 nodes): `GameContextImport.scala`
|
||||
Too small to be a meaningful cluster - may be noise or needs more connections extracted.
|
||||
- **Thin community `Community 131`** (1 nodes): `build.gradle.kts`
|
||||
Too small to be a meaningful cluster - may be noise or needs more connections extracted.
|
||||
- **Thin community `Community 132`** (1 nodes): `RuleSet.scala`
|
||||
Too small to be a meaningful cluster - may be noise or needs more connections extracted.
|
||||
- **Thin community `Community 133`** (1 nodes): `build.gradle.kts`
|
||||
Too small to be a meaningful cluster - may be noise or needs more connections extracted.
|
||||
- **Thin community `Community 134`** (1 nodes): `Get/create data directory.`
|
||||
Too small to be a meaningful cluster - may be noise or needs more connections extracted.
|
||||
- **Thin community `Community 135`** (1 nodes): `Get/create data directory.`
|
||||
Too small to be a meaningful cluster - may be noise or needs more connections extracted.
|
||||
- **Thin community `Community 136`** (1 nodes): `Get/create weights directory.`
|
||||
Too small to be a meaningful cluster - may be noise or needs more connections extracted.
|
||||
- **Thin community `Community 137`** (1 nodes): `List available checkpoint versions.`
|
||||
Too small to be a meaningful cluster - may be noise or needs more connections extracted.
|
||||
- **Thin community `Community 138`** (1 nodes): `Display application header.`
|
||||
Too small to be a meaningful cluster - may be noise or needs more connections extracted.
|
||||
- **Thin community `Community 139`** (1 nodes): `Display available checkpoints in a table.`
|
||||
Too small to be a meaningful cluster - may be noise or needs more connections extracted.
|
||||
- **Thin community `Community 140`** (1 nodes): `Display and handle main menu.`
|
||||
Too small to be a meaningful cluster - may be noise or needs more connections extracted.
|
||||
- **Thin community `Community 141`** (1 nodes): `Interactive training menu.`
|
||||
Too small to be a meaningful cluster - may be noise or needs more connections extracted.
|
||||
- **Thin community `Community 142`** (1 nodes): `Interactive burst training menu.`
|
||||
Too small to be a meaningful cluster - may be noise or needs more connections extracted.
|
||||
- **Thin community `Community 143`** (1 nodes): `Interactive export menu.`
|
||||
Too small to be a meaningful cluster - may be noise or needs more connections extracted.
|
||||
- **Thin community `Community 144`** (1 nodes): `Interactive tactical positions extraction and merge menu.`
|
||||
Too small to be a meaningful cluster - may be noise or needs more connections extracted.
|
||||
- **Thin community `Community 145`** (1 nodes): `Load PyTorch weights and export as binary file.`
|
||||
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:_
|
||||
|
||||
- **What connects `Strip the package prefix from the full method path.`, `Lines that are branch points and have at least one uncovered branch statement.`, `[1,2,3,5,7,8,9] → '1-3, 5, 7-9` to the rest of the system?**
|
||||
_147 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.1 - nodes in this community are weakly interconnected._
|
||||
- **Should `Community 2` be split into smaller, more focused modules?**
|
||||
_Cohesion score 0.09 - nodes in this community are weakly interconnected._
|
||||
- **Should `Community 3` be split into smaller, more focused modules?**
|
||||
_Cohesion score 0.13 - 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._
|
||||
- **Should `Community 5` be split into smaller, more focused modules?**
|
||||
_Cohesion score 0.11 - nodes in this community are weakly interconnected._
|
||||
-20594
File diff suppressed because it is too large
Load Diff
@@ -34,3 +34,11 @@
|
||||
* NCS-14 implemented insufficient moves rule ([#30](https://git.janis-eccarius.de/NowChess/NowChessSystems/issues/30)) ([b0399a4](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/b0399a4e489950083066c9538df9a84dcc7a4613))
|
||||
* NCS-21 Write Scripts to automate certain tasks ([#15](https://git.janis-eccarius.de/NowChess/NowChessSystems/issues/15)) ([8051871](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/80518719d536a087d339fe02530825dc07f8b388))
|
||||
* NCS-25 Add linters to keep quality up ([#27](https://git.janis-eccarius.de/NowChess/NowChessSystems/issues/27)) ([fd4e67d](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/fd4e67d4f782a7e955822d90cb909d0a81676fb2))
|
||||
## (2026-04-16)
|
||||
|
||||
### Features
|
||||
|
||||
* NCS-13 Implement Threefold Repetition ([#31](https://git.janis-eccarius.de/NowChess/NowChessSystems/issues/31)) ([767d305](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/767d3051a76c266050b6335774d66e2db2273c16))
|
||||
* NCS-14 implemented insufficient moves rule ([#30](https://git.janis-eccarius.de/NowChess/NowChessSystems/issues/30)) ([b0399a4](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/b0399a4e489950083066c9538df9a84dcc7a4613))
|
||||
* NCS-21 Write Scripts to automate certain tasks ([#15](https://git.janis-eccarius.de/NowChess/NowChessSystems/issues/15)) ([8051871](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/80518719d536a087d339fe02530825dc07f8b388))
|
||||
* NCS-25 Add linters to keep quality up ([#27](https://git.janis-eccarius.de/NowChess/NowChessSystems/issues/27)) ([fd4e67d](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/fd4e67d4f782a7e955822d90cb909d0a81676fb2))
|
||||
|
||||
@@ -1,3 +1,3 @@
|
||||
MAJOR=0
|
||||
MINOR=5
|
||||
MINOR=6
|
||||
PATCH=0
|
||||
|
||||
@@ -37,6 +37,7 @@ class AlphaBetaSearchTest extends AnyFunSuite with Matchers:
|
||||
def isStalemate(context: GameContext): Boolean = false
|
||||
def isInsufficientMaterial(context: GameContext): Boolean = false
|
||||
def isFiftyMoveRule(context: GameContext): Boolean = false
|
||||
def isThreefoldRepetition(context: GameContext): Boolean = false
|
||||
def applyMove(context: GameContext)(move: Move): GameContext = context
|
||||
|
||||
val search = AlphaBetaSearch(stubRules, weights = EvaluationClassic)
|
||||
@@ -54,6 +55,7 @@ class AlphaBetaSearchTest extends AnyFunSuite with Matchers:
|
||||
def isStalemate(context: GameContext): Boolean = false
|
||||
def isInsufficientMaterial(context: GameContext): Boolean = false
|
||||
def isFiftyMoveRule(context: GameContext): Boolean = false
|
||||
def isThreefoldRepetition(context: GameContext): Boolean = false
|
||||
def applyMove(context: GameContext)(move: Move): GameContext = context
|
||||
|
||||
val search = AlphaBetaSearch(stubRules, weights = EvaluationClassic)
|
||||
@@ -101,6 +103,7 @@ class AlphaBetaSearchTest extends AnyFunSuite with Matchers:
|
||||
def isStalemate(context: GameContext): Boolean = true
|
||||
def isInsufficientMaterial(context: GameContext): Boolean = false
|
||||
def isFiftyMoveRule(context: GameContext): Boolean = false
|
||||
def isThreefoldRepetition(context: GameContext): Boolean = false
|
||||
def applyMove(context: GameContext)(move: Move): GameContext = context
|
||||
|
||||
val search = AlphaBetaSearch(stalematRules, weights = EvaluationClassic)
|
||||
@@ -117,6 +120,7 @@ class AlphaBetaSearchTest extends AnyFunSuite with Matchers:
|
||||
def isStalemate(context: GameContext): Boolean = false
|
||||
def isInsufficientMaterial(context: GameContext): Boolean = true
|
||||
def isFiftyMoveRule(context: GameContext): Boolean = false
|
||||
def isThreefoldRepetition(context: GameContext): Boolean = false
|
||||
def applyMove(context: GameContext)(move: Move): GameContext = context
|
||||
|
||||
val search = AlphaBetaSearch(insufficientRules, weights = EvaluationClassic)
|
||||
@@ -133,6 +137,7 @@ class AlphaBetaSearchTest extends AnyFunSuite with Matchers:
|
||||
def isStalemate(context: GameContext): Boolean = false
|
||||
def isInsufficientMaterial(context: GameContext): Boolean = false
|
||||
def isFiftyMoveRule(context: GameContext): Boolean = true
|
||||
def isThreefoldRepetition(context: GameContext): Boolean = false
|
||||
def applyMove(context: GameContext)(move: Move): GameContext = context
|
||||
|
||||
val search = AlphaBetaSearch(fiftyMoveRules, weights = EvaluationClassic)
|
||||
@@ -159,6 +164,7 @@ class AlphaBetaSearchTest extends AnyFunSuite with Matchers:
|
||||
def isStalemate(context: GameContext): Boolean = false
|
||||
def isInsufficientMaterial(context: GameContext): Boolean = false
|
||||
def isFiftyMoveRule(context: GameContext): Boolean = false
|
||||
def isThreefoldRepetition(context: GameContext): Boolean = false
|
||||
def applyMove(context: GameContext)(move: Move): GameContext = context
|
||||
|
||||
val search = AlphaBetaSearch(rulesWithCapture, weights = EvaluationClassic)
|
||||
@@ -176,6 +182,7 @@ class AlphaBetaSearchTest extends AnyFunSuite with Matchers:
|
||||
def isStalemate(context: GameContext): Boolean = false
|
||||
def isInsufficientMaterial(context: GameContext): Boolean = false
|
||||
def isFiftyMoveRule(context: GameContext): Boolean = false
|
||||
def isThreefoldRepetition(context: GameContext): Boolean = false
|
||||
def applyMove(context: GameContext)(move: Move): GameContext = context
|
||||
|
||||
val search = AlphaBetaSearch(rulesQuiet, weights = EvaluationClassic)
|
||||
|
||||
@@ -35,6 +35,7 @@ class ClassicalBotTest extends AnyFunSuite with Matchers:
|
||||
def isStalemate(context: GameContext): Boolean = false
|
||||
def isInsufficientMaterial(context: GameContext): Boolean = false
|
||||
def isFiftyMoveRule(context: GameContext): Boolean = false
|
||||
def isThreefoldRepetition(context: GameContext): Boolean = false
|
||||
def applyMove(context: GameContext)(move: Move): GameContext = context
|
||||
|
||||
val bot = ClassicalBot(BotDifficulty.Easy, stubRules)
|
||||
@@ -65,6 +66,7 @@ class ClassicalBotTest extends AnyFunSuite with Matchers:
|
||||
def isStalemate(context: GameContext): Boolean = false
|
||||
def isInsufficientMaterial(context: GameContext): Boolean = false
|
||||
def isFiftyMoveRule(context: GameContext): Boolean = false
|
||||
def isThreefoldRepetition(context: GameContext): Boolean = false
|
||||
def applyMove(context: GameContext)(move: Move): GameContext = context
|
||||
|
||||
val bot = ClassicalBot(BotDifficulty.Easy, stubRules)
|
||||
@@ -87,6 +89,7 @@ class ClassicalBotTest extends AnyFunSuite with Matchers:
|
||||
def isStalemate(context: GameContext): Boolean = false
|
||||
def isInsufficientMaterial(context: GameContext): Boolean = false
|
||||
def isFiftyMoveRule(context: GameContext): Boolean = false
|
||||
def isThreefoldRepetition(context: GameContext): Boolean = false
|
||||
def applyMove(context: GameContext)(move: Move): GameContext = context
|
||||
|
||||
val context = GameContext.initial.copy(moves = List(repeatedMove, repeatedMove, repeatedMove))
|
||||
|
||||
@@ -260,3 +260,29 @@
|
||||
* correct test board positions and captureOutput/withInput interaction ([f0481e2](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/f0481e2561b779df00925b46ee281dc36a795150))
|
||||
* update main class path in build configuration and adjust VCS directory mapping ([7b1f8b1](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/7b1f8b117623d327232a1a92a8a44d18582e0189))
|
||||
* update move validation to check for king safety ([#13](https://git.janis-eccarius.de/NowChess/NowChessSystems/issues/13)) ([e5e20c5](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/e5e20c566e368b12ca1dc59680c34e9112bf6762))
|
||||
## (2026-04-16)
|
||||
|
||||
### Features
|
||||
|
||||
* add GameRules stub with PositionStatus enum ([76d4168](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/76d4168038de23e5d6083d4e8f0504fbf31d15a3))
|
||||
* add MovedInCheck/Checkmate/Stalemate MoveResult variants (stub dispatch) ([8b7ec57](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/8b7ec57e5ea6ee1615a1883848a426dc07d26364))
|
||||
* implement GameRules with isInCheck, legalMoves, gameStatus ([94a02ff](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/94a02ff6849436d9496c70a0f16c21666dae8e4e))
|
||||
* implement legal castling ([#1](https://git.janis-eccarius.de/NowChess/NowChessSystems/issues/1)) ([00d326c](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/00d326c1ba67711fbe180f04e1100c3f01dd0254))
|
||||
* NCS-10 Implement Pawn Promotion ([#12](https://git.janis-eccarius.de/NowChess/NowChessSystems/issues/12)) ([13bfc16](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/13bfc16cfe25db78ec607db523ca6d993c13430c))
|
||||
* NCS-11 50-move rule ([#9](https://git.janis-eccarius.de/NowChess/NowChessSystems/issues/9)) ([412ed98](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/412ed986a95703a3b282276540153480ceed229d))
|
||||
* NCS-13 Implement Threefold Repetition ([#31](https://git.janis-eccarius.de/NowChess/NowChessSystems/issues/31)) ([767d305](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/767d3051a76c266050b6335774d66e2db2273c16))
|
||||
* NCS-14 implemented insufficient moves rule ([#30](https://git.janis-eccarius.de/NowChess/NowChessSystems/issues/30)) ([b0399a4](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/b0399a4e489950083066c9538df9a84dcc7a4613))
|
||||
* NCS-16 Core Separation via Patterns ([#10](https://git.janis-eccarius.de/NowChess/NowChessSystems/issues/10)) ([1361dfc](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/1361dfc89553b146864fb8ff3526cf12cf3f293a))
|
||||
* NCS-17 Implement basic ScalaFX UI ([#14](https://git.janis-eccarius.de/NowChess/NowChessSystems/issues/14)) ([3ff8031](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/3ff80318b4f16c59733a46498581a5c27f048287))
|
||||
* NCS-21 Write Scripts to automate certain tasks ([#15](https://git.janis-eccarius.de/NowChess/NowChessSystems/issues/15)) ([8051871](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/80518719d536a087d339fe02530825dc07f8b388))
|
||||
* NCS-25 Add linters to keep quality up ([#27](https://git.janis-eccarius.de/NowChess/NowChessSystems/issues/27)) ([fd4e67d](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/fd4e67d4f782a7e955822d90cb909d0a81676fb2))
|
||||
* NCS-6 Implementing FEN & PGN ([#7](https://git.janis-eccarius.de/NowChess/NowChessSystems/issues/7)) ([f28e69d](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/f28e69dc181416aa2f221fdc4b45c2cda5efbf07))
|
||||
* NCS-9 En passant implementation ([#8](https://git.janis-eccarius.de/NowChess/NowChessSystems/issues/8)) ([919beb3](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/919beb3b4bfa8caf2f90976a415fe9b19b7e9747))
|
||||
* wire check/checkmate/stalemate into processMove and gameLoop ([5264a22](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/5264a225418b885c5e6ea6411b96f85e38837f6c))
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* add missing kings to gameLoop capture test board ([aedd787](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/aedd787b77203c2af934751dba7b784eaf165032))
|
||||
* correct test board positions and captureOutput/withInput interaction ([f0481e2](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/f0481e2561b779df00925b46ee281dc36a795150))
|
||||
* update main class path in build configuration and adjust VCS directory mapping ([7b1f8b1](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/7b1f8b117623d327232a1a92a8a44d18582e0189))
|
||||
* update move validation to check for king safety ([#13](https://git.janis-eccarius.de/NowChess/NowChessSystems/issues/13)) ([e5e20c5](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/e5e20c566e368b12ca1dc59680c34e9112bf6762))
|
||||
|
||||
@@ -19,20 +19,17 @@ class GameEngine(
|
||||
val ruleSet: RuleSet = DefaultRules,
|
||||
val participants: Map[Color, Participant] = Map(Color.White -> Human, Color.Black -> Human),
|
||||
) extends Observable:
|
||||
// Ensure that initialBoard is set correctly for threefold repetition detection
|
||||
private val contextWithInitialBoard = if initialContext.moves.isEmpty && initialContext.board != initialContext.initialBoard then
|
||||
initialContext.copy(initialBoard = initialContext.board)
|
||||
else
|
||||
initialContext
|
||||
@SuppressWarnings(Array("DisableSyntax.var"))
|
||||
private var currentContext: GameContext = initialContext
|
||||
private var currentContext: GameContext = contextWithInitialBoard
|
||||
private val invoker = new CommandInvoker()
|
||||
|
||||
/** Pending promotion: the Move that triggered it (from/to only, moveType filled in later). */
|
||||
private case class PendingPromotion(from: Square, to: Square, contextBefore: GameContext)
|
||||
@SuppressWarnings(Array("DisableSyntax.var"))
|
||||
private var pendingPromotion: Option[PendingPromotion] = None
|
||||
|
||||
private implicit val ec: ExecutionContext = ExecutionContext.global
|
||||
|
||||
/** True if a pawn promotion move is pending and needs a piece choice. */
|
||||
def isPendingPromotion: Boolean = synchronized(pendingPromotion.isDefined)
|
||||
|
||||
// Synchronized accessors for current state
|
||||
def board: Board = synchronized(currentContext.board)
|
||||
def turn: Color = synchronized(currentContext.turn)
|
||||
@@ -67,11 +64,15 @@ class GameEngine(
|
||||
currentContext = currentContext.withResult(Some(GameResult.Draw(DrawReason.FiftyMoveRule)))
|
||||
invoker.clear()
|
||||
notifyObservers(DrawEvent(currentContext, DrawReason.FiftyMoveRule))
|
||||
else if ruleSet.isThreefoldRepetition(currentContext) then
|
||||
currentContext = currentContext.withResult(Some(GameResult.Draw(DrawReason.ThreefoldRepetition)))
|
||||
invoker.clear()
|
||||
notifyObservers(DrawEvent(currentContext, DrawReason.ThreefoldRepetition))
|
||||
else
|
||||
notifyObservers(
|
||||
InvalidMoveEvent(
|
||||
currentContext,
|
||||
"Draw cannot be claimed: the 50-move rule has not been triggered.",
|
||||
"Draw cannot be claimed: neither the 50-move rule nor threefold repetition has been triggered.",
|
||||
),
|
||||
)
|
||||
|
||||
@@ -87,11 +88,11 @@ class GameEngine(
|
||||
s"Invalid move format '$moveInput'. Use coordinate notation, e.g. e2e4.",
|
||||
),
|
||||
)
|
||||
case Some((from, to)) =>
|
||||
handleParsedMove(from, to)
|
||||
case Some((from, to, promotionPiece: Option[PromotionPiece])) =>
|
||||
handleParsedMove(from, to, promotionPiece)
|
||||
}
|
||||
|
||||
private def handleParsedMove(from: Square, to: Square): Unit =
|
||||
private def handleParsedMove(from: Square, to: Square, promotionPiece: Option[PromotionPiece]): Unit =
|
||||
currentContext.board.pieceAt(from) match
|
||||
case None =>
|
||||
notifyObservers(InvalidMoveEvent(currentContext, "No piece on that square."))
|
||||
@@ -104,11 +105,13 @@ class GameEngine(
|
||||
candidates match
|
||||
case Nil =>
|
||||
notifyObservers(InvalidMoveEvent(currentContext, "Illegal move."))
|
||||
case moves if isPromotionMove(piece, to) =>
|
||||
// Multiple moves (one per promotion piece) — ask user to choose
|
||||
val contextBefore = currentContext
|
||||
pendingPromotion = Some(PendingPromotion(from, to, contextBefore))
|
||||
notifyObservers(PromotionRequiredEvent(currentContext, from, to))
|
||||
case _ if isPromotionMove(piece, to) =>
|
||||
if promotionPiece.isEmpty then
|
||||
notifyObservers(InvalidMoveEvent(currentContext, "Promotion piece required: append q, r, b, or n to the move."))
|
||||
else
|
||||
candidates.find(_.moveType == MoveType.Promotion(promotionPiece.get)) match
|
||||
case None => notifyObservers(InvalidMoveEvent(currentContext, "Error completing promotion: no matching legal move."))
|
||||
case Some(move) => executeMove(move)
|
||||
case move :: _ =>
|
||||
executeMove(move)
|
||||
|
||||
@@ -118,21 +121,6 @@ class GameEngine(
|
||||
to.rank.ordinal == promoRank
|
||||
}
|
||||
|
||||
/** Apply a player's promotion piece choice. Must only be called when isPendingPromotion is true.
|
||||
*/
|
||||
def completePromotion(piece: PromotionPiece): Unit = synchronized {
|
||||
pendingPromotion match
|
||||
case None =>
|
||||
notifyObservers(InvalidMoveEvent(currentContext, "No promotion pending."))
|
||||
case Some(pending) =>
|
||||
pendingPromotion = None
|
||||
val move = Move(pending.from, pending.to, MoveType.Promotion(piece))
|
||||
// Verify it's actually legal
|
||||
val legal = ruleSet.legalMoves(currentContext)(pending.from)
|
||||
if legal.contains(move) then executeMove(move)
|
||||
else notifyObservers(InvalidMoveEvent(currentContext, "Error completing promotion."))
|
||||
}
|
||||
|
||||
/** Undo the last move. */
|
||||
def undo(): Unit = synchronized(performUndo())
|
||||
|
||||
@@ -154,11 +142,10 @@ class GameEngine(
|
||||
private def replayGame(ctx: GameContext): Either[String, Unit] =
|
||||
val savedContext = currentContext
|
||||
currentContext = GameContext.initial
|
||||
pendingPromotion = None
|
||||
invoker.clear()
|
||||
|
||||
if ctx.moves.isEmpty then
|
||||
currentContext = ctx
|
||||
currentContext = ctx.copy(initialBoard = ctx.board)
|
||||
Right(())
|
||||
else replayMoves(ctx.moves, savedContext)
|
||||
|
||||
@@ -170,14 +157,13 @@ class GameEngine(
|
||||
result
|
||||
|
||||
private def applyReplayMove(move: Move): Either[String, Unit] =
|
||||
handleParsedMove(move.from, move.to)
|
||||
move.moveType match
|
||||
case MoveType.Promotion(pp) if pendingPromotion.isDefined =>
|
||||
completePromotion(pp)
|
||||
Right(())
|
||||
case MoveType.Promotion(_) =>
|
||||
Left(s"Promotion required for move ${move.from}${move.to}")
|
||||
case _ => Right(())
|
||||
val legal = ruleSet.legalMoves(currentContext)(move.from)
|
||||
val candidate = move.moveType match
|
||||
case MoveType.Promotion(pp) => legal.find(m => m.to == move.to && m.moveType == MoveType.Promotion(pp))
|
||||
case _ => legal.find(_.to == move.to)
|
||||
candidate match
|
||||
case None => Left("Illegal move.")
|
||||
case Some(lm) => executeMove(lm); Right(())
|
||||
|
||||
/** Export the current game context using the provided exporter. */
|
||||
def exportGame(exporter: GameContextExport): String = synchronized {
|
||||
@@ -186,7 +172,11 @@ class GameEngine(
|
||||
|
||||
/** Load an arbitrary board position, clearing all history and undo/redo state. */
|
||||
def loadPosition(newContext: GameContext): Unit = synchronized {
|
||||
currentContext = newContext
|
||||
val contextWithInitialBoard = if newContext.moves.isEmpty then
|
||||
newContext.copy(initialBoard = newContext.board)
|
||||
else
|
||||
newContext
|
||||
currentContext = contextWithInitialBoard
|
||||
invoker.clear()
|
||||
notifyObservers(BoardResetEvent(currentContext))
|
||||
}
|
||||
@@ -243,10 +233,7 @@ class GameEngine(
|
||||
else if ruleSet.isCheck(currentContext) then notifyObservers(CheckDetectedEvent(currentContext))
|
||||
|
||||
if currentContext.halfMoveClock >= 100 then notifyObservers(FiftyMoveRuleAvailableEvent(currentContext))
|
||||
|
||||
// Request bot move if it's the opponent bot's turn
|
||||
if ruleSet.isCheckmate(currentContext) || ruleSet.isStalemate(currentContext) then
|
||||
() // Game is over, don't request bot move
|
||||
if ruleSet.isThreefoldRepetition(currentContext) then notifyObservers(ThreefoldRepetitionAvailableEvent(currentContext))
|
||||
else requestBotMoveIfNeeded()
|
||||
|
||||
private def translateMoveToNotation(move: Move, boardBefore: Board): String =
|
||||
@@ -336,7 +323,7 @@ class GameEngine(
|
||||
if ruleSet.isCheckmate(currentContext) then
|
||||
val winner = currentContext.turn.opposite
|
||||
notifyObservers(CheckmateEvent(currentContext, winner))
|
||||
else if ruleSet.isStalemate(currentContext) then notifyObservers(StalemateEvent(currentContext))
|
||||
else if ruleSet.isStalemate(currentContext) then notifyObservers(DrawEvent(currentContext, DrawReason.Stalemate))
|
||||
}
|
||||
|
||||
private def performUndo(): Unit =
|
||||
|
||||
@@ -1,3 +1,3 @@
|
||||
MAJOR=0
|
||||
MINOR=13
|
||||
MINOR=14
|
||||
PATCH=0
|
||||
|
||||
@@ -47,3 +47,12 @@
|
||||
* NCS-29 JSON - Cherry Picked ([#28](https://git.janis-eccarius.de/NowChess/NowChessSystems/issues/28)) ([dbcafd2](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/dbcafd286993e0604a6fa286c5543581a149439e))
|
||||
* NCS-30 FEN Parser using ParserCombinators ([#21](https://git.janis-eccarius.de/NowChess/NowChessSystems/issues/21)) ([b4bc72f](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/b4bc72f7e49f94d6e1bc805c68680e5fe8ef8e36))
|
||||
* NCS-31 FastParse FEN ([#22](https://git.janis-eccarius.de/NowChess/NowChessSystems/issues/22)) ([7a045d3](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/7a045d31d757bbc5aa6f4bad2664ebe8b8519cac))
|
||||
## (2026-04-16)
|
||||
|
||||
### Features
|
||||
|
||||
* NCS-14 implemented insufficient moves rule ([#30](https://git.janis-eccarius.de/NowChess/NowChessSystems/issues/30)) ([b0399a4](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/b0399a4e489950083066c9538df9a84dcc7a4613))
|
||||
* NCS-25 Add linters to keep quality up ([#27](https://git.janis-eccarius.de/NowChess/NowChessSystems/issues/27)) ([fd4e67d](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/fd4e67d4f782a7e955822d90cb909d0a81676fb2))
|
||||
* NCS-29 JSON - Cherry Picked ([#28](https://git.janis-eccarius.de/NowChess/NowChessSystems/issues/28)) ([dbcafd2](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/dbcafd286993e0604a6fa286c5543581a149439e))
|
||||
* NCS-30 FEN Parser using ParserCombinators ([#21](https://git.janis-eccarius.de/NowChess/NowChessSystems/issues/21)) ([b4bc72f](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/b4bc72f7e49f94d6e1bc805c68680e5fe8ef8e36))
|
||||
* NCS-31 FastParse FEN ([#22](https://git.janis-eccarius.de/NowChess/NowChessSystems/issues/22)) ([7a045d3](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/7a045d31d757bbc5aa6f4bad2664ebe8b8519cac))
|
||||
|
||||
@@ -1,3 +1,3 @@
|
||||
MAJOR=0
|
||||
MINOR=7
|
||||
MINOR=8
|
||||
PATCH=0
|
||||
|
||||
@@ -44,3 +44,14 @@
|
||||
### Bug Fixes
|
||||
|
||||
* NCS-32 Queenside Castle doesn't care about pieces in the way ([#23](https://git.janis-eccarius.de/NowChess/NowChessSystems/issues/23)) ([fe8e3c0](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/fe8e3c05397f433bfa34d1999e9738c82790adf7))
|
||||
## (2026-04-16)
|
||||
|
||||
### Features
|
||||
|
||||
* NCS-13 Implement Threefold Repetition ([#31](https://git.janis-eccarius.de/NowChess/NowChessSystems/issues/31)) ([767d305](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/767d3051a76c266050b6335774d66e2db2273c16))
|
||||
* NCS-14 implemented insufficient moves rule ([#30](https://git.janis-eccarius.de/NowChess/NowChessSystems/issues/30)) ([b0399a4](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/b0399a4e489950083066c9538df9a84dcc7a4613))
|
||||
* NCS-25 Add linters to keep quality up ([#27](https://git.janis-eccarius.de/NowChess/NowChessSystems/issues/27)) ([fd4e67d](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/fd4e67d4f782a7e955822d90cb909d0a81676fb2))
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* NCS-32 Queenside Castle doesn't care about pieces in the way ([#23](https://git.janis-eccarius.de/NowChess/NowChessSystems/issues/23)) ([fe8e3c0](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/fe8e3c05397f433bfa34d1999e9738c82790adf7))
|
||||
|
||||
@@ -458,18 +458,11 @@ object DefaultRules extends RuleSet:
|
||||
private def squareColor(sq: Square): Int = (sq.file.ordinal + sq.rank.ordinal) % 2
|
||||
|
||||
private def insufficientMaterial(board: Board): Boolean =
|
||||
val nonKings = board.pieces.toList.filter(_._2.pieceType != PieceType.King)
|
||||
val nonKings = board.pieces.toList.filter { case (_, p) => p.pieceType != PieceType.King }
|
||||
nonKings match
|
||||
case Nil => true
|
||||
case List((_, p)) if p.pieceType == PieceType.Bishop || p.pieceType == PieceType.Knight => true
|
||||
case List((sq1, p1), (sq2, p2))
|
||||
if p1.pieceType == PieceType.Bishop && p2.pieceType == PieceType.Bishop
|
||||
&& p1.color != p2.color
|
||||
&& squareColor(sq1) == squareColor(sq2) =>
|
||||
true
|
||||
case bishops
|
||||
if bishops.forall(_._2.pieceType == PieceType.Bishop)
|
||||
&& bishops.map(_._2.color).distinct.size == 1
|
||||
&& bishops.map(e => squareColor(e._1)).distinct.size == 1 =>
|
||||
true
|
||||
case bishops if bishops.forall { case (_, p) => p.pieceType == PieceType.Bishop } =>
|
||||
// All non-king pieces are bishops: draw only if they all share the same square color
|
||||
bishops.map { case (sq, _) => squareColor(sq) }.distinct.sizeIs == 1
|
||||
case _ => false
|
||||
|
||||
@@ -32,12 +32,7 @@ class DefaultRulesTest extends AnyFunSuite with Matchers:
|
||||
val fen = "8/8/8/3p4/4P3/8/8/8 w - - 0 1"
|
||||
val context = FenParser.parseFen(fen).fold(_ => fail(), identity)
|
||||
val moves = rules.allLegalMoves(context)
|
||||
val captures = moves.filter { m =>
|
||||
m.from == Square(File.E, Rank.R4) && (m.moveType match
|
||||
case _: MoveType.Normal => true
|
||||
case _ => false
|
||||
)
|
||||
}
|
||||
val captures = moves.filter(m => m.from == Square(File.E, Rank.R4) && (m.moveType match { case _: MoveType.Normal => true; case _ => false }))
|
||||
captures.exists(m => m.to == Square(File.D, Rank.R5)) shouldBe true
|
||||
|
||||
test("pawn cannot move backward"):
|
||||
|
||||
@@ -1,3 +1,3 @@
|
||||
MAJOR=0
|
||||
MINOR=2
|
||||
MINOR=3
|
||||
PATCH=0
|
||||
|
||||
@@ -79,3 +79,15 @@
|
||||
* NCS-21 Write Scripts to automate certain tasks ([#15](https://git.janis-eccarius.de/NowChess/NowChessSystems/issues/15)) ([8051871](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/80518719d536a087d339fe02530825dc07f8b388))
|
||||
* NCS-25 Add linters to keep quality up ([#27](https://git.janis-eccarius.de/NowChess/NowChessSystems/issues/27)) ([fd4e67d](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/fd4e67d4f782a7e955822d90cb909d0a81676fb2))
|
||||
* NCS-29 JSON - Cherry Picked ([#28](https://git.janis-eccarius.de/NowChess/NowChessSystems/issues/28)) ([dbcafd2](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/dbcafd286993e0604a6fa286c5543581a149439e))
|
||||
## (2026-04-16)
|
||||
|
||||
### Features
|
||||
|
||||
* NCS-10 Implement Pawn Promotion ([#12](https://git.janis-eccarius.de/NowChess/NowChessSystems/issues/12)) ([13bfc16](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/13bfc16cfe25db78ec607db523ca6d993c13430c))
|
||||
* NCS-13 Implement Threefold Repetition ([#31](https://git.janis-eccarius.de/NowChess/NowChessSystems/issues/31)) ([767d305](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/767d3051a76c266050b6335774d66e2db2273c16))
|
||||
* NCS-14 implemented insufficient moves rule ([#30](https://git.janis-eccarius.de/NowChess/NowChessSystems/issues/30)) ([b0399a4](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/b0399a4e489950083066c9538df9a84dcc7a4613))
|
||||
* NCS-16 Core Separation via Patterns ([#10](https://git.janis-eccarius.de/NowChess/NowChessSystems/issues/10)) ([1361dfc](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/1361dfc89553b146864fb8ff3526cf12cf3f293a))
|
||||
* NCS-17 Implement basic ScalaFX UI ([#14](https://git.janis-eccarius.de/NowChess/NowChessSystems/issues/14)) ([3ff8031](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/3ff80318b4f16c59733a46498581a5c27f048287))
|
||||
* NCS-21 Write Scripts to automate certain tasks ([#15](https://git.janis-eccarius.de/NowChess/NowChessSystems/issues/15)) ([8051871](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/80518719d536a087d339fe02530825dc07f8b388))
|
||||
* NCS-25 Add linters to keep quality up ([#27](https://git.janis-eccarius.de/NowChess/NowChessSystems/issues/27)) ([fd4e67d](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/fd4e67d4f782a7e955822d90cb909d0a81676fb2))
|
||||
* NCS-29 JSON - Cherry Picked ([#28](https://git.janis-eccarius.de/NowChess/NowChessSystems/issues/28)) ([dbcafd2](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/dbcafd286993e0604a6fa286c5543581a149439e))
|
||||
|
||||
@@ -38,11 +38,6 @@ tasks.withType<ScalaCompile> {
|
||||
scalaCompileOptions.additionalParameters = listOf("-encoding", "UTF-8")
|
||||
}
|
||||
|
||||
// Disable scalafix for UI module due to mutable state requirements
|
||||
tasks.matching { it.name.startsWith("scalafix") }.configureEach {
|
||||
enabled = false
|
||||
}
|
||||
|
||||
tasks.named<JavaExec>("run") {
|
||||
jvmArgs("-Dfile.encoding=UTF-8", "-Dstdout.encoding=UTF-8", "-Dstderr.encoding=UTF-8")
|
||||
standardInput = System.`in`
|
||||
|
||||
@@ -1,7 +1,8 @@
|
||||
package de.nowchess.ui.terminal
|
||||
|
||||
import java.util.concurrent.atomic.AtomicBoolean
|
||||
import scala.io.StdIn
|
||||
import de.nowchess.api.move.PromotionPiece
|
||||
import de.nowchess.api.game.DrawReason
|
||||
import de.nowchess.chess.engine.GameEngine
|
||||
import de.nowchess.chess.observer.*
|
||||
import de.nowchess.ui.utils.Renderer
|
||||
@@ -11,7 +12,6 @@ import de.nowchess.ui.utils.Renderer
|
||||
*/
|
||||
class TerminalUI(engine: GameEngine) extends Observer:
|
||||
private val running = new AtomicBoolean(true)
|
||||
private val awaitingPromotion = new AtomicBoolean(false)
|
||||
|
||||
/** Called by GameEngine whenever a game event occurs. */
|
||||
override def onGameEvent(event: GameEvent): Unit =
|
||||
@@ -63,9 +63,6 @@ class TerminalUI(engine: GameEngine) extends Observer:
|
||||
print(Renderer.render(e.context.board))
|
||||
printPrompt(e.context.turn)
|
||||
|
||||
case _: PromotionRequiredEvent =>
|
||||
println("Promote to: q=Queen, r=Rook, b=Bishop, n=Knight")
|
||||
awaitingPromotion.set(true)
|
||||
case _: FiftyMoveRuleAvailableEvent =>
|
||||
println("50-move rule is now available — type 'draw' to claim.")
|
||||
|
||||
@@ -91,16 +88,6 @@ class TerminalUI(engine: GameEngine) extends Observer:
|
||||
while running.get() do
|
||||
val input = Option(StdIn.readLine()).getOrElse("quit").trim
|
||||
synchronized {
|
||||
if awaitingPromotion.get() then
|
||||
input.toLowerCase match
|
||||
case "q" => awaitingPromotion.set(false); engine.completePromotion(PromotionPiece.Queen)
|
||||
case "r" => awaitingPromotion.set(false); engine.completePromotion(PromotionPiece.Rook)
|
||||
case "b" => awaitingPromotion.set(false); engine.completePromotion(PromotionPiece.Bishop)
|
||||
case "n" => awaitingPromotion.set(false); engine.completePromotion(PromotionPiece.Knight)
|
||||
case _ =>
|
||||
println("Invalid choice. Enter q, r, b, or n.")
|
||||
println("Promote to: q=Queen, r=Rook, b=Bishop, n=Knight")
|
||||
else
|
||||
input.toLowerCase match
|
||||
case "quit" | "q" =>
|
||||
running.set(false)
|
||||
|
||||
@@ -1,3 +1,3 @@
|
||||
MAJOR=0
|
||||
MINOR=10
|
||||
MINOR=11
|
||||
PATCH=0
|
||||
|
||||
Reference in New Issue
Block a user