feat: I/O json export import, tests should be 100%
Build & Test (NowChessSystems) TeamCity build finished

This commit is contained in:
shahdlala66
2026-04-06 21:57:09 +02:00
parent 638139602c
commit 33c0260b75
11 changed files with 1003 additions and 1 deletions
+41
View File
@@ -0,0 +1,41 @@
{
"metadata": {
"event": "Game",
"players": {
"white": "White Player",
"black": "Black Player"
},
"date": "2026-04-06",
"result": "*"
},
"gameState": {
"board": [{"square": "g8", "color": "Black", "piece": "Knight"}, {"square": "d8", "color": "Black", "piece": "Queen"}, {"square": "f8", "color": "Black", "piece": "Bishop"}, {"square": "b2", "color": "White", "piece": "Pawn"}, {"square": "c1", "color": "White", "piece": "Bishop"}, {"square": "c7", "color": "Black", "piece": "Pawn"}, {"square": "f7", "color": "Black", "piece": "Pawn"}, {"square": "b7", "color": "Black", "piece": "Pawn"}, {"square": "b1", "color": "White", "piece": "Knight"}, {"square": "h8", "color": "Black", "piece": "Rook"}, {"square": "a1", "color": "White", "piece": "Rook"}, {"square": "g2", "color": "White", "piece": "Pawn"}, {"square": "e1", "color": "White", "piece": "King"}, {"square": "c2", "color": "White", "piece": "Pawn"}, {"square": "h2", "color": "White", "piece": "Pawn"}, {"square": "a8", "color": "Black", "piece": "Rook"}, {"square": "f1", "color": "White", "piece": "Bishop"}, {"square": "d6", "color": "Black", "piece": "Pawn"}, {"square": "a2", "color": "White", "piece": "Pawn"}, {"square": "d1", "color": "White", "piece": "Queen"}, {"square": "e2", "color": "White", "piece": "Pawn"}, {"square": "c8", "color": "Black", "piece": "Bishop"}, {"square": "a7", "color": "Black", "piece": "Pawn"}, {"square": "b8", "color": "Black", "piece": "Knight"}, {"square": "d2", "color": "White", "piece": "Pawn"}, {"square": "e8", "color": "Black", "piece": "King"}, {"square": "f4", "color": "White", "piece": "Pawn"}, {"square": "g7", "color": "Black", "piece": "Pawn"}, {"square": "h7", "color": "Black", "piece": "Pawn"}, {"square": "e7", "color": "Black", "piece": "Pawn"}, {"square": "h1", "color": "White", "piece": "Rook"}, {"square": "g1", "color": "White", "piece": "Knight"}],
"turn": "White",
"castlingRights": {
"whiteKingSide": true,
"whiteQueenSide": true,
"blackKingSide": true,
"blackQueenSide": true
},
"enPassantSquare": null,
"halfMoveClock": 0
},
"moveHistory": "[Event \"?\"]\n[White \"?\"]\n[Black \"?\"]\n[Result \"*\"]\n\n1. f4 d6 *",
"moves": [
{
"from": "f2",
"to": "f4",
"type": {"type": "normal", "isCapture": false}
},
{
"from": "d7",
"to": "d6",
"type": {"type": "normal", "isCapture": false}
}
],
"capturedPieces": {
"byWhite": ["Pawn"],
"byBlack": ["Pawn"]
},
"timestamp": "2026-04-06T11:39:00.746137480Z[UTC]"
}
@@ -16,7 +16,11 @@ import de.nowchess.chess.command.{MoveCommand, MoveResult}
import de.nowchess.chess.engine.GameEngine
import de.nowchess.io.fen.{FenExporter, FenParser}
import de.nowchess.io.pgn.{PgnExporter, PgnParser}
import de.nowchess.io.{GameContextExport, GameContextImport}
import de.nowchess.io.json.{JsonExporter, JsonParser}
import de.nowchess.io.{GameContextExport, GameContextImport, GameFileService, FileSystemGameService}
import java.nio.file.Paths
import scalafx.stage.FileChooser
import scalafx.stage.FileChooser.ExtensionFilter
/** ScalaFX chess board view that displays the game state.
* Uses chess sprites and color palette.
@@ -124,6 +128,22 @@ class ChessBoardView(val stage: Stage, private val engine: GameEngine) extends B
style = "-fx-background-radius: 8; -fx-background-color: #B9DAC4;"
}
)
},
new HBox {
spacing = 10
alignment = Pos.Center
children = Seq(
new Button("JSON Export") {
font = Font.font(comicSansFontFamily, 12)
onAction = _ => doJsonExport()
style = "-fx-background-radius: 8; -fx-background-color: #B9C4DA;"
},
new Button("JSON Import") {
font = Font.font(comicSansFontFamily, 12)
onAction = _ => doJsonImport()
style = "-fx-background-radius: 8; -fx-background-color: #C4B9DA;"
}
)
}
)
}
@@ -289,6 +309,45 @@ class ChessBoardView(val stage: Stage, private val engine: GameEngine) extends B
private def doPgnImport(): Unit =
doImport(PgnParser, "PGN")
private def doJsonExport(): Unit =
val fileChooser = new FileChooser {
title = "Export Game as JSON"
initialFileName = "chess_game.json"
extensionFilters.add(new ExtensionFilter("JSON files (*.json)", "*.json"))
extensionFilters.add(new ExtensionFilter("All files", "*.*"))
}
val selectedFile = fileChooser.showSaveDialog(stage)
if selectedFile != null then
val result = FileSystemGameService.saveGameToFile(
engine.context,
selectedFile.toPath,
JsonExporter
)
result match
case Right(_) => showMessage(s"✓ Game saved to: ${selectedFile.getName}")
case Left(err) => showMessage(s"⚠️ Error saving file: $err")
private def doJsonImport(): Unit =
val fileChooser = new FileChooser {
title = "Import Game from JSON"
extensionFilters.add(new ExtensionFilter("JSON files (*.json)", "*.json"))
extensionFilters.add(new ExtensionFilter("All files", "*.*"))
}
val selectedFile = fileChooser.showOpenDialog(stage)
if selectedFile != null then
val result = FileSystemGameService.loadGameFromFile(
selectedFile.toPath,
JsonParser
)
result match
case Right(gameContext) =>
engine.loadPosition(gameContext)
showMessage(s"✓ Game loaded from: ${selectedFile.getName}")
case Left(err) =>
showMessage(s"⚠️ Error: $err")
private def doExport(exporter: GameContextExport, formatName: String): Unit = {
val exported = exporter.exportGameContext(engine.context)
showCopyDialog(s"$formatName Export", exported)