From eb30f5cd13be8d1c16c0aceb11e76208b959f367 Mon Sep 17 00:00:00 2001 From: Vickvick2002 Date: Sun, 5 Jan 2025 15:18:52 +0100 Subject: [PATCH] =?UTF-8?q?=C3=84nderungen=20f=C3=BCr=20Redo=20und=20Undo?= =?UTF-8?q?=20Button=20vorgenommen?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../PR2/HitoriSpiel/Domain/StateManager.java | 64 +++++++-- .../java/PR2/HitoriSpiel/GUI/GameBoard.java | 132 +++++++++--------- .../main/java/PR2/HitoriSpiel/Main/Main.java | 34 +++-- 3 files changed, 142 insertions(+), 88 deletions(-) diff --git a/Hitori/src/main/java/PR2/HitoriSpiel/Domain/StateManager.java b/Hitori/src/main/java/PR2/HitoriSpiel/Domain/StateManager.java index 2705a93..ab4fe1c 100644 --- a/Hitori/src/main/java/PR2/HitoriSpiel/Domain/StateManager.java +++ b/Hitori/src/main/java/PR2/HitoriSpiel/Domain/StateManager.java @@ -1,37 +1,77 @@ package PR2.HitoriSpiel.Domain; +import java.io.*; import java.util.Stack; -public class StateManager { +public class StateManager implements Serializable { private final Stack undoStack = new Stack<>(); private final Stack redoStack = new Stack<>(); public void saveState(int[][] state) { - undoStack.push(copyArray(state)); + undoStack.push(copyState(state)); redoStack.clear(); // Redo-Stack leeren, da ein neuer Zustand hinzugefügt wurde } + // Macht die letzte Änderung rückgängig public int[][] undo(int[][] currentState) { if (!undoStack.isEmpty()) { - redoStack.push(copyArray(currentState)); // Aktuellen Zustand im Redo-Stack speichern - return undoStack.pop(); + redoStack.push(copyState(currentState)); // Speichere aktuellen Zustand für Redo + return undoStack.pop(); // Gib den vorherigen Zustand zurück } - return null; // Kein Zustand zum Zurücksetzen + return null; // Kein Zustand mehr verfügbar } + // Wiederholt die letzte rückgängig gemachte Änderung public int[][] redo(int[][] currentState) { if (!redoStack.isEmpty()) { - undoStack.push(copyArray(currentState)); // Aktuellen Zustand im Undo-Stack speichern - return redoStack.pop(); + undoStack.push(copyState(currentState)); // Speichere aktuellen Zustand für Undo + return redoStack.pop(); // Gib den Redo-Zustand zurück } - return null; // Kein Zustand zum Wiederherstellen + return null; // Kein Zustand verfügbar } - private int[][] copyArray(int[][] original) { - int[][] copy = new int[original.length][]; - for (int i = 0; i < original.length; i++) { - copy[i] = original[i].clone(); + // Hilfsmethode, um eine Kopie des Zustands zu erstellen + private int[][] copyState(int[][] state) { + int[][] copy = new int[state.length][state[0].length]; + for (int i = 0; i < state.length; i++) { + System.arraycopy(state[i], 0, copy[i], 0, state[i].length); } return copy; } + + // Speichert die gesamte StateManager-Instanz in einer Datei + public void saveStateToFile() { + try (ObjectOutputStream out = new ObjectOutputStream(new FileOutputStream("undoRedoState.dat"))) { + out.writeObject(undoStack); // Schreibe den Undo-Stack + out.writeObject(redoStack); // Schreibe den Redo-Stack + System.out.println("Zustände wurden erfolgreich gespeichert."); + } catch (IOException e) { + System.err.println("Fehler beim Speichern der Zustände: " + e.getMessage()); + } + } + + // Lädt den StateManager aus einer Datei + public static StateManager loadStateFromFile() { + try (ObjectInputStream in = new ObjectInputStream(new FileInputStream("undoRedoState.dat"))) { + StateManager stateManager = new StateManager(); + stateManager.undoStack.addAll((Stack) in.readObject()); + stateManager.redoStack.addAll((Stack) in.readObject()); + System.out.println("Zustände wurden erfolgreich geladen."); + return stateManager; + } catch (IOException | ClassNotFoundException e) { + System.err.println("Fehler beim Laden der Zustände: " + e.getMessage()); + return new StateManager(); // Gibt eine neue Instanz zurück, falls ein Fehler auftritt + } + } + + // Überprüft, ob Undo-Operationen verfügbar sind + public boolean canUndo() { + return !undoStack.isEmpty(); + } + + // Überprüft, ob Redo-Operationen verfügbar sind + public boolean canRedo() { + return !redoStack.isEmpty(); + + } } diff --git a/Hitori/src/main/java/PR2/HitoriSpiel/GUI/GameBoard.java b/Hitori/src/main/java/PR2/HitoriSpiel/GUI/GameBoard.java index 6f395c7..0d104ba 100644 --- a/Hitori/src/main/java/PR2/HitoriSpiel/GUI/GameBoard.java +++ b/Hitori/src/main/java/PR2/HitoriSpiel/GUI/GameBoard.java @@ -17,6 +17,7 @@ public class GameBoard extends JPanel { private Timer timer; private long startTime; private JLabel timerLabel; + private JPanel gamePanel; // Das Spielfeld als JPanel private final StateManager stateManager = new StateManager(); @@ -34,14 +35,7 @@ public class GameBoard extends JPanel { startTimer(); // Spielfeld erstellen - JPanel gamePanel = new JPanel(new GridLayout(board.getSize(), board.getSize())); - for (int i = 0; i < board.getSize(); i++) { - for (int j = 0; j < board.getSize(); j++) { - HitoriCell cell = board.getCell(i, j); - JButton button = createCellButton(cell, i, j); - gamePanel.add(button); - } - } + gamePanel = createGamePanel(); add(gamePanel, BorderLayout.CENTER); // Kontroll-Buttons unten hinzufügen @@ -71,7 +65,7 @@ public class GameBoard extends JPanel { resetButton.addActionListener(e -> { saveStateForUndo(); resetBoard(); - refreshBoard(); + //refreshBoard(); }); JButton undoButton = Setup.createGameBoardButton("Undo", 80, 30); @@ -79,7 +73,7 @@ public class GameBoard extends JPanel { int[][] previousState = stateManager.undo(board.getNumbers()); if (previousState != null) { board.setNumbers(previousState); - refreshBoard(); + updateBoard(); } else { JOptionPane.showMessageDialog(this, "Kein Zustand zum Zurücksetzen vorhanden.", "Undo", JOptionPane.INFORMATION_MESSAGE); } @@ -112,7 +106,6 @@ public class GameBoard extends JPanel { showPauseMenu(); }); - controlPanel.add(resetButton); controlPanel.add(undoButton); controlPanel.add(redoButton); @@ -122,35 +115,6 @@ public class GameBoard extends JPanel { return controlPanel; } - public void resetBoard() { - // Spiellogik zurücksetzen - board.resetBoard(); - - // Spielfeld (CENTER) entfernen und neu erstellen - if (getLayout() instanceof BorderLayout) { - BorderLayout layout = (BorderLayout) getLayout(); - - // Komponente im CENTER entfernen - Component centerComponent = layout.getLayoutComponent(BorderLayout.CENTER); - if (centerComponent != null) { - remove(centerComponent); - } - - // Neues Spielfeld hinzufügen - add(createGamePanel(), BorderLayout.CENTER); - - // Kontroll-Buttons (SOUTH) entfernen und neu hinzufügen - Component southComponent = layout.getLayoutComponent(BorderLayout.SOUTH); - if (southComponent != null) { - remove(southComponent); - } - add(createControlPanel(), BorderLayout.SOUTH); - } - - // Oberfläche aktualisieren - revalidate(); - repaint(); - } public boolean validateCurrentBoard() { HitoriValidator validator = new HitoriValidator(board); @@ -178,12 +142,10 @@ public class GameBoard extends JPanel { } private void toggleCellState(HitoriCell cell) { - if (cell == null) { System.err.println("Ungültige Zelle! Der Zustand kann nicht geändert werden."); return; } - if (cell.getState() == HitoriCell.CellState.GRAY) { cell.setState(HitoriCell.CellState.BLACK); } else if (cell.getState() == HitoriCell.CellState.BLACK) { @@ -211,22 +173,8 @@ public class GameBoard extends JPanel { } } - private void saveGame() { - try { - FileWriter writer = new FileWriter("hitori_savegame.txt"); - writer.write("Spielzeit: " + (System.currentTimeMillis() - startTime) / 1000 + " Sekunden\n"); - writer.write("Spielfeldzustand:\n"); - for (int i = 0; i < board.getSize(); i++) { - for (int j = 0; j < board.getSize(); j++) { - writer.write(board.getCell(i, j).getState().name() + " "); - } - writer.write("\n"); - } - writer.close(); - JOptionPane.showMessageDialog(this, "Spiel erfolgreich gespeichert."); - } catch (IOException ex) { - JOptionPane.showMessageDialog(this, "Fehler beim Speichern des Spiels: " + ex.getMessage(), "Fehler", JOptionPane.ERROR_MESSAGE); - } + private void saveStateForUndo() { + stateManager.saveState(board.getNumbers()); } private void addHighscore() { @@ -280,22 +228,60 @@ public class GameBoard extends JPanel { } } - private JButton createButton(String text, int width, int height) { - JButton button = new JButton(text); - button.setPreferredSize(new Dimension(width, height)); - return button; - } + public void resetBoard() { + // Spiellogik zurücksetzen + board.resetBoard(); + // Spielfeld (CENTER) entfernen und neu erstellen + if (getLayout() instanceof BorderLayout) { + BorderLayout layout = (BorderLayout) getLayout(); - private void refreshBoard() { - remove(1); // Entferne das aktuelle Spielfeld im CENTER - add(createGamePanel(), BorderLayout.CENTER); // Füge das neue Spielfeld hinzu + // Komponente im CENTER entfernen + Component centerComponent = layout.getLayoutComponent(BorderLayout.CENTER); + if (centerComponent != null) { + remove(centerComponent); + } + // Neues Spielfeld hinzufügen + add(createGamePanel(), BorderLayout.CENTER); + + // Kontroll-Buttons (SOUTH) entfernen und neu hinzufügen + Component southComponent = layout.getLayoutComponent(BorderLayout.SOUTH); + if (southComponent != null) { + remove(southComponent); + } + add(createControlPanel(), BorderLayout.SOUTH); + } + + // Oberfläche aktualisieren revalidate(); repaint(); } - private void saveStateForUndo() { - stateManager.saveState(board.getNumbers()); + private void refreshBoard() { + remove(1); // Entferne das aktuelle Spielfeld im CENTER + if (getLayout() instanceof BorderLayout) { + BorderLayout layout = (BorderLayout) getLayout(); + + // Komponente im CENTER entfernen + Component centerComponent = layout.getLayoutComponent(BorderLayout.CENTER); + if (centerComponent != null) { + remove(centerComponent); + } + + // Neues Spielfeld hinzufügen + add(createGamePanel(), BorderLayout.CENTER); + + // Kontroll-Buttons (SOUTH) entfernen und neu hinzufügen + Component southComponent = layout.getLayoutComponent(BorderLayout.SOUTH); + if (southComponent != null) { + remove(southComponent); + } + add(createControlPanel(), BorderLayout.SOUTH); + } + + // Oberfläche aktualisieren + revalidate(); + repaint(); } private JPanel createGamePanel() { @@ -311,4 +297,14 @@ public class GameBoard extends JPanel { return gamePanel; } + private void updateBoard() { + for (int i = 0; i < board.getSize(); i++) { + for (int j = 0; j < board.getSize(); j++) { + HitoriCell cell = board.getCell(i, j); + JButton button = (JButton) gamePanel.getComponent(i * board.getSize() + j); // Hole den Button + updateButtonState(button, cell); // Aktualisiere den Button basierend auf dem Zustand + } + } + } + } diff --git a/Hitori/src/main/java/PR2/HitoriSpiel/Main/Main.java b/Hitori/src/main/java/PR2/HitoriSpiel/Main/Main.java index 69681b0..b2a93d5 100644 --- a/Hitori/src/main/java/PR2/HitoriSpiel/Main/Main.java +++ b/Hitori/src/main/java/PR2/HitoriSpiel/Main/Main.java @@ -1,6 +1,7 @@ package PR2.HitoriSpiel.Main; import PR2.HitoriSpiel.GUI.StartMenu; +import PR2.HitoriSpiel.Domain.StateManager; import javax.swing.*; @@ -12,15 +13,32 @@ import javax.swing.*; public class Main { public static void main(String[] args) { - SwingUtilities.invokeLater(() -> { - JFrame frame = new JFrame("Hitori - Hauptmenü"); - frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); - frame.setSize(800, 600); - frame.setLocationRelativeTo(null); - StartMenu startMenu = new StartMenu(frame); - frame.add(startMenu); - frame.setVisible(true); + // Initialisiere den StateManager + StateManager stateManager = new StateManager(); + + // Füge einen Shutdown-Hook hinzu, um Zustände bei Beendigung zu speichern + Runtime.getRuntime().addShutdownHook(new Thread(() -> { + stateManager.saveStateToFile(); // Speichert die aktuellen Zustände in einer Datei + System.out.println("Spielzustände wurden gespeichert."); + })); + + + // Starte das Hauptmenü der Anwendung + SwingUtilities.invokeLater(() -> { + try { + JFrame frame = new JFrame("Hitori - Hauptmenü"); + frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); + frame.setSize(800, 600); + + // Lade das Startmenü + frame.add(new StartMenu(frame)); + frame.setVisible(true); + frame.setLocationRelativeTo(null); + } catch (Exception e) { + e.printStackTrace(); + JOptionPane.showMessageDialog(null, "Ein schwerer Fehler ist aufgetreten: " + e.getMessage(), "Fehler", JOptionPane.ERROR_MESSAGE); + } }); } } \ No newline at end of file