feat(game): add GameWritebackEventDto and update related services for game state management
Build & Test (NowChessSystems) TeamCity build failed

This commit is contained in:
2026-04-29 20:52:50 +02:00
parent 91efed1370
commit 75be096c5a
23 changed files with 349 additions and 298 deletions
+7
View File
@@ -31,8 +31,15 @@ jobs:
strategy: strategy:
matrix: matrix:
module: module:
- account
- bot-platform
- coordinator
- core - core
- io - io
- official-bots
- rule
- store
- ws
steps: steps:
- uses: actions/checkout@v4 - uses: actions/checkout@v4
+1 -1
View File
@@ -5,7 +5,7 @@
<option name="linkedExternalProjectsSettings"> <option name="linkedExternalProjectsSettings">
<GradleProjectSettings> <GradleProjectSettings>
<option name="externalProjectPath" value="$PROJECT_DIR$" /> <option name="externalProjectPath" value="$PROJECT_DIR$" />
<option name="gradleJvm" value="corretto-21" /> <option name="gradleJvm" value="ms-21" />
<option name="modules"> <option name="modules">
<set> <set>
<option value="$PROJECT_DIR$" /> <option value="$PROJECT_DIR$" />
+2 -1
View File
@@ -1,9 +1,10 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4"> <project version="4">
<component name="ExternalStorageConfigurationManager" enabled="true" /> <component name="ExternalStorageConfigurationManager" enabled="true" />
<component name="FrameworkDetectionExcludesConfiguration"> <component name="FrameworkDetectionExcludesConfiguration">
<file type="web" url="file://$PROJECT_DIR$" /> <file type="web" url="file://$PROJECT_DIR$" />
</component> </component>
<component name="ProjectRootManager" version="2" languageLevel="JDK_21" default="true" project-jdk-name="corretto-21" project-jdk-type="JavaSDK"> <component name="ProjectRootManager" version="2" languageLevel="JDK_21" default="true" project-jdk-name="ms-21" project-jdk-type="JavaSDK">
<output url="file://$PROJECT_DIR$/out" /> <output url="file://$PROJECT_DIR$/out" />
</component> </component>
</project> </project>
+1 -1
View File
@@ -12,7 +12,7 @@ version = "1.0-SNAPSHOT"
// converted to scoverage regexes via globToScoverageRegex for instrumentation-time exclusion. // converted to scoverage regexes via globToScoverageRegex for instrumentation-time exclusion.
val coverageExclusions = listOf( val coverageExclusions = listOf(
// UI renders JavaFX components; headless test environments cannot exercise rendering paths // UI renders JavaFX components; headless test environments cannot exercise rendering paths
"modules/ui/**", "modules/api/**",
// FastParse macro-generated combinators produce synthetic branches that scoverage marks as uncovered // FastParse macro-generated combinators produce synthetic branches that scoverage marks as uncovered
"modules/io/src/main/scala/de/nowchess/io/fen/FenParserFastParse*", "modules/io/src/main/scala/de/nowchess/io/fen/FenParserFastParse*",
// NNUE inference pipeline — coverage requires a trained model file not present in CI // NNUE inference pipeline — coverage requires a trained model file not present in CI
@@ -30,7 +30,7 @@ nowchess:
port: 6379 port: 6379
prefix: nowchess prefix: nowchess
internal: internal:
secret: ${INTERNAL_SECRET} secret: 123abc
"%deployed": "%deployed":
quarkus: quarkus:
@@ -1,4 +1,4 @@
package de.nowchess.chess.redis package de.nowchess.api.dto
case class GameWritebackEventDto( case class GameWritebackEventDto(
gameId: String, gameId: String,
@@ -0,0 +1,107 @@
package de.nowchess.api.grpc
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 scala.jdk.CollectionConverters.*
trait ProtoMapperBase[PC, PPT, PMK, PM, PSP, PBoard, PCR, PRK, PGC]:
def toProtoColor(c: Color): PC
def fromProtoColor(c: PC): Color
def toProtoPieceType(pt: PieceType): PPT
def fromProtoPieceType(pt: PPT): PieceType
def toProtoMoveKind(mt: MoveType): PMK
def fromProtoMoveKind(k: PMK): MoveType
def toProtoMove(m: DomainMove): PM
def fromProtoMove(m: PM): Option[DomainMove]
def toProtoSquarePiece(sq: Square, piece: Piece): PSP
def fromProtoSquarePiece(sp: PSP): Option[(Square, Piece)]
def toProtoBoard(board: Board): java.util.List[PSP]
def fromProtoBoard(pieces: java.util.List[PSP]): Board
def toProtoResultKind(r: Option[GameResult]): PRK
def fromProtoResultKind(k: PRK): Option[GameResult]
def toProtoCastlingRights(cr: DomainCastlingRights): PCR
def fromProtoCastlingRights(pcr: PCR): DomainCastlingRights
def toProtoGameContext(ctx: GameContext): PGC
def fromProtoGameContext(p: PGC): GameContext
object ProtoMapperBase:
def colorConversions[PC](white: PC, black: PC): (Color => PC, PC => Color) =
(
(c: Color) =>
c match
case Color.White => white
case Color.Black => black,
(pc: PC) =>
if pc == white then Color.White
else Color.Black,
)
def pieceTypeConversions[PPT](
pawn: PPT,
knight: PPT,
bishop: PPT,
rook: PPT,
queen: PPT,
king: PPT,
): (PieceType => PPT, PPT => PieceType) =
(
(pt: PieceType) =>
pt match
case PieceType.Pawn => pawn
case PieceType.Knight => knight
case PieceType.Bishop => bishop
case PieceType.Rook => rook
case PieceType.Queen => queen
case PieceType.King => king,
(ppt: PPT) =>
if ppt == pawn then PieceType.Pawn
else if ppt == knight then PieceType.Knight
else if ppt == bishop then PieceType.Bishop
else if ppt == rook then PieceType.Rook
else if ppt == queen then PieceType.Queen
else PieceType.King,
)
def moveKindConversions[PMK](
quiet: PMK,
capture: PMK,
castleKingside: PMK,
castleQueenside: PMK,
enPassant: PMK,
promoQueen: PMK,
promoRook: PMK,
promoBishop: PMK,
promoKnight: PMK,
): (MoveType => PMK, PMK => MoveType) =
(
(mt: MoveType) =>
mt match
case MoveType.Normal(false) => quiet
case MoveType.Normal(true) => capture
case MoveType.CastleKingside => castleKingside
case MoveType.CastleQueenside => castleQueenside
case MoveType.EnPassant => enPassant
case MoveType.Promotion(PromotionPiece.Queen) => promoQueen
case MoveType.Promotion(PromotionPiece.Rook) => promoRook
case MoveType.Promotion(PromotionPiece.Bishop) => promoBishop
case MoveType.Promotion(PromotionPiece.Knight) => promoKnight,
(pmk: PMK) =>
if pmk == quiet then MoveType.Normal(false)
else if pmk == capture then MoveType.Normal(true)
else if pmk == castleKingside then MoveType.CastleKingside
else if pmk == castleQueenside then MoveType.CastleQueenside
else if pmk == enPassant then MoveType.EnPassant
else if pmk == promoQueen then MoveType.Promotion(PromotionPiece.Queen)
else if pmk == promoRook then MoveType.Promotion(PromotionPiece.Rook)
else if pmk == promoBishop then MoveType.Promotion(PromotionPiece.Bishop)
else if pmk == promoKnight then MoveType.Promotion(PromotionPiece.Knight)
else MoveType.Normal(false),
)
@@ -26,7 +26,7 @@ nowchess:
prefix: nowchess prefix: nowchess
internal: internal:
secret: ${INTERNAL_SECRET} secret: 123abc
coordinator: coordinator:
enabled: ${NOWCHESS_COORDINATOR_ENABLED:false} enabled: ${NOWCHESS_COORDINATOR_ENABLED:false}
@@ -3,61 +3,42 @@ package de.nowchess.chess.grpc
import de.nowchess.api.board.* import de.nowchess.api.board.*
import de.nowchess.api.board.CastlingRights as DomainCastlingRights import de.nowchess.api.board.CastlingRights as DomainCastlingRights
import de.nowchess.api.game.{DrawReason, GameContext, GameResult, WinReason} import de.nowchess.api.game.{DrawReason, GameContext, GameResult, WinReason}
import de.nowchess.api.move.{Move as DomainMove, MoveType, PromotionPiece} import de.nowchess.api.grpc.ProtoMapperBase
import de.nowchess.api.move.{Move as DomainMove, MoveType}
import de.nowchess.core.proto.* import de.nowchess.core.proto.*
import scala.jdk.CollectionConverters.* import scala.jdk.CollectionConverters.*
object CoreProtoMapper: object CoreProtoMapper extends ProtoMapperBase[ProtoColor, ProtoPieceType, ProtoMoveKind, ProtoMove, ProtoSquarePiece, java.util.List[ProtoSquarePiece], ProtoCastlingRights, ProtoGameResultKind, ProtoGameContext]:
private val (colorTo, colorFrom) = ProtoMapperBase.colorConversions(ProtoColor.WHITE, ProtoColor.BLACK)
private val (pieceTypeTo, pieceTypeFrom) = ProtoMapperBase.pieceTypeConversions(
ProtoPieceType.PAWN,
ProtoPieceType.KNIGHT,
ProtoPieceType.BISHOP,
ProtoPieceType.ROOK,
ProtoPieceType.QUEEN,
ProtoPieceType.KING,
)
private val (moveKindTo, moveKindFrom) = ProtoMapperBase.moveKindConversions(
ProtoMoveKind.QUIET,
ProtoMoveKind.CAPTURE,
ProtoMoveKind.CASTLE_KINGSIDE,
ProtoMoveKind.CASTLE_QUEENSIDE,
ProtoMoveKind.EN_PASSANT,
ProtoMoveKind.PROMO_QUEEN,
ProtoMoveKind.PROMO_ROOK,
ProtoMoveKind.PROMO_BISHOP,
ProtoMoveKind.PROMO_KNIGHT,
)
def toProtoColor(c: Color): ProtoColor = c match override def toProtoColor(c: Color): ProtoColor = colorTo(c)
case Color.White => ProtoColor.WHITE override def fromProtoColor(c: ProtoColor): Color = colorFrom(c)
case Color.Black => ProtoColor.BLACK override def toProtoPieceType(pt: PieceType): ProtoPieceType = pieceTypeTo(pt)
override def fromProtoPieceType(pt: ProtoPieceType): PieceType = pieceTypeFrom(pt)
override def toProtoMoveKind(mt: MoveType): ProtoMoveKind = moveKindTo(mt)
override def fromProtoMoveKind(k: ProtoMoveKind): MoveType = moveKindFrom(k)
def fromProtoColor(c: ProtoColor): Color = c match override def toProtoMove(m: DomainMove): ProtoMove =
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 ProtoMove
.newBuilder() .newBuilder()
.setFrom(m.from.toString) .setFrom(m.from.toString)
@@ -65,42 +46,44 @@ object CoreProtoMapper:
.setMoveKind(toProtoMoveKind(m.moveType)) .setMoveKind(toProtoMoveKind(m.moveType))
.build() .build()
def fromProtoMove(m: ProtoMove): Option[DomainMove] = override def fromProtoMove(m: ProtoMove): Option[DomainMove] =
for for
from <- Square.fromAlgebraic(m.getFrom) from <- Square.fromAlgebraic(m.getFrom)
to <- Square.fromAlgebraic(m.getTo) to <- Square.fromAlgebraic(m.getTo)
yield DomainMove(from, to, fromProtoMoveKind(m.getMoveKind)) yield DomainMove(from, to, fromProtoMoveKind(m.getMoveKind))
def toProtoBoard(board: Board): java.util.List[ProtoSquarePiece] = override def toProtoSquarePiece(sq: Square, piece: Piece): ProtoSquarePiece =
board.pieces ProtoSquarePiece
.map { (sq, piece) => .newBuilder()
ProtoSquarePiece .setSquare(sq.toString)
.setPiece(
ProtoPiece
.newBuilder() .newBuilder()
.setSquare(sq.toString) .setColor(toProtoColor(piece.color))
.setPiece( .setPieceType(toProtoPieceType(piece.pieceType))
ProtoPiece .build(),
.newBuilder() )
.setColor(toProtoColor(piece.color)) .build()
.setPieceType(toProtoPieceType(piece.pieceType))
.build(), override def fromProtoSquarePiece(sp: ProtoSquarePiece): Option[(Square, Piece)] =
) Square
.build() .fromAlgebraic(sp.getSquare)
} .map(_ -> Piece(fromProtoColor(sp.getPiece.getColor), fromProtoPieceType(sp.getPiece.getPieceType)))
override def toProtoBoard(board: Board): java.util.List[ProtoSquarePiece] =
board.pieces
.map { (sq, piece) => toProtoSquarePiece(sq, piece) }
.toSeq .toSeq
.asJava .asJava
def fromProtoBoard(pieces: java.util.List[ProtoSquarePiece]): Board = override def fromProtoBoard(pieces: java.util.List[ProtoSquarePiece]): Board =
Board( Board(
pieces.asScala pieces.asScala
.flatMap(sp => .flatMap(fromProtoSquarePiece)
Square
.fromAlgebraic(sp.getSquare)
.map(_ -> Piece(fromProtoColor(sp.getPiece.getColor), fromProtoPieceType(sp.getPiece.getPieceType))),
)
.toMap, .toMap,
) )
def toProtoResultKind(r: Option[GameResult]): ProtoGameResultKind = r match override def toProtoResultKind(r: Option[GameResult]): ProtoGameResultKind = r match
case None => ProtoGameResultKind.ONGOING case None => ProtoGameResultKind.ONGOING
case Some(GameResult.Win(Color.White, WinReason.Checkmate)) => ProtoGameResultKind.WIN_CHECKMATE_W 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.Black, WinReason.Checkmate)) => ProtoGameResultKind.WIN_CHECKMATE_B
@@ -114,7 +97,7 @@ object CoreProtoMapper:
case Some(GameResult.Draw(DrawReason.ThreefoldRepetition)) => ProtoGameResultKind.DRAW_THREEFOLD case Some(GameResult.Draw(DrawReason.ThreefoldRepetition)) => ProtoGameResultKind.DRAW_THREEFOLD
case Some(GameResult.Draw(DrawReason.Agreement)) => ProtoGameResultKind.DRAW_AGREEMENT case Some(GameResult.Draw(DrawReason.Agreement)) => ProtoGameResultKind.DRAW_AGREEMENT
def fromProtoResultKind(k: ProtoGameResultKind): Option[GameResult] = k match override def fromProtoResultKind(k: ProtoGameResultKind): Option[GameResult] = k match
case ProtoGameResultKind.ONGOING => None case ProtoGameResultKind.ONGOING => None
case ProtoGameResultKind.WIN_CHECKMATE_W => Some(GameResult.Win(Color.White, WinReason.Checkmate)) 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_CHECKMATE_B => Some(GameResult.Win(Color.Black, WinReason.Checkmate))
@@ -129,20 +112,24 @@ object CoreProtoMapper:
case ProtoGameResultKind.DRAW_AGREEMENT => Some(GameResult.Draw(DrawReason.Agreement)) case ProtoGameResultKind.DRAW_AGREEMENT => Some(GameResult.Draw(DrawReason.Agreement))
case _ => None case _ => None
def toProtoGameContext(ctx: GameContext): ProtoGameContext = override def toProtoCastlingRights(cr: DomainCastlingRights): ProtoCastlingRights =
ProtoCastlingRights
.newBuilder()
.setWhiteKingSide(cr.whiteKingSide)
.setWhiteQueenSide(cr.whiteQueenSide)
.setBlackKingSide(cr.blackKingSide)
.setBlackQueenSide(cr.blackQueenSide)
.build()
override def fromProtoCastlingRights(pcr: ProtoCastlingRights): DomainCastlingRights =
DomainCastlingRights(pcr.getWhiteKingSide, pcr.getWhiteQueenSide, pcr.getBlackKingSide, pcr.getBlackQueenSide)
override def toProtoGameContext(ctx: GameContext): ProtoGameContext =
ProtoGameContext ProtoGameContext
.newBuilder() .newBuilder()
.addAllBoard(toProtoBoard(ctx.board)) .addAllBoard(toProtoBoard(ctx.board))
.setTurn(toProtoColor(ctx.turn)) .setTurn(toProtoColor(ctx.turn))
.setCastlingRights( .setCastlingRights(toProtoCastlingRights(ctx.castlingRights))
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("")) .setEnPassantSquare(ctx.enPassantSquare.map(_.toString).getOrElse(""))
.setHalfMoveClock(ctx.halfMoveClock) .setHalfMoveClock(ctx.halfMoveClock)
.addAllMoves(ctx.moves.map(toProtoMove).asJava) .addAllMoves(ctx.moves.map(toProtoMove).asJava)
@@ -150,13 +137,11 @@ object CoreProtoMapper:
.addAllInitialBoard(toProtoBoard(ctx.initialBoard)) .addAllInitialBoard(toProtoBoard(ctx.initialBoard))
.build() .build()
def fromProtoGameContext(p: ProtoGameContext): GameContext = override def fromProtoGameContext(p: ProtoGameContext): GameContext =
val cr = p.getCastlingRights
GameContext( GameContext(
board = fromProtoBoard(p.getBoardList), board = fromProtoBoard(p.getBoardList),
turn = fromProtoColor(p.getTurn), turn = fromProtoColor(p.getTurn),
castlingRights = castlingRights = fromProtoCastlingRights(p.getCastlingRights),
DomainCastlingRights(cr.getWhiteKingSide, cr.getWhiteQueenSide, cr.getBlackKingSide, cr.getBlackQueenSide),
enPassantSquare = Option(p.getEnPassantSquare).filter(_.nonEmpty).flatMap(Square.fromAlgebraic), enPassantSquare = Option(p.getEnPassantSquare).filter(_.nonEmpty).flatMap(Square.fromAlgebraic),
halfMoveClock = p.getHalfMoveClock, halfMoveClock = p.getHalfMoveClock,
moves = p.getMovesList.asScala.flatMap(fromProtoMove).toList, moves = p.getMovesList.asScala.flatMap(fromProtoMove).toList,
@@ -1,7 +1,7 @@
package de.nowchess.chess.redis package de.nowchess.chess.redis
import com.fasterxml.jackson.databind.ObjectMapper import com.fasterxml.jackson.databind.ObjectMapper
import de.nowchess.api.dto.GameStateEventDto import de.nowchess.api.dto.{GameStateEventDto, GameWritebackEventDto}
import de.nowchess.api.game.{CorrespondenceClockState, LiveClockState} import de.nowchess.api.game.{CorrespondenceClockState, LiveClockState}
import de.nowchess.chess.grpc.IoGrpcClientWrapper import de.nowchess.chess.grpc.IoGrpcClientWrapper
import de.nowchess.api.game.{DrawReason, GameResult, WinReason} import de.nowchess.api.game.{DrawReason, GameResult, WinReason}
@@ -9,7 +9,7 @@ quarkus:
nowchess: nowchess:
internal: internal:
secret: ${INTERNAL_SECRET} secret: 123abc
smallrye-openapi: smallrye-openapi:
info-title: NowChess IO Service info-title: NowChess IO Service
info-version: 1.0.0 info-version: 1.0.0
@@ -3,61 +3,42 @@ package de.nowchess.io.grpc
import de.nowchess.api.board.* import de.nowchess.api.board.*
import de.nowchess.api.board.CastlingRights as DomainCastlingRights import de.nowchess.api.board.CastlingRights as DomainCastlingRights
import de.nowchess.api.game.{DrawReason, GameContext, GameResult, WinReason} import de.nowchess.api.game.{DrawReason, GameContext, GameResult, WinReason}
import de.nowchess.api.move.{Move as DomainMove, MoveType, PromotionPiece} import de.nowchess.api.grpc.ProtoMapperBase
import de.nowchess.api.move.{Move as DomainMove, MoveType}
import de.nowchess.io.proto.* import de.nowchess.io.proto.*
import scala.jdk.CollectionConverters.* import scala.jdk.CollectionConverters.*
object IoProtoMapper: object IoProtoMapper extends ProtoMapperBase[ProtoColor, ProtoPieceType, ProtoMoveKind, ProtoMove, ProtoSquarePiece, java.util.List[ProtoSquarePiece], ProtoCastlingRights, ProtoGameResultKind, ProtoGameContext]:
private val (colorTo, colorFrom) = ProtoMapperBase.colorConversions(ProtoColor.WHITE, ProtoColor.BLACK)
private val (pieceTypeTo, pieceTypeFrom) = ProtoMapperBase.pieceTypeConversions(
ProtoPieceType.PAWN,
ProtoPieceType.KNIGHT,
ProtoPieceType.BISHOP,
ProtoPieceType.ROOK,
ProtoPieceType.QUEEN,
ProtoPieceType.KING,
)
private val (moveKindTo, moveKindFrom) = ProtoMapperBase.moveKindConversions(
ProtoMoveKind.QUIET,
ProtoMoveKind.CAPTURE,
ProtoMoveKind.CASTLE_KINGSIDE,
ProtoMoveKind.CASTLE_QUEENSIDE,
ProtoMoveKind.EN_PASSANT,
ProtoMoveKind.PROMO_QUEEN,
ProtoMoveKind.PROMO_ROOK,
ProtoMoveKind.PROMO_BISHOP,
ProtoMoveKind.PROMO_KNIGHT,
)
def toProtoColor(c: Color): ProtoColor = c match override def toProtoColor(c: Color): ProtoColor = colorTo(c)
case Color.White => ProtoColor.WHITE override def fromProtoColor(c: ProtoColor): Color = colorFrom(c)
case Color.Black => ProtoColor.BLACK override def toProtoPieceType(pt: PieceType): ProtoPieceType = pieceTypeTo(pt)
override def fromProtoPieceType(pt: ProtoPieceType): PieceType = pieceTypeFrom(pt)
override def toProtoMoveKind(mt: MoveType): ProtoMoveKind = moveKindTo(mt)
override def fromProtoMoveKind(k: ProtoMoveKind): MoveType = moveKindFrom(k)
def fromProtoColor(c: ProtoColor): Color = c match override def toProtoMove(m: DomainMove): ProtoMove =
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 ProtoMove
.newBuilder() .newBuilder()
.setFrom(m.from.toString) .setFrom(m.from.toString)
@@ -65,42 +46,44 @@ object IoProtoMapper:
.setMoveKind(toProtoMoveKind(m.moveType)) .setMoveKind(toProtoMoveKind(m.moveType))
.build() .build()
def fromProtoMove(m: ProtoMove): Option[DomainMove] = override def fromProtoMove(m: ProtoMove): Option[DomainMove] =
for for
from <- Square.fromAlgebraic(m.getFrom) from <- Square.fromAlgebraic(m.getFrom)
to <- Square.fromAlgebraic(m.getTo) to <- Square.fromAlgebraic(m.getTo)
yield DomainMove(from, to, fromProtoMoveKind(m.getMoveKind)) yield DomainMove(from, to, fromProtoMoveKind(m.getMoveKind))
def toProtoBoard(board: Board): java.util.List[ProtoSquarePiece] = override def toProtoSquarePiece(sq: Square, piece: Piece): ProtoSquarePiece =
board.pieces ProtoSquarePiece
.map { (sq, piece) => .newBuilder()
ProtoSquarePiece .setSquare(sq.toString)
.setPiece(
ProtoPiece
.newBuilder() .newBuilder()
.setSquare(sq.toString) .setColor(toProtoColor(piece.color))
.setPiece( .setPieceType(toProtoPieceType(piece.pieceType))
ProtoPiece .build(),
.newBuilder() )
.setColor(toProtoColor(piece.color)) .build()
.setPieceType(toProtoPieceType(piece.pieceType))
.build(), override def fromProtoSquarePiece(sp: ProtoSquarePiece): Option[(Square, Piece)] =
) Square
.build() .fromAlgebraic(sp.getSquare)
} .map(_ -> Piece(fromProtoColor(sp.getPiece.getColor), fromProtoPieceType(sp.getPiece.getPieceType)))
override def toProtoBoard(board: Board): java.util.List[ProtoSquarePiece] =
board.pieces
.map { (sq, piece) => toProtoSquarePiece(sq, piece) }
.toSeq .toSeq
.asJava .asJava
def fromProtoBoard(pieces: java.util.List[ProtoSquarePiece]): Board = override def fromProtoBoard(pieces: java.util.List[ProtoSquarePiece]): Board =
Board( Board(
pieces.asScala pieces.asScala
.flatMap(sp => .flatMap(fromProtoSquarePiece)
Square
.fromAlgebraic(sp.getSquare)
.map(_ -> Piece(fromProtoColor(sp.getPiece.getColor), fromProtoPieceType(sp.getPiece.getPieceType))),
)
.toMap, .toMap,
) )
def toProtoResultKind(r: Option[GameResult]): ProtoGameResultKind = r match override def toProtoResultKind(r: Option[GameResult]): ProtoGameResultKind = r match
case None => ProtoGameResultKind.ONGOING case None => ProtoGameResultKind.ONGOING
case Some(GameResult.Win(Color.White, WinReason.Checkmate)) => ProtoGameResultKind.WIN_CHECKMATE_W 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.Black, WinReason.Checkmate)) => ProtoGameResultKind.WIN_CHECKMATE_B
@@ -114,7 +97,7 @@ object IoProtoMapper:
case Some(GameResult.Draw(DrawReason.ThreefoldRepetition)) => ProtoGameResultKind.DRAW_THREEFOLD case Some(GameResult.Draw(DrawReason.ThreefoldRepetition)) => ProtoGameResultKind.DRAW_THREEFOLD
case Some(GameResult.Draw(DrawReason.Agreement)) => ProtoGameResultKind.DRAW_AGREEMENT case Some(GameResult.Draw(DrawReason.Agreement)) => ProtoGameResultKind.DRAW_AGREEMENT
def fromProtoResultKind(k: ProtoGameResultKind): Option[GameResult] = k match override def fromProtoResultKind(k: ProtoGameResultKind): Option[GameResult] = k match
case ProtoGameResultKind.ONGOING => None case ProtoGameResultKind.ONGOING => None
case ProtoGameResultKind.WIN_CHECKMATE_W => Some(GameResult.Win(Color.White, WinReason.Checkmate)) 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_CHECKMATE_B => Some(GameResult.Win(Color.Black, WinReason.Checkmate))
@@ -129,20 +112,24 @@ object IoProtoMapper:
case ProtoGameResultKind.DRAW_AGREEMENT => Some(GameResult.Draw(DrawReason.Agreement)) case ProtoGameResultKind.DRAW_AGREEMENT => Some(GameResult.Draw(DrawReason.Agreement))
case _ => None case _ => None
def toProtoGameContext(ctx: GameContext): ProtoGameContext = override def toProtoCastlingRights(cr: DomainCastlingRights): ProtoCastlingRights =
ProtoCastlingRights
.newBuilder()
.setWhiteKingSide(cr.whiteKingSide)
.setWhiteQueenSide(cr.whiteQueenSide)
.setBlackKingSide(cr.blackKingSide)
.setBlackQueenSide(cr.blackQueenSide)
.build()
override def fromProtoCastlingRights(pcr: ProtoCastlingRights): DomainCastlingRights =
DomainCastlingRights(pcr.getWhiteKingSide, pcr.getWhiteQueenSide, pcr.getBlackKingSide, pcr.getBlackQueenSide)
override def toProtoGameContext(ctx: GameContext): ProtoGameContext =
ProtoGameContext ProtoGameContext
.newBuilder() .newBuilder()
.addAllBoard(toProtoBoard(ctx.board)) .addAllBoard(toProtoBoard(ctx.board))
.setTurn(toProtoColor(ctx.turn)) .setTurn(toProtoColor(ctx.turn))
.setCastlingRights( .setCastlingRights(toProtoCastlingRights(ctx.castlingRights))
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("")) .setEnPassantSquare(ctx.enPassantSquare.map(_.toString).getOrElse(""))
.setHalfMoveClock(ctx.halfMoveClock) .setHalfMoveClock(ctx.halfMoveClock)
.addAllMoves(ctx.moves.map(toProtoMove).asJava) .addAllMoves(ctx.moves.map(toProtoMove).asJava)
@@ -150,13 +137,11 @@ object IoProtoMapper:
.addAllInitialBoard(toProtoBoard(ctx.initialBoard)) .addAllInitialBoard(toProtoBoard(ctx.initialBoard))
.build() .build()
def fromProtoGameContext(p: ProtoGameContext): GameContext = override def fromProtoGameContext(p: ProtoGameContext): GameContext =
val cr = p.getCastlingRights
GameContext( GameContext(
board = fromProtoBoard(p.getBoardList), board = fromProtoBoard(p.getBoardList),
turn = fromProtoColor(p.getTurn), turn = fromProtoColor(p.getTurn),
castlingRights = castlingRights = fromProtoCastlingRights(p.getCastlingRights),
DomainCastlingRights(cr.getWhiteKingSide, cr.getWhiteQueenSide, cr.getBlackKingSide, cr.getBlackQueenSide),
enPassantSquare = Option(p.getEnPassantSquare).filter(_.nonEmpty).flatMap(Square.fromAlgebraic), enPassantSquare = Option(p.getEnPassantSquare).filter(_.nonEmpty).flatMap(Square.fromAlgebraic),
halfMoveClock = p.getHalfMoveClock, halfMoveClock = p.getHalfMoveClock,
moves = p.getMovesList.asScala.flatMap(fromProtoMove).toList, moves = p.getMovesList.asScala.flatMap(fromProtoMove).toList,
@@ -9,4 +9,4 @@ quarkus:
nowchess: nowchess:
internal: internal:
secret: ${INTERNAL_SECRET} secret: 123abc
@@ -2,61 +2,42 @@ package de.nowchess.rules.grpc
import de.nowchess.api.board.{CastlingRights as DomainCastlingRights, *} import de.nowchess.api.board.{CastlingRights as DomainCastlingRights, *}
import de.nowchess.api.game.{DrawReason, GameContext, GameResult, WinReason} import de.nowchess.api.game.{DrawReason, GameContext, GameResult, WinReason}
import de.nowchess.api.move.{Move as DomainMove, MoveType, PromotionPiece} import de.nowchess.api.grpc.ProtoMapperBase
import de.nowchess.api.move.{Move as DomainMove, MoveType}
import de.nowchess.rules.proto.* import de.nowchess.rules.proto.*
import scala.jdk.CollectionConverters.* import scala.jdk.CollectionConverters.*
object ProtoMapper: object ProtoMapper extends ProtoMapperBase[ProtoColor, ProtoPieceType, ProtoMoveKind, ProtoMove, ProtoSquarePiece, java.util.List[ProtoSquarePiece], ProtoCastlingRights, ProtoGameResultKind, ProtoGameContext]:
private val (colorTo, colorFrom) = ProtoMapperBase.colorConversions(ProtoColor.WHITE, ProtoColor.BLACK)
private val (pieceTypeTo, pieceTypeFrom) = ProtoMapperBase.pieceTypeConversions(
ProtoPieceType.PAWN,
ProtoPieceType.KNIGHT,
ProtoPieceType.BISHOP,
ProtoPieceType.ROOK,
ProtoPieceType.QUEEN,
ProtoPieceType.KING,
)
private val (moveKindTo, moveKindFrom) = ProtoMapperBase.moveKindConversions(
ProtoMoveKind.QUIET,
ProtoMoveKind.CAPTURE,
ProtoMoveKind.CASTLE_KINGSIDE,
ProtoMoveKind.CASTLE_QUEENSIDE,
ProtoMoveKind.EN_PASSANT,
ProtoMoveKind.PROMO_QUEEN,
ProtoMoveKind.PROMO_ROOK,
ProtoMoveKind.PROMO_BISHOP,
ProtoMoveKind.PROMO_KNIGHT,
)
def toProtoColor(c: Color): ProtoColor = c match override def toProtoColor(c: Color): ProtoColor = colorTo(c)
case Color.White => ProtoColor.WHITE override def fromProtoColor(c: ProtoColor): Color = colorFrom(c)
case Color.Black => ProtoColor.BLACK override def toProtoPieceType(pt: PieceType): ProtoPieceType = pieceTypeTo(pt)
override def fromProtoPieceType(pt: ProtoPieceType): PieceType = pieceTypeFrom(pt)
override def toProtoMoveKind(mt: MoveType): ProtoMoveKind = moveKindTo(mt)
override def fromProtoMoveKind(k: ProtoMoveKind): MoveType = moveKindFrom(k)
def fromProtoColor(c: ProtoColor): Color = c match override def toProtoMove(m: DomainMove): ProtoMove =
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 ProtoMove
.newBuilder() .newBuilder()
.setFrom(m.from.toString) .setFrom(m.from.toString)
@@ -64,42 +45,44 @@ object ProtoMapper:
.setMoveKind(toProtoMoveKind(m.moveType)) .setMoveKind(toProtoMoveKind(m.moveType))
.build() .build()
def fromProtoMove(m: ProtoMove): Option[DomainMove] = override def fromProtoMove(m: ProtoMove): Option[DomainMove] =
for for
from <- Square.fromAlgebraic(m.getFrom) from <- Square.fromAlgebraic(m.getFrom)
to <- Square.fromAlgebraic(m.getTo) to <- Square.fromAlgebraic(m.getTo)
yield DomainMove(from, to, fromProtoMoveKind(m.getMoveKind)) yield DomainMove(from, to, fromProtoMoveKind(m.getMoveKind))
def toProtoBoard(board: Board): java.util.List[ProtoSquarePiece] = override def toProtoSquarePiece(sq: Square, piece: Piece): ProtoSquarePiece =
board.pieces ProtoSquarePiece
.map { (sq, piece) => .newBuilder()
ProtoSquarePiece .setSquare(sq.toString)
.setPiece(
ProtoPiece
.newBuilder() .newBuilder()
.setSquare(sq.toString) .setColor(toProtoColor(piece.color))
.setPiece( .setPieceType(toProtoPieceType(piece.pieceType))
ProtoPiece .build(),
.newBuilder() )
.setColor(toProtoColor(piece.color)) .build()
.setPieceType(toProtoPieceType(piece.pieceType))
.build(), override def fromProtoSquarePiece(sp: ProtoSquarePiece): Option[(Square, Piece)] =
) Square
.build() .fromAlgebraic(sp.getSquare)
} .map(_ -> Piece(fromProtoColor(sp.getPiece.getColor), fromProtoPieceType(sp.getPiece.getPieceType)))
override def toProtoBoard(board: Board): java.util.List[ProtoSquarePiece] =
board.pieces
.map { (sq, piece) => toProtoSquarePiece(sq, piece) }
.toSeq .toSeq
.asJava .asJava
def fromProtoBoard(pieces: java.util.List[ProtoSquarePiece]): Board = override def fromProtoBoard(pieces: java.util.List[ProtoSquarePiece]): Board =
Board( Board(
pieces.asScala pieces.asScala
.flatMap(sp => .flatMap(fromProtoSquarePiece)
Square
.fromAlgebraic(sp.getSquare)
.map(_ -> Piece(fromProtoColor(sp.getPiece.getColor), fromProtoPieceType(sp.getPiece.getPieceType))),
)
.toMap, .toMap,
) )
def toProtoResultKind(r: Option[GameResult]): ProtoGameResultKind = r match override def toProtoResultKind(r: Option[GameResult]): ProtoGameResultKind = r match
case None => ProtoGameResultKind.ONGOING case None => ProtoGameResultKind.ONGOING
case Some(GameResult.Win(Color.White, WinReason.Checkmate)) => ProtoGameResultKind.WIN_CHECKMATE_W 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.Black, WinReason.Checkmate)) => ProtoGameResultKind.WIN_CHECKMATE_B
@@ -113,7 +96,7 @@ object ProtoMapper:
case Some(GameResult.Draw(DrawReason.ThreefoldRepetition)) => ProtoGameResultKind.DRAW_THREEFOLD case Some(GameResult.Draw(DrawReason.ThreefoldRepetition)) => ProtoGameResultKind.DRAW_THREEFOLD
case Some(GameResult.Draw(DrawReason.Agreement)) => ProtoGameResultKind.DRAW_AGREEMENT case Some(GameResult.Draw(DrawReason.Agreement)) => ProtoGameResultKind.DRAW_AGREEMENT
def fromProtoResultKind(k: ProtoGameResultKind): Option[GameResult] = k match override def fromProtoResultKind(k: ProtoGameResultKind): Option[GameResult] = k match
case ProtoGameResultKind.ONGOING => None case ProtoGameResultKind.ONGOING => None
case ProtoGameResultKind.WIN_CHECKMATE_W => Some(GameResult.Win(Color.White, WinReason.Checkmate)) 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_CHECKMATE_B => Some(GameResult.Win(Color.Black, WinReason.Checkmate))
@@ -128,20 +111,24 @@ object ProtoMapper:
case ProtoGameResultKind.DRAW_AGREEMENT => Some(GameResult.Draw(DrawReason.Agreement)) case ProtoGameResultKind.DRAW_AGREEMENT => Some(GameResult.Draw(DrawReason.Agreement))
case _ => None case _ => None
def toProtoGameContext(ctx: GameContext): ProtoGameContext = override def toProtoCastlingRights(cr: DomainCastlingRights): ProtoCastlingRights =
ProtoCastlingRights
.newBuilder()
.setWhiteKingSide(cr.whiteKingSide)
.setWhiteQueenSide(cr.whiteQueenSide)
.setBlackKingSide(cr.blackKingSide)
.setBlackQueenSide(cr.blackQueenSide)
.build()
override def fromProtoCastlingRights(pcr: ProtoCastlingRights): DomainCastlingRights =
DomainCastlingRights(pcr.getWhiteKingSide, pcr.getWhiteQueenSide, pcr.getBlackKingSide, pcr.getBlackQueenSide)
override def toProtoGameContext(ctx: GameContext): ProtoGameContext =
ProtoGameContext ProtoGameContext
.newBuilder() .newBuilder()
.addAllBoard(toProtoBoard(ctx.board)) .addAllBoard(toProtoBoard(ctx.board))
.setTurn(toProtoColor(ctx.turn)) .setTurn(toProtoColor(ctx.turn))
.setCastlingRights( .setCastlingRights(toProtoCastlingRights(ctx.castlingRights))
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("")) .setEnPassantSquare(ctx.enPassantSquare.map(_.toString).getOrElse(""))
.setHalfMoveClock(ctx.halfMoveClock) .setHalfMoveClock(ctx.halfMoveClock)
.addAllMoves(ctx.moves.map(toProtoMove).asJava) .addAllMoves(ctx.moves.map(toProtoMove).asJava)
@@ -149,13 +136,11 @@ object ProtoMapper:
.addAllInitialBoard(toProtoBoard(ctx.initialBoard)) .addAllInitialBoard(toProtoBoard(ctx.initialBoard))
.build() .build()
def fromProtoGameContext(p: ProtoGameContext): GameContext = override def fromProtoGameContext(p: ProtoGameContext): GameContext =
val cr = p.getCastlingRights
GameContext( GameContext(
board = fromProtoBoard(p.getBoardList), board = fromProtoBoard(p.getBoardList),
turn = fromProtoColor(p.getTurn), turn = fromProtoColor(p.getTurn),
castlingRights = castlingRights = fromProtoCastlingRights(p.getCastlingRights),
DomainCastlingRights(cr.getWhiteKingSide, cr.getWhiteQueenSide, cr.getBlackKingSide, cr.getBlackQueenSide),
enPassantSquare = Option(p.getEnPassantSquare).filter(_.nonEmpty).flatMap(Square.fromAlgebraic), enPassantSquare = Option(p.getEnPassantSquare).filter(_.nonEmpty).flatMap(Square.fromAlgebraic),
halfMoveClock = p.getHalfMoveClock, halfMoveClock = p.getHalfMoveClock,
moves = p.getMovesList.asScala.flatMap(fromProtoMove).toList, moves = p.getMovesList.asScala.flatMap(fromProtoMove).toList,
@@ -12,7 +12,7 @@ class InternalGrpcSecretClientInterceptor extends ClientInterceptor:
private val secretKey = Metadata.Key.of("x-internal-secret", Metadata.ASCII_STRING_MARSHALLER) private val secretKey = Metadata.Key.of("x-internal-secret", Metadata.ASCII_STRING_MARSHALLER)
@ConfigProperty(name = "nowchess.internal.secret") @ConfigProperty(name = "nowchess.internal.secret", defaultValue = "")
// scalafix:off DisableSyntax.var // scalafix:off DisableSyntax.var
var secret: String = uninitialized var secret: String = uninitialized
// scalafix:on DisableSyntax.var // scalafix:on DisableSyntax.var
@@ -8,7 +8,7 @@ import scala.compiletime.uninitialized
@ApplicationScoped @ApplicationScoped
class InternalSecretClientFilter extends ClientRequestFilter: class InternalSecretClientFilter extends ClientRequestFilter:
@ConfigProperty(name = "nowchess.internal.secret") @ConfigProperty(name = "nowchess.internal.secret", defaultValue = "")
// scalafix:off DisableSyntax.var // scalafix:off DisableSyntax.var
var secret: String = uninitialized var secret: String = uninitialized
// scalafix:on DisableSyntax.var // scalafix:on DisableSyntax.var
+1
View File
@@ -31,6 +31,7 @@ val quarkusPlatformArtifactId: String by project
val quarkusPlatformVersion: String by project val quarkusPlatformVersion: String by project
dependencies { dependencies {
implementation(project(":modules:api"))
runtimeOnly("io.quarkus:quarkus-jdbc-h2") runtimeOnly("io.quarkus:quarkus-jdbc-h2")
@@ -1,7 +1,7 @@
package de.nowchess.store.config package de.nowchess.store.config
import de.nowchess.api.dto.{GameWritebackEventDto}
import de.nowchess.store.domain.GameRecord import de.nowchess.store.domain.GameRecord
import de.nowchess.store.redis.GameWritebackEventDto
import io.quarkus.runtime.annotations.RegisterForReflection import io.quarkus.runtime.annotations.RegisterForReflection
@RegisterForReflection( @RegisterForReflection(
@@ -86,6 +86,9 @@ class GameRecord extends PanacheEntityBase:
@Column @Column
var pendingDrawOffer: String = uninitialized var pendingDrawOffer: String = uninitialized
@Column
var pendingTakebackOffer: String = uninitialized
// Game result // Game result
@Column @Column
var result: String = uninitialized var result: String = uninitialized
@@ -1,26 +0,0 @@
package de.nowchess.store.redis
case class GameWritebackEventDto(
gameId: String,
fen: String,
pgn: String,
moveCount: Int,
whiteId: String,
whiteName: String,
blackId: String,
blackName: String,
mode: String,
resigned: Boolean,
limitSeconds: Option[Int],
incrementSeconds: Option[Int],
daysPerMove: Option[Int],
whiteRemainingMs: Option[Long],
blackRemainingMs: Option[Long],
incrementMs: Option[Long],
clockLastTickAt: Option[Long],
clockMoveDeadline: Option[Long],
clockActiveColor: Option[String],
pendingDrawOffer: Option[String],
result: Option[String] = None,
terminationReason: Option[String] = None,
)
@@ -1,6 +1,7 @@
package de.nowchess.store.redis package de.nowchess.store.redis
import com.fasterxml.jackson.databind.ObjectMapper import com.fasterxml.jackson.databind.ObjectMapper
import de.nowchess.api.dto.GameWritebackEventDto
import de.nowchess.store.service.GameWritebackService import de.nowchess.store.service.GameWritebackService
import io.quarkus.redis.datasource.RedisDataSource import io.quarkus.redis.datasource.RedisDataSource
import jakarta.annotation.PostConstruct import jakarta.annotation.PostConstruct
@@ -25,7 +25,7 @@ class GameRecordRepository:
def findByPlayerId(playerId: String, offset: Int, limit: Int): List[GameRecord] = def findByPlayerId(playerId: String, offset: Int, limit: Int): List[GameRecord] =
em.createQuery( em.createQuery(
"SELECT g FROM GameRecord g WHERE g.whiteId = :id OR g.blackId = :id ORDER BY g.updatedAt DESC", "SELECT g FROM GameRecord g WHERE g.whiteId = :id OR g.blackId = :id AND g.result != null ORDER BY g.updatedAt DESC",
classOf[GameRecord], classOf[GameRecord],
).setParameter("id", playerId) ).setParameter("id", playerId)
.setFirstResult(offset) .setFirstResult(offset)
@@ -1,11 +1,12 @@
package de.nowchess.store.service package de.nowchess.store.service
import de.nowchess.api.dto.GameWritebackEventDto
import de.nowchess.store.domain.GameRecord import de.nowchess.store.domain.GameRecord
import de.nowchess.store.redis.GameWritebackEventDto
import de.nowchess.store.repository.GameRecordRepository import de.nowchess.store.repository.GameRecordRepository
import jakarta.enterprise.context.ApplicationScoped import jakarta.enterprise.context.ApplicationScoped
import jakarta.inject.Inject import jakarta.inject.Inject
import jakarta.transaction.Transactional import jakarta.transaction.Transactional
import scala.compiletime.uninitialized import scala.compiletime.uninitialized
import java.time.Instant import java.time.Instant
@@ -66,6 +67,7 @@ class GameWritebackService:
r.clockMoveDeadline = event.clockMoveDeadline.map(java.lang.Long.valueOf).orNull r.clockMoveDeadline = event.clockMoveDeadline.map(java.lang.Long.valueOf).orNull
r.clockActiveColor = event.clockActiveColor.orNull r.clockActiveColor = event.clockActiveColor.orNull
r.pendingDrawOffer = event.pendingDrawOffer.orNull r.pendingDrawOffer = event.pendingDrawOffer.orNull
r.pendingTakebackOffer = event.pendingTakebackRequest.orNull
r.result = event.result.orNull r.result = event.result.orNull
r.terminationReason = event.terminationReason.orNull r.terminationReason = event.terminationReason.orNull
r.updatedAt = Instant.now() r.updatedAt = Instant.now()