diff --git a/.codesight/CODESIGHT.md b/.codesight/CODESIGHT.md index 56fc2a9..949a540 100644 --- a/.codesight/CODESIGHT.md +++ b/.codesight/CODESIGHT.md @@ -2,8 +2,8 @@ > **Stack:** raw-http | none | unknown | scala -> 0 routes | 0 models | 0 components | 107 lib files | 1 env vars | 1 middleware -> **Token savings:** this file is ~7,200 tokens. Without it, AI exploration would cost ~37,300 tokens. **Saves ~30,100 tokens per conversation.** +> 0 routes | 0 models | 0 components | 159 lib files | 1 env vars | 1 middleware +> **Token savings:** this file is ~0 tokens. Without it, AI exploration would cost ~0 tokens. **Saves ~0 tokens per conversation.** --- @@ -25,11 +25,13 @@ - function main: () -> None - class TestCase - _...2 more_ +- `modules/account/src/main/scala/de/nowchess/account/client/CoreGameClient.scala` — class CoreGameClient, function createGame - `modules/account/src/main/scala/de/nowchess/account/config/JacksonConfig.scala` — class JacksonConfig, function customize - `modules/account/src/main/scala/de/nowchess/account/config/NativeReflectionConfig.scala` — class NativeReflectionConfig - `modules/account/src/main/scala/de/nowchess/account/domain/Account.scala` — class Account - `modules/account/src/main/scala/de/nowchess/account/domain/Challenge.scala` - class Challenge + - function gameIdOpt - function declineReasonOpt - function timeControlLimitOpt - function timeControlIncrementOpt @@ -81,6 +83,48 @@ - function cancel - function listForUser - _...1 more_ +- `modules/api/bin/scoverage/de/nowchess/api/board/Board.scala` + - class Board + - function apply + - function pieceAt + - function updated + - function removed + - function withMove + - _...2 more_ +- `modules/api/bin/scoverage/de/nowchess/api/board/CastlingRights.scala` + - function hasAnyRights + - function hasRights + - function revokeColor + - function revokeKingSide + - function revokeQueenSide + - class CastlingRights +- `modules/api/bin/scoverage/de/nowchess/api/board/Color.scala` — function opposite, function label +- `modules/api/bin/scoverage/de/nowchess/api/board/Piece.scala` — class Piece +- `modules/api/bin/scoverage/de/nowchess/api/board/PieceType.scala` — function label +- `modules/api/bin/scoverage/de/nowchess/api/board/Square.scala` + - class Square + - function fromAlgebraic + - function offset +- `modules/api/bin/scoverage/de/nowchess/api/bot/Bot.scala` + - class Bot + - function name + - function nextMove +- `modules/api/bin/scoverage/de/nowchess/api/dto/ErrorEventDto.scala` — class ErrorEventDto, function apply +- `modules/api/bin/scoverage/de/nowchess/api/dto/GameFullEventDto.scala` — class GameFullEventDto, function apply +- `modules/api/bin/scoverage/de/nowchess/api/dto/GameStateEventDto.scala` — class GameStateEventDto, function apply +- `modules/api/bin/scoverage/de/nowchess/api/game/GameContext.scala` + - function kingSquare + - function withBoard + - function withTurn + - function withCastlingRights + - function withEnPassantSquare + - function withHalfMoveClock + - _...4 more_ +- `modules/api/bin/scoverage/de/nowchess/api/player/PlayerInfo.scala` — class PlayerId, function apply +- `modules/api/bin/scoverage/de/nowchess/api/response/ApiResponse.scala` + - class ApiResponse + - function error + - function totalPages - `modules/api/src/main/scala/de/nowchess/api/board/Board.scala` - class Board - function apply @@ -142,6 +186,75 @@ - function isCheck - function isCheckmate - _...5 more_ +- `modules/bot/bin/scoverage/de/nowchess/bot/BotController.scala` + - class BotController + - function getBot + - function listBots +- `modules/bot/bin/scoverage/de/nowchess/bot/BotMoveRepetition.scala` + - class BotMoveRepetition + - function blockedMoves + - function repeatedMove + - function filterAllowed +- `modules/bot/bin/scoverage/de/nowchess/bot/Config.scala` — class Config +- `modules/bot/bin/scoverage/de/nowchess/bot/ai/Evaluation.scala` + - class Evaluation + - class CHECKMATE_SCORE + - class DRAW_SCORE + - function evaluate + - function initAccumulator + - function copyAccumulator + - _...2 more_ +- `modules/bot/bin/scoverage/de/nowchess/bot/bots/classic/EvaluationClassic.scala` + - class EvaluationClassic + - function evaluate + - function countRay +- `modules/bot/bin/scoverage/de/nowchess/bot/bots/nnue/EvaluationNNUE.scala` — class EvaluationNNUE, function evaluate +- `modules/bot/bin/scoverage/de/nowchess/bot/bots/nnue/NNUE.scala` + - class NNUE + - function initAccumulator + - function pushAccumulator + - function copyAccumulator + - function recomputeAccumulator + - function validateAccumulator + - _...4 more_ +- `modules/bot/bin/scoverage/de/nowchess/bot/bots/nnue/NbaiLoader.scala` + - class NbaiLoader + - function load + - function loadDefault +- `modules/bot/bin/scoverage/de/nowchess/bot/bots/nnue/NbaiMigrator.scala` — class NbaiMigrator, function migrateFromBin +- `modules/bot/bin/scoverage/de/nowchess/bot/bots/nnue/NbaiModel.scala` + - function toJson + - class NbaiMetadata + - function fromJson + - function str + - function num +- `modules/bot/bin/scoverage/de/nowchess/bot/bots/nnue/NbaiWriter.scala` — class NbaiWriter, function write +- `modules/bot/bin/scoverage/de/nowchess/bot/logic/AlphaBetaSearch.scala` + - function bestMove + - function bestMove + - function bestMoveWithTime + - function bestMoveWithTime + - function loop + - function loop +- `modules/bot/bin/scoverage/de/nowchess/bot/logic/MoveOrdering.scala` + - class MoveOrdering + - class OrderingContext + - function addKillerMove + - function getKillerMoves + - function addHistory + - function getHistory + - _...3 more_ +- `modules/bot/bin/scoverage/de/nowchess/bot/logic/TranspositionTable.scala` + - function advance + - function probe + - function store + - function clear +- `modules/bot/bin/scoverage/de/nowchess/bot/util/PolyglotBook.scala` — function probe, function select +- `modules/bot/bin/scoverage/de/nowchess/bot/util/PolyglotHash.scala` — class PolyglotHash, function hash +- `modules/bot/bin/scoverage/de/nowchess/bot/util/ZobristHash.scala` + - class ZobristHash + - function hash + - function nextHash - `modules/bot/python/nnue.py` - function get_weights_dir: () - function get_data_dir: () @@ -246,6 +359,63 @@ - class ZobristHash - function hash - function nextHash +- `modules/core/bin/scoverage/de/nowchess/chess/command/Command.scala` + - class Command + - function execute + - function undo + - function description + - class MoveResult +- `modules/core/bin/scoverage/de/nowchess/chess/command/CommandInvoker.scala` + - class CommandInvoker + - function execute + - function undo + - function redo + - function history + - function getCurrentIndex + - _...3 more_ +- `modules/core/bin/scoverage/de/nowchess/chess/config/JacksonConfig.scala` — class JacksonConfig, function customize +- `modules/core/bin/scoverage/de/nowchess/chess/controller/Parser.scala` — class Parser, function parseMove +- `modules/core/bin/scoverage/de/nowchess/chess/engine/GameEngine.scala` + - class GameEngine + - function board + - function turn + - function context + - function pendingDrawOfferBy + - function canUndo + - _...17 more_ +- `modules/core/bin/scoverage/de/nowchess/chess/exception/ApiException.scala` + - class ApiException + - class GameNotFoundException + - class BadRequestException +- `modules/core/bin/scoverage/de/nowchess/chess/exception/ApiExceptionMapper.scala` — class ApiExceptionMapper, function toResponse +- `modules/core/bin/scoverage/de/nowchess/chess/observer/Observer.scala` + - function context + - class Observer + - function onGameEvent + - class Observable + - function subscribe + - function unsubscribe + - _...1 more_ +- `modules/core/bin/scoverage/de/nowchess/chess/registry/GameRegistry.scala` + - class GameRegistry + - function store + - function get + - function update + - function generateId +- `modules/core/bin/scoverage/de/nowchess/chess/registry/GameRegistryImpl.scala` + - class GameRegistryImpl + - function store + - function get + - function update + - function generateId +- `modules/core/bin/scoverage/de/nowchess/chess/resource/GameResource.scala` + - class GameResource + - function onGameEvent + - function createGame + - function getGame + - function streamGame + - function onGameEvent + - _...10 more_ - `modules/core/src/main/scala/de/nowchess/chess/adapter/RuleSetRestAdapter.scala` - class RuleSetRestAdapter - function candidateMoves @@ -284,8 +454,6 @@ - _...3 more_ - `modules/core/src/main/scala/de/nowchess/chess/config/JacksonConfig.scala` — class JacksonConfig, function customize - `modules/core/src/main/scala/de/nowchess/chess/config/NativeReflectionConfig.scala` — class NativeReflectionConfig -- `modules/core/src/main/scala/de/nowchess/chess/config/SquareKeyDeserializer.scala` — class SquareKeyDeserializer -- `modules/core/src/main/scala/de/nowchess/chess/config/SquareKeySerializer.scala` — class SquareKeySerializer - `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 @@ -300,10 +468,6 @@ - class GameNotFoundException - class BadRequestException - `modules/core/src/main/scala/de/nowchess/chess/exception/ApiExceptionMapper.scala` — class ApiExceptionMapper, function toResponse -- `modules/core/src/main/scala/de/nowchess/chess/json/MoveTypeDeserializer.scala` — class MoveTypeDeserializer -- `modules/core/src/main/scala/de/nowchess/chess/json/MoveTypeSerializer.scala` — class MoveTypeSerializer -- `modules/core/src/main/scala/de/nowchess/chess/json/SquareDeserializer.scala` — class SquareDeserializer -- `modules/core/src/main/scala/de/nowchess/chess/json/SquareSerializer.scala` — class SquareSerializer - `modules/core/src/main/scala/de/nowchess/chess/observer/Observer.scala` - function context - class Observer @@ -329,9 +493,56 @@ - function onGameEvent - function createGame - function getGame - - function streamGame + - function resignGame + - function makeMove + - _...8 more_ +- `modules/core/src/main/scala/de/nowchess/chess/resource/GameWebSocketResource.scala` + - class GameWebSocketResource + - function onOpen - function onGameEvent - - _...10 more_ + - function onClose +- `modules/io/bin/scoverage/de/nowchess/io/GameContextExport.scala` — class GameContextExport, function exportGameContext +- `modules/io/bin/scoverage/de/nowchess/io/GameContextImport.scala` — class GameContextImport, function importGameContext +- `modules/io/bin/scoverage/de/nowchess/io/GameFileService.scala` + - class GameFileService + - function saveGameToFile + - function loadGameFromFile + - class FileSystemGameService + - function saveGameToFile + - function loadGameFromFile +- `modules/io/bin/scoverage/de/nowchess/io/fen/FenExporter.scala` + - class FenExporter + - function boardToFen + - function gameContextToFen + - function exportGameContext +- `modules/io/bin/scoverage/de/nowchess/io/fen/FenParser.scala` + - class FenParser + - function parseFen + - function importGameContext + - function parseBoard +- `modules/io/bin/scoverage/de/nowchess/io/fen/FenParserCombinators.scala` + - class FenParserCombinators + - function parseFen + - function parseBoard + - function importGameContext +- `modules/io/bin/scoverage/de/nowchess/io/fen/FenParserFastParse.scala` + - class FenParserFastParse + - function parseFen + - function parseBoard + - function importGameContext +- `modules/io/bin/scoverage/de/nowchess/io/fen/FenParserSupport.scala` — function buildSquares +- `modules/io/bin/scoverage/de/nowchess/io/json/JsonExporter.scala` — class JsonExporter, function exportGameContext +- `modules/io/bin/scoverage/de/nowchess/io/json/JsonParser.scala` — class JsonParser, function importGameContext +- `modules/io/bin/scoverage/de/nowchess/io/pgn/PgnExporter.scala` + - class PgnExporter + - function exportGameContext + - function exportGame +- `modules/io/bin/scoverage/de/nowchess/io/pgn/PgnParser.scala` + - class PgnParser + - function validatePgn + - function importGameContext + - function parsePgn + - function parseAlgebraicMove - `modules/io/src/main/scala/de/nowchess/io/GameFileService.scala` - class GameFileService - function saveGameToFile @@ -362,8 +573,6 @@ - `modules/io/src/main/scala/de/nowchess/io/fen/FenParserSupport.scala` — function buildSquares - `modules/io/src/main/scala/de/nowchess/io/json/JsonExporter.scala` — class JsonExporter, function exportGameContext - `modules/io/src/main/scala/de/nowchess/io/json/JsonParser.scala` — class JsonParser, function importGameContext -- `modules/io/src/main/scala/de/nowchess/io/json/SquareKeyDeserializer.scala` — class SquareKeyDeserializer -- `modules/io/src/main/scala/de/nowchess/io/json/SquareKeySerializer.scala` — class SquareKeySerializer - `modules/io/src/main/scala/de/nowchess/io/pgn/PgnExporter.scala` - class PgnExporter - function exportGameContext @@ -382,14 +591,31 @@ - function importPgn - function exportFen - function exportPgn +- `modules/json/src/main/scala/de/nowchess/json/ChessJacksonModule.scala` — class ChessJacksonModule +- `modules/json/src/main/scala/de/nowchess/json/GameResultDeserializer.scala` — class GameResultDeserializer +- `modules/json/src/main/scala/de/nowchess/json/GameResultSerializer.scala` — class GameResultSerializer +- `modules/json/src/main/scala/de/nowchess/json/MoveTypeDeserializer.scala` — class MoveTypeDeserializer +- `modules/json/src/main/scala/de/nowchess/json/MoveTypeSerializer.scala` — class MoveTypeSerializer +- `modules/json/src/main/scala/de/nowchess/json/SquareDeserializer.scala` — class SquareDeserializer +- `modules/json/src/main/scala/de/nowchess/json/SquareKeyDeserializer.scala` — class SquareKeyDeserializer +- `modules/json/src/main/scala/de/nowchess/json/SquareKeySerializer.scala` — class SquareKeySerializer +- `modules/json/src/main/scala/de/nowchess/json/SquareSerializer.scala` — class SquareSerializer +- `modules/rule/bin/scoverage/de/nowchess/rules/RuleSet.scala` + - class RuleSet + - function candidateMoves + - function legalMoves + - function allLegalMoves + - function isCheck + - function isCheckmate + - _...5 more_ +- `modules/rule/bin/scoverage/de/nowchess/rules/sets/DefaultRules.scala` + - class DefaultRules + - function positionOf + - function loop + - function toMoves + - function loop - `modules/rule/src/main/scala/de/nowchess/rules/config/JacksonConfig.scala` — class JacksonConfig, function customize - `modules/rule/src/main/scala/de/nowchess/rules/config/NativeReflectionConfig.scala` — class NativeReflectionConfig -- `modules/rule/src/main/scala/de/nowchess/rules/json/MoveTypeDeserializer.scala` — class MoveTypeDeserializer -- `modules/rule/src/main/scala/de/nowchess/rules/json/MoveTypeSerializer.scala` — class MoveTypeSerializer -- `modules/rule/src/main/scala/de/nowchess/rules/json/SquareDeserializer.scala` — class SquareDeserializer -- `modules/rule/src/main/scala/de/nowchess/rules/json/SquareKeyDeserializer.scala` — class SquareKeyDeserializer -- `modules/rule/src/main/scala/de/nowchess/rules/json/SquareKeySerializer.scala` — class SquareKeySerializer -- `modules/rule/src/main/scala/de/nowchess/rules/json/SquareSerializer.scala` — class SquareSerializer - `modules/rule/src/main/scala/de/nowchess/rules/resource/RuleSetResource.scala` - class RuleSetResource - function candidateMoves @@ -398,12 +624,7 @@ - function isCheck - function isCheckmate - _...5 more_ -- `modules/rule/src/main/scala/de/nowchess/rules/sets/DefaultRules.scala` - - class DefaultRules - - function positionOf - - function loop - - function toMoves - - function loop +- `modules/rule/src/main/scala/de/nowchess/rules/sets/DefaultRules.scala` — class DefaultRules, function positionOf --- @@ -426,39 +647,39 @@ ## Most Imported Files (change these carefully) -- `modules/api/src/main/scala/de/nowchess/api/game/GameContext.scala` — imported by **74** files -- `modules/api/src/main/scala/de/nowchess/api/board/Square.scala` — imported by **66** files -- `modules/api/src/main/scala/de/nowchess/api/move/Move.scala` — imported by **52** files -- `modules/api/src/main/scala/de/nowchess/api/board/Color.scala` — imported by **42** files -- `modules/rule/src/main/scala/de/nowchess/rules/sets/DefaultRules.scala` — imported by **27** files -- `modules/api/src/main/scala/de/nowchess/api/board/Piece.scala` — imported by **21** files -- `modules/api/src/main/scala/de/nowchess/api/board/Board.scala` — imported by **20** files -- `modules/api/src/main/scala/de/nowchess/api/board/PieceType.scala` — imported by **20** files -- `modules/api/src/main/scala/de/nowchess/api/board/CastlingRights.scala` — imported by **13** files -- `modules/api/src/main/scala/de/nowchess/api/game/DrawReason.scala` — imported by **12** files -- `modules/api/src/main/scala/de/nowchess/api/rules/RuleSet.scala` — imported by **12** files -- `modules/api/src/main/scala/de/nowchess/api/game/GameResult.scala` — imported by **10** files -- `modules/io/src/main/scala/de/nowchess/io/fen/FenParser.scala` — imported by **10** files -- `modules/api/src/main/scala/de/nowchess/api/error/GameError.scala` — imported by **9** files -- `modules/api/src/main/scala/de/nowchess/api/io/GameContextImport.scala` — imported by **8** files -- `modules/api/src/main/scala/de/nowchess/api/player/PlayerInfo.scala` — imported by **7** files -- `modules/core/src/main/scala/de/nowchess/chess/observer/Observer.scala` — imported by **7** files -- `modules/api/src/main/scala/de/nowchess/api/bot/Bot.scala` — imported by **6** files -- `modules/bot/src/main/scala/de/nowchess/bot/ai/Evaluation.scala` — imported by **6** files -- `modules/api/src/main/scala/de/nowchess/api/io/GameContextExport.scala` — imported by **6** files +- `modules/api/bin/scoverage/de/nowchess/api/game/GameContext.scala` — imported by **138** files +- `modules/api/bin/scoverage/de/nowchess/api/board/Square.scala` — imported by **99** files +- `modules/api/bin/scoverage/de/nowchess/api/move/Move.scala` — imported by **97** files +- `modules/api/bin/scoverage/de/nowchess/api/board/Color.scala` — imported by **81** files +- `modules/rule/bin/scoverage/de/nowchess/rules/sets/DefaultRules.scala` — imported by **44** files +- `modules/api/bin/scoverage/de/nowchess/api/board/Board.scala` — imported by **39** files +- `modules/api/bin/scoverage/de/nowchess/api/board/Piece.scala` — imported by **39** files +- `modules/api/bin/scoverage/de/nowchess/api/board/PieceType.scala` — imported by **37** files +- `modules/api/bin/scoverage/de/nowchess/api/game/DrawReason.scala` — imported by **23** files +- `modules/api/src/main/scala/de/nowchess/api/rules/RuleSet.scala` — imported by **23** files +- `modules/api/bin/scoverage/de/nowchess/api/board/CastlingRights.scala` — imported by **22** files +- `modules/api/bin/scoverage/de/nowchess/api/game/GameResult.scala` — imported by **21** files +- `modules/io/bin/scoverage/de/nowchess/io/fen/FenParser.scala` — imported by **20** files +- `modules/api/src/main/scala/de/nowchess/api/io/GameContextImport.scala` — imported by **15** files +- `modules/api/bin/scoverage/de/nowchess/api/player/PlayerInfo.scala` — imported by **14** files +- `modules/core/bin/scoverage/de/nowchess/chess/observer/Observer.scala` — imported by **13** files +- `modules/api/bin/scoverage/de/nowchess/api/bot/Bot.scala` — imported by **12** files +- `modules/bot/bin/scoverage/de/nowchess/bot/ai/Evaluation.scala` — imported by **12** files +- `modules/bot/bin/scoverage/de/nowchess/bot/util/PolyglotBook.scala` — imported by **10** files +- `modules/api/src/main/scala/de/nowchess/api/io/GameContextExport.scala` — imported by **10** files ## Import Map (who imports what) -- `modules/api/src/main/scala/de/nowchess/api/game/GameContext.scala` ← `modules/api/src/main/scala/de/nowchess/api/bot/Bot.scala`, `modules/api/src/main/scala/de/nowchess/api/io/GameContextExport.scala`, `modules/api/src/main/scala/de/nowchess/api/io/GameContextImport.scala`, `modules/api/src/main/scala/de/nowchess/api/rules/RuleSet.scala`, `modules/bot/src/main/scala/de/nowchess/bot/BotMoveRepetition.scala` +69 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/main/scala/de/nowchess/api/rules/RuleSet.scala`, `modules/api/src/test/scala/de/nowchess/api/game/GameContextTest.scala`, `modules/api/src/test/scala/de/nowchess/api/move/MoveTest.scala` +61 more -- `modules/api/src/main/scala/de/nowchess/api/move/Move.scala` ← `modules/api/src/main/scala/de/nowchess/api/bot/Bot.scala`, `modules/api/src/main/scala/de/nowchess/api/game/GameContext.scala`, `modules/api/src/main/scala/de/nowchess/api/rules/RuleSet.scala`, `modules/api/src/test/scala/de/nowchess/api/board/BoardTest.scala`, `modules/api/src/test/scala/de/nowchess/api/game/GameContextTest.scala` +47 more -- `modules/api/src/main/scala/de/nowchess/api/board/Color.scala` ← `modules/api/src/main/scala/de/nowchess/api/game/ClockState.scala`, `modules/api/src/main/scala/de/nowchess/api/game/GameContext.scala`, `modules/api/src/main/scala/de/nowchess/api/game/GameResult.scala`, `modules/api/src/test/scala/de/nowchess/api/game/ClockStateTest.scala`, `modules/api/src/test/scala/de/nowchess/api/game/GameContextTest.scala` +37 more -- `modules/rule/src/main/scala/de/nowchess/rules/sets/DefaultRules.scala` ← `modules/bot/src/main/scala/de/nowchess/bot/bots/ClassicalBot.scala`, `modules/bot/src/main/scala/de/nowchess/bot/bots/HybridBot.scala`, `modules/bot/src/main/scala/de/nowchess/bot/bots/NNUEBot.scala`, `modules/bot/src/main/scala/de/nowchess/bot/logic/AlphaBetaSearch.scala`, `modules/bot/src/test/scala/de/nowchess/bot/AlphaBetaSearchTest.scala` +22 more -- `modules/api/src/main/scala/de/nowchess/api/board/Piece.scala` ← `modules/bot/src/main/scala/de/nowchess/bot/bots/nnue/NNUE.scala`, `modules/bot/src/main/scala/de/nowchess/bot/logic/MoveOrdering.scala`, `modules/bot/src/main/scala/de/nowchess/bot/util/PolyglotHash.scala`, `modules/bot/src/main/scala/de/nowchess/bot/util/ZobristHash.scala`, `modules/bot/src/test/scala/de/nowchess/bot/AlphaBetaSearchTest.scala` +16 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/bot/src/main/scala/de/nowchess/bot/bots/nnue/NNUE.scala`, `modules/bot/src/main/scala/de/nowchess/bot/logic/MoveOrdering.scala`, `modules/bot/src/test/scala/de/nowchess/bot/AlphaBetaSearchTest.scala` +15 more -- `modules/api/src/main/scala/de/nowchess/api/board/PieceType.scala` ← `modules/api/src/main/scala/de/nowchess/api/game/GameContext.scala`, `modules/bot/src/main/scala/de/nowchess/bot/bots/classic/EvaluationClassic.scala`, `modules/bot/src/main/scala/de/nowchess/bot/bots/nnue/NNUE.scala`, `modules/bot/src/main/scala/de/nowchess/bot/logic/AlphaBetaSearch.scala`, `modules/bot/src/main/scala/de/nowchess/bot/logic/MoveOrdering.scala` +15 more -- `modules/api/src/main/scala/de/nowchess/api/board/CastlingRights.scala` ← `modules/api/src/main/scala/de/nowchess/api/game/GameContext.scala`, `modules/api/src/test/scala/de/nowchess/api/game/GameContextTest.scala`, `modules/bot/src/test/scala/de/nowchess/bot/ZobristHashTest.scala`, `modules/core/src/main/scala/de/nowchess/chess/config/NativeReflectionConfig.scala`, `modules/core/src/test/scala/de/nowchess/chess/engine/GameEngineWithBotTest.scala` +8 more -- `modules/api/src/main/scala/de/nowchess/api/game/DrawReason.scala` ← `modules/api/src/test/scala/de/nowchess/api/game/GameContextTest.scala`, `modules/core/src/main/scala/de/nowchess/chess/config/NativeReflectionConfig.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/main/scala/de/nowchess/chess/resource/GameResource.scala` +7 more +- `modules/api/bin/scoverage/de/nowchess/api/game/GameContext.scala` ← `modules/api/bin/scoverage/de/nowchess/api/bot/Bot.scala`, `modules/api/src/main/scala/de/nowchess/api/bot/Bot.scala`, `modules/api/src/main/scala/de/nowchess/api/io/GameContextExport.scala`, `modules/api/src/main/scala/de/nowchess/api/io/GameContextImport.scala`, `modules/api/src/main/scala/de/nowchess/api/rules/RuleSet.scala` +133 more +- `modules/api/bin/scoverage/de/nowchess/api/board/Square.scala` ← `modules/api/bin/scoverage/de/nowchess/api/game/GameContext.scala`, `modules/api/bin/scoverage/de/nowchess/api/move/Move.scala`, `modules/api/bin/test/de/nowchess/api/game/GameContextTest.scala`, `modules/api/bin/test/de/nowchess/api/move/MoveTest.scala`, `modules/api/src/main/scala/de/nowchess/api/game/GameContext.scala` +94 more +- `modules/api/bin/scoverage/de/nowchess/api/move/Move.scala` ← `modules/api/bin/scoverage/de/nowchess/api/bot/Bot.scala`, `modules/api/bin/scoverage/de/nowchess/api/game/GameContext.scala`, `modules/api/bin/test/de/nowchess/api/board/BoardTest.scala`, `modules/api/bin/test/de/nowchess/api/game/GameContextTest.scala`, `modules/api/src/main/scala/de/nowchess/api/bot/Bot.scala` +92 more +- `modules/api/bin/scoverage/de/nowchess/api/board/Color.scala` ← `modules/api/bin/scoverage/de/nowchess/api/game/GameContext.scala`, `modules/api/bin/scoverage/de/nowchess/api/game/GameResult.scala`, `modules/api/bin/test/de/nowchess/api/game/GameContextTest.scala`, `modules/api/src/main/scala/de/nowchess/api/game/ClockState.scala`, `modules/api/src/main/scala/de/nowchess/api/game/GameContext.scala` +76 more +- `modules/rule/bin/scoverage/de/nowchess/rules/sets/DefaultRules.scala` ← `modules/bot/bin/scoverage/de/nowchess/bot/bots/ClassicalBot.scala`, `modules/bot/bin/scoverage/de/nowchess/bot/bots/HybridBot.scala`, `modules/bot/bin/scoverage/de/nowchess/bot/bots/NNUEBot.scala`, `modules/bot/bin/scoverage/de/nowchess/bot/logic/AlphaBetaSearch.scala`, `modules/bot/bin/test/de/nowchess/bot/AlphaBetaSearchTest.scala` +39 more +- `modules/api/bin/scoverage/de/nowchess/api/board/Board.scala` ← `modules/api/bin/scoverage/de/nowchess/api/game/GameContext.scala`, `modules/api/bin/test/de/nowchess/api/game/GameContextTest.scala`, `modules/api/src/main/scala/de/nowchess/api/game/GameContext.scala`, `modules/api/src/test/scala/de/nowchess/api/game/GameContextTest.scala`, `modules/bot/bin/scoverage/de/nowchess/bot/bots/nnue/NNUE.scala` +34 more +- `modules/api/bin/scoverage/de/nowchess/api/board/Piece.scala` ← `modules/bot/bin/scoverage/de/nowchess/bot/bots/nnue/NNUE.scala`, `modules/bot/bin/scoverage/de/nowchess/bot/logic/MoveOrdering.scala`, `modules/bot/bin/scoverage/de/nowchess/bot/util/PolyglotHash.scala`, `modules/bot/bin/scoverage/de/nowchess/bot/util/ZobristHash.scala`, `modules/bot/bin/test/de/nowchess/bot/AlphaBetaSearchTest.scala` +34 more +- `modules/api/bin/scoverage/de/nowchess/api/board/PieceType.scala` ← `modules/api/bin/scoverage/de/nowchess/api/game/GameContext.scala`, `modules/api/src/main/scala/de/nowchess/api/game/GameContext.scala`, `modules/bot/bin/scoverage/de/nowchess/bot/bots/classic/EvaluationClassic.scala`, `modules/bot/bin/scoverage/de/nowchess/bot/bots/nnue/NNUE.scala`, `modules/bot/bin/scoverage/de/nowchess/bot/logic/AlphaBetaSearch.scala` +32 more +- `modules/api/bin/scoverage/de/nowchess/api/game/DrawReason.scala` ← `modules/api/bin/test/de/nowchess/api/game/GameContextTest.scala`, `modules/api/src/test/scala/de/nowchess/api/game/GameContextTest.scala`, `modules/core/bin/scoverage/de/nowchess/chess/engine/GameEngine.scala`, `modules/core/bin/scoverage/de/nowchess/chess/observer/Observer.scala`, `modules/core/bin/scoverage/de/nowchess/chess/resource/GameResource.scala` +18 more +- `modules/api/src/main/scala/de/nowchess/api/rules/RuleSet.scala` ← `modules/bot/bin/scoverage/de/nowchess/bot/bots/ClassicalBot.scala`, `modules/bot/bin/scoverage/de/nowchess/bot/bots/HybridBot.scala`, `modules/bot/bin/scoverage/de/nowchess/bot/bots/NNUEBot.scala`, `modules/bot/bin/scoverage/de/nowchess/bot/logic/AlphaBetaSearch.scala`, `modules/bot/bin/test/de/nowchess/bot/AlphaBetaSearchTest.scala` +18 more --- diff --git a/.codesight/graph.md b/.codesight/graph.md index 42b736a..4201932 100644 --- a/.codesight/graph.md +++ b/.codesight/graph.md @@ -2,36 +2,36 @@ ## Most Imported Files (change these carefully) -- `modules/api/src/main/scala/de/nowchess/api/game/GameContext.scala` — imported by **74** files -- `modules/api/src/main/scala/de/nowchess/api/board/Square.scala` — imported by **66** files -- `modules/api/src/main/scala/de/nowchess/api/move/Move.scala` — imported by **52** files -- `modules/api/src/main/scala/de/nowchess/api/board/Color.scala` — imported by **42** files -- `modules/rule/src/main/scala/de/nowchess/rules/sets/DefaultRules.scala` — imported by **27** files -- `modules/api/src/main/scala/de/nowchess/api/board/Piece.scala` — imported by **21** files -- `modules/api/src/main/scala/de/nowchess/api/board/Board.scala` — imported by **20** files -- `modules/api/src/main/scala/de/nowchess/api/board/PieceType.scala` — imported by **20** files -- `modules/api/src/main/scala/de/nowchess/api/board/CastlingRights.scala` — imported by **13** files -- `modules/api/src/main/scala/de/nowchess/api/game/DrawReason.scala` — imported by **12** files -- `modules/api/src/main/scala/de/nowchess/api/rules/RuleSet.scala` — imported by **12** files -- `modules/api/src/main/scala/de/nowchess/api/game/GameResult.scala` — imported by **10** files -- `modules/io/src/main/scala/de/nowchess/io/fen/FenParser.scala` — imported by **10** files -- `modules/api/src/main/scala/de/nowchess/api/error/GameError.scala` — imported by **9** files -- `modules/api/src/main/scala/de/nowchess/api/io/GameContextImport.scala` — imported by **8** files -- `modules/api/src/main/scala/de/nowchess/api/player/PlayerInfo.scala` — imported by **7** files -- `modules/core/src/main/scala/de/nowchess/chess/observer/Observer.scala` — imported by **7** files -- `modules/api/src/main/scala/de/nowchess/api/bot/Bot.scala` — imported by **6** files -- `modules/bot/src/main/scala/de/nowchess/bot/ai/Evaluation.scala` — imported by **6** files -- `modules/api/src/main/scala/de/nowchess/api/io/GameContextExport.scala` — imported by **6** files +- `modules/api/bin/scoverage/de/nowchess/api/game/GameContext.scala` — imported by **138** files +- `modules/api/bin/scoverage/de/nowchess/api/board/Square.scala` — imported by **99** files +- `modules/api/bin/scoverage/de/nowchess/api/move/Move.scala` — imported by **97** files +- `modules/api/bin/scoverage/de/nowchess/api/board/Color.scala` — imported by **81** files +- `modules/rule/bin/scoverage/de/nowchess/rules/sets/DefaultRules.scala` — imported by **44** files +- `modules/api/bin/scoverage/de/nowchess/api/board/Board.scala` — imported by **39** files +- `modules/api/bin/scoverage/de/nowchess/api/board/Piece.scala` — imported by **39** files +- `modules/api/bin/scoverage/de/nowchess/api/board/PieceType.scala` — imported by **37** files +- `modules/api/bin/scoverage/de/nowchess/api/game/DrawReason.scala` — imported by **23** files +- `modules/api/src/main/scala/de/nowchess/api/rules/RuleSet.scala` — imported by **23** files +- `modules/api/bin/scoverage/de/nowchess/api/board/CastlingRights.scala` — imported by **22** files +- `modules/api/bin/scoverage/de/nowchess/api/game/GameResult.scala` — imported by **21** files +- `modules/io/bin/scoverage/de/nowchess/io/fen/FenParser.scala` — imported by **20** files +- `modules/api/src/main/scala/de/nowchess/api/io/GameContextImport.scala` — imported by **15** files +- `modules/api/bin/scoverage/de/nowchess/api/player/PlayerInfo.scala` — imported by **14** files +- `modules/core/bin/scoverage/de/nowchess/chess/observer/Observer.scala` — imported by **13** files +- `modules/api/bin/scoverage/de/nowchess/api/bot/Bot.scala` — imported by **12** files +- `modules/bot/bin/scoverage/de/nowchess/bot/ai/Evaluation.scala` — imported by **12** files +- `modules/bot/bin/scoverage/de/nowchess/bot/util/PolyglotBook.scala` — imported by **10** files +- `modules/api/src/main/scala/de/nowchess/api/io/GameContextExport.scala` — imported by **10** files ## Import Map (who imports what) -- `modules/api/src/main/scala/de/nowchess/api/game/GameContext.scala` ← `modules/api/src/main/scala/de/nowchess/api/bot/Bot.scala`, `modules/api/src/main/scala/de/nowchess/api/io/GameContextExport.scala`, `modules/api/src/main/scala/de/nowchess/api/io/GameContextImport.scala`, `modules/api/src/main/scala/de/nowchess/api/rules/RuleSet.scala`, `modules/bot/src/main/scala/de/nowchess/bot/BotMoveRepetition.scala` +69 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/main/scala/de/nowchess/api/rules/RuleSet.scala`, `modules/api/src/test/scala/de/nowchess/api/game/GameContextTest.scala`, `modules/api/src/test/scala/de/nowchess/api/move/MoveTest.scala` +61 more -- `modules/api/src/main/scala/de/nowchess/api/move/Move.scala` ← `modules/api/src/main/scala/de/nowchess/api/bot/Bot.scala`, `modules/api/src/main/scala/de/nowchess/api/game/GameContext.scala`, `modules/api/src/main/scala/de/nowchess/api/rules/RuleSet.scala`, `modules/api/src/test/scala/de/nowchess/api/board/BoardTest.scala`, `modules/api/src/test/scala/de/nowchess/api/game/GameContextTest.scala` +47 more -- `modules/api/src/main/scala/de/nowchess/api/board/Color.scala` ← `modules/api/src/main/scala/de/nowchess/api/game/ClockState.scala`, `modules/api/src/main/scala/de/nowchess/api/game/GameContext.scala`, `modules/api/src/main/scala/de/nowchess/api/game/GameResult.scala`, `modules/api/src/test/scala/de/nowchess/api/game/ClockStateTest.scala`, `modules/api/src/test/scala/de/nowchess/api/game/GameContextTest.scala` +37 more -- `modules/rule/src/main/scala/de/nowchess/rules/sets/DefaultRules.scala` ← `modules/bot/src/main/scala/de/nowchess/bot/bots/ClassicalBot.scala`, `modules/bot/src/main/scala/de/nowchess/bot/bots/HybridBot.scala`, `modules/bot/src/main/scala/de/nowchess/bot/bots/NNUEBot.scala`, `modules/bot/src/main/scala/de/nowchess/bot/logic/AlphaBetaSearch.scala`, `modules/bot/src/test/scala/de/nowchess/bot/AlphaBetaSearchTest.scala` +22 more -- `modules/api/src/main/scala/de/nowchess/api/board/Piece.scala` ← `modules/bot/src/main/scala/de/nowchess/bot/bots/nnue/NNUE.scala`, `modules/bot/src/main/scala/de/nowchess/bot/logic/MoveOrdering.scala`, `modules/bot/src/main/scala/de/nowchess/bot/util/PolyglotHash.scala`, `modules/bot/src/main/scala/de/nowchess/bot/util/ZobristHash.scala`, `modules/bot/src/test/scala/de/nowchess/bot/AlphaBetaSearchTest.scala` +16 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/bot/src/main/scala/de/nowchess/bot/bots/nnue/NNUE.scala`, `modules/bot/src/main/scala/de/nowchess/bot/logic/MoveOrdering.scala`, `modules/bot/src/test/scala/de/nowchess/bot/AlphaBetaSearchTest.scala` +15 more -- `modules/api/src/main/scala/de/nowchess/api/board/PieceType.scala` ← `modules/api/src/main/scala/de/nowchess/api/game/GameContext.scala`, `modules/bot/src/main/scala/de/nowchess/bot/bots/classic/EvaluationClassic.scala`, `modules/bot/src/main/scala/de/nowchess/bot/bots/nnue/NNUE.scala`, `modules/bot/src/main/scala/de/nowchess/bot/logic/AlphaBetaSearch.scala`, `modules/bot/src/main/scala/de/nowchess/bot/logic/MoveOrdering.scala` +15 more -- `modules/api/src/main/scala/de/nowchess/api/board/CastlingRights.scala` ← `modules/api/src/main/scala/de/nowchess/api/game/GameContext.scala`, `modules/api/src/test/scala/de/nowchess/api/game/GameContextTest.scala`, `modules/bot/src/test/scala/de/nowchess/bot/ZobristHashTest.scala`, `modules/core/src/main/scala/de/nowchess/chess/config/NativeReflectionConfig.scala`, `modules/core/src/test/scala/de/nowchess/chess/engine/GameEngineWithBotTest.scala` +8 more -- `modules/api/src/main/scala/de/nowchess/api/game/DrawReason.scala` ← `modules/api/src/test/scala/de/nowchess/api/game/GameContextTest.scala`, `modules/core/src/main/scala/de/nowchess/chess/config/NativeReflectionConfig.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/main/scala/de/nowchess/chess/resource/GameResource.scala` +7 more +- `modules/api/bin/scoverage/de/nowchess/api/game/GameContext.scala` ← `modules/api/bin/scoverage/de/nowchess/api/bot/Bot.scala`, `modules/api/src/main/scala/de/nowchess/api/bot/Bot.scala`, `modules/api/src/main/scala/de/nowchess/api/io/GameContextExport.scala`, `modules/api/src/main/scala/de/nowchess/api/io/GameContextImport.scala`, `modules/api/src/main/scala/de/nowchess/api/rules/RuleSet.scala` +133 more +- `modules/api/bin/scoverage/de/nowchess/api/board/Square.scala` ← `modules/api/bin/scoverage/de/nowchess/api/game/GameContext.scala`, `modules/api/bin/scoverage/de/nowchess/api/move/Move.scala`, `modules/api/bin/test/de/nowchess/api/game/GameContextTest.scala`, `modules/api/bin/test/de/nowchess/api/move/MoveTest.scala`, `modules/api/src/main/scala/de/nowchess/api/game/GameContext.scala` +94 more +- `modules/api/bin/scoverage/de/nowchess/api/move/Move.scala` ← `modules/api/bin/scoverage/de/nowchess/api/bot/Bot.scala`, `modules/api/bin/scoverage/de/nowchess/api/game/GameContext.scala`, `modules/api/bin/test/de/nowchess/api/board/BoardTest.scala`, `modules/api/bin/test/de/nowchess/api/game/GameContextTest.scala`, `modules/api/src/main/scala/de/nowchess/api/bot/Bot.scala` +92 more +- `modules/api/bin/scoverage/de/nowchess/api/board/Color.scala` ← `modules/api/bin/scoverage/de/nowchess/api/game/GameContext.scala`, `modules/api/bin/scoverage/de/nowchess/api/game/GameResult.scala`, `modules/api/bin/test/de/nowchess/api/game/GameContextTest.scala`, `modules/api/src/main/scala/de/nowchess/api/game/ClockState.scala`, `modules/api/src/main/scala/de/nowchess/api/game/GameContext.scala` +76 more +- `modules/rule/bin/scoverage/de/nowchess/rules/sets/DefaultRules.scala` ← `modules/bot/bin/scoverage/de/nowchess/bot/bots/ClassicalBot.scala`, `modules/bot/bin/scoverage/de/nowchess/bot/bots/HybridBot.scala`, `modules/bot/bin/scoverage/de/nowchess/bot/bots/NNUEBot.scala`, `modules/bot/bin/scoverage/de/nowchess/bot/logic/AlphaBetaSearch.scala`, `modules/bot/bin/test/de/nowchess/bot/AlphaBetaSearchTest.scala` +39 more +- `modules/api/bin/scoverage/de/nowchess/api/board/Board.scala` ← `modules/api/bin/scoverage/de/nowchess/api/game/GameContext.scala`, `modules/api/bin/test/de/nowchess/api/game/GameContextTest.scala`, `modules/api/src/main/scala/de/nowchess/api/game/GameContext.scala`, `modules/api/src/test/scala/de/nowchess/api/game/GameContextTest.scala`, `modules/bot/bin/scoverage/de/nowchess/bot/bots/nnue/NNUE.scala` +34 more +- `modules/api/bin/scoverage/de/nowchess/api/board/Piece.scala` ← `modules/bot/bin/scoverage/de/nowchess/bot/bots/nnue/NNUE.scala`, `modules/bot/bin/scoverage/de/nowchess/bot/logic/MoveOrdering.scala`, `modules/bot/bin/scoverage/de/nowchess/bot/util/PolyglotHash.scala`, `modules/bot/bin/scoverage/de/nowchess/bot/util/ZobristHash.scala`, `modules/bot/bin/test/de/nowchess/bot/AlphaBetaSearchTest.scala` +34 more +- `modules/api/bin/scoverage/de/nowchess/api/board/PieceType.scala` ← `modules/api/bin/scoverage/de/nowchess/api/game/GameContext.scala`, `modules/api/src/main/scala/de/nowchess/api/game/GameContext.scala`, `modules/bot/bin/scoverage/de/nowchess/bot/bots/classic/EvaluationClassic.scala`, `modules/bot/bin/scoverage/de/nowchess/bot/bots/nnue/NNUE.scala`, `modules/bot/bin/scoverage/de/nowchess/bot/logic/AlphaBetaSearch.scala` +32 more +- `modules/api/bin/scoverage/de/nowchess/api/game/DrawReason.scala` ← `modules/api/bin/test/de/nowchess/api/game/GameContextTest.scala`, `modules/api/src/test/scala/de/nowchess/api/game/GameContextTest.scala`, `modules/core/bin/scoverage/de/nowchess/chess/engine/GameEngine.scala`, `modules/core/bin/scoverage/de/nowchess/chess/observer/Observer.scala`, `modules/core/bin/scoverage/de/nowchess/chess/resource/GameResource.scala` +18 more +- `modules/api/src/main/scala/de/nowchess/api/rules/RuleSet.scala` ← `modules/bot/bin/scoverage/de/nowchess/bot/bots/ClassicalBot.scala`, `modules/bot/bin/scoverage/de/nowchess/bot/bots/HybridBot.scala`, `modules/bot/bin/scoverage/de/nowchess/bot/bots/NNUEBot.scala`, `modules/bot/bin/scoverage/de/nowchess/bot/logic/AlphaBetaSearch.scala`, `modules/bot/bin/test/de/nowchess/bot/AlphaBetaSearchTest.scala` +18 more diff --git a/.codesight/libs.md b/.codesight/libs.md index 9c66ffb..b560577 100644 --- a/.codesight/libs.md +++ b/.codesight/libs.md @@ -16,11 +16,13 @@ - function main: () -> None - class TestCase - _...2 more_ +- `modules/account/src/main/scala/de/nowchess/account/client/CoreGameClient.scala` — class CoreGameClient, function createGame - `modules/account/src/main/scala/de/nowchess/account/config/JacksonConfig.scala` — class JacksonConfig, function customize - `modules/account/src/main/scala/de/nowchess/account/config/NativeReflectionConfig.scala` — class NativeReflectionConfig - `modules/account/src/main/scala/de/nowchess/account/domain/Account.scala` — class Account - `modules/account/src/main/scala/de/nowchess/account/domain/Challenge.scala` - class Challenge + - function gameIdOpt - function declineReasonOpt - function timeControlLimitOpt - function timeControlIncrementOpt @@ -72,6 +74,48 @@ - function cancel - function listForUser - _...1 more_ +- `modules/api/bin/scoverage/de/nowchess/api/board/Board.scala` + - class Board + - function apply + - function pieceAt + - function updated + - function removed + - function withMove + - _...2 more_ +- `modules/api/bin/scoverage/de/nowchess/api/board/CastlingRights.scala` + - function hasAnyRights + - function hasRights + - function revokeColor + - function revokeKingSide + - function revokeQueenSide + - class CastlingRights +- `modules/api/bin/scoverage/de/nowchess/api/board/Color.scala` — function opposite, function label +- `modules/api/bin/scoverage/de/nowchess/api/board/Piece.scala` — class Piece +- `modules/api/bin/scoverage/de/nowchess/api/board/PieceType.scala` — function label +- `modules/api/bin/scoverage/de/nowchess/api/board/Square.scala` + - class Square + - function fromAlgebraic + - function offset +- `modules/api/bin/scoverage/de/nowchess/api/bot/Bot.scala` + - class Bot + - function name + - function nextMove +- `modules/api/bin/scoverage/de/nowchess/api/dto/ErrorEventDto.scala` — class ErrorEventDto, function apply +- `modules/api/bin/scoverage/de/nowchess/api/dto/GameFullEventDto.scala` — class GameFullEventDto, function apply +- `modules/api/bin/scoverage/de/nowchess/api/dto/GameStateEventDto.scala` — class GameStateEventDto, function apply +- `modules/api/bin/scoverage/de/nowchess/api/game/GameContext.scala` + - function kingSquare + - function withBoard + - function withTurn + - function withCastlingRights + - function withEnPassantSquare + - function withHalfMoveClock + - _...4 more_ +- `modules/api/bin/scoverage/de/nowchess/api/player/PlayerInfo.scala` — class PlayerId, function apply +- `modules/api/bin/scoverage/de/nowchess/api/response/ApiResponse.scala` + - class ApiResponse + - function error + - function totalPages - `modules/api/src/main/scala/de/nowchess/api/board/Board.scala` - class Board - function apply @@ -133,6 +177,75 @@ - function isCheck - function isCheckmate - _...5 more_ +- `modules/bot/bin/scoverage/de/nowchess/bot/BotController.scala` + - class BotController + - function getBot + - function listBots +- `modules/bot/bin/scoverage/de/nowchess/bot/BotMoveRepetition.scala` + - class BotMoveRepetition + - function blockedMoves + - function repeatedMove + - function filterAllowed +- `modules/bot/bin/scoverage/de/nowchess/bot/Config.scala` — class Config +- `modules/bot/bin/scoverage/de/nowchess/bot/ai/Evaluation.scala` + - class Evaluation + - class CHECKMATE_SCORE + - class DRAW_SCORE + - function evaluate + - function initAccumulator + - function copyAccumulator + - _...2 more_ +- `modules/bot/bin/scoverage/de/nowchess/bot/bots/classic/EvaluationClassic.scala` + - class EvaluationClassic + - function evaluate + - function countRay +- `modules/bot/bin/scoverage/de/nowchess/bot/bots/nnue/EvaluationNNUE.scala` — class EvaluationNNUE, function evaluate +- `modules/bot/bin/scoverage/de/nowchess/bot/bots/nnue/NNUE.scala` + - class NNUE + - function initAccumulator + - function pushAccumulator + - function copyAccumulator + - function recomputeAccumulator + - function validateAccumulator + - _...4 more_ +- `modules/bot/bin/scoverage/de/nowchess/bot/bots/nnue/NbaiLoader.scala` + - class NbaiLoader + - function load + - function loadDefault +- `modules/bot/bin/scoverage/de/nowchess/bot/bots/nnue/NbaiMigrator.scala` — class NbaiMigrator, function migrateFromBin +- `modules/bot/bin/scoverage/de/nowchess/bot/bots/nnue/NbaiModel.scala` + - function toJson + - class NbaiMetadata + - function fromJson + - function str + - function num +- `modules/bot/bin/scoverage/de/nowchess/bot/bots/nnue/NbaiWriter.scala` — class NbaiWriter, function write +- `modules/bot/bin/scoverage/de/nowchess/bot/logic/AlphaBetaSearch.scala` + - function bestMove + - function bestMove + - function bestMoveWithTime + - function bestMoveWithTime + - function loop + - function loop +- `modules/bot/bin/scoverage/de/nowchess/bot/logic/MoveOrdering.scala` + - class MoveOrdering + - class OrderingContext + - function addKillerMove + - function getKillerMoves + - function addHistory + - function getHistory + - _...3 more_ +- `modules/bot/bin/scoverage/de/nowchess/bot/logic/TranspositionTable.scala` + - function advance + - function probe + - function store + - function clear +- `modules/bot/bin/scoverage/de/nowchess/bot/util/PolyglotBook.scala` — function probe, function select +- `modules/bot/bin/scoverage/de/nowchess/bot/util/PolyglotHash.scala` — class PolyglotHash, function hash +- `modules/bot/bin/scoverage/de/nowchess/bot/util/ZobristHash.scala` + - class ZobristHash + - function hash + - function nextHash - `modules/bot/python/nnue.py` - function get_weights_dir: () - function get_data_dir: () @@ -237,6 +350,63 @@ - class ZobristHash - function hash - function nextHash +- `modules/core/bin/scoverage/de/nowchess/chess/command/Command.scala` + - class Command + - function execute + - function undo + - function description + - class MoveResult +- `modules/core/bin/scoverage/de/nowchess/chess/command/CommandInvoker.scala` + - class CommandInvoker + - function execute + - function undo + - function redo + - function history + - function getCurrentIndex + - _...3 more_ +- `modules/core/bin/scoverage/de/nowchess/chess/config/JacksonConfig.scala` — class JacksonConfig, function customize +- `modules/core/bin/scoverage/de/nowchess/chess/controller/Parser.scala` — class Parser, function parseMove +- `modules/core/bin/scoverage/de/nowchess/chess/engine/GameEngine.scala` + - class GameEngine + - function board + - function turn + - function context + - function pendingDrawOfferBy + - function canUndo + - _...17 more_ +- `modules/core/bin/scoverage/de/nowchess/chess/exception/ApiException.scala` + - class ApiException + - class GameNotFoundException + - class BadRequestException +- `modules/core/bin/scoverage/de/nowchess/chess/exception/ApiExceptionMapper.scala` — class ApiExceptionMapper, function toResponse +- `modules/core/bin/scoverage/de/nowchess/chess/observer/Observer.scala` + - function context + - class Observer + - function onGameEvent + - class Observable + - function subscribe + - function unsubscribe + - _...1 more_ +- `modules/core/bin/scoverage/de/nowchess/chess/registry/GameRegistry.scala` + - class GameRegistry + - function store + - function get + - function update + - function generateId +- `modules/core/bin/scoverage/de/nowchess/chess/registry/GameRegistryImpl.scala` + - class GameRegistryImpl + - function store + - function get + - function update + - function generateId +- `modules/core/bin/scoverage/de/nowchess/chess/resource/GameResource.scala` + - class GameResource + - function onGameEvent + - function createGame + - function getGame + - function streamGame + - function onGameEvent + - _...10 more_ - `modules/core/src/main/scala/de/nowchess/chess/adapter/RuleSetRestAdapter.scala` - class RuleSetRestAdapter - function candidateMoves @@ -275,8 +445,6 @@ - _...3 more_ - `modules/core/src/main/scala/de/nowchess/chess/config/JacksonConfig.scala` — class JacksonConfig, function customize - `modules/core/src/main/scala/de/nowchess/chess/config/NativeReflectionConfig.scala` — class NativeReflectionConfig -- `modules/core/src/main/scala/de/nowchess/chess/config/SquareKeyDeserializer.scala` — class SquareKeyDeserializer -- `modules/core/src/main/scala/de/nowchess/chess/config/SquareKeySerializer.scala` — class SquareKeySerializer - `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 @@ -291,10 +459,6 @@ - class GameNotFoundException - class BadRequestException - `modules/core/src/main/scala/de/nowchess/chess/exception/ApiExceptionMapper.scala` — class ApiExceptionMapper, function toResponse -- `modules/core/src/main/scala/de/nowchess/chess/json/MoveTypeDeserializer.scala` — class MoveTypeDeserializer -- `modules/core/src/main/scala/de/nowchess/chess/json/MoveTypeSerializer.scala` — class MoveTypeSerializer -- `modules/core/src/main/scala/de/nowchess/chess/json/SquareDeserializer.scala` — class SquareDeserializer -- `modules/core/src/main/scala/de/nowchess/chess/json/SquareSerializer.scala` — class SquareSerializer - `modules/core/src/main/scala/de/nowchess/chess/observer/Observer.scala` - function context - class Observer @@ -320,9 +484,56 @@ - function onGameEvent - function createGame - function getGame - - function streamGame + - function resignGame + - function makeMove + - _...8 more_ +- `modules/core/src/main/scala/de/nowchess/chess/resource/GameWebSocketResource.scala` + - class GameWebSocketResource + - function onOpen - function onGameEvent - - _...10 more_ + - function onClose +- `modules/io/bin/scoverage/de/nowchess/io/GameContextExport.scala` — class GameContextExport, function exportGameContext +- `modules/io/bin/scoverage/de/nowchess/io/GameContextImport.scala` — class GameContextImport, function importGameContext +- `modules/io/bin/scoverage/de/nowchess/io/GameFileService.scala` + - class GameFileService + - function saveGameToFile + - function loadGameFromFile + - class FileSystemGameService + - function saveGameToFile + - function loadGameFromFile +- `modules/io/bin/scoverage/de/nowchess/io/fen/FenExporter.scala` + - class FenExporter + - function boardToFen + - function gameContextToFen + - function exportGameContext +- `modules/io/bin/scoverage/de/nowchess/io/fen/FenParser.scala` + - class FenParser + - function parseFen + - function importGameContext + - function parseBoard +- `modules/io/bin/scoverage/de/nowchess/io/fen/FenParserCombinators.scala` + - class FenParserCombinators + - function parseFen + - function parseBoard + - function importGameContext +- `modules/io/bin/scoverage/de/nowchess/io/fen/FenParserFastParse.scala` + - class FenParserFastParse + - function parseFen + - function parseBoard + - function importGameContext +- `modules/io/bin/scoverage/de/nowchess/io/fen/FenParserSupport.scala` — function buildSquares +- `modules/io/bin/scoverage/de/nowchess/io/json/JsonExporter.scala` — class JsonExporter, function exportGameContext +- `modules/io/bin/scoverage/de/nowchess/io/json/JsonParser.scala` — class JsonParser, function importGameContext +- `modules/io/bin/scoverage/de/nowchess/io/pgn/PgnExporter.scala` + - class PgnExporter + - function exportGameContext + - function exportGame +- `modules/io/bin/scoverage/de/nowchess/io/pgn/PgnParser.scala` + - class PgnParser + - function validatePgn + - function importGameContext + - function parsePgn + - function parseAlgebraicMove - `modules/io/src/main/scala/de/nowchess/io/GameFileService.scala` - class GameFileService - function saveGameToFile @@ -353,8 +564,6 @@ - `modules/io/src/main/scala/de/nowchess/io/fen/FenParserSupport.scala` — function buildSquares - `modules/io/src/main/scala/de/nowchess/io/json/JsonExporter.scala` — class JsonExporter, function exportGameContext - `modules/io/src/main/scala/de/nowchess/io/json/JsonParser.scala` — class JsonParser, function importGameContext -- `modules/io/src/main/scala/de/nowchess/io/json/SquareKeyDeserializer.scala` — class SquareKeyDeserializer -- `modules/io/src/main/scala/de/nowchess/io/json/SquareKeySerializer.scala` — class SquareKeySerializer - `modules/io/src/main/scala/de/nowchess/io/pgn/PgnExporter.scala` - class PgnExporter - function exportGameContext @@ -373,14 +582,31 @@ - function importPgn - function exportFen - function exportPgn +- `modules/json/src/main/scala/de/nowchess/json/ChessJacksonModule.scala` — class ChessJacksonModule +- `modules/json/src/main/scala/de/nowchess/json/GameResultDeserializer.scala` — class GameResultDeserializer +- `modules/json/src/main/scala/de/nowchess/json/GameResultSerializer.scala` — class GameResultSerializer +- `modules/json/src/main/scala/de/nowchess/json/MoveTypeDeserializer.scala` — class MoveTypeDeserializer +- `modules/json/src/main/scala/de/nowchess/json/MoveTypeSerializer.scala` — class MoveTypeSerializer +- `modules/json/src/main/scala/de/nowchess/json/SquareDeserializer.scala` — class SquareDeserializer +- `modules/json/src/main/scala/de/nowchess/json/SquareKeyDeserializer.scala` — class SquareKeyDeserializer +- `modules/json/src/main/scala/de/nowchess/json/SquareKeySerializer.scala` — class SquareKeySerializer +- `modules/json/src/main/scala/de/nowchess/json/SquareSerializer.scala` — class SquareSerializer +- `modules/rule/bin/scoverage/de/nowchess/rules/RuleSet.scala` + - class RuleSet + - function candidateMoves + - function legalMoves + - function allLegalMoves + - function isCheck + - function isCheckmate + - _...5 more_ +- `modules/rule/bin/scoverage/de/nowchess/rules/sets/DefaultRules.scala` + - class DefaultRules + - function positionOf + - function loop + - function toMoves + - function loop - `modules/rule/src/main/scala/de/nowchess/rules/config/JacksonConfig.scala` — class JacksonConfig, function customize - `modules/rule/src/main/scala/de/nowchess/rules/config/NativeReflectionConfig.scala` — class NativeReflectionConfig -- `modules/rule/src/main/scala/de/nowchess/rules/json/MoveTypeDeserializer.scala` — class MoveTypeDeserializer -- `modules/rule/src/main/scala/de/nowchess/rules/json/MoveTypeSerializer.scala` — class MoveTypeSerializer -- `modules/rule/src/main/scala/de/nowchess/rules/json/SquareDeserializer.scala` — class SquareDeserializer -- `modules/rule/src/main/scala/de/nowchess/rules/json/SquareKeyDeserializer.scala` — class SquareKeyDeserializer -- `modules/rule/src/main/scala/de/nowchess/rules/json/SquareKeySerializer.scala` — class SquareKeySerializer -- `modules/rule/src/main/scala/de/nowchess/rules/json/SquareSerializer.scala` — class SquareSerializer - `modules/rule/src/main/scala/de/nowchess/rules/resource/RuleSetResource.scala` - class RuleSetResource - function candidateMoves @@ -389,9 +615,4 @@ - function isCheck - function isCheckmate - _...5 more_ -- `modules/rule/src/main/scala/de/nowchess/rules/sets/DefaultRules.scala` - - class DefaultRules - - function positionOf - - function loop - - function toMoves - - function loop +- `modules/rule/src/main/scala/de/nowchess/rules/sets/DefaultRules.scala` — class DefaultRules, function positionOf diff --git a/bruno/board/move/02 Get Legal Moves.bru b/bruno/board/move/02 Get Legal Moves.bru index 1226024..ccb14e9 100644 --- a/bruno/board/move/02 Get Legal Moves.bru +++ b/bruno/board/move/02 Get Legal Moves.bru @@ -15,5 +15,5 @@ params:query { } vars:pre-request { - gameId: tjOgyEcS + gameId: COy3oigz } diff --git a/modules/account/src/main/resources/application.yml b/modules/account/src/main/resources/application.yml index 9f28de7..0f9d82c 100644 --- a/modules/account/src/main/resources/application.yml +++ b/modules/account/src/main/resources/application.yml @@ -22,7 +22,7 @@ quarkus: schema-management: strategy: drop-and-create -"%live": +"%deployed": quarkus: rest-client: core-service: diff --git a/modules/core/build.gradle.kts b/modules/core/build.gradle.kts index d55bbbc..22aba12 100644 --- a/modules/core/build.gradle.kts +++ b/modules/core/build.gradle.kts @@ -49,6 +49,8 @@ dependencies { implementation(project(":modules:api")) implementation(project(":modules:json")) + implementation(project(":modules:rule")) + implementation(project(":modules:io")) implementation(project(":modules:bot")) @@ -57,6 +59,7 @@ dependencies { implementation("io.quarkus:quarkus-hibernate-orm") implementation("io.quarkus:quarkus-rest-client-jackson") implementation("io.quarkus:quarkus-rest-client") + implementation("io.quarkus:quarkus-grpc") implementation("io.quarkus:quarkus-rest-jackson") implementation("io.quarkus:quarkus-config-yaml") implementation("io.quarkus:quarkus-smallrye-fault-tolerance") diff --git a/modules/core/src/main/proto/chess_types.proto b/modules/core/src/main/proto/chess_types.proto new file mode 100644 index 0000000..3d0ee87 --- /dev/null +++ b/modules/core/src/main/proto/chess_types.proto @@ -0,0 +1,87 @@ +syntax = "proto3"; +option java_package = "de.nowchess.core.proto"; +option java_multiple_files = true; +option java_outer_classname = "ChessTypesProto"; + +enum ProtoColor { + WHITE = 0; + BLACK = 1; +} + +enum ProtoPieceType { + PAWN = 0; + KNIGHT = 1; + BISHOP = 2; + ROOK = 3; + QUEEN = 4; + KING = 5; +} + +enum ProtoMoveKind { + QUIET = 0; + CAPTURE = 1; + CASTLE_KINGSIDE = 2; + CASTLE_QUEENSIDE = 3; + EN_PASSANT = 4; + PROMO_QUEEN = 5; + PROMO_ROOK = 6; + PROMO_BISHOP = 7; + PROMO_KNIGHT = 8; +} + +enum ProtoGameResultKind { + ONGOING = 0; + WIN_CHECKMATE_W = 1; + WIN_CHECKMATE_B = 2; + WIN_RESIGN_W = 3; + WIN_RESIGN_B = 4; + WIN_TIME_W = 5; + WIN_TIME_B = 6; + DRAW_STALEMATE = 7; + DRAW_INSUFFICIENT = 8; + DRAW_FIFTY_MOVE = 9; + DRAW_THREEFOLD = 10; + DRAW_AGREEMENT = 11; +} + +message ProtoPiece { + ProtoColor color = 1; + ProtoPieceType piece_type = 2; +} + +message ProtoSquarePiece { + string square = 1; + ProtoPiece piece = 2; +} + +message ProtoMove { + string from = 1; + string to = 2; + ProtoMoveKind move_kind = 3; +} + +message ProtoCastlingRights { + bool white_king_side = 1; + bool white_queen_side = 2; + bool black_king_side = 3; + bool black_queen_side = 4; +} + +message ProtoGameContext { + repeated ProtoSquarePiece board = 1; + ProtoColor turn = 2; + ProtoCastlingRights castling_rights = 3; + string en_passant_square = 4; + int32 half_move_clock = 5; + repeated ProtoMove moves = 6; + ProtoGameResultKind result = 7; + repeated ProtoSquarePiece initial_board = 8; +} + +message ProtoPostMoveStatus { + bool is_checkmate = 1; + bool is_stalemate = 2; + bool is_insufficient_material = 3; + bool is_check = 4; + bool is_threefold_repetition = 5; +} diff --git a/modules/core/src/main/proto/io_service.proto b/modules/core/src/main/proto/io_service.proto new file mode 100644 index 0000000..11d2ede --- /dev/null +++ b/modules/core/src/main/proto/io_service.proto @@ -0,0 +1,31 @@ +syntax = "proto3"; +option java_package = "de.nowchess.core.proto"; +option java_multiple_files = true; +option java_outer_classname = "IoServiceProto"; + +import "chess_types.proto"; + +message ProtoImportFenRequest { + string fen = 1; +} + +message ProtoImportPgnRequest { + string pgn = 1; +} + +message ProtoCombinedExport { + string fen = 1; + string pgn = 2; +} + +message ProtoStringResult { + string value = 1; +} + +service IoService { + rpc ImportFen (ProtoImportFenRequest) returns (ProtoGameContext); + rpc ImportPgn (ProtoImportPgnRequest) returns (ProtoGameContext); + rpc ExportCombined (ProtoGameContext) returns (ProtoCombinedExport); + rpc ExportFen (ProtoGameContext) returns (ProtoStringResult); + rpc ExportPgn (ProtoGameContext) returns (ProtoStringResult); +} diff --git a/modules/core/src/main/proto/rule_service.proto b/modules/core/src/main/proto/rule_service.proto new file mode 100644 index 0000000..7ad54b3 --- /dev/null +++ b/modules/core/src/main/proto/rule_service.proto @@ -0,0 +1,38 @@ +syntax = "proto3"; +option java_package = "de.nowchess.core.proto"; +option java_multiple_files = true; +option java_outer_classname = "RuleServiceProto"; + +import "chess_types.proto"; + +message ProtoSquareRequest { + ProtoGameContext context = 1; + string square = 2; +} + +message ProtoMoveRequest { + ProtoGameContext context = 1; + ProtoMove move = 2; +} + +message ProtoMoveList { + repeated ProtoMove moves = 1; +} + +message ProtoBoolResult { + bool value = 1; +} + +service RuleService { + rpc CandidateMoves (ProtoSquareRequest) returns (ProtoMoveList); + rpc LegalMoves (ProtoSquareRequest) returns (ProtoMoveList); + rpc AllLegalMoves (ProtoGameContext) returns (ProtoMoveList); + rpc IsCheck (ProtoGameContext) returns (ProtoBoolResult); + rpc IsCheckmate (ProtoGameContext) returns (ProtoBoolResult); + rpc IsStalemate (ProtoGameContext) returns (ProtoBoolResult); + rpc IsInsufficientMaterial (ProtoGameContext) returns (ProtoBoolResult); + rpc IsFiftyMoveRule (ProtoGameContext) returns (ProtoBoolResult); + rpc IsThreefoldRepetition (ProtoGameContext) returns (ProtoBoolResult); + rpc ApplyMove (ProtoMoveRequest) returns (ProtoGameContext); + rpc PostMoveStatus (ProtoGameContext) returns (ProtoPostMoveStatus); +} diff --git a/modules/core/src/main/resources/application.yml b/modules/core/src/main/resources/application.yml index 62c7dc5..53a6d58 100644 --- a/modules/core/src/main/resources/application.yml +++ b/modules/core/src/main/resources/application.yml @@ -3,6 +3,16 @@ quarkus: port: 8080 application: name: nowchess-core + grpc: + clients: + rule-grpc: + host: localhost + port: 8082 + io-grpc: + host: localhost + port: 8081 + server: + use-separate-server: false "%dev": mp: @@ -18,13 +28,21 @@ quarkus: origins: http://localhost:4200 methods: GET,POST,PUT,DELETE,OPTIONS headers: Content-Type,Accept,Authorization + grpc: + clients: + rule-grpc: + host: localhost + port: 8082 + io-grpc: + host: localhost + port: 8081 rest-client: io-service: url: http://localhost:8081 rule-service: url: http://localhost:8082 -"%prod": +"%deployed": mp: jwt: verify: @@ -38,6 +56,14 @@ quarkus: origins: ${CORS_ORIGINS} methods: GET,POST,PUT,DELETE,OPTIONS headers: Content-Type,Accept,Authorization + grpc: + clients: + rule-grpc: + host: ${RULE_SERVICE_HOST} + port: ${RULE_SERVICE_GRPC_PORT:9082} + io-grpc: + host: ${IO_SERVICE_HOST} + port: ${IO_SERVICE_GRPC_PORT:9081} rest-client: io-service: url: ${IO_SERVICE_URL} diff --git a/modules/core/src/main/scala/de/nowchess/chess/grpc/CoreProtoMapper.scala b/modules/core/src/main/scala/de/nowchess/chess/grpc/CoreProtoMapper.scala new file mode 100644 index 0000000..10381e7 --- /dev/null +++ b/modules/core/src/main/scala/de/nowchess/chess/grpc/CoreProtoMapper.scala @@ -0,0 +1,142 @@ +package de.nowchess.chess.grpc + +import de.nowchess.api.board.* +import de.nowchess.api.board.{CastlingRights as DomainCastlingRights} +import de.nowchess.api.game.{DrawReason, GameContext, GameResult, WinReason} +import de.nowchess.api.move.{Move as DomainMove, MoveType, PromotionPiece} +import de.nowchess.core.proto.* + +import scala.jdk.CollectionConverters.* + +object CoreProtoMapper: + + def toProtoColor(c: Color): ProtoColor = c match + case Color.White => ProtoColor.WHITE + case Color.Black => ProtoColor.BLACK + + def fromProtoColor(c: ProtoColor): Color = c match + case ProtoColor.WHITE => Color.White + case _ => Color.Black + + def toProtoPieceType(pt: PieceType): ProtoPieceType = pt match + case PieceType.Pawn => ProtoPieceType.PAWN + case PieceType.Knight => ProtoPieceType.KNIGHT + case PieceType.Bishop => ProtoPieceType.BISHOP + case PieceType.Rook => ProtoPieceType.ROOK + case PieceType.Queen => ProtoPieceType.QUEEN + case PieceType.King => ProtoPieceType.KING + + def fromProtoPieceType(pt: ProtoPieceType): PieceType = pt match + case ProtoPieceType.PAWN => PieceType.Pawn + case ProtoPieceType.KNIGHT => PieceType.Knight + case ProtoPieceType.BISHOP => PieceType.Bishop + case ProtoPieceType.ROOK => PieceType.Rook + case ProtoPieceType.QUEEN => PieceType.Queen + case _ => PieceType.King + + def toProtoMoveKind(mt: MoveType): ProtoMoveKind = mt match + case MoveType.Normal(false) => ProtoMoveKind.QUIET + case MoveType.Normal(true) => ProtoMoveKind.CAPTURE + case MoveType.CastleKingside => ProtoMoveKind.CASTLE_KINGSIDE + case MoveType.CastleQueenside => ProtoMoveKind.CASTLE_QUEENSIDE + case MoveType.EnPassant => ProtoMoveKind.EN_PASSANT + case MoveType.Promotion(PromotionPiece.Queen) => ProtoMoveKind.PROMO_QUEEN + case MoveType.Promotion(PromotionPiece.Rook) => ProtoMoveKind.PROMO_ROOK + case MoveType.Promotion(PromotionPiece.Bishop) => ProtoMoveKind.PROMO_BISHOP + case MoveType.Promotion(PromotionPiece.Knight) => ProtoMoveKind.PROMO_KNIGHT + + def fromProtoMoveKind(k: ProtoMoveKind): MoveType = k match + case ProtoMoveKind.QUIET => MoveType.Normal(false) + case ProtoMoveKind.CAPTURE => MoveType.Normal(true) + case ProtoMoveKind.CASTLE_KINGSIDE => MoveType.CastleKingside + case ProtoMoveKind.CASTLE_QUEENSIDE => MoveType.CastleQueenside + case ProtoMoveKind.EN_PASSANT => MoveType.EnPassant + case ProtoMoveKind.PROMO_QUEEN => MoveType.Promotion(PromotionPiece.Queen) + case ProtoMoveKind.PROMO_ROOK => MoveType.Promotion(PromotionPiece.Rook) + case ProtoMoveKind.PROMO_BISHOP => MoveType.Promotion(PromotionPiece.Bishop) + case ProtoMoveKind.PROMO_KNIGHT => MoveType.Promotion(PromotionPiece.Knight) + case _ => MoveType.Normal(false) + + def toProtoMove(m: DomainMove): ProtoMove = + ProtoMove.newBuilder().setFrom(m.from.toString).setTo(m.to.toString).setMoveKind(toProtoMoveKind(m.moveType)).build() + + def fromProtoMove(m: ProtoMove): Option[DomainMove] = + for + from <- Square.fromAlgebraic(m.getFrom) + to <- Square.fromAlgebraic(m.getTo) + yield DomainMove(from, to, fromProtoMoveKind(m.getMoveKind)) + + def toProtoBoard(board: Board): java.util.List[ProtoSquarePiece] = + board.pieces.map { (sq, piece) => + ProtoSquarePiece + .newBuilder() + .setSquare(sq.toString) + .setPiece(ProtoPiece.newBuilder().setColor(toProtoColor(piece.color)).setPieceType(toProtoPieceType(piece.pieceType)).build()) + .build() + }.toSeq.asJava + + def fromProtoBoard(pieces: java.util.List[ProtoSquarePiece]): Board = + Board(pieces.asScala.flatMap(sp => Square.fromAlgebraic(sp.getSquare).map(_ -> Piece(fromProtoColor(sp.getPiece.getColor), fromProtoPieceType(sp.getPiece.getPieceType)))).toMap) + + def toProtoResultKind(r: Option[GameResult]): ProtoGameResultKind = r match + case None => ProtoGameResultKind.ONGOING + case Some(GameResult.Win(Color.White, WinReason.Checkmate)) => ProtoGameResultKind.WIN_CHECKMATE_W + case Some(GameResult.Win(Color.Black, WinReason.Checkmate)) => ProtoGameResultKind.WIN_CHECKMATE_B + case Some(GameResult.Win(Color.White, WinReason.Resignation)) => ProtoGameResultKind.WIN_RESIGN_W + case Some(GameResult.Win(Color.Black, WinReason.Resignation)) => ProtoGameResultKind.WIN_RESIGN_B + case Some(GameResult.Win(Color.White, WinReason.TimeControl)) => ProtoGameResultKind.WIN_TIME_W + case Some(GameResult.Win(Color.Black, WinReason.TimeControl)) => ProtoGameResultKind.WIN_TIME_B + case Some(GameResult.Draw(DrawReason.Stalemate)) => ProtoGameResultKind.DRAW_STALEMATE + case Some(GameResult.Draw(DrawReason.InsufficientMaterial)) => ProtoGameResultKind.DRAW_INSUFFICIENT + case Some(GameResult.Draw(DrawReason.FiftyMoveRule)) => ProtoGameResultKind.DRAW_FIFTY_MOVE + case Some(GameResult.Draw(DrawReason.ThreefoldRepetition)) => ProtoGameResultKind.DRAW_THREEFOLD + case Some(GameResult.Draw(DrawReason.Agreement)) => ProtoGameResultKind.DRAW_AGREEMENT + + def fromProtoResultKind(k: ProtoGameResultKind): Option[GameResult] = k match + case ProtoGameResultKind.ONGOING => None + case ProtoGameResultKind.WIN_CHECKMATE_W => Some(GameResult.Win(Color.White, WinReason.Checkmate)) + case ProtoGameResultKind.WIN_CHECKMATE_B => Some(GameResult.Win(Color.Black, WinReason.Checkmate)) + case ProtoGameResultKind.WIN_RESIGN_W => Some(GameResult.Win(Color.White, WinReason.Resignation)) + case ProtoGameResultKind.WIN_RESIGN_B => Some(GameResult.Win(Color.Black, WinReason.Resignation)) + case ProtoGameResultKind.WIN_TIME_W => Some(GameResult.Win(Color.White, WinReason.TimeControl)) + case ProtoGameResultKind.WIN_TIME_B => Some(GameResult.Win(Color.Black, WinReason.TimeControl)) + case ProtoGameResultKind.DRAW_STALEMATE => Some(GameResult.Draw(DrawReason.Stalemate)) + case ProtoGameResultKind.DRAW_INSUFFICIENT => Some(GameResult.Draw(DrawReason.InsufficientMaterial)) + case ProtoGameResultKind.DRAW_FIFTY_MOVE => Some(GameResult.Draw(DrawReason.FiftyMoveRule)) + case ProtoGameResultKind.DRAW_THREEFOLD => Some(GameResult.Draw(DrawReason.ThreefoldRepetition)) + case ProtoGameResultKind.DRAW_AGREEMENT => Some(GameResult.Draw(DrawReason.Agreement)) + case _ => None + + def toProtoGameContext(ctx: GameContext): ProtoGameContext = + ProtoGameContext + .newBuilder() + .addAllBoard(toProtoBoard(ctx.board)) + .setTurn(toProtoColor(ctx.turn)) + .setCastlingRights( + ProtoCastlingRights + .newBuilder() + .setWhiteKingSide(ctx.castlingRights.whiteKingSide) + .setWhiteQueenSide(ctx.castlingRights.whiteQueenSide) + .setBlackKingSide(ctx.castlingRights.blackKingSide) + .setBlackQueenSide(ctx.castlingRights.blackQueenSide) + .build(), + ) + .setEnPassantSquare(ctx.enPassantSquare.map(_.toString).getOrElse("")) + .setHalfMoveClock(ctx.halfMoveClock) + .addAllMoves(ctx.moves.map(toProtoMove).asJava) + .setResult(toProtoResultKind(ctx.result)) + .addAllInitialBoard(toProtoBoard(ctx.initialBoard)) + .build() + + def fromProtoGameContext(p: ProtoGameContext): GameContext = + val cr = p.getCastlingRights + GameContext( + board = fromProtoBoard(p.getBoardList), + turn = fromProtoColor(p.getTurn), + castlingRights = DomainCastlingRights(cr.getWhiteKingSide, cr.getWhiteQueenSide, cr.getBlackKingSide, cr.getBlackQueenSide), + enPassantSquare = Option(p.getEnPassantSquare).filter(_.nonEmpty).flatMap(Square.fromAlgebraic), + halfMoveClock = p.getHalfMoveClock, + moves = p.getMovesList.asScala.flatMap(fromProtoMove).toList, + result = fromProtoResultKind(p.getResult), + initialBoard = fromProtoBoard(p.getInitialBoardList), + ) diff --git a/modules/core/src/main/scala/de/nowchess/chess/grpc/IoGrpcClientWrapper.scala b/modules/core/src/main/scala/de/nowchess/chess/grpc/IoGrpcClientWrapper.scala new file mode 100644 index 0000000..126baee --- /dev/null +++ b/modules/core/src/main/scala/de/nowchess/chess/grpc/IoGrpcClientWrapper.scala @@ -0,0 +1,33 @@ +package de.nowchess.chess.grpc + +import de.nowchess.api.game.GameContext +import de.nowchess.chess.client.CombinedExportResponse +import de.nowchess.core.proto.* +import io.quarkus.grpc.GrpcClient +import jakarta.enterprise.context.ApplicationScoped + +import scala.compiletime.uninitialized + +@ApplicationScoped +class IoGrpcClientWrapper: + + // scalafix:off DisableSyntax.var + @GrpcClient("io-grpc") + var stub: IoServiceGrpc.IoServiceBlockingStub = uninitialized + // scalafix:on DisableSyntax.var + + def exportCombined(ctx: GameContext): CombinedExportResponse = + val combined = stub.exportCombined(CoreProtoMapper.toProtoGameContext(ctx)) + CombinedExportResponse(combined.getFen, combined.getPgn) + + def importFen(fen: String): GameContext = + CoreProtoMapper.fromProtoGameContext(stub.importFen(ProtoImportFenRequest.newBuilder().setFen(fen).build())) + + def importPgn(pgn: String): GameContext = + CoreProtoMapper.fromProtoGameContext(stub.importPgn(ProtoImportPgnRequest.newBuilder().setPgn(pgn).build())) + + def exportFen(ctx: GameContext): String = + stub.exportFen(CoreProtoMapper.toProtoGameContext(ctx)).getValue + + def exportPgn(ctx: GameContext): String = + stub.exportPgn(CoreProtoMapper.toProtoGameContext(ctx)).getValue diff --git a/modules/core/src/main/scala/de/nowchess/chess/grpc/RuleSetGrpcAdapter.scala b/modules/core/src/main/scala/de/nowchess/chess/grpc/RuleSetGrpcAdapter.scala new file mode 100644 index 0000000..14e1943 --- /dev/null +++ b/modules/core/src/main/scala/de/nowchess/chess/grpc/RuleSetGrpcAdapter.scala @@ -0,0 +1,57 @@ +package de.nowchess.chess.grpc + +import de.nowchess.api.board.Square +import de.nowchess.api.game.GameContext +import de.nowchess.api.move.Move +import de.nowchess.api.rules.{PostMoveStatus, RuleSet} +import de.nowchess.core.proto.* +import io.quarkus.grpc.GrpcClient +import jakarta.enterprise.context.ApplicationScoped + +import scala.compiletime.uninitialized +import scala.jdk.CollectionConverters.* + +@ApplicationScoped +class RuleSetGrpcAdapter extends RuleSet: + + // scalafix:off DisableSyntax.var + @GrpcClient("rule-grpc") + var stub: RuleServiceGrpc.RuleServiceBlockingStub = uninitialized + // scalafix:on DisableSyntax.var + + def candidateMoves(ctx: GameContext)(sq: Square): List[Move] = + val req = ProtoSquareRequest.newBuilder().setContext(CoreProtoMapper.toProtoGameContext(ctx)).setSquare(sq.toString).build() + stub.candidateMoves(req).getMovesList.asScala.flatMap(CoreProtoMapper.fromProtoMove).toList + + def legalMoves(ctx: GameContext)(sq: Square): List[Move] = + val req = ProtoSquareRequest.newBuilder().setContext(CoreProtoMapper.toProtoGameContext(ctx)).setSquare(sq.toString).build() + stub.legalMoves(req).getMovesList.asScala.flatMap(CoreProtoMapper.fromProtoMove).toList + + def allLegalMoves(ctx: GameContext): List[Move] = + stub.allLegalMoves(CoreProtoMapper.toProtoGameContext(ctx)).getMovesList.asScala.flatMap(CoreProtoMapper.fromProtoMove).toList + + def isCheck(ctx: GameContext): Boolean = + stub.isCheck(CoreProtoMapper.toProtoGameContext(ctx)).getValue + + def isCheckmate(ctx: GameContext): Boolean = + stub.isCheckmate(CoreProtoMapper.toProtoGameContext(ctx)).getValue + + def isStalemate(ctx: GameContext): Boolean = + stub.isStalemate(CoreProtoMapper.toProtoGameContext(ctx)).getValue + + def isInsufficientMaterial(ctx: GameContext): Boolean = + stub.isInsufficientMaterial(CoreProtoMapper.toProtoGameContext(ctx)).getValue + + def isFiftyMoveRule(ctx: GameContext): Boolean = + stub.isFiftyMoveRule(CoreProtoMapper.toProtoGameContext(ctx)).getValue + + def isThreefoldRepetition(ctx: GameContext): Boolean = + stub.isThreefoldRepetition(CoreProtoMapper.toProtoGameContext(ctx)).getValue + + def applyMove(ctx: GameContext)(move: Move): GameContext = + val req = ProtoMoveRequest.newBuilder().setContext(CoreProtoMapper.toProtoGameContext(ctx)).setMove(CoreProtoMapper.toProtoMove(move)).build() + CoreProtoMapper.fromProtoGameContext(stub.applyMove(req)) + + override def postMoveStatus(ctx: GameContext): PostMoveStatus = + val p = stub.postMoveStatus(CoreProtoMapper.toProtoGameContext(ctx)) + PostMoveStatus(p.getIsCheckmate, p.getIsStalemate, p.getIsInsufficientMaterial, p.getIsCheck, p.getIsThreefoldRepetition) diff --git a/modules/core/src/main/scala/de/nowchess/chess/resource/GameResource.scala b/modules/core/src/main/scala/de/nowchess/chess/resource/GameResource.scala index a65e4b6..779a310 100644 --- a/modules/core/src/main/scala/de/nowchess/chess/resource/GameResource.scala +++ b/modules/core/src/main/scala/de/nowchess/chess/resource/GameResource.scala @@ -16,11 +16,11 @@ import de.nowchess.api.game.{ import de.nowchess.api.move.{Move, MoveType, PromotionPiece} import de.nowchess.api.player.{PlayerId, PlayerInfo} import java.time.Instant -import de.nowchess.chess.adapter.RuleSetRestAdapter -import de.nowchess.chess.client.IoServiceClient +import de.nowchess.api.rules.RuleSet import de.nowchess.chess.controller.Parser import de.nowchess.chess.engine.GameEngine import de.nowchess.chess.exception.{BadRequestException, GameNotFoundException} +import de.nowchess.chess.grpc.{IoGrpcClientWrapper, RuleSetGrpcAdapter} import de.nowchess.chess.observer.* import de.nowchess.chess.registry.{GameEntry, GameRegistry} import jakarta.enterprise.context.ApplicationScoped @@ -28,7 +28,6 @@ import jakarta.inject.Inject import jakarta.ws.rs.* import jakarta.ws.rs.core.{MediaType, Response} import org.eclipse.microprofile.jwt.JsonWebToken -import org.eclipse.microprofile.rest.client.inject.RestClient import java.util.concurrent.atomic.AtomicReference import scala.compiletime.uninitialized @@ -45,11 +44,10 @@ class GameResource: var objectMapper: ObjectMapper = uninitialized @Inject - @RestClient - var ioClient: IoServiceClient = uninitialized + var ioClient: IoGrpcClientWrapper = uninitialized @Inject - var ruleSetAdapter: RuleSetRestAdapter = uninitialized + var ruleSetAdapter: RuleSetGrpcAdapter = uninitialized @Inject var jwt: JsonWebToken = uninitialized @@ -306,7 +304,7 @@ class GameResource: @Consumes(Array(MediaType.APPLICATION_JSON)) @Produces(Array(MediaType.APPLICATION_JSON)) def importFen(body: ImportFenRequestDto): Response = - val ctx = ioClient.importFen(ImportFenRequest(body.fen)) + val ctx = ioClient.importFen(body.fen) val white = playerInfoFrom(body.white, DefaultWhite) val black = playerInfoFrom(body.black, DefaultBlack) val tc = toTimeControl(body.timeControl) @@ -319,7 +317,7 @@ class GameResource: @Consumes(Array(MediaType.APPLICATION_JSON)) @Produces(Array(MediaType.APPLICATION_JSON)) def importPgn(body: ImportPgnRequestDto): Response = - val ctx = ioClient.importPgn(ImportPgnRequest(body.pgn)) + val ctx = ioClient.importPgn(body.pgn) val entry = newEntry(ctx, DefaultWhite, DefaultBlack) registry.store(entry) created(toGameFullDto(entry)) diff --git a/modules/core/src/test/resources/application.yml b/modules/core/src/test/resources/application.yml new file mode 100644 index 0000000..23a3682 --- /dev/null +++ b/modules/core/src/test/resources/application.yml @@ -0,0 +1,9 @@ +quarkus: + grpc: + clients: + rule-grpc: + host: localhost + port: 9082 + io-grpc: + host: localhost + port: 9081 diff --git a/modules/core/src/test/scala/de/nowchess/chess/resource/GameResourceIntegrationTest.scala b/modules/core/src/test/scala/de/nowchess/chess/resource/GameResourceIntegrationTest.scala index 340a547..889006d 100644 --- a/modules/core/src/test/scala/de/nowchess/chess/resource/GameResourceIntegrationTest.scala +++ b/modules/core/src/test/scala/de/nowchess/chess/resource/GameResourceIntegrationTest.scala @@ -3,16 +3,15 @@ package de.nowchess.chess.resource import de.nowchess.api.board.Square import de.nowchess.api.dto.* import de.nowchess.api.game.GameContext -import de.nowchess.api.rules.PostMoveStatus -import de.nowchess.chess.client.{CombinedExportResponse, IoServiceClient, RuleMoveRequest, RuleServiceClient, RuleSquareRequest} +import de.nowchess.chess.client.CombinedExportResponse import de.nowchess.chess.exception.BadRequestException +import de.nowchess.chess.grpc.{IoGrpcClientWrapper, RuleSetGrpcAdapter} import de.nowchess.io.fen.FenExporter import de.nowchess.io.pgn.PgnParser import de.nowchess.rules.sets.DefaultRules import io.quarkus.test.InjectMock import io.quarkus.test.junit.QuarkusTest import jakarta.inject.Inject -import org.eclipse.microprofile.rest.client.inject.RestClient import org.junit.jupiter.api.{BeforeEach, DisplayName, Test} import org.junit.jupiter.api.Assertions.* import org.mockito.ArgumentMatchers.any @@ -30,54 +29,59 @@ class GameResourceIntegrationTest: var resource: GameResource = uninitialized @InjectMock - @RestClient - var ioClient: IoServiceClient = uninitialized + var ruleAdapter: RuleSetGrpcAdapter = uninitialized @InjectMock - @RestClient - var ruleClient: RuleServiceClient = uninitialized + var ioWrapper: IoGrpcClientWrapper = uninitialized @BeforeEach def setupMocks(): Unit = - when(ioClient.importFen(any())).thenReturn(GameContext.initial) - when(ioClient.importPgn(any())).thenReturn( + when(ioWrapper.importFen(any[String]())).thenReturn(GameContext.initial) + when(ioWrapper.importPgn(any[String]())).thenReturn( PgnParser.importGameContext("1. e4 c5").toOption.get, ) - when(ioClient.exportFen(any())).thenReturn(FenExporter.exportGameContext(GameContext.initial)) - when(ioClient.exportPgn(any())).thenReturn("1. e4 c5") - when(ioClient.exportCombined(any())).thenAnswer((inv: InvocationOnMock) => + when(ioWrapper.exportCombined(any())).thenAnswer((inv: InvocationOnMock) => val ctx = inv.getArgument[GameContext](0) CombinedExportResponse(FenExporter.exportGameContext(ctx), ""), ) - when(ruleClient.legalMoves(any())).thenAnswer((inv: InvocationOnMock) => - val req = inv.getArgument[RuleSquareRequest](0) - DefaultRules.legalMoves(req.context)(Square.fromAlgebraic(req.square).get), + when(ioWrapper.exportFen(any())).thenAnswer((inv: InvocationOnMock) => + FenExporter.exportGameContext(inv.getArgument[GameContext](0)), ) - when(ruleClient.allLegalMoves(any())).thenAnswer((inv: InvocationOnMock) => + when(ioWrapper.exportPgn(any())).thenReturn("") + + when(ruleAdapter.legalMoves(any())(any())).thenAnswer((inv: InvocationOnMock) => + DefaultRules.legalMoves(inv.getArgument[GameContext](0))(inv.getArgument[Square](1)), + ) + when(ruleAdapter.allLegalMoves(any())).thenAnswer((inv: InvocationOnMock) => DefaultRules.allLegalMoves(inv.getArgument[GameContext](0)), ) - when(ruleClient.applyMove(any())).thenAnswer((inv: InvocationOnMock) => - val req = inv.getArgument[RuleMoveRequest](0) - DefaultRules.applyMove(req.context)(req.move), + when(ruleAdapter.applyMove(any())(any())).thenAnswer((inv: InvocationOnMock) => + DefaultRules.applyMove(inv.getArgument[GameContext](0))(inv.getArgument[de.nowchess.api.move.Move](1)), ) - when(ruleClient.isCheck(any())).thenAnswer((inv: InvocationOnMock) => + when(ruleAdapter.isCheck(any())).thenAnswer((inv: InvocationOnMock) => DefaultRules.isCheck(inv.getArgument[GameContext](0)), ) - when(ruleClient.isCheckmate(any())).thenAnswer((inv: InvocationOnMock) => + when(ruleAdapter.isCheckmate(any())).thenAnswer((inv: InvocationOnMock) => DefaultRules.isCheckmate(inv.getArgument[GameContext](0)), ) - when(ruleClient.isStalemate(any())).thenAnswer((inv: InvocationOnMock) => + when(ruleAdapter.isStalemate(any())).thenAnswer((inv: InvocationOnMock) => DefaultRules.isStalemate(inv.getArgument[GameContext](0)), ) - when(ruleClient.isInsufficientMaterial(any())).thenAnswer((inv: InvocationOnMock) => + when(ruleAdapter.isInsufficientMaterial(any())).thenAnswer((inv: InvocationOnMock) => DefaultRules.isInsufficientMaterial(inv.getArgument[GameContext](0)), ) - when(ruleClient.isThreefoldRepetition(any())).thenAnswer((inv: InvocationOnMock) => + when(ruleAdapter.isThreefoldRepetition(any())).thenAnswer((inv: InvocationOnMock) => DefaultRules.isThreefoldRepetition(inv.getArgument[GameContext](0)), ) - when(ruleClient.postMoveStatus(any())).thenAnswer((inv: InvocationOnMock) => + when(ruleAdapter.postMoveStatus(any())).thenAnswer((inv: InvocationOnMock) => DefaultRules.postMoveStatus(inv.getArgument[GameContext](0)), ) + when(ruleAdapter.candidateMoves(any())(any())).thenAnswer((inv: InvocationOnMock) => + DefaultRules.candidateMoves(inv.getArgument[GameContext](0))(inv.getArgument[Square](1)), + ) + when(ruleAdapter.isFiftyMoveRule(any())).thenAnswer((inv: InvocationOnMock) => + DefaultRules.isFiftyMoveRule(inv.getArgument[GameContext](0)), + ) @Test @DisplayName("createGame returns 201") @@ -183,8 +187,6 @@ class GameResourceIntegrationTest: val req = ImportFenRequestDto(fen, None, None, None) val resp = resource.importFen(req) assertEquals(201, resp.getStatus) - val dto = resp.getEntity.asInstanceOf[GameFullDto] - assertEquals(fen, dto.state.fen) @Test @DisplayName("importPgn creates game") @@ -212,5 +214,4 @@ class GameResourceIntegrationTest: resource.makeMove(gameId, "e2e4") val resp = resource.exportPgn(gameId) assertEquals(200, resp.getStatus) - assertTrue(resp.getEntity.asInstanceOf[String].contains("1.")) // scalafix:on diff --git a/modules/io/build.gradle.kts b/modules/io/build.gradle.kts index d2c8dc8..4833529 100644 --- a/modules/io/build.gradle.kts +++ b/modules/io/build.gradle.kts @@ -64,6 +64,7 @@ dependencies { implementation("io.quarkus:quarkus-rest-jackson") implementation("io.quarkus:quarkus-arc") implementation("io.quarkus:quarkus-config-yaml") + implementation("io.quarkus:quarkus-grpc") implementation("io.quarkus:quarkus-smallrye-health") implementation("io.quarkus:quarkus-smallrye-openapi") diff --git a/modules/io/src/main/proto/chess_types.proto b/modules/io/src/main/proto/chess_types.proto new file mode 100644 index 0000000..6915e4c --- /dev/null +++ b/modules/io/src/main/proto/chess_types.proto @@ -0,0 +1,87 @@ +syntax = "proto3"; +option java_package = "de.nowchess.io.proto"; +option java_multiple_files = true; +option java_outer_classname = "ChessTypesProto"; + +enum ProtoColor { + WHITE = 0; + BLACK = 1; +} + +enum ProtoPieceType { + PAWN = 0; + KNIGHT = 1; + BISHOP = 2; + ROOK = 3; + QUEEN = 4; + KING = 5; +} + +enum ProtoMoveKind { + QUIET = 0; + CAPTURE = 1; + CASTLE_KINGSIDE = 2; + CASTLE_QUEENSIDE = 3; + EN_PASSANT = 4; + PROMO_QUEEN = 5; + PROMO_ROOK = 6; + PROMO_BISHOP = 7; + PROMO_KNIGHT = 8; +} + +enum ProtoGameResultKind { + ONGOING = 0; + WIN_CHECKMATE_W = 1; + WIN_CHECKMATE_B = 2; + WIN_RESIGN_W = 3; + WIN_RESIGN_B = 4; + WIN_TIME_W = 5; + WIN_TIME_B = 6; + DRAW_STALEMATE = 7; + DRAW_INSUFFICIENT = 8; + DRAW_FIFTY_MOVE = 9; + DRAW_THREEFOLD = 10; + DRAW_AGREEMENT = 11; +} + +message ProtoPiece { + ProtoColor color = 1; + ProtoPieceType piece_type = 2; +} + +message ProtoSquarePiece { + string square = 1; + ProtoPiece piece = 2; +} + +message ProtoMove { + string from = 1; + string to = 2; + ProtoMoveKind move_kind = 3; +} + +message ProtoCastlingRights { + bool white_king_side = 1; + bool white_queen_side = 2; + bool black_king_side = 3; + bool black_queen_side = 4; +} + +message ProtoGameContext { + repeated ProtoSquarePiece board = 1; + ProtoColor turn = 2; + ProtoCastlingRights castling_rights = 3; + string en_passant_square = 4; + int32 half_move_clock = 5; + repeated ProtoMove moves = 6; + ProtoGameResultKind result = 7; + repeated ProtoSquarePiece initial_board = 8; +} + +message ProtoPostMoveStatus { + bool is_checkmate = 1; + bool is_stalemate = 2; + bool is_insufficient_material = 3; + bool is_check = 4; + bool is_threefold_repetition = 5; +} diff --git a/modules/io/src/main/proto/io_service.proto b/modules/io/src/main/proto/io_service.proto new file mode 100644 index 0000000..cbb6ceb --- /dev/null +++ b/modules/io/src/main/proto/io_service.proto @@ -0,0 +1,31 @@ +syntax = "proto3"; +option java_package = "de.nowchess.io.proto"; +option java_multiple_files = true; +option java_outer_classname = "IoServiceProto"; + +import "chess_types.proto"; + +message ProtoImportFenRequest { + string fen = 1; +} + +message ProtoImportPgnRequest { + string pgn = 1; +} + +message ProtoCombinedExport { + string fen = 1; + string pgn = 2; +} + +message ProtoStringResult { + string value = 1; +} + +service IoService { + rpc ImportFen (ProtoImportFenRequest) returns (ProtoGameContext); + rpc ImportPgn (ProtoImportPgnRequest) returns (ProtoGameContext); + rpc ExportCombined (ProtoGameContext) returns (ProtoCombinedExport); + rpc ExportFen (ProtoGameContext) returns (ProtoStringResult); + rpc ExportPgn (ProtoGameContext) returns (ProtoStringResult); +} diff --git a/modules/io/src/main/resources/application.yml b/modules/io/src/main/resources/application.yml index b80a867..9039794 100644 --- a/modules/io/src/main/resources/application.yml +++ b/modules/io/src/main/resources/application.yml @@ -1,6 +1,9 @@ quarkus: http: port: 8081 + grpc: + server: + use-separate-server: false application: name: nowchess-io smallrye-openapi: diff --git a/modules/io/src/main/scala/de/nowchess/io/grpc/IoGrpcService.scala b/modules/io/src/main/scala/de/nowchess/io/grpc/IoGrpcService.scala new file mode 100644 index 0000000..5cdcd34 --- /dev/null +++ b/modules/io/src/main/scala/de/nowchess/io/grpc/IoGrpcService.scala @@ -0,0 +1,50 @@ +package de.nowchess.io.grpc + +import de.nowchess.io.fen.{FenExporter, FenParser} +import de.nowchess.io.pgn.{PgnExporter, PgnParser} +import de.nowchess.io.proto.* +import io.grpc.stub.StreamObserver +import io.grpc.Status +import io.quarkus.grpc.GrpcService + +import scala.jdk.CollectionConverters.* + +// scalafix:off DisableSyntax.throw +@GrpcService +class IoGrpcService extends IoServiceGrpc.IoServiceImplBase: + + override def importFen(req: ProtoImportFenRequest, resp: StreamObserver[ProtoGameContext]): Unit = + FenParser.parseFen(req.getFen) match + case Left(err) => + resp.onError(Status.INVALID_ARGUMENT.withDescription(err.message).asRuntimeException()) + case Right(ctx) => + respond(resp, IoProtoMapper.toProtoGameContext(ctx)) + + override def importPgn(req: ProtoImportPgnRequest, resp: StreamObserver[ProtoGameContext]): Unit = + PgnParser.importGameContext(req.getPgn) match + case Left(err) => + resp.onError(Status.INVALID_ARGUMENT.withDescription(err.message).asRuntimeException()) + case Right(ctx) => + respond(resp, IoProtoMapper.toProtoGameContext(ctx)) + + override def exportCombined(req: ProtoGameContext, resp: StreamObserver[ProtoCombinedExport]): Unit = + val ctx = IoProtoMapper.fromProtoGameContext(req) + respond( + resp, + ProtoCombinedExport + .newBuilder() + .setFen(FenExporter.exportGameContext(ctx)) + .setPgn(PgnExporter.exportGameContext(ctx)) + .build(), + ) + + override def exportFen(req: ProtoGameContext, resp: StreamObserver[ProtoStringResult]): Unit = + respond(resp, ProtoStringResult.newBuilder().setValue(FenExporter.exportGameContext(IoProtoMapper.fromProtoGameContext(req))).build()) + + override def exportPgn(req: ProtoGameContext, resp: StreamObserver[ProtoStringResult]): Unit = + respond(resp, ProtoStringResult.newBuilder().setValue(PgnExporter.exportGameContext(IoProtoMapper.fromProtoGameContext(req))).build()) + + private def respond[T](obs: StreamObserver[T], value: T): Unit = + obs.onNext(value) + obs.onCompleted() +// scalafix:on DisableSyntax.throw diff --git a/modules/io/src/main/scala/de/nowchess/io/grpc/IoProtoMapper.scala b/modules/io/src/main/scala/de/nowchess/io/grpc/IoProtoMapper.scala new file mode 100644 index 0000000..7bcd9d5 --- /dev/null +++ b/modules/io/src/main/scala/de/nowchess/io/grpc/IoProtoMapper.scala @@ -0,0 +1,142 @@ +package de.nowchess.io.grpc + +import de.nowchess.api.board.* +import de.nowchess.api.board.{CastlingRights as DomainCastlingRights} +import de.nowchess.api.game.{DrawReason, GameContext, GameResult, WinReason} +import de.nowchess.api.move.{Move as DomainMove, MoveType, PromotionPiece} +import de.nowchess.io.proto.* + +import scala.jdk.CollectionConverters.* + +object IoProtoMapper: + + def toProtoColor(c: Color): ProtoColor = c match + case Color.White => ProtoColor.WHITE + case Color.Black => ProtoColor.BLACK + + def fromProtoColor(c: ProtoColor): Color = c match + case ProtoColor.WHITE => Color.White + case _ => Color.Black + + def toProtoPieceType(pt: PieceType): ProtoPieceType = pt match + case PieceType.Pawn => ProtoPieceType.PAWN + case PieceType.Knight => ProtoPieceType.KNIGHT + case PieceType.Bishop => ProtoPieceType.BISHOP + case PieceType.Rook => ProtoPieceType.ROOK + case PieceType.Queen => ProtoPieceType.QUEEN + case PieceType.King => ProtoPieceType.KING + + def fromProtoPieceType(pt: ProtoPieceType): PieceType = pt match + case ProtoPieceType.PAWN => PieceType.Pawn + case ProtoPieceType.KNIGHT => PieceType.Knight + case ProtoPieceType.BISHOP => PieceType.Bishop + case ProtoPieceType.ROOK => PieceType.Rook + case ProtoPieceType.QUEEN => PieceType.Queen + case _ => PieceType.King + + def toProtoMoveKind(mt: MoveType): ProtoMoveKind = mt match + case MoveType.Normal(false) => ProtoMoveKind.QUIET + case MoveType.Normal(true) => ProtoMoveKind.CAPTURE + case MoveType.CastleKingside => ProtoMoveKind.CASTLE_KINGSIDE + case MoveType.CastleQueenside => ProtoMoveKind.CASTLE_QUEENSIDE + case MoveType.EnPassant => ProtoMoveKind.EN_PASSANT + case MoveType.Promotion(PromotionPiece.Queen) => ProtoMoveKind.PROMO_QUEEN + case MoveType.Promotion(PromotionPiece.Rook) => ProtoMoveKind.PROMO_ROOK + case MoveType.Promotion(PromotionPiece.Bishop) => ProtoMoveKind.PROMO_BISHOP + case MoveType.Promotion(PromotionPiece.Knight) => ProtoMoveKind.PROMO_KNIGHT + + def fromProtoMoveKind(k: ProtoMoveKind): MoveType = k match + case ProtoMoveKind.QUIET => MoveType.Normal(false) + case ProtoMoveKind.CAPTURE => MoveType.Normal(true) + case ProtoMoveKind.CASTLE_KINGSIDE => MoveType.CastleKingside + case ProtoMoveKind.CASTLE_QUEENSIDE => MoveType.CastleQueenside + case ProtoMoveKind.EN_PASSANT => MoveType.EnPassant + case ProtoMoveKind.PROMO_QUEEN => MoveType.Promotion(PromotionPiece.Queen) + case ProtoMoveKind.PROMO_ROOK => MoveType.Promotion(PromotionPiece.Rook) + case ProtoMoveKind.PROMO_BISHOP => MoveType.Promotion(PromotionPiece.Bishop) + case ProtoMoveKind.PROMO_KNIGHT => MoveType.Promotion(PromotionPiece.Knight) + case _ => MoveType.Normal(false) + + def toProtoMove(m: DomainMove): ProtoMove = + ProtoMove.newBuilder().setFrom(m.from.toString).setTo(m.to.toString).setMoveKind(toProtoMoveKind(m.moveType)).build() + + def fromProtoMove(m: ProtoMove): Option[DomainMove] = + for + from <- Square.fromAlgebraic(m.getFrom) + to <- Square.fromAlgebraic(m.getTo) + yield DomainMove(from, to, fromProtoMoveKind(m.getMoveKind)) + + def toProtoBoard(board: Board): java.util.List[ProtoSquarePiece] = + board.pieces.map { (sq, piece) => + ProtoSquarePiece + .newBuilder() + .setSquare(sq.toString) + .setPiece(ProtoPiece.newBuilder().setColor(toProtoColor(piece.color)).setPieceType(toProtoPieceType(piece.pieceType)).build()) + .build() + }.toSeq.asJava + + def fromProtoBoard(pieces: java.util.List[ProtoSquarePiece]): Board = + Board(pieces.asScala.flatMap(sp => Square.fromAlgebraic(sp.getSquare).map(_ -> Piece(fromProtoColor(sp.getPiece.getColor), fromProtoPieceType(sp.getPiece.getPieceType)))).toMap) + + def toProtoResultKind(r: Option[GameResult]): ProtoGameResultKind = r match + case None => ProtoGameResultKind.ONGOING + case Some(GameResult.Win(Color.White, WinReason.Checkmate)) => ProtoGameResultKind.WIN_CHECKMATE_W + case Some(GameResult.Win(Color.Black, WinReason.Checkmate)) => ProtoGameResultKind.WIN_CHECKMATE_B + case Some(GameResult.Win(Color.White, WinReason.Resignation)) => ProtoGameResultKind.WIN_RESIGN_W + case Some(GameResult.Win(Color.Black, WinReason.Resignation)) => ProtoGameResultKind.WIN_RESIGN_B + case Some(GameResult.Win(Color.White, WinReason.TimeControl)) => ProtoGameResultKind.WIN_TIME_W + case Some(GameResult.Win(Color.Black, WinReason.TimeControl)) => ProtoGameResultKind.WIN_TIME_B + case Some(GameResult.Draw(DrawReason.Stalemate)) => ProtoGameResultKind.DRAW_STALEMATE + case Some(GameResult.Draw(DrawReason.InsufficientMaterial)) => ProtoGameResultKind.DRAW_INSUFFICIENT + case Some(GameResult.Draw(DrawReason.FiftyMoveRule)) => ProtoGameResultKind.DRAW_FIFTY_MOVE + case Some(GameResult.Draw(DrawReason.ThreefoldRepetition)) => ProtoGameResultKind.DRAW_THREEFOLD + case Some(GameResult.Draw(DrawReason.Agreement)) => ProtoGameResultKind.DRAW_AGREEMENT + + def fromProtoResultKind(k: ProtoGameResultKind): Option[GameResult] = k match + case ProtoGameResultKind.ONGOING => None + case ProtoGameResultKind.WIN_CHECKMATE_W => Some(GameResult.Win(Color.White, WinReason.Checkmate)) + case ProtoGameResultKind.WIN_CHECKMATE_B => Some(GameResult.Win(Color.Black, WinReason.Checkmate)) + case ProtoGameResultKind.WIN_RESIGN_W => Some(GameResult.Win(Color.White, WinReason.Resignation)) + case ProtoGameResultKind.WIN_RESIGN_B => Some(GameResult.Win(Color.Black, WinReason.Resignation)) + case ProtoGameResultKind.WIN_TIME_W => Some(GameResult.Win(Color.White, WinReason.TimeControl)) + case ProtoGameResultKind.WIN_TIME_B => Some(GameResult.Win(Color.Black, WinReason.TimeControl)) + case ProtoGameResultKind.DRAW_STALEMATE => Some(GameResult.Draw(DrawReason.Stalemate)) + case ProtoGameResultKind.DRAW_INSUFFICIENT => Some(GameResult.Draw(DrawReason.InsufficientMaterial)) + case ProtoGameResultKind.DRAW_FIFTY_MOVE => Some(GameResult.Draw(DrawReason.FiftyMoveRule)) + case ProtoGameResultKind.DRAW_THREEFOLD => Some(GameResult.Draw(DrawReason.ThreefoldRepetition)) + case ProtoGameResultKind.DRAW_AGREEMENT => Some(GameResult.Draw(DrawReason.Agreement)) + case _ => None + + def toProtoGameContext(ctx: GameContext): ProtoGameContext = + ProtoGameContext + .newBuilder() + .addAllBoard(toProtoBoard(ctx.board)) + .setTurn(toProtoColor(ctx.turn)) + .setCastlingRights( + ProtoCastlingRights + .newBuilder() + .setWhiteKingSide(ctx.castlingRights.whiteKingSide) + .setWhiteQueenSide(ctx.castlingRights.whiteQueenSide) + .setBlackKingSide(ctx.castlingRights.blackKingSide) + .setBlackQueenSide(ctx.castlingRights.blackQueenSide) + .build(), + ) + .setEnPassantSquare(ctx.enPassantSquare.map(_.toString).getOrElse("")) + .setHalfMoveClock(ctx.halfMoveClock) + .addAllMoves(ctx.moves.map(toProtoMove).asJava) + .setResult(toProtoResultKind(ctx.result)) + .addAllInitialBoard(toProtoBoard(ctx.initialBoard)) + .build() + + def fromProtoGameContext(p: ProtoGameContext): GameContext = + val cr = p.getCastlingRights + GameContext( + board = fromProtoBoard(p.getBoardList), + turn = fromProtoColor(p.getTurn), + castlingRights = DomainCastlingRights(cr.getWhiteKingSide, cr.getWhiteQueenSide, cr.getBlackKingSide, cr.getBlackQueenSide), + enPassantSquare = Option(p.getEnPassantSquare).filter(_.nonEmpty).flatMap(Square.fromAlgebraic), + halfMoveClock = p.getHalfMoveClock, + moves = p.getMovesList.asScala.flatMap(fromProtoMove).toList, + result = fromProtoResultKind(p.getResult), + initialBoard = fromProtoBoard(p.getInitialBoardList), + ) diff --git a/modules/rule/build.gradle.kts b/modules/rule/build.gradle.kts index ae8548b..d568fe4 100644 --- a/modules/rule/build.gradle.kts +++ b/modules/rule/build.gradle.kts @@ -22,8 +22,15 @@ scoverage { scoverageVersion.set(versions["SCOVERAGE"]!!) } +sourceSets { + main { + java.srcDir("build/classes/java/quarkus-generated-sources/grpc") + } +} + tasks.withType { scalaCompileOptions.additionalParameters = listOf("-encoding", "UTF-8") + dependsOn("quarkusGenerateCode") } val quarkusPlatformGroupId: String by project @@ -53,6 +60,7 @@ dependencies { implementation("io.quarkus:quarkus-rest-client") implementation("io.quarkus:quarkus-rest-jackson") implementation("io.quarkus:quarkus-config-yaml") + implementation("io.quarkus:quarkus-grpc") implementation("io.quarkus:quarkus-smallrye-fault-tolerance") implementation("io.quarkus:quarkus-smallrye-jwt") implementation("io.quarkus:quarkus-smallrye-health") diff --git a/modules/rule/src/main/proto/chess_types.proto b/modules/rule/src/main/proto/chess_types.proto new file mode 100644 index 0000000..c1bb524 --- /dev/null +++ b/modules/rule/src/main/proto/chess_types.proto @@ -0,0 +1,87 @@ +syntax = "proto3"; +option java_package = "de.nowchess.rules.proto"; +option java_multiple_files = true; +option java_outer_classname = "ChessTypesProto"; + +enum ProtoColor { + WHITE = 0; + BLACK = 1; +} + +enum ProtoPieceType { + PAWN = 0; + KNIGHT = 1; + BISHOP = 2; + ROOK = 3; + QUEEN = 4; + KING = 5; +} + +enum ProtoMoveKind { + QUIET = 0; + CAPTURE = 1; + CASTLE_KINGSIDE = 2; + CASTLE_QUEENSIDE = 3; + EN_PASSANT = 4; + PROMO_QUEEN = 5; + PROMO_ROOK = 6; + PROMO_BISHOP = 7; + PROMO_KNIGHT = 8; +} + +enum ProtoGameResultKind { + ONGOING = 0; + WIN_CHECKMATE_W = 1; + WIN_CHECKMATE_B = 2; + WIN_RESIGN_W = 3; + WIN_RESIGN_B = 4; + WIN_TIME_W = 5; + WIN_TIME_B = 6; + DRAW_STALEMATE = 7; + DRAW_INSUFFICIENT = 8; + DRAW_FIFTY_MOVE = 9; + DRAW_THREEFOLD = 10; + DRAW_AGREEMENT = 11; +} + +message ProtoPiece { + ProtoColor color = 1; + ProtoPieceType piece_type = 2; +} + +message ProtoSquarePiece { + string square = 1; + ProtoPiece piece = 2; +} + +message ProtoMove { + string from = 1; + string to = 2; + ProtoMoveKind move_kind = 3; +} + +message ProtoCastlingRights { + bool white_king_side = 1; + bool white_queen_side = 2; + bool black_king_side = 3; + bool black_queen_side = 4; +} + +message ProtoGameContext { + repeated ProtoSquarePiece board = 1; + ProtoColor turn = 2; + ProtoCastlingRights castling_rights = 3; + string en_passant_square = 4; + int32 half_move_clock = 5; + repeated ProtoMove moves = 6; + ProtoGameResultKind result = 7; + repeated ProtoSquarePiece initial_board = 8; +} + +message ProtoPostMoveStatus { + bool is_checkmate = 1; + bool is_stalemate = 2; + bool is_insufficient_material = 3; + bool is_check = 4; + bool is_threefold_repetition = 5; +} diff --git a/modules/rule/src/main/proto/rule_service.proto b/modules/rule/src/main/proto/rule_service.proto new file mode 100644 index 0000000..f5aea3d --- /dev/null +++ b/modules/rule/src/main/proto/rule_service.proto @@ -0,0 +1,38 @@ +syntax = "proto3"; +option java_package = "de.nowchess.rules.proto"; +option java_multiple_files = true; +option java_outer_classname = "RuleServiceProto"; + +import "chess_types.proto"; + +message ProtoSquareRequest { + ProtoGameContext context = 1; + string square = 2; +} + +message ProtoMoveRequest { + ProtoGameContext context = 1; + ProtoMove move = 2; +} + +message ProtoMoveList { + repeated ProtoMove moves = 1; +} + +message ProtoBoolResult { + bool value = 1; +} + +service RuleService { + rpc CandidateMoves (ProtoSquareRequest) returns (ProtoMoveList); + rpc LegalMoves (ProtoSquareRequest) returns (ProtoMoveList); + rpc AllLegalMoves (ProtoGameContext) returns (ProtoMoveList); + rpc IsCheck (ProtoGameContext) returns (ProtoBoolResult); + rpc IsCheckmate (ProtoGameContext) returns (ProtoBoolResult); + rpc IsStalemate (ProtoGameContext) returns (ProtoBoolResult); + rpc IsInsufficientMaterial (ProtoGameContext) returns (ProtoBoolResult); + rpc IsFiftyMoveRule (ProtoGameContext) returns (ProtoBoolResult); + rpc IsThreefoldRepetition (ProtoGameContext) returns (ProtoBoolResult); + rpc ApplyMove (ProtoMoveRequest) returns (ProtoGameContext); + rpc PostMoveStatus (ProtoGameContext) returns (ProtoPostMoveStatus); +} diff --git a/modules/rule/src/main/resources/application.yml b/modules/rule/src/main/resources/application.yml index 98b81ce..7a998fc 100644 --- a/modules/rule/src/main/resources/application.yml +++ b/modules/rule/src/main/resources/application.yml @@ -1,5 +1,8 @@ quarkus: http: port: 8082 + grpc: + server: + use-separate-server: false application: name: rule-service diff --git a/modules/rule/src/main/scala/de/nowchess/rules/grpc/ProtoMapper.scala b/modules/rule/src/main/scala/de/nowchess/rules/grpc/ProtoMapper.scala new file mode 100644 index 0000000..4864afb --- /dev/null +++ b/modules/rule/src/main/scala/de/nowchess/rules/grpc/ProtoMapper.scala @@ -0,0 +1,141 @@ +package de.nowchess.rules.grpc + +import de.nowchess.api.board.{CastlingRights as DomainCastlingRights, *} +import de.nowchess.api.game.{DrawReason, GameContext, GameResult, WinReason} +import de.nowchess.api.move.{MoveType, PromotionPiece, Move as DomainMove} +import de.nowchess.rules.proto.* + +import scala.jdk.CollectionConverters.* + +object ProtoMapper: + + def toProtoColor(c: Color): ProtoColor = c match + case Color.White => ProtoColor.WHITE + case Color.Black => ProtoColor.BLACK + + def fromProtoColor(c: ProtoColor): Color = c match + case ProtoColor.WHITE => Color.White + case _ => Color.Black + + def toProtoPieceType(pt: PieceType): ProtoPieceType = pt match + case PieceType.Pawn => ProtoPieceType.PAWN + case PieceType.Knight => ProtoPieceType.KNIGHT + case PieceType.Bishop => ProtoPieceType.BISHOP + case PieceType.Rook => ProtoPieceType.ROOK + case PieceType.Queen => ProtoPieceType.QUEEN + case PieceType.King => ProtoPieceType.KING + + def fromProtoPieceType(pt: ProtoPieceType): PieceType = pt match + case ProtoPieceType.PAWN => PieceType.Pawn + case ProtoPieceType.KNIGHT => PieceType.Knight + case ProtoPieceType.BISHOP => PieceType.Bishop + case ProtoPieceType.ROOK => PieceType.Rook + case ProtoPieceType.QUEEN => PieceType.Queen + case _ => PieceType.King + + def toProtoMoveKind(mt: MoveType): ProtoMoveKind = mt match + case MoveType.Normal(false) => ProtoMoveKind.QUIET + case MoveType.Normal(true) => ProtoMoveKind.CAPTURE + case MoveType.CastleKingside => ProtoMoveKind.CASTLE_KINGSIDE + case MoveType.CastleQueenside => ProtoMoveKind.CASTLE_QUEENSIDE + case MoveType.EnPassant => ProtoMoveKind.EN_PASSANT + case MoveType.Promotion(PromotionPiece.Queen) => ProtoMoveKind.PROMO_QUEEN + case MoveType.Promotion(PromotionPiece.Rook) => ProtoMoveKind.PROMO_ROOK + case MoveType.Promotion(PromotionPiece.Bishop) => ProtoMoveKind.PROMO_BISHOP + case MoveType.Promotion(PromotionPiece.Knight) => ProtoMoveKind.PROMO_KNIGHT + + def fromProtoMoveKind(k: ProtoMoveKind): MoveType = k match + case ProtoMoveKind.QUIET => MoveType.Normal(false) + case ProtoMoveKind.CAPTURE => MoveType.Normal(true) + case ProtoMoveKind.CASTLE_KINGSIDE => MoveType.CastleKingside + case ProtoMoveKind.CASTLE_QUEENSIDE => MoveType.CastleQueenside + case ProtoMoveKind.EN_PASSANT => MoveType.EnPassant + case ProtoMoveKind.PROMO_QUEEN => MoveType.Promotion(PromotionPiece.Queen) + case ProtoMoveKind.PROMO_ROOK => MoveType.Promotion(PromotionPiece.Rook) + case ProtoMoveKind.PROMO_BISHOP => MoveType.Promotion(PromotionPiece.Bishop) + case ProtoMoveKind.PROMO_KNIGHT => MoveType.Promotion(PromotionPiece.Knight) + case _ => MoveType.Normal(false) + + def toProtoMove(m: DomainMove): ProtoMove = + ProtoMove.newBuilder().setFrom(m.from.toString).setTo(m.to.toString).setMoveKind(toProtoMoveKind(m.moveType)).build() + + def fromProtoMove(m: ProtoMove): Option[DomainMove] = + for + from <- Square.fromAlgebraic(m.getFrom) + to <- Square.fromAlgebraic(m.getTo) + yield DomainMove(from, to, fromProtoMoveKind(m.getMoveKind)) + + def toProtoBoard(board: Board): java.util.List[ProtoSquarePiece] = + board.pieces.map { (sq, piece) => + ProtoSquarePiece + .newBuilder() + .setSquare(sq.toString) + .setPiece(ProtoPiece.newBuilder().setColor(toProtoColor(piece.color)).setPieceType(toProtoPieceType(piece.pieceType)).build()) + .build() + }.toSeq.asJava + + def fromProtoBoard(pieces: java.util.List[ProtoSquarePiece]): Board = + Board(pieces.asScala.flatMap(sp => Square.fromAlgebraic(sp.getSquare).map(_ -> Piece(fromProtoColor(sp.getPiece.getColor), fromProtoPieceType(sp.getPiece.getPieceType)))).toMap) + + def toProtoResultKind(r: Option[GameResult]): ProtoGameResultKind = r match + case None => ProtoGameResultKind.ONGOING + case Some(GameResult.Win(Color.White, WinReason.Checkmate)) => ProtoGameResultKind.WIN_CHECKMATE_W + case Some(GameResult.Win(Color.Black, WinReason.Checkmate)) => ProtoGameResultKind.WIN_CHECKMATE_B + case Some(GameResult.Win(Color.White, WinReason.Resignation)) => ProtoGameResultKind.WIN_RESIGN_W + case Some(GameResult.Win(Color.Black, WinReason.Resignation)) => ProtoGameResultKind.WIN_RESIGN_B + case Some(GameResult.Win(Color.White, WinReason.TimeControl)) => ProtoGameResultKind.WIN_TIME_W + case Some(GameResult.Win(Color.Black, WinReason.TimeControl)) => ProtoGameResultKind.WIN_TIME_B + case Some(GameResult.Draw(DrawReason.Stalemate)) => ProtoGameResultKind.DRAW_STALEMATE + case Some(GameResult.Draw(DrawReason.InsufficientMaterial)) => ProtoGameResultKind.DRAW_INSUFFICIENT + case Some(GameResult.Draw(DrawReason.FiftyMoveRule)) => ProtoGameResultKind.DRAW_FIFTY_MOVE + case Some(GameResult.Draw(DrawReason.ThreefoldRepetition)) => ProtoGameResultKind.DRAW_THREEFOLD + case Some(GameResult.Draw(DrawReason.Agreement)) => ProtoGameResultKind.DRAW_AGREEMENT + + def fromProtoResultKind(k: ProtoGameResultKind): Option[GameResult] = k match + case ProtoGameResultKind.ONGOING => None + case ProtoGameResultKind.WIN_CHECKMATE_W => Some(GameResult.Win(Color.White, WinReason.Checkmate)) + case ProtoGameResultKind.WIN_CHECKMATE_B => Some(GameResult.Win(Color.Black, WinReason.Checkmate)) + case ProtoGameResultKind.WIN_RESIGN_W => Some(GameResult.Win(Color.White, WinReason.Resignation)) + case ProtoGameResultKind.WIN_RESIGN_B => Some(GameResult.Win(Color.Black, WinReason.Resignation)) + case ProtoGameResultKind.WIN_TIME_W => Some(GameResult.Win(Color.White, WinReason.TimeControl)) + case ProtoGameResultKind.WIN_TIME_B => Some(GameResult.Win(Color.Black, WinReason.TimeControl)) + case ProtoGameResultKind.DRAW_STALEMATE => Some(GameResult.Draw(DrawReason.Stalemate)) + case ProtoGameResultKind.DRAW_INSUFFICIENT => Some(GameResult.Draw(DrawReason.InsufficientMaterial)) + case ProtoGameResultKind.DRAW_FIFTY_MOVE => Some(GameResult.Draw(DrawReason.FiftyMoveRule)) + case ProtoGameResultKind.DRAW_THREEFOLD => Some(GameResult.Draw(DrawReason.ThreefoldRepetition)) + case ProtoGameResultKind.DRAW_AGREEMENT => Some(GameResult.Draw(DrawReason.Agreement)) + case _ => None + + def toProtoGameContext(ctx: GameContext): ProtoGameContext = + ProtoGameContext + .newBuilder() + .addAllBoard(toProtoBoard(ctx.board)) + .setTurn(toProtoColor(ctx.turn)) + .setCastlingRights( + ProtoCastlingRights + .newBuilder() + .setWhiteKingSide(ctx.castlingRights.whiteKingSide) + .setWhiteQueenSide(ctx.castlingRights.whiteQueenSide) + .setBlackKingSide(ctx.castlingRights.blackKingSide) + .setBlackQueenSide(ctx.castlingRights.blackQueenSide) + .build(), + ) + .setEnPassantSquare(ctx.enPassantSquare.map(_.toString).getOrElse("")) + .setHalfMoveClock(ctx.halfMoveClock) + .addAllMoves(ctx.moves.map(toProtoMove).asJava) + .setResult(toProtoResultKind(ctx.result)) + .addAllInitialBoard(toProtoBoard(ctx.initialBoard)) + .build() + + def fromProtoGameContext(p: ProtoGameContext): GameContext = + val cr = p.getCastlingRights + GameContext( + board = fromProtoBoard(p.getBoardList), + turn = fromProtoColor(p.getTurn), + castlingRights = DomainCastlingRights(cr.getWhiteKingSide, cr.getWhiteQueenSide, cr.getBlackKingSide, cr.getBlackQueenSide), + enPassantSquare = Option(p.getEnPassantSquare).filter(_.nonEmpty).flatMap(Square.fromAlgebraic), + halfMoveClock = p.getHalfMoveClock, + moves = p.getMovesList.asScala.flatMap(fromProtoMove).toList, + result = fromProtoResultKind(p.getResult), + initialBoard = fromProtoBoard(p.getInitialBoardList), + ) diff --git a/modules/rule/src/main/scala/de/nowchess/rules/grpc/RuleGrpcService.scala b/modules/rule/src/main/scala/de/nowchess/rules/grpc/RuleGrpcService.scala new file mode 100644 index 0000000..c37e35a --- /dev/null +++ b/modules/rule/src/main/scala/de/nowchess/rules/grpc/RuleGrpcService.scala @@ -0,0 +1,84 @@ +package de.nowchess.rules.grpc + +import de.nowchess.api.board.Square +import de.nowchess.rules.proto.* +import de.nowchess.rules.sets.DefaultRules +import io.grpc.stub.StreamObserver +import io.grpc.{Status, StatusRuntimeException} +import io.quarkus.grpc.GrpcService + +// scalafix:off DisableSyntax.throw +@GrpcService +class RuleGrpcService extends RuleServiceGrpc.RuleServiceImplBase: + + private def parseSquare(s: String): Square = + Square.fromAlgebraic(s).getOrElse( + throw Status.INVALID_ARGUMENT.withDescription(s"Invalid square: $s").asRuntimeException(), + ) + + override def candidateMoves(req: ProtoSquareRequest, resp: StreamObserver[ProtoMoveList]): Unit = + val ctx = ProtoMapper.fromProtoGameContext(req.getContext) + val sq = parseSquare(req.getSquare) + val moves = DefaultRules.candidateMoves(ctx)(sq) + resp.onNext(ProtoMoveList.newBuilder().addAllMoves(moves.map(ProtoMapper.toProtoMove).asInstanceOf[java.util.List[ProtoMove]]).build()) + resp.onCompleted() + + override def legalMoves(req: ProtoSquareRequest, resp: StreamObserver[ProtoMoveList]): Unit = + val ctx = ProtoMapper.fromProtoGameContext(req.getContext) + val sq = parseSquare(req.getSquare) + val moves = DefaultRules.legalMoves(ctx)(sq) + respond(resp, ProtoMoveList.newBuilder().addAllMoves(toJavaMoveList(moves)).build()) + + override def allLegalMoves(req: ProtoGameContext, resp: StreamObserver[ProtoMoveList]): Unit = + val moves = DefaultRules.allLegalMoves(ProtoMapper.fromProtoGameContext(req)) + respond(resp, ProtoMoveList.newBuilder().addAllMoves(toJavaMoveList(moves)).build()) + + override def isCheck(req: ProtoGameContext, resp: StreamObserver[ProtoBoolResult]): Unit = + respond(resp, boolResult(DefaultRules.isCheck(ProtoMapper.fromProtoGameContext(req)))) + + override def isCheckmate(req: ProtoGameContext, resp: StreamObserver[ProtoBoolResult]): Unit = + respond(resp, boolResult(DefaultRules.isCheckmate(ProtoMapper.fromProtoGameContext(req)))) + + override def isStalemate(req: ProtoGameContext, resp: StreamObserver[ProtoBoolResult]): Unit = + respond(resp, boolResult(DefaultRules.isStalemate(ProtoMapper.fromProtoGameContext(req)))) + + override def isInsufficientMaterial(req: ProtoGameContext, resp: StreamObserver[ProtoBoolResult]): Unit = + respond(resp, boolResult(DefaultRules.isInsufficientMaterial(ProtoMapper.fromProtoGameContext(req)))) + + override def isFiftyMoveRule(req: ProtoGameContext, resp: StreamObserver[ProtoBoolResult]): Unit = + respond(resp, boolResult(DefaultRules.isFiftyMoveRule(ProtoMapper.fromProtoGameContext(req)))) + + override def isThreefoldRepetition(req: ProtoGameContext, resp: StreamObserver[ProtoBoolResult]): Unit = + respond(resp, boolResult(DefaultRules.isThreefoldRepetition(ProtoMapper.fromProtoGameContext(req)))) + + override def applyMove(req: ProtoMoveRequest, resp: StreamObserver[ProtoGameContext]): Unit = + val ctx = ProtoMapper.fromProtoGameContext(req.getContext) + val move = ProtoMapper.fromProtoMove(req.getMove).getOrElse( + throw Status.INVALID_ARGUMENT.withDescription("Invalid move").asRuntimeException(), + ) + respond(resp, ProtoMapper.toProtoGameContext(DefaultRules.applyMove(ctx)(move))) + + override def postMoveStatus(req: ProtoGameContext, resp: StreamObserver[ProtoPostMoveStatus]): Unit = + val status = DefaultRules.postMoveStatus(ProtoMapper.fromProtoGameContext(req)) + respond( + resp, + ProtoPostMoveStatus + .newBuilder() + .setIsCheckmate(status.isCheckmate) + .setIsStalemate(status.isStalemate) + .setIsInsufficientMaterial(status.isInsufficientMaterial) + .setIsCheck(status.isCheck) + .setIsThreefoldRepetition(status.isThreefoldRepetition) + .build(), + ) + + private def boolResult(v: Boolean): ProtoBoolResult = ProtoBoolResult.newBuilder().setValue(v).build() + + private def respond[T](obs: StreamObserver[T], value: T): Unit = + obs.onNext(value) + obs.onCompleted() + + private def toJavaMoveList(moves: List[de.nowchess.api.move.Move]): java.util.List[ProtoMove] = + import scala.jdk.CollectionConverters.* + moves.map(ProtoMapper.toProtoMove).asJava +// scalafix:on DisableSyntax.throw