diff --git a/schach/src/main/java/de/hs_mannheim/informatik/chess/controller/GameController.java b/schach/src/main/java/de/hs_mannheim/informatik/chess/controller/GameController.java index c0b4d56..5641c2a 100644 --- a/schach/src/main/java/de/hs_mannheim/informatik/chess/controller/GameController.java +++ b/schach/src/main/java/de/hs_mannheim/informatik/chess/controller/GameController.java @@ -8,6 +8,8 @@ import java.util.List; import javax.swing.BorderFactory; +import com.github.bhlangonijr.chesslib.game.Game; + import de.hs_mannheim.informatik.chess.model.ChessEngine; import de.hs_mannheim.informatik.chess.model.MoveDTO; import de.hs_mannheim.informatik.chess.model.PieceDTO; @@ -68,6 +70,25 @@ public class GameController { engine.setPositionToMoveIndex(engine.getMoveListSize()); updateGuiBoard(); }); + + gui.getBtnSave().addActionListener(e -> { + System.out.println("Save-Button wurde geklickt!"); + Game currentGame = engine.getCurrentGame(); + javax.swing.JFileChooser fileChooser = new javax.swing.JFileChooser(); + fileChooser.setDialogTitle("PGN speichern unter..."); + int userSelection = fileChooser.showSaveDialog(null); + + if (userSelection == javax.swing.JFileChooser.APPROVE_OPTION) { + java.io.File fileToSave = fileChooser.getSelectedFile(); + try { + engine.saveAsPgn(currentGame, fileToSave.getParent(), fileToSave.getName()); + gui.displayMessage("PGN gespeichert: " + fileToSave.getAbsolutePath()); + } catch (Exception ex) { + gui.displayMessage("Fehler beim Speichern: " + ex.getMessage()); + } + } + }); + gui.getFlipBoardButton().addActionListener(e -> { diff --git a/schach/src/main/java/de/hs_mannheim/informatik/chess/model/ChessEngine.java b/schach/src/main/java/de/hs_mannheim/informatik/chess/model/ChessEngine.java index 1b9fb78..5ca97cf 100644 --- a/schach/src/main/java/de/hs_mannheim/informatik/chess/model/ChessEngine.java +++ b/schach/src/main/java/de/hs_mannheim/informatik/chess/model/ChessEngine.java @@ -14,9 +14,13 @@ import java.util.logging.SimpleFormatter; import com.github.bhlangonijr.chesslib.Board; import com.github.bhlangonijr.chesslib.Piece; import com.github.bhlangonijr.chesslib.Square; -import com.github.bhlangonijr.chesslib.game.Game; import com.github.bhlangonijr.chesslib.move.Move; import com.github.bhlangonijr.chesslib.pgn.PgnHolder; +import com.github.bhlangonijr.chesslib.game.*; +import com.github.bhlangonijr.chesslib.move.MoveList; +import java.time.LocalDate; +import com.github.bhlangonijr.chesslib.Side; + public class ChessEngine { private Board board; @@ -242,14 +246,17 @@ public class ChessEngine { } public void saveAsPgn(Game game, String path, String dateiname) { - String event = game.getRound().getEvent().getName(); - String site = game.getRound().getEvent().getSite(); + // Sicher alle Strings holen (nie null) + String event = safe(game.getRound().getEvent().getName()); + String site = safe(game.getRound().getEvent().getSite()); String round = "" + game.getRound().getNumber(); - String date = game.getRound().getEvent().getStartDate(); - String wName = game.getWhitePlayer().getName(); - String bName = game.getBlackPlayer().getName(); - String result = game.getResult().getDescription(); + // Datum für PGN-Format (YYYY.MM.DD) + String date = safe(game.getRound().getEvent().getStartDate()).replace("-", "."); + String wName = safe(game.getWhitePlayer().getName()); + String bName = safe(game.getBlackPlayer().getName()); + String result = safe(game.getResult().getDescription()); + // PGN-Header zusammenbauen StringBuilder header = new StringBuilder(); header.append("[Event \"" + event + "\"]\n"); header.append("[Site \"" + site + "\"]\n"); @@ -257,29 +264,90 @@ public class ChessEngine { header.append("[Round \"" + round + "\"]\n"); header.append("[White \"" + wName + "\"]\n"); header.append("[Black \"" + bName + "\"]\n"); - header.append("[Result \"" + result + "\"]\n"); - header.append("\n"); + header.append("[Result \"" + result + "\"]\n\n"); - StringBuilder sb = new StringBuilder(); + // Züge als SAN holen + StringBuilder moves = new StringBuilder(); String[] sanArray = game.getHalfMoves().toSanArray(); for (int i = 0; i < sanArray.length; i++) { if (i % 2 == 0) { - sb.append((i / 2 + 1)).append(". "); + moves.append((i / 2 + 1)).append(". "); } - sb.append(sanArray[i]).append(" "); + moves.append(sanArray[i]).append(" "); + // Optional: Zeilenumbruch für Lesbarkeit + // if (i > 0 && i % 8 == 0) moves.append("\n"); } + moves.append(result); // Ergebnis am Ende! - sb.append(result); // Endergebnis muss auch am Ende stehen! - - String file = header.toString() + sb.toString(); + String file = header + moves.toString(); + // Datei schreiben try { Files.writeString(Path.of(path, dateiname), file, StandardCharsets.UTF_8); } catch (IOException e) { e.printStackTrace(); } } + + // Hilfsfunktion für Null-Sicherheit + private String safe(String s) { + return s == null ? "?" : s; + } + + public Game getCurrentGame() { + return getCurrentGame(this.board, this.moves, this.currentMoveIndex); + } + + public Game getCurrentGame(Board board, java.util.List moves, int currentMoveIndex) { + // Event und Turnierdaten setzen + Event event = new Event(); + event.setName("Generated Game"); + event.setSite("Local"); + event.setStartDate(LocalDate.now().toString()); // Format: yyyy-MM-dd + + // Runde anlegen + Round round = new Round(event); + round.setNumber(1); + + // Spiel initialisieren + Game game = new Game("1", round); // "1" ist die Game-ID + + // Spieler setzen (deine MyPlayer-Klasse) + game.setWhitePlayer(new MyPlayer("White")); + game.setBlackPlayer(new MyPlayer("Black")); + + // Ergebnis setzen + if (board.isMated()) { + game.setResult(board.getSideToMove() == Side.WHITE ? GameResult.BLACK_WON : GameResult.WHITE_WON); + } else if (board.isStaleMate() || board.isDraw()) { + game.setResult(GameResult.DRAW); + } else { + game.setResult(GameResult.ONGOING); + } + + // Züge übernehmen + MoveList moveList = new MoveList(); + for (Move move : moves) { + moveList.add(move); + } + game.setHalfMoves(moveList); + + // Position auf aktuellen Zug setzen (letzter gespielter Halbzug) + if (currentMoveIndex > 0 && currentMoveIndex <= moveList.size()) { + game.setPosition(currentMoveIndex - 1); + } else { + game.setPosition(moveList.size() - 1); + } + + // FEN setzen: JETZT das aktuelle Board-FEN verwenden! + game.setBoard(new Board()); + game.getBoard().loadFromFen(board.getFen()); + + return game; + } + + public void loadMoves(List moveList) { board = new Board(); // Neues leeres Brett diff --git a/schach/src/main/java/de/hs_mannheim/informatik/chess/view/GameGui.java b/schach/src/main/java/de/hs_mannheim/informatik/chess/view/GameGui.java index 5d9dac3..e418b51 100644 --- a/schach/src/main/java/de/hs_mannheim/informatik/chess/view/GameGui.java +++ b/schach/src/main/java/de/hs_mannheim/informatik/chess/view/GameGui.java @@ -32,6 +32,7 @@ public class GameGui { JButton btnPrev = new JButton("<"); JButton btnNext = new JButton(">"); JButton btnLast = new JButton(">|"); + JButton btnSave = new JButton("SavePgn"); Color LIGHT = new Color(0xe0e1dd); Color DARK = new Color(0x778da9); @@ -179,12 +180,14 @@ public class GameGui { btnPrev.setBackground(new Color(0x212529)); btnPrev.setForeground(Color.WHITE); btnNext.setBackground(new Color(0x212529)); btnNext.setForeground(Color.WHITE); btnLast.setBackground(new Color(0x212529)); btnLast.setForeground(Color.WHITE); + btnLast.setBackground(new Color(0x212529)); btnSave.setForeground(Color.WHITE); // Hinzufügen buttonPanel.add(btnFirst); buttonPanel.add(btnPrev); buttonPanel.add(btnNext); buttonPanel.add(btnLast); + buttonPanel.add(btnSave); // Unten ins BorderLayout statsPanel.add(buttonPanel, BorderLayout.SOUTH); @@ -243,6 +246,7 @@ public class GameGui { public JButton getBtnPrev() { return btnPrev; } public JButton getBtnNext() { return btnNext; } public JButton getBtnLast() { return btnLast; } + public JButton getBtnSave() { return btnSave; } public void updateBoard(BoardDTO boardDTO) { PieceDTO[][] board = boardDTO.getBoard();