From ae07b4d719050d60669f78735c80a6f588832850 Mon Sep 17 00:00:00 2001 From: Justin Date: Tue, 24 Jun 2025 00:50:32 +0200 Subject: [PATCH] Added undoMove feature and fixed replay issue --- .../chess/controller/GameController.java | 39 ++++++++++++++++++- .../informatik/chess/model/ChessEngine.java | 26 ++++++++++++- .../informatik/chess/view/GameGui.java | 18 ++++++++- 3 files changed, 80 insertions(+), 3 deletions(-) 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 b20b1ed..c42bc2d 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 @@ -125,7 +125,7 @@ public class GameController { // --- AUFGEBEN-BUTTON --- gui.getResignButton().addActionListener(e -> { - if (gameOver) return; // Nichts tun wenn Spiel vorbei + if (gameOver) return; int answer = javax.swing.JOptionPane.showConfirmDialog( null, @@ -161,14 +161,50 @@ public class GameController { askForRestart(); } }); + + gui.getUndoButton().addActionListener(e -> { + // Wer ist am Zug? (Das ist der, der gefragt wird) + String currentPlayer = engine.getCurrentPlayer(); // "WHITE" oder "BLACK" + // Wer möchte zurücknehmen? (Das ist der, der NICHT am Zug ist) + String currentName = currentPlayer.equals("WHITE") ? "Weiß" : "Schwarz"; + String previousName = currentPlayer.equals("WHITE") ? "Schwarz" : "Weiß"; + + int answer = javax.swing.JOptionPane.showConfirmDialog( + null, + currentName + " ist am Zug. " + + previousName + " möchte seinen letzten Zug zurücknehmen.\n" + + currentName + ", erlaubst du das?", + "Zug zurücknehmen?", + javax.swing.JOptionPane.YES_NO_OPTION + ); + + if (answer == javax.swing.JOptionPane.YES_OPTION) { + engine.undoLastMove(); + updateGuiBoard(); + gui.updateMoveList(engine.getMoveListStringsGrouped()); + gui.setOpeningLabel(engine.getOpeningName()); + gui.displayMessage("Der letzte Zug wurde zurückgenommen."); + } else if (answer == javax.swing.JOptionPane.NO_OPTION) { + gui.displayMessage("Das Zurücknehmen wurde abgelehnt."); + } + }); } + private boolean isAtLatestMove() { + return engine.getCurrentMoveIndex() == engine.getMoveListSize(); + } + private void handleClick(int guiRow, int guiCol) { if (gameOver) return; + if (!isAtLatestMove()) { + gui.displayMessage("Du bist im Zug-Archiv und kannst keine Figuren bewegen. Klick auf '>|', um zum letzten Zug zu gehen."); + return; + } + int modelRow = flipRow(guiRow); int modelCol = flipCol(guiCol); @@ -265,6 +301,7 @@ public class GameController { public void updateGuiBoard() { BoardDTO board = engine.getBoardAsDTO(); gui.updateBoard(board); + gui.setOpeningLabel(engine.getOpeningName()); } private void switchTimers() { 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 d4d6a10..cc3de40 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 @@ -31,6 +31,8 @@ public class ChessEngine { private Timer whiteTimer; private Timer blackTimer; + private Opening detectedOpening = null; + public ChessEngine() { logging(); board = new Board(); @@ -53,7 +55,7 @@ public class ChessEngine { // Opening-Erkennung nach jedem erfolgreichen Zug String playedMovesUci = movesToUciString(moves); - Opening detectedOpening = Opening.detect(playedMovesUci); + detectedOpening = Opening.detect(playedMovesUci); if (detectedOpening != null) { logger.info("Aktuelles Opening erkannt: " + detectedOpening.getEco() + " - " + detectedOpening.getName()); @@ -65,6 +67,13 @@ public class ChessEngine { return false; } + public String getOpeningName() { + if (detectedOpening != null) { + return detectedOpening.getEco() + " - " + detectedOpening.getName(); + } else { + return "unbekannt"; + } + } private String movesToUciString(List moves) { StringBuilder sb = new StringBuilder(); @@ -186,6 +195,9 @@ public class ChessEngine { board.doMove(moves.get(i)); } currentMoveIndex = idx; + + String playedMovesUci = movesToUciString(moves.subList(0, idx)); + detectedOpening = Opening.detect(playedMovesUci); } public int getCurrentMoveIndex() { @@ -372,6 +384,18 @@ public class ChessEngine { } + public void undoLastMove() { + if (currentMoveIndex > 0 && moves.size() > 0) { + board.undoMove(); // 1. Brett zurücksetzen + moves.remove(currentMoveIndex - 1); // 2. Zug aus Move-Liste löschen + currentMoveIndex--; // 3. Index anpassen + + // 4. Erkennung Opening neu machen! + String playedMovesUci = movesToUciString(moves.subList(0, currentMoveIndex)); + detectedOpening = Opening.detect(playedMovesUci); + } + } + 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 c915414..6c6f39d 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 @@ -44,6 +44,7 @@ public class GameGui { private JButton resignButton; private JButton drawButton; private JButton quickSaveButton; + private JButton undoButton; Color LIGHT = new Color(0xe0e1dd); Color DARK = new Color(0x778da9); @@ -194,7 +195,15 @@ public class GameGui { flipBoardButton.setBackground(new Color(0x5500ff)); flipBoardButton.setForeground(Color.WHITE); flipBoardButton.setFocusPainted(false); - + + undoButton = new JButton("↧"); + undoButton.setPreferredSize(new Dimension(70, 70)); + undoButton.setFont(new Font("SansSerif", Font.BOLD, 40)); + undoButton.setBackground(new Color(0xffa500)); // Orange + undoButton.setForeground(Color.WHITE); + undoButton.setFocusPainted(false); + + buttonRow.add(undoButton); buttonRow.add(resignButton); buttonRow.add(drawButton); buttonRow.add(flipBoardButton); @@ -356,6 +365,13 @@ public class GameGui { public JLabel getWhiteTimerLabel() { return whiteTimerLabel; } public JLabel getBlackTimerLabel() { return blackTimerLabel; } + public void setOpeningLabel(String text) { + openingLabel.setText("Eröffnung: " + text); + } + + public JButton getUndoButton() { + return undoButton; + } public void displayMessage(String msg) { JOptionPane.showMessageDialog(null, msg);