From 5544ea5e65111220ce32551a52f969bed40e3e0c Mon Sep 17 00:00:00 2001 From: "Ioana P." <3015825@stud.hs-mannheim.de> Date: Mon, 13 Jan 2025 23:38:13 +0100 Subject: [PATCH] Javadocs, bessere Trennung von GUI, Fassade und Domain, andere Files angepasst --- Hitori/pom.xml | 191 +++++++++----- Hitori/src/main/highscores/highscores.txt | 3 +- .../java/PR2/HitoriSpiel/Domain/Action.java | 32 +++ .../PR2/HitoriSpiel/Domain/HitoriBoard.java | 38 +-- .../PR2/HitoriSpiel/Domain/HitoriCell.java | 13 +- .../HitoriSpiel/Domain/HitoriValidator.java | 24 +- .../HitoriSpiel/Domain/StateFileManager.java | 30 ++- .../PR2/HitoriSpiel/Fassade/BoardManager.java | 24 ++ .../PR2/HitoriSpiel/Fassade/GameBoard.java | 238 ++++++++++++------ .../PR2/HitoriSpiel/Fassade/GameManager.java | 1 + .../HitoriSpiel/Fassade/HighscoreManager.java | 82 +++++- .../Fassade/HitoriSolutionLoader.java | 12 +- .../java/PR2/HitoriSpiel/Fassade/Setup.java | 4 + .../PR2/HitoriSpiel/Fassade/StateManager.java | 33 +++ .../java/PR2/HitoriSpiel/GUI/BoardLoader.java | 41 +-- .../PR2/HitoriSpiel/GUI/HighscoreDialog.java | 28 ++- .../java/PR2/HitoriSpiel/GUI/PauseMenu.java | 15 ++ .../java/PR2/HitoriSpiel/GUI/StartMenu.java | 51 +++- .../main/java/PR2/HitoriSpiel/Main/Main.java | 3 - .../PR2/HitoriSpiel/project_structure.puml | 6 +- .../src/test/java/Domain/HitoriBoardTest.java | 8 - 21 files changed, 644 insertions(+), 233 deletions(-) create mode 100644 Hitori/src/main/java/PR2/HitoriSpiel/Fassade/BoardManager.java diff --git a/Hitori/pom.xml b/Hitori/pom.xml index d70a88f..4020365 100644 --- a/Hitori/pom.xml +++ b/Hitori/pom.xml @@ -1,71 +1,132 @@ - + 4.0.0 - org.example HitoriTeamProjekt 1.0-SNAPSHOT - jar + + UTF-8 + 21 + 21 + + + + org.junit.jupiter + junit-jupiter-api + 5.8.1 + test + + + org.junit.jupiter + junit-jupiter-engine + 5.8.1 + test + + + org.apache.logging.log4j + log4j-core + 2.24.2 + + + + + + + org.apache.maven.plugins + maven-compiler-plugin + 3.13.0 + + ${maven.compiler.source} + ${maven.compiler.target} + + + + + org.apache.maven.plugins + maven-shade-plugin + 3.6.0 + + false + + + + package + + shade + + + + + PR2.HitoriSpiel.Main.Main + + + + + + + + + org.jacoco + jacoco-maven-plugin + 0.8.12 + + + + prepare-agent + + + + report + test + + report + + + + + + + org.apache.maven.plugins + maven-pmd-plugin + 3.26.0 + + false + true + + + + verify + + check + + + + + + + + + + + org.apache.maven.plugins + maven-javadoc-plugin + 3.3.1 + + private + true + + - - 21 - 21 - UTF-8 - - - - - - org.assertj - assertj-swing - 3.17.1 - test - - - junit - junit - 4.13.1 - test - - - org.junit.jupiter - junit-jupiter - 5.8.2 - test - - - org.mockito - mockito-core - 4.5.1 - test - - - - - - - org.apache.maven.plugins - maven-compiler-plugin - 3.11.0 - - 21 - 21 - - - - org.apache.maven.plugins - maven-jar-plugin - 3.2.0 - - - - PR2.HitoriSpiel.Main.Main - - - - - - - + + org.apache.maven.plugins + maven-checkstyle-plugin + 3.1.2 + + checkstyle.xml + true + + + + + \ No newline at end of file diff --git a/Hitori/src/main/highscores/highscores.txt b/Hitori/src/main/highscores/highscores.txt index 167a4d9..3d5c33d 100644 --- a/Hitori/src/main/highscores/highscores.txt +++ b/Hitori/src/main/highscores/highscores.txt @@ -5,4 +5,5 @@ Test3,100,Hitori8x8_medium.csv,0 Test4,200,Hitori15x15_medium.csv,10 IOANA VERSUCH 156,105,Hitori5x5_leicht.csv,0 IOANA VERSUCH 439,44,Hitori5x5_leicht.csv,0 -Yovu,46,Hitori4x4_leicht.csv,0 \ No newline at end of file +Yovu,46,Hitori4x4_leicht.csv,0 +hi,18,Hitori4x4_leicht.csv,0 diff --git a/Hitori/src/main/java/PR2/HitoriSpiel/Domain/Action.java b/Hitori/src/main/java/PR2/HitoriSpiel/Domain/Action.java index b15c8eb..9e4488e 100644 --- a/Hitori/src/main/java/PR2/HitoriSpiel/Domain/Action.java +++ b/Hitori/src/main/java/PR2/HitoriSpiel/Domain/Action.java @@ -1,11 +1,27 @@ package PR2.HitoriSpiel.Domain; +/** + * Die Klasse Action repräsentiert eine Aktion im Hitori-Spiel, die eine Änderung + * an einer bestimmten Zelle des Spielfelds beschreibt, einschließlich der Koordinaten, + * des alten Zustands und des neuen Zustands. + */ + public class Action { private final int row; // Zeile, in der die Änderung erfolgt ist private final int col; // Spalte, in der die Änderung erfolgt ist private final String oldState; // Alter Zustand der Zelle private final String newState; // Neuer Zustand der Zelle + /** + * Erstellt ein neues Action-Objekt mit den angegebenen Koordinaten, + * dem alten Zustand und dem neuen Zustand. + * + * @param row Die Zeile, in der die Änderung erfolgt ist. + * @param col Die Spalte, in der die Änderung erfolgt ist. + * @param oldState Der alte Zustand der Zelle. + * @param newState Der neue Zustand der Zelle. + */ + public Action(int row, int col, String oldState, String newState) { this.row = row; this.col = col; @@ -13,6 +29,15 @@ public class Action { this.newState = newState; } + /** + * Erstellt ein neues Action-Objekt mit den angegebenen Koordinaten + * und dem neuen Zustand; der alte Zustand wird auf "GRAY" gesetzt. + * + * @param row Die Zeile, in der die Änderung erfolgt ist. + * @param col Die Spalte, in der die Änderung erfolgt ist. + * @param newState Der neue Zustand der Zelle. + */ + // Alternative Konstruktor für Standardwerte public Action(int row, int col, String newState) { this(row, col, "GRAY", newState); @@ -52,6 +77,13 @@ public class Action { newState.equals(action.newState); } + /** + * Berechnet den Hashcode für das Action-Objekt basierend + * auf den Attributen row, col, oldState und newState. + * + * @return Der berechnete Hashcode. + */ + @Override public int hashCode() { int result = row; diff --git a/Hitori/src/main/java/PR2/HitoriSpiel/Domain/HitoriBoard.java b/Hitori/src/main/java/PR2/HitoriSpiel/Domain/HitoriBoard.java index cf0280d..c4b10f8 100644 --- a/Hitori/src/main/java/PR2/HitoriSpiel/Domain/HitoriBoard.java +++ b/Hitori/src/main/java/PR2/HitoriSpiel/Domain/HitoriBoard.java @@ -3,7 +3,8 @@ package PR2.HitoriSpiel.Domain; import java.util.List; /** - * Represents the Hitori game board. + * Die Klasse HitoriBoard repräsentiert das Spielfeld des Hitori-Spiels. + * Sie enthält die Zellen des Spielfelds, die Lösungskonfiguration und den Namen des Spielfelds. */ public class HitoriBoard { @@ -12,6 +13,15 @@ public class HitoriBoard { private final String boardName; // Name des Spielfelds + /** + * Konstruktor, der das Spielfeld mit den Zahlen, der Lösungskonfiguration + * und dem Namen des Spielfelds initialisiert. + * + * @param numbers 2D-Array mit den Zahlen des Spielfelds. + * @param solutionCoordinates Liste der Koordinaten, die zur Lösung gehören. + * @param boardName Name des Spielfelds. + */ + public HitoriBoard(int[][] numbers, List solutionCoordinates, String boardName) { this.board = new HitoriCell[numbers.length][numbers[0].length]; this.solutionCoordinates = solutionCoordinates; @@ -81,32 +91,6 @@ public class HitoriBoard { } } - /** - * Gibt das gesamte Spielfeld als 2D-Array zurück. - * - * @return 2D-Array mit den Zahlen des Spielfelds. - */ - public int[][] getNumbers() { - int[][] numbers = new int[board.length][board[0].length]; - for (int i = 0; i < board.length; i++) { - for (int j = 0; j < board[i].length; j++) { - numbers[i][j] = board[i][j].getNumber(); - } - } - return numbers; - } - /** - * Setzt die Zahlen des Spielfelds basierend auf einem 2D-Array. - * - * @param numbers 2D-Array mit den neuen Zahlen. - */ - public void setNumbers(int[][] numbers) { - for (int i = 0; i < board.length; i++) { - for (int j = 0; j < board[i].length; j++) { - board[i][j].setNumber(numbers[i][j]); - } - } - } } diff --git a/Hitori/src/main/java/PR2/HitoriSpiel/Domain/HitoriCell.java b/Hitori/src/main/java/PR2/HitoriSpiel/Domain/HitoriCell.java index bc085b5..9e425b5 100644 --- a/Hitori/src/main/java/PR2/HitoriSpiel/Domain/HitoriCell.java +++ b/Hitori/src/main/java/PR2/HitoriSpiel/Domain/HitoriCell.java @@ -1,17 +1,28 @@ package PR2.HitoriSpiel.Domain; /** - * Represents a single cell on the Hitori board. + * Die Klasse HitoriCell repräsentiert eine einzelne Zelle auf dem Hitori-Spielfeld. + * Sie speichert die Zahl der Zelle und deren Zustand (GRAY, WHITE, BLACK). */ public class HitoriCell { + /** + * Enum zur Darstellung der möglichen Zustände einer Zelle. + */ + public enum CellState { GRAY, WHITE, BLACK } private int number; private CellState state; + /** + * Konstruktor, der eine Zelle mit einer Zahl erstellt und den Zustand auf GRAY setzt. + * + * @param number Die Zahl der Zelle. + */ + public HitoriCell(int number) { this.number = number; this.state = CellState.GRAY; diff --git a/Hitori/src/main/java/PR2/HitoriSpiel/Domain/HitoriValidator.java b/Hitori/src/main/java/PR2/HitoriSpiel/Domain/HitoriValidator.java index a69c1cf..fc37deb 100644 --- a/Hitori/src/main/java/PR2/HitoriSpiel/Domain/HitoriValidator.java +++ b/Hitori/src/main/java/PR2/HitoriSpiel/Domain/HitoriValidator.java @@ -3,32 +3,44 @@ package PR2.HitoriSpiel.Domain; import java.util.List; /** - * Validates the Hitori board against the solution. + * Die Klasse HitoriValidator überprüft, ob das aktuelle Spielfeld des Hitori-Spiels korrekt gelöst ist, + * indem es mit der angegebenen Lösung verglichen wird. */ + public class HitoriValidator { private final HitoriBoard board; + /** + * Konstruktor, der den Validator mit einem Hitori-Spielfeld initialisiert. + * + * @param board Das zu überprüfende Hitori-Spielfeld. + */ + public HitoriValidator(HitoriBoard board) { this.board = board; } /** - * Validates the current board against the solution. - * @param solutionCoordinates The coordinates of the correct black cells in "row,column" format. - * @return true if the current board matches the solution, false otherwise. + * Überprüft, ob das aktuelle Spielfeld der Lösung entspricht. + * + * @param solutionCoordinates Die Koordinaten der korrekten schwarzen Felder im Format "row,column". + * @return true, wenn das aktuelle Spielfeld der Lösung entspricht, andernfalls false. */ + public boolean validateBoard(List solutionCoordinates) { + // Überprüfe, ob alle Koordinaten der Lösung korrekt schwarz markiert sind for (String coordinate : solutionCoordinates) { String[] parts = coordinate.split(","); int row = Integer.parseInt(parts[0]) - 1; int col = Integer.parseInt(parts[1]) - 1; if (board.getCell(row,col).getState() != HitoriCell.CellState.BLACK){ - return false; + return false; // Ein Feld, das schwarz sein sollte, ist aber nicht } } + // Überprüfe alle Zellen des Spielfelds for (int i = 0; i < board.getSize(); i++) { for (int j = 0; j < board.getSize(); j++) { HitoriCell cell = board.getCell(i, j); @@ -44,7 +56,7 @@ public class HitoriValidator { } } - return true; + return true; // Das Spielfeld entspricht der Lösung } } diff --git a/Hitori/src/main/java/PR2/HitoriSpiel/Domain/StateFileManager.java b/Hitori/src/main/java/PR2/HitoriSpiel/Domain/StateFileManager.java index ca02e0f..809963f 100644 --- a/Hitori/src/main/java/PR2/HitoriSpiel/Domain/StateFileManager.java +++ b/Hitori/src/main/java/PR2/HitoriSpiel/Domain/StateFileManager.java @@ -1,17 +1,23 @@ package PR2.HitoriSpiel.Domain; import java.io.*; -import java.nio.file.Files; -import java.nio.file.Path; -import java.nio.file.Paths; +import java.nio.file.*; import java.util.Stack; +/** + * Die Klasse StateFileManager verwaltet das Speichern und Laden der Zustände des Undo- und Redo-Stacks + * in eine Datei. Sie stellt sicher, dass der Speicherort existiert und ermöglicht so die Persistenz der Spielzustände. + */ + public class StateFileManager { // Speicherort für die Undo/Redo-Datei im Benutzerverzeichnis private static final String BASE_DIR = System.getProperty("user.home") + "/HitoriGame"; private static final String FILE_NAME = BASE_DIR + "/undoRedoLog.txt"; - // Stellt sicher, dass der Ordner und die Datei existieren + /** + * Stellt sicher, dass der Ordner und die Datei existieren. + */ + private static void ensureFileExists() { try { // Erstellt den Ordner, falls er nicht existiert @@ -32,7 +38,13 @@ public class StateFileManager { } } - // Speichert den Zustand in der Datei + /** + * Speichert den Zustand der Undo- und Redo-Stacks in der Datei. + * + * @param undoStack Der aktuelle Undo-Stack. + * @param redoStack Der aktuelle Redo-Stack. + */ + public static void saveState(Stack undoStack, Stack redoStack) { ensureFileExists(); // Stellt sicher, dass die Datei existiert try (BufferedWriter writer = new BufferedWriter(new FileWriter(FILE_NAME))) { @@ -54,7 +66,13 @@ public class StateFileManager { } } - // Lädt den Zustand aus der Datei + /** + * Lädt den Zustand der Undo- und Redo-Stacks aus der Datei. + * + * @param undoStack Der Stack, in den die Undo-Zustände geladen werden. + * @param redoStack Der Stack, in den die Redo-Zustände geladen werden. + */ + public static void loadState(Stack undoStack, Stack redoStack) { ensureFileExists(); // Stellt sicher, dass die Datei existiert try (BufferedReader reader = new BufferedReader(new FileReader(FILE_NAME))) { diff --git a/Hitori/src/main/java/PR2/HitoriSpiel/Fassade/BoardManager.java b/Hitori/src/main/java/PR2/HitoriSpiel/Fassade/BoardManager.java new file mode 100644 index 0000000..a1a4f41 --- /dev/null +++ b/Hitori/src/main/java/PR2/HitoriSpiel/Fassade/BoardManager.java @@ -0,0 +1,24 @@ +package PR2.HitoriSpiel.Fassade; + +import PR2.HitoriSpiel.Domain.HitoriBoard; + +import java.util.List; + +/** + * Die Klasse BoardManager dient als Fassade, um ein HitoriBoard-Objekt zu erstellen + * und die Spielfeld-Initialisierung zu kapseln. + */ + +public class BoardManager { + /** + * Erstellt und gibt ein HitoriBoard-Objekt basierend auf den angegebenen Parametern zurück. + * + * @param boardData Die Daten des Spielfelds. + * @param solutionCoordinates Die Koordinaten der Lösung. + * @param selectedFile Die ausgewählte Datei mit den Spielfeldinformationen. + * @return Das erstellte HitoriBoard-Objekt. + */ + public HitoriBoard createBoard(int[][] boardData, List solutionCoordinates, String selectedFile) { + return new HitoriBoard(boardData, solutionCoordinates, selectedFile); + } +} diff --git a/Hitori/src/main/java/PR2/HitoriSpiel/Fassade/GameBoard.java b/Hitori/src/main/java/PR2/HitoriSpiel/Fassade/GameBoard.java index 4ca781f..e6de42a 100644 --- a/Hitori/src/main/java/PR2/HitoriSpiel/Fassade/GameBoard.java +++ b/Hitori/src/main/java/PR2/HitoriSpiel/Fassade/GameBoard.java @@ -10,15 +10,26 @@ import PR2.HitoriSpiel.GUI.StartMenu; import javax.swing.*; import java.awt.*; +/** + * Die Klasse GameBoard repräsentiert das Spielfeld des Hitori-Spiels mit zugehörigen Steuerungselementen. + * Sie bietet Funktionalitäten wie Timer, Spielfeldvalidierung, Undo/Redo und Highscore-Management. + */ + public class GameBoard extends JPanel { - private final HitoriBoard board; - private Timer timer; - private long startTime; - private JLabel timerLabel; + private final HitoriBoard board; // Das Hitori-Spielfeld-Objekt + private Timer timer; // Timer für die Spielzeitmessung + private long startTime; // Startzeit des Timers + private JLabel timerLabel; // Anzeigeelement für die aktuelle Spielzeit private long pausedTime = 0; // Zeit, die beim Pausieren bereits abgelaufen ist private JPanel gamePanel; // Das Spielfeld als JPanel - private final StateManager stateManager = new StateManager(); + private final StateManager stateManager = new StateManager(); // Manager für Undo/Redo-Operationen + private long elapsedTime = 0; + /** + * Konstruktor, der das Spielfeld und die Steuerungselemente initialisiert. + * + * @param board Das Hitori-Spielfeld. + */ public GameBoard(HitoriBoard board) { this.board = board; @@ -32,13 +43,17 @@ public class GameBoard extends JPanel { // Spielfeld erstellen gamePanel = createGamePanel(); - add(gamePanel, BorderLayout.CENTER); + add(gamePanel, BorderLayout.CENTER); // Spielfeld im Zentrum hinzufügen // Kontroll-Buttons unten hinzufügen JPanel controlPanel = createControlPanel(); - add(controlPanel, BorderLayout.SOUTH); + add(controlPanel, BorderLayout.SOUTH); // Buttons am unteren Rand platzieren } + /** + * Initialisiert das Timer-Label. + */ + private void initializeTimerLabel() { timerLabel = new JLabel("Zeit: 0 Sekunden"); timerLabel.setHorizontalAlignment(SwingConstants.CENTER); @@ -46,42 +61,12 @@ public class GameBoard extends JPanel { add(timerLabel, BorderLayout.NORTH); } - private void startTimer() { - if (timer == null) { // Timer nur beim ersten Start erstellen - timer = new Timer(1000, e -> { - long elapsedTime = (System.currentTimeMillis() - startTime + pausedTime) / 1000; // Zeit berechnen - timerLabel.setText("Zeit: " + elapsedTime + " Sekunden"); - }); - } - startTime = System.currentTimeMillis(); // Startzeit setzen, bevor der Timer gestartet wird - timer.start(); // Timer starten - System.out.println("Startzeit: " + startTime); - System.out.println("Pausierte Zeit: " + pausedTime); - } - - private void stopTimer() { - if (timer != null && timer.isRunning()) { - timer.stop(); // Timer anhalten - pausedTime += System.currentTimeMillis() - startTime; // Zeit während der Pause speichern - System.out.println("Timer gestoppt. Pausierte Zeit: " + pausedTime); - } - } - - public void resumeTimer() { - startTime = System.currentTimeMillis(); // Startzeit neu setzen - startTimer(); // Timer erneut starten - System.out.println("Timer fortgesetzt. Startzeit: " + startTime + ", Pausierte Zeit: " + pausedTime); - } - - private void resetTimer() { - if (timer != null) { - timer.stop(); - } - startTime = 0; - pausedTime = 0; - timerLabel.setText("Zeit: 0 Sekunden"); - } + /** + * Erstellt das Steuerungspanel mit Kontroll-Buttons. + * + * @return Das erstellte Panel. + */ private JPanel createControlPanel() { JPanel controlPanel = new JPanel(); @@ -95,24 +80,36 @@ public class GameBoard extends JPanel { return controlPanel; } + /** + * Erstellt den "Zurücksetzen"-Button. + * + * @return Der Reset-Button. + */ + private JButton createResetButton() { JButton resetButton = Setup.createGameBoardButton("Zurücksetzen", 150, 30); resetButton.addActionListener(e -> { //saveStateForUndo(); - resetBoard(); + resetBoard(); // Spielfeld zurücksetzen }); return resetButton; } + /** + * Erstellt den "Undo"-Button. + * + * @return Der Undo-Button. + */ + private JButton createUndoButton() { JButton undoButton = Setup.createGameBoardButton("Undo", 80, 30); undoButton.addActionListener(e -> { - Action action = stateManager.undo(); + Action action = stateManager.undo(); // Letzte Aktion rückgängig machen if (action != null) { - HitoriCell cell = board.getCell(action.getRow(), action.getCol()); - cell.setState(HitoriCell.CellState.valueOf(action.getOldState())); + HitoriCell cell = board.getCell(action.getRow(), action.getCol()); // Betroffene Zelle abrufen + cell.setState(HitoriCell.CellState.valueOf(action.getOldState())); // Zustand der Zelle zurücksetzen JButton button = (JButton) gamePanel.getComponent(action.getRow() * board.getSize() + action.getCol()); - updateButtonState(button, cell); + updateButtonState(button, cell); // Button-Status aktualisieren } else { JOptionPane.showMessageDialog(this, "Kein Zustand zum Zurücksetzen vorhanden.", "Undo", JOptionPane.INFORMATION_MESSAGE); } @@ -121,10 +118,16 @@ public class GameBoard extends JPanel { return undoButton; } + /** + * Erstellt den "Redo"-Button. + * + * @return Der Redo-Button. + */ + private JButton createRedoButton() { JButton redoButton = Setup.createGameBoardButton("Redo", 80, 30); redoButton.addActionListener(e -> { - Action action = stateManager.redo(); + Action action = stateManager.redo(); // Letzte rückgängig gemachte Aktion wiederherstellen if (action != null) { HitoriCell cell = board.getCell(action.getRow(), action.getCol()); cell.setState(HitoriCell.CellState.valueOf(action.getNewState())); @@ -137,12 +140,18 @@ public class GameBoard extends JPanel { return redoButton; } + /** + * Erstellt den "Lösen"-Button. + * + * @return Der Validate-Button. + */ + private JButton createValidateButton() { JButton validateButton = Setup.createGameBoardButton("Lösen", 80, 30); validateButton.addActionListener(e -> { - if (validateCurrentBoard()) { - stopTimer(); - handleHighscore(); + if (validateCurrentBoard()) { // Prüfen, ob das Spielfeld korrekt gelöst ist + stopTimer(); // Timer anhalten + handleHighscore(); // Highscore bearbeiten } else { JOptionPane.showMessageDialog(this, "Das Spielfeld enthält Fehler!", "Fehler", JOptionPane.ERROR_MESSAGE); } @@ -150,6 +159,12 @@ public class GameBoard extends JPanel { return validateButton; } + /** + * Erstellt den "Pause"-Button. + * + * @return Der Pause-Button. + */ + private JButton createPauseButton() { JButton pauseButton = Setup.createGameBoardButton("Pause", 80, 30); pauseButton.addActionListener(e -> { @@ -159,18 +174,28 @@ public class GameBoard extends JPanel { return pauseButton; } - public boolean validateCurrentBoard() { + /** + * Validiert das aktuelle Spielfeld gegen die Lösung. + * + * @return true, wenn das Spielfeld korrekt ist, sonst false. + */ + + public boolean validateCurrentBoard() { HitoriValidator validator = new HitoriValidator(board); - return validator.validateBoard(board.getSolutionCoordinates()); + return validator.validateBoard(board.getSolutionCoordinates()); // Prüfen, ob das Spielfeld korrekt ist } + /** + * Verarbeitet die Highscore-Logik, einschließlich der Überprüfung, ob ein neuer Highscore erreicht wurde, + * und speichert den Highscore, wenn der Spieler seinen Namen eingibt. + */ + private void handleHighscore() { - int elapsedTime = (int) ((System.currentTimeMillis() - startTime) / 1000); // Spielzeit in Sekunden String boardName = board.getBoardName(); int errors = 0; // Aktuelle Fehlerzahl (falls vorhanden, muss noch angepasst werden) HighscoreManager manager = new HighscoreManager(); - boolean isNewHighscore = manager.isNewHighscore(elapsedTime, boardName); + boolean isNewHighscore = manager.isNewHighscore((int)elapsedTime, boardName); // Prüfen, ob ein neuer Highscore erreicht wurde // Zeige ein Dialogfenster zur Namenseingabe String playerName = JOptionPane.showInputDialog(this, @@ -186,7 +211,7 @@ public class GameBoard extends JPanel { } // Speichere den Highscore - manager.addHighscore(playerName, elapsedTime, boardName, errors); + manager.addHighscore(playerName, (int)elapsedTime, boardName, errors); JOptionPane.showMessageDialog(this, isNewHighscore @@ -200,6 +225,10 @@ public class GameBoard extends JPanel { } + /** + * Zeigt das Pausenmenü an. + */ + private void showPauseMenu() { stopTimer(); // Timer pausieren PauseMenu pauseMenu = new PauseMenu( @@ -212,6 +241,15 @@ public class GameBoard extends JPanel { pauseMenu.setVisible(true); } + /** + * Erstellt einen Button für eine Zelle des Spielfelds. + * + * @param cell Die Zelle. + * @param row Die Zeile der Zelle. + * @param col Die Spalte der Zelle. + * @return Der Button. + */ + private JButton createCellButton(HitoriCell cell, int row, int col) { JButton button = new JButton(String.valueOf(cell.getNumber())); button.setBackground(Color.LIGHT_GRAY); @@ -222,6 +260,14 @@ public class GameBoard extends JPanel { return button; } + /** + * Schaltet den Zustand einer Zelle um. + * + * @param cell Die zu toggelnde Zelle. + * @param row Die Zeile der Zelle. + * @param col Die Spalte der Zelle. + */ + public void toggleCellState(HitoriCell cell, int row, int col) { if (cell == null) { System.err.println("Ungültige Zelle! Der Zustand kann nicht geändert werden."); @@ -252,6 +298,13 @@ public class GameBoard extends JPanel { System.out.println("Aktion gespeichert: " + oldState + " -> " + newState); } + /** + * Aktualisiert die Darstellung eines Buttons basierend auf dem Zustand der Zelle. + * + * @param button Der Button. + * @param cell Die Zelle. + */ + private void updateButtonState(JButton button, HitoriCell cell) { switch (cell.getState()) { case GRAY -> { @@ -272,22 +325,9 @@ public class GameBoard extends JPanel { } } - private void addHighscore(int elapsedTime, String boardName, int errors) { - String playerName = JOptionPane.showInputDialog(this, - "Neuer Highscore! Bitte Namen eingeben:", - "Highscore speichern", - JOptionPane.PLAIN_MESSAGE); - - if (playerName == null || playerName.trim().isEmpty()) return; - - HighscoreManager manager = new HighscoreManager(); - manager.addHighscore(playerName, elapsedTime, boardName, errors); - - JOptionPane.showMessageDialog(this, - "Highscore erfolgreich gespeichert!", - "Erfolg", - JOptionPane.INFORMATION_MESSAGE); - } + /** + * Kehrt ins Hauptmenü zurück. + */ private void returnToMainMenu() { /// Eltern-Frame abrufen @@ -304,6 +344,10 @@ public class GameBoard extends JPanel { } } + /** + * Setzt das Spielfeld zurück. + */ + public void resetBoard() { // Spiellogik zurücksetzen board.resetBoard(); @@ -330,6 +374,7 @@ public class GameBoard extends JPanel { repaint(); } + // Aktualisiert das Spielfeld private void refreshBoard() { remove(1); // Entferne das aktuelle Spielfeld im CENTER if (getLayout() instanceof BorderLayout) { @@ -357,6 +402,12 @@ public class GameBoard extends JPanel { repaint(); } + /** + * Erstellt das Spielfeld als JPanel. + * + * @return Das erstellte JPanel mit Spielfeldzellen. + */ + private JPanel createGamePanel() { JPanel gamePanel = new JPanel(new GridLayout(board.getSize(), board.getSize())); for (int i = 0; i < board.getSize(); i++) { @@ -381,4 +432,47 @@ public class GameBoard extends JPanel { } + // --------Hilfsmethoden--------- + + // Startet den Timer + private void startTimer() { + if (timer == null) { // Timer nur beim ersten Start erstellen + timer = new Timer(1000, e -> { + elapsedTime = (System.currentTimeMillis() - startTime + pausedTime) / 1000; // Zeit berechnen + timerLabel.setText("Zeit: " + elapsedTime + " Sekunden"); + }); + } + + startTime = System.currentTimeMillis(); // Startzeit setzen, bevor der Timer gestartet wird + timer.start(); // Timer starten + System.out.println("Startzeit: " + startTime); + System.out.println("Pausierte Zeit: " + pausedTime); + } + + // Hält den Timer an + private void stopTimer() { + if (timer != null && timer.isRunning()) { + timer.stop(); // Timer anhalten + pausedTime += System.currentTimeMillis() - startTime; // Zeit während der Pause speichern + System.out.println("Timer gestoppt. Pausierte Zeit: " + pausedTime); + } + } + + // Setzt den Timer fort + public void resumeTimer() { + startTime = System.currentTimeMillis(); // Startzeit neu setzen + startTimer(); // Timer erneut starten + System.out.println("Timer fortgesetzt. Startzeit: " + startTime + ", Pausierte Zeit: " + pausedTime); + } + + // Setzt den Timer zurück + private void resetTimer() { + if (timer != null) { + timer.stop(); + } + startTime = 0; + pausedTime = 0; + timerLabel.setText("Zeit: 0 Sekunden"); + } + } diff --git a/Hitori/src/main/java/PR2/HitoriSpiel/Fassade/GameManager.java b/Hitori/src/main/java/PR2/HitoriSpiel/Fassade/GameManager.java index 7d0cc11..8f2b29d 100644 --- a/Hitori/src/main/java/PR2/HitoriSpiel/Fassade/GameManager.java +++ b/Hitori/src/main/java/PR2/HitoriSpiel/Fassade/GameManager.java @@ -1,5 +1,6 @@ package PR2.HitoriSpiel.Fassade; +// TODO: Spiel fortsetzen public class GameManager { private static GameBoard gameBoard; diff --git a/Hitori/src/main/java/PR2/HitoriSpiel/Fassade/HighscoreManager.java b/Hitori/src/main/java/PR2/HitoriSpiel/Fassade/HighscoreManager.java index 2ab2a85..1c2a4eb 100644 --- a/Hitori/src/main/java/PR2/HitoriSpiel/Fassade/HighscoreManager.java +++ b/Hitori/src/main/java/PR2/HitoriSpiel/Fassade/HighscoreManager.java @@ -4,6 +4,12 @@ import java.io.*; import java.util.*; import java.util.concurrent.locks.ReentrantLock; +/** + * Die Klasse HighscoreManager verwaltet die Highscores für das Hitori-Spiel. + * Sie unterstützt das Hinzufügen, Speichern, Laden und Analysieren von Highscore-Daten + * sowie die Berechnung von Durchschnittszeiten pro Spielfeld. + */ + public class HighscoreManager { private static final String HIGHSCORE_FILE = "Hitori/src/main/highscores/highscores.txt"; @@ -11,11 +17,22 @@ public class HighscoreManager { // Highscore-Datenstruktur private final List highscoreList = new ArrayList<>(); + /** + * Konstruktor, der Highscores aus der Datei lädt. + */ + public HighscoreManager() { loadHighscores(); } - // Prüft, ob die gegebene Zeit ein neuer Highscore ist + /** + * Überprüft, ob die gegebene Zeit ein neuer Highscore für das angegebene Spielfeld ist. + * + * @param elapsedTime Die benötigte Zeit. + * @param boardName Der Name des Spielfelds. + * @return true, wenn es ein neuer Highscore ist, sonst false. + */ + public boolean isNewHighscore(int elapsedTime, String boardName) { // Filtere die Highscores für das gegebene Spielfeld List highscoresForBoard = getHighscoresForBoard(boardName); @@ -34,13 +51,27 @@ public class HighscoreManager { return elapsedTime < bestTime; } - // Highscore hinzufügen + /** + * Fügt einen neuen Highscore hinzu und speichert die aktualisierten Highscores. + * + * @param playerName Der Name des Spielers. + * @param time Die benötigte Zeit. + * @param boardName Der Name des Spielfelds. + * @param errors Die Anzahl der Fehler. + */ + public synchronized void addHighscore(String playerName, int time, String boardName, int errors) { highscoreList.add(new Highscore(playerName, time, boardName, errors)); saveHighscores(); } - // Highscores für ein bestimmtes Spielfeld abrufen + /** + * Gibt die Highscores für ein bestimmtes Spielfeld zurück, sortiert nach kürzester Zeit. + * + * @param boardName Der Name des Spielfelds. + * @return Eine Liste der Top 10 Highscores für das Spielfeld. + */ + public List getHighscoresForBoard(String boardName) { return highscoreList.stream() .filter(highscore -> highscore.getBoardName().equals(boardName)) @@ -49,7 +80,10 @@ public class HighscoreManager { .toList(); } - // Highscores speichern + /** + * Speichert die Highscores in einer Datei. + */ + private void saveHighscores() { try (BufferedWriter writer = new BufferedWriter(new FileWriter(HIGHSCORE_FILE))) { for (Highscore highscore : highscoreList) { @@ -61,7 +95,10 @@ public class HighscoreManager { } } - // Highscores laden + /** + * Lädt die Highscores aus einer Datei. + */ + private void loadHighscores() { try (BufferedReader reader = new BufferedReader(new FileReader(HIGHSCORE_FILE))) { String line; @@ -94,7 +131,12 @@ public class HighscoreManager { } } - // Durchschnittszeit für jedes Spielfeld berechnen + /** + * Berechnet die Durchschnittszeiten für jedes Spielfeld. + * + * @return Eine Map mit Spielfeldnamen und deren Durchschnittszeiten. + */ + public Map getAverageTimesByBoard() { fileLock.lock(); try { @@ -117,12 +159,20 @@ public class HighscoreManager { } } - // Highscores abrufen + /** + * Gibt alle Highscores zurück. + * + * @return Eine Liste aller Highscores. + */ + public List getHighscores() { return new ArrayList<>(highscoreList); // Modifizierbare Kopie zurückgeben } - - // Löscht alle Highscores + + /** + * Löscht alle Highscores und aktualisiert die Datei. + */ + public void clearHighscores() { fileLock.lock(); try { @@ -133,13 +183,25 @@ public class HighscoreManager { } } - // Innere Highscore-Klasse + /** + * Innere Klasse, die einen Highscore repräsentiert. + */ + public static class Highscore { private final String playerName; private final int time; private final String boardName; private final int errors; + /** + * Konstruktor für einen Highscore-Eintrag. + * + * @param playerName Der Name des Spielers. + * @param score Die benötigte Zeit. + * @param boardName Der Name des Spielfelds. + * @param errors Die Anzahl der Fehler. + */ + public Highscore(String playerName, int score, String boardName, int errors) { this.playerName = playerName; this.time = score; diff --git a/Hitori/src/main/java/PR2/HitoriSpiel/Fassade/HitoriSolutionLoader.java b/Hitori/src/main/java/PR2/HitoriSpiel/Fassade/HitoriSolutionLoader.java index 97ce4e2..2f25d60 100644 --- a/Hitori/src/main/java/PR2/HitoriSpiel/Fassade/HitoriSolutionLoader.java +++ b/Hitori/src/main/java/PR2/HitoriSpiel/Fassade/HitoriSolutionLoader.java @@ -4,10 +4,20 @@ import java.io.*; import java.util.*; /** - * Utility class to load the solution from a CSV file. + * Die Klasse HitoriSolutionLoader ist eine Hilfsklasse zum Laden der Lösung für ein Hitori-Spielfeld aus einer CSV-Datei. + * Die Lösung wird im Abschnitt "//Lösung" der Datei erwartet und enthält die Koordinaten der schwarzen Zellen. */ + public class HitoriSolutionLoader { + /** + * Lädt die Lösung für ein Hitori-Spielfeld aus einer Ressourcendatei. + * + * @param resourcePath Der Pfad zur Ressourcendatei. + * @return Eine Liste der Koordinaten der schwarzen Zellen im Format "row,column". + * @throws IOException Wenn die Datei nicht gefunden wird oder ein Lesefehler auftritt. + */ + public static List loadSolution(String resourcePath) throws IOException { List solutionCoordinates = new ArrayList<>(); boolean solutionSectionFound = false; diff --git a/Hitori/src/main/java/PR2/HitoriSpiel/Fassade/Setup.java b/Hitori/src/main/java/PR2/HitoriSpiel/Fassade/Setup.java index 5175ec4..05e5ee4 100644 --- a/Hitori/src/main/java/PR2/HitoriSpiel/Fassade/Setup.java +++ b/Hitori/src/main/java/PR2/HitoriSpiel/Fassade/Setup.java @@ -5,6 +5,10 @@ import java.awt.*; import java.awt.event.MouseAdapter; import java.awt.event.MouseEvent; +/** + * Die Klasse Setup bietet zentrale Methoden und Konstanten zur Gestaltung und Vereinheitlichung der GUI-Komponenten für das Hitori-Spiel. + */ + public class Setup { // Standardfarben diff --git a/Hitori/src/main/java/PR2/HitoriSpiel/Fassade/StateManager.java b/Hitori/src/main/java/PR2/HitoriSpiel/Fassade/StateManager.java index ed43030..11134d8 100644 --- a/Hitori/src/main/java/PR2/HitoriSpiel/Fassade/StateManager.java +++ b/Hitori/src/main/java/PR2/HitoriSpiel/Fassade/StateManager.java @@ -6,16 +6,38 @@ import PR2.HitoriSpiel.Domain.StateFileManager; import java.io.*; import java.util.Stack; +/** + * Die Klasse StateManager verwaltet die Undo- und Redo-Funktionalität für das Hitori-Spiel + * und speichert Zustandsänderungen in einer Datei. + */ + public class StateManager implements Serializable { private final Stack undoStack = new Stack<>(); private final Stack redoStack = new Stack<>(); + /** + * Speichert eine neue Aktion im Undo-Stack und leert den Redo-Stack. + * Speichert zudem den aktuellen Zustand in einer Datei. + * + * @param row Die Zeile der Aktion. + * @param col Die Spalte der Aktion. + * @param oldState Der alte Zustand. + * @param newState Der neue Zustand. + */ + public void saveAction(int row, int col, String oldState, String newState) { undoStack.push(new Action(row, col, oldState, newState)); redoStack.clear(); // Redo-Stack leeren, da ein neuer Zustand hinzugefügt wurde StateFileManager.saveState(undoStack, redoStack); // Speichern in Datei } + /** + * Führt eine Undo-Aktion aus, verschiebt die Aktion in den Redo-Stack + * und speichert den aktuellen Zustand in einer Datei. + * + * @return Die rückgängig gemachte Aktion oder null, wenn der Undo-Stack leer ist. + */ + public Action undo() { if (!undoStack.isEmpty()) { Action action = undoStack.pop(); @@ -26,6 +48,13 @@ public class StateManager implements Serializable { return null; } + /** + * Führt eine Redo-Aktion aus, verschiebt die Aktion in den Undo-Stack + * und speichert den aktuellen Zustand in einer Datei. + * + * @return Die wiederhergestellte Aktion oder null, wenn der Redo-Stack leer ist. + */ + public Action redo() { if (!redoStack.isEmpty()) { Action action = redoStack.pop(); @@ -36,6 +65,10 @@ public class StateManager implements Serializable { return null; } + /** + * Lädt die Undo- und Redo-Stacks aus einer Datei, um den letzten gespeicherten Zustand wiederherzustellen. + */ + public void loadStateFromFile() { StateFileManager.loadState(undoStack, redoStack); // Stacks aus Datei laden } diff --git a/Hitori/src/main/java/PR2/HitoriSpiel/GUI/BoardLoader.java b/Hitori/src/main/java/PR2/HitoriSpiel/GUI/BoardLoader.java index 6d24734..fc40c1e 100644 --- a/Hitori/src/main/java/PR2/HitoriSpiel/GUI/BoardLoader.java +++ b/Hitori/src/main/java/PR2/HitoriSpiel/GUI/BoardLoader.java @@ -5,25 +5,19 @@ import java.net.URLDecoder; import java.util.*; import java.util.jar.*; +/** + * Die Klasse BoardLoader lädt Spielfeld-Dateien für das Hitori-Spiel aus dem Dateisystem oder einem JAR-Archiv + * und bietet Funktionen zum Parsen der Dateien in ein 2D-Array. + */ + public class BoardLoader { - public static class BoardData { - private final int[][] board; - private final List solution; - - public BoardData(int[][] board, List solution) { - this.board = board; - this.solution = solution; - } - - public int[][] getBoard() { - return board; - } - - public List getSolution() { - return solution; - } - } + /** + * Lädt eine Liste von Spielfelddateien aus dem Verzeichnis oder dem JAR-Archiv. + * Sortiert die Dateien nach Schwierigkeitsgrad (leicht, medium) und Größe. + * + * @return Eine Liste der gefundenen Spielfelddateien. + */ public static List loadBoardsAsList() { List boardFiles = new ArrayList<>(); @@ -87,8 +81,13 @@ public class BoardLoader { return boardFiles; } - - + /** + * Lädt ein Spielfeld aus einer Ressourcendatei und gibt es als 2D-Array zurück. + * + * @param resourcePath Der Pfad zur Ressourcendatei. + * @return Ein 2D-Array, das das geladene Spielfeld darstellt. + * @throws IOException Wenn die Datei nicht gefunden oder fehlerhaft ist. + */ public static int[][] loadBoard(String resourcePath) throws IOException { List rows = new ArrayList<>(); @@ -142,6 +141,10 @@ public class BoardLoader { } + + //--------------------------Hilfsmethoden---------------------------------- + + // Hilfsmethode zum Extrahieren der Größe aus dem Dateinamen private static int extractSize(String fileName) { try { diff --git a/Hitori/src/main/java/PR2/HitoriSpiel/GUI/HighscoreDialog.java b/Hitori/src/main/java/PR2/HitoriSpiel/GUI/HighscoreDialog.java index f498ba2..4fc504c 100644 --- a/Hitori/src/main/java/PR2/HitoriSpiel/GUI/HighscoreDialog.java +++ b/Hitori/src/main/java/PR2/HitoriSpiel/GUI/HighscoreDialog.java @@ -2,22 +2,34 @@ package PR2.HitoriSpiel.GUI; import PR2.HitoriSpiel.Fassade.HighscoreManager; import PR2.HitoriSpiel.Fassade.Setup; -import javax.swing.table.DefaultTableModel; +import javax.swing.table.DefaultTableModel; import javax.swing.*; import java.awt.*; -import java.util.ArrayList; -import java.util.LinkedHashMap; +import java.util.*; import java.util.List; -import java.util.Map; -// aktueller Stand + +/** + * Die Klasse HighscoreDialog erstellt ein Dialogfenster, das die Highscores für verschiedene Spielfelder des Hitori-Spiels + * anzeigt und verwaltet. Sie ermöglicht die Auswahl eines Spielfelds, das Anzeigen der zugehörigen Highscores und die + * Berechnung der Durchschnittszeiten. + */ + + public class HighscoreDialog extends JDialog { private final HighscoreManager highscoreManager; private final DefaultTableModel tableModel; private final JComboBox boardSelector; + /** + * Konstruktor, der das Highscore-Dialogfenster erstellt und initialisiert. + * + * @param parentFrame Das übergeordnete Fenster, in dem der Dialog angezeigt wird. + * @param boardNames Eine Liste von Spielfelddateinamen. + */ + public HighscoreDialog(JFrame parentFrame, List boardNames) { super(parentFrame, "Highscoreliste", true); @@ -64,7 +76,6 @@ public class HighscoreDialog extends JDialog { closeButton.setFont(new Font(closeButton.getFont().getName(), closeButton.getFont().getStyle(), 18)); // Schriftgröße ändern closeButton.addActionListener(e -> dispose()); buttonPanel.add(closeButton); - Setup.stylePanel(buttonPanel); // Hintergrundstil setzen add(buttonPanel, BorderLayout.SOUTH); @@ -75,6 +86,11 @@ public class HighscoreDialog extends JDialog { } } + /** + * Lädt die Highscores für ein ausgewähltes Spielfeld und aktualisiert die Tabelle. + * + * @param boardName Der Name des ausgewählten Spielfelds. + */ private void loadHighscoresForBoard(String boardName) { tableModel.setRowCount(0); // Tabelle zurücksetzen diff --git a/Hitori/src/main/java/PR2/HitoriSpiel/GUI/PauseMenu.java b/Hitori/src/main/java/PR2/HitoriSpiel/GUI/PauseMenu.java index 7dce088..7b80534 100644 --- a/Hitori/src/main/java/PR2/HitoriSpiel/GUI/PauseMenu.java +++ b/Hitori/src/main/java/PR2/HitoriSpiel/GUI/PauseMenu.java @@ -7,9 +7,24 @@ import javax.swing.*; import java.awt.*; import java.awt.event.ActionListener; +/** + * Die Klasse PauseMenu erstellt ein Dialogfenster, das während einer Pause im Hitori-Spiel angezeigt wird. + * Sie bietet Optionen, das Spiel fortzusetzen, zum Hauptmenü zurückzukehren oder das Spiel zu beenden. + */ + public class PauseMenu extends JDialog { private final GameBoard gameBoard; + /** + * Konstruktor, der das Pause-Menü erstellt und die entsprechenden Buttons konfiguriert. + * + * @param parent Das übergeordnete Fenster, in dem der Dialog angezeigt wird. + * @param gameBoard Das aktuelle GameBoard-Objekt, um den Timer fortzusetzen. + * @param resumeAction Aktion, die ausgeführt wird, wenn der "Spiel fortsetzen"-Button geklickt wird. + * @param mainMenuAction Aktion, die ausgeführt wird, wenn der "Zum Hauptmenü"-Button geklickt wird. + * @param exitAction Aktion, die ausgeführt wird, wenn der "Spiel beenden"-Button geklickt wird. + */ + public PauseMenu(JFrame parent, GameBoard gameBoard, ActionListener resumeAction, ActionListener mainMenuAction, ActionListener exitAction) { super(parent, "Pause", true); this.gameBoard = gameBoard; // Instanz speichern diff --git a/Hitori/src/main/java/PR2/HitoriSpiel/GUI/StartMenu.java b/Hitori/src/main/java/PR2/HitoriSpiel/GUI/StartMenu.java index d84c79f..bad10d2 100644 --- a/Hitori/src/main/java/PR2/HitoriSpiel/GUI/StartMenu.java +++ b/Hitori/src/main/java/PR2/HitoriSpiel/GUI/StartMenu.java @@ -1,22 +1,31 @@ package PR2.HitoriSpiel.GUI; -import PR2.HitoriSpiel.Domain.HitoriBoard; +import PR2.HitoriSpiel.Fassade.BoardManager; import PR2.HitoriSpiel.Fassade.GameBoard; import PR2.HitoriSpiel.Fassade.HitoriSolutionLoader; import PR2.HitoriSpiel.Fassade.Setup; import javax.swing.*; import java.awt.*; -import java.util.LinkedHashMap; +import java.util.*; import java.util.List; -import java.util.Map; -import java.util.Random; import static PR2.HitoriSpiel.GUI.BoardLoader.loadBoard; +/** + * Die Klasse StartMenu erstellt das Hauptmenü des Hitori-Spiels und bietet Optionen wie Spielfeldauswahl, + * Fortsetzen eines Spiels, Start eines zufälligen Spielfelds, Highscore-Anzeige und Spielbeendigung. + */ + public class StartMenu extends JPanel { private final JFrame parentFrame; + /** + * Konstruktor, der das Hauptmenü erstellt und alle relevanten Buttons und Aktionen initialisiert. + * + * @param parentFrame Das übergeordnete JFrame-Fenster, in dem das Menü angezeigt wird. + */ + public StartMenu(JFrame parentFrame) { this.parentFrame = parentFrame; setLayout(new GridBagLayout()); @@ -56,11 +65,21 @@ public class StartMenu extends JPanel { } + /** + * Aktion für den "Spiel fortsetzen"-Button. + * Zeigt einen Hinweis an, da die Funktion noch nicht implementiert ist. + */ + public void continueGame() { // TODO: Logik zum Fortsetzen des Spiels implementieren JOptionPane.showMessageDialog(this, "Spiel fortsetzen wurde angeklickt"); } + /** + * Aktion für den "Spielfeld aussuchen"-Button. + * Öffnet ein Dialogfenster zur Auswahl eines Spielfelds aus der verfügbaren Liste. + */ + public void selectBoard() { // Lade die Liste der Dateinamen @@ -109,6 +128,10 @@ public class StartMenu extends JPanel { } } + /** + * Aktion für den "Zufälliges Spielfeld"-Button. + * Wählt ein zufälliges Spielfeld aus der Liste und lädt es. + */ public void randomBoard() { List boardFileNames = BoardLoader.loadBoardsAsList(); @@ -121,6 +144,10 @@ public class StartMenu extends JPanel { loadAndDisplayBoard(randomFile); } + /** + * Aktion für den "Highscoreliste anschauen"-Button. + * Öffnet das Highscore-Dialogfenster. + */ public void highscorelist() { List boardNames = BoardLoader.loadBoardsAsList(); // Lade die Spielfeldnamen @@ -132,6 +159,12 @@ public class StartMenu extends JPanel { new HighscoreDialog((JFrame) SwingUtilities.getWindowAncestor(this), boardNames).setVisible(true); } + /** + * Lädt ein Spielfeld aus einer Datei und zeigt es im Hauptfenster an. + * + * @param selectedFile Der Name der ausgewählten Datei. + */ + private void loadAndDisplayBoard(String selectedFile) { try { String resourcePath = "/persistent/Hitori_Spielfelder/" + selectedFile; @@ -140,8 +173,10 @@ public class StartMenu extends JPanel { int[][] boardData = loadBoard(resourcePath); java.util.List solutionCoordinates = HitoriSolutionLoader.loadSolution(resourcePath); - HitoriBoard hitoriBoard = new HitoriBoard(boardData, solutionCoordinates, selectedFile); // Stelle sicher, dass die Lösung korrekt geladen wird - GameBoard gameBoard = new GameBoard(hitoriBoard); + //HitoriBoard hitoriBoard = new HitoriBoard(boardData, solutionCoordinates, selectedFile); // Stelle sicher, dass die Lösung korrekt geladen wird + // BoardManager-Instanz erstellen + BoardManager boardManager = new BoardManager(); + GameBoard gameBoard = new GameBoard(boardManager.createBoard(boardData, solutionCoordinates, selectedFile)); loadGameBoard(gameBoard, solutionCoordinates); System.out.println("Ausgewählte Datei: " + selectedFile); @@ -152,7 +187,9 @@ public class StartMenu extends JPanel { } } - // Hilfsmethoden + // --------------------Hilfsmethoden-------------------------------------------- + + //Aktualisiert die Benutzeroberfläche, um das geladene Spielfeld anzuzeigen private void loadGameBoard(GameBoard gameBoard, java.util.List solutionCoordinates) { removeAll(); setLayout(new BorderLayout()); diff --git a/Hitori/src/main/java/PR2/HitoriSpiel/Main/Main.java b/Hitori/src/main/java/PR2/HitoriSpiel/Main/Main.java index 5469b63..ad70667 100644 --- a/Hitori/src/main/java/PR2/HitoriSpiel/Main/Main.java +++ b/Hitori/src/main/java/PR2/HitoriSpiel/Main/Main.java @@ -11,9 +11,6 @@ import javax.swing.*; public class Main { public static void main(String[] args) { - // 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 diff --git a/Hitori/src/main/java/PR2/HitoriSpiel/project_structure.puml b/Hitori/src/main/java/PR2/HitoriSpiel/project_structure.puml index 3a4ffbe..209e04a 100644 --- a/Hitori/src/main/java/PR2/HitoriSpiel/project_structure.puml +++ b/Hitori/src/main/java/PR2/HitoriSpiel/project_structure.puml @@ -71,6 +71,10 @@ package PR2.HitoriSpiel.Fassade { + addHighscore(String playerName, int score, String boardName, int errors): void + getHighscoresForBoard(String boardName): List } + + class BoardManager { + + createBoard(int[][] boardData, List solutionCoordinates, String selectedFile): HitoriBoard + } } package PR2.HitoriSpiel.GUI { @@ -106,7 +110,7 @@ package PR2.HitoriSpiel.Main { PR2.HitoriSpiel.Domain.HitoriBoard "1" *-- "many" PR2.HitoriSpiel.Domain.HitoriCell PR2.HitoriSpiel.Domain.StateManager "1" *-- "many" PR2.HitoriSpiel.Domain.Action PR2.HitoriSpiel.Fassade.GameBoard "1" *-- "1" PR2.HitoriSpiel.Domain.HitoriBoard -PR2.HitoriSpiel.GUI.BoardLoader ..> PR2.HitoriSpiel.Domain.HitoriBoard +PR2.HitoriSpiel.Fassade.BoardManager ..> PR2.HitoriSpiel.GUI.StartMenu PR2.HitoriSpiel.GUI.HighscoreDialog ..> PR2.HitoriSpiel.Fassade.HighscoreManager PR2.HitoriSpiel.GUI.PauseMenu --> PR2.HitoriSpiel.Fassade.GameBoard PR2.HitoriSpiel.GUI.StartMenu --> PR2.HitoriSpiel.GUI.BoardLoader diff --git a/Hitori/src/test/java/Domain/HitoriBoardTest.java b/Hitori/src/test/java/Domain/HitoriBoardTest.java index ac4b2de..94f7e36 100644 --- a/Hitori/src/test/java/Domain/HitoriBoardTest.java +++ b/Hitori/src/test/java/Domain/HitoriBoardTest.java @@ -25,12 +25,4 @@ public class HitoriBoardTest { assertEquals(HitoriCell.CellState.GRAY, board.getCell(0, 0).getState()); } - @Test - public void testSetAndGetNumbers() { - int[][] initialNumbers = {{9, 10}, {11, 12}}; - HitoriBoard board = new HitoriBoard(initialNumbers, Arrays.asList(), "SetNumbersTest"); - int[][] newNumbers = {{1, 2}, {3, 4}}; - board.setNumbers(newNumbers); - assertArrayEquals(newNumbers, board.getNumbers()); - } }