From f7868e042f25fd3b68bfc1b7024aaf2c85d79292 Mon Sep 17 00:00:00 2001 From: Vickvick2002 Date: Sun, 5 Jan 2025 16:22:30 +0100 Subject: [PATCH] =?UTF-8?q?Highscore=20Eintrag=20f=C3=BCr=20Name=20hinzuge?= =?UTF-8?q?f=C3=BCgt?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../java/PR2/HitoriSpiel/GUI/GameBoard.java | 129 +++++++++--------- .../PR2/HitoriSpiel/GUI/HighscoreDialog.java | 62 ++++++--- .../HitoriSpiel/Utils/HighscoreManager.java | 54 ++++++-- .../src/main/resources/Files/highscores.txt | 4 +- 4 files changed, 153 insertions(+), 96 deletions(-) diff --git a/Hitori/src/main/java/PR2/HitoriSpiel/GUI/GameBoard.java b/Hitori/src/main/java/PR2/HitoriSpiel/GUI/GameBoard.java index 0d104ba..7e11e2d 100644 --- a/Hitori/src/main/java/PR2/HitoriSpiel/GUI/GameBoard.java +++ b/Hitori/src/main/java/PR2/HitoriSpiel/GUI/GameBoard.java @@ -9,8 +9,6 @@ import PR2.HitoriSpiel.Utils.Setup; import javax.swing.*; import java.awt.*; -import java.io.FileWriter; -import java.io.IOException; public class GameBoard extends JPanel { private final HitoriBoard board; @@ -25,11 +23,8 @@ public class GameBoard extends JPanel { this.board = board; setLayout(new BorderLayout()); - // Timer-Label oben hinzufügen - timerLabel = new JLabel("Zeit: 0 Sekunden"); - timerLabel.setHorizontalAlignment(SwingConstants.CENTER); - Setup.styleLabel(timerLabel); - add(timerLabel, BorderLayout.NORTH); + // Timer-Label hinzufügen + initializeTimerLabel(); // Timer starten startTimer(); @@ -43,6 +38,13 @@ public class GameBoard extends JPanel { add(controlPanel, BorderLayout.SOUTH); } + private void initializeTimerLabel() { + timerLabel = new JLabel("Zeit: 0 Sekunden"); + timerLabel.setHorizontalAlignment(SwingConstants.CENTER); + Setup.styleLabel(timerLabel); + add(timerLabel, BorderLayout.NORTH); + } + private void startTimer() { startTime = System.currentTimeMillis(); timer = new Timer(1000, e -> { @@ -61,13 +63,25 @@ public class GameBoard extends JPanel { private JPanel createControlPanel() { JPanel controlPanel = new JPanel(); + controlPanel.add(createResetButton()); + controlPanel.add(createUndoButton()); + controlPanel.add(createRedoButton()); + controlPanel.add(createValidateButton()); + controlPanel.add(createPauseButton()); + + return controlPanel; + } + + private JButton createResetButton() { JButton resetButton = Setup.createGameBoardButton("Zurücksetzen", 150, 30); resetButton.addActionListener(e -> { saveStateForUndo(); resetBoard(); - //refreshBoard(); }); + return resetButton; + } + private JButton createUndoButton() { JButton undoButton = Setup.createGameBoardButton("Undo", 80, 30); undoButton.addActionListener(e -> { int[][] previousState = stateManager.undo(board.getNumbers()); @@ -78,49 +92,64 @@ public class GameBoard extends JPanel { JOptionPane.showMessageDialog(this, "Kein Zustand zum Zurücksetzen vorhanden.", "Undo", JOptionPane.INFORMATION_MESSAGE); } }); + return undoButton; + } + private JButton createRedoButton() { JButton redoButton = Setup.createGameBoardButton("Redo", 80, 30); redoButton.addActionListener(e -> { int[][] nextState = stateManager.redo(board.getNumbers()); if (nextState != null) { board.setNumbers(nextState); - refreshBoard(); + updateBoard(); } else { JOptionPane.showMessageDialog(this, "Kein Zustand zum Wiederholen vorhanden.", "Redo", JOptionPane.INFORMATION_MESSAGE); } }); + return redoButton; + } + private JButton createValidateButton() { JButton validateButton = Setup.createGameBoardButton("Lösen", 80, 30); validateButton.addActionListener(e -> { if (validateCurrentBoard()) { stopTimer(); - JOptionPane.showMessageDialog(this, "Das Spielfeld ist korrekt gelöst!", "Erfolg", JOptionPane.INFORMATION_MESSAGE); + handleHighscore(); } else { JOptionPane.showMessageDialog(this, "Das Spielfeld enthält Fehler!", "Fehler", JOptionPane.ERROR_MESSAGE); } }); + return validateButton; + } + private JButton createPauseButton() { JButton pauseButton = Setup.createGameBoardButton("Pause", 80, 30); pauseButton.addActionListener(e -> { stopTimer(); showPauseMenu(); }); - - controlPanel.add(resetButton); - controlPanel.add(undoButton); - controlPanel.add(redoButton); - controlPanel.add(validateButton); - controlPanel.add(pauseButton); - - return controlPanel; + return pauseButton; } - public boolean validateCurrentBoard() { HitoriValidator validator = new HitoriValidator(board); return validator.validateBoard(board.getSolutionCoordinates()); } + private void handleHighscore() { + int elapsedTime = (int) ((System.currentTimeMillis() - startTime) / 1000); + String boardName = board.getBoardName(); + + HighscoreManager manager = new HighscoreManager(); + boolean isNewHighscore = manager.isNewHighscore(elapsedTime, boardName); + + if (isNewHighscore) { + addHighscore(elapsedTime, boardName); + } else { + JOptionPane.showMessageDialog(this, "Das Spielfeld ist korrekt gelöst!", "Erfolg", JOptionPane.INFORMATION_MESSAGE); + } + } + private void showPauseMenu() { PauseMenu pauseMenu = new PauseMenu( (JFrame) SwingUtilities.getWindowAncestor(this), @@ -146,30 +175,27 @@ public class GameBoard extends JPanel { 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) { - cell.setState(HitoriCell.CellState.WHITE); - } else { - cell.setState(HitoriCell.CellState.GRAY); + switch (cell.getState()) { + case GRAY -> cell.setState(HitoriCell.CellState.BLACK); + case BLACK -> cell.setState(HitoriCell.CellState.WHITE); + case WHITE -> cell.setState(HitoriCell.CellState.GRAY); } } private void updateButtonState(JButton button, HitoriCell cell) { switch (cell.getState()) { - case GRAY: + case GRAY -> { button.setBackground(Color.LIGHT_GRAY); button.setText(String.valueOf(cell.getNumber())); - break; - case BLACK: + } + case BLACK -> { button.setBackground(Color.BLACK); button.setForeground(Color.WHITE); - break; - case WHITE: + } + case WHITE -> { button.setBackground(Color.WHITE); - button.setText(String.valueOf(cell.getNumber())); button.setForeground(Color.BLACK); - break; + } } } @@ -177,41 +203,23 @@ public class GameBoard extends JPanel { stateManager.saveState(board.getNumbers()); } - private void addHighscore() { + private void addHighscore(int elapsedTime, String boardName) { String playerName = JOptionPane.showInputDialog(this, - "Bitte geben Sie Ihren Namen ein:", + "Neuer Highscore! Bitte Namen eingeben:", "Highscore speichern", JOptionPane.PLAIN_MESSAGE); - if (playerName == null || playerName.trim().isEmpty()) { - JOptionPane.showMessageDialog(this, - "Highscore wurde nicht gespeichert. Kein Name eingegeben.", - "Info", - JOptionPane.INFORMATION_MESSAGE); - return; - } + if (playerName == null || playerName.trim().isEmpty()) return; - int elapsedTime = (int) ((System.currentTimeMillis() - startTime) / 1000); + HighscoreManager manager = new HighscoreManager(); + manager.addHighscore(playerName, elapsedTime, boardName); - String boardName = board.getBoardName(); - - try { - HighscoreManager manager = new HighscoreManager(); - manager.addHighscore(playerName, elapsedTime, boardName); - - JOptionPane.showMessageDialog(this, - "Highscore erfolgreich gespeichert!", - "Erfolg", - JOptionPane.INFORMATION_MESSAGE); - } catch (Exception e) { - JOptionPane.showMessageDialog(this, - "Fehler beim Speichern des Highscores: " + e.getMessage(), - "Fehler", - JOptionPane.ERROR_MESSAGE); - } + JOptionPane.showMessageDialog(this, + "Highscore erfolgreich gespeichert!", + "Erfolg", + JOptionPane.INFORMATION_MESSAGE); } - private void returnToMainMenu() { /// Eltern-Frame abrufen JFrame parentFrame = (JFrame) SwingUtilities.getWindowAncestor(this); @@ -240,10 +248,8 @@ public class GameBoard extends JPanel { 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) { @@ -251,7 +257,6 @@ public class GameBoard extends JPanel { } add(createControlPanel(), BorderLayout.SOUTH); } - // Oberfläche aktualisieren revalidate(); repaint(); diff --git a/Hitori/src/main/java/PR2/HitoriSpiel/GUI/HighscoreDialog.java b/Hitori/src/main/java/PR2/HitoriSpiel/GUI/HighscoreDialog.java index ce64491..6ae2412 100644 --- a/Hitori/src/main/java/PR2/HitoriSpiel/GUI/HighscoreDialog.java +++ b/Hitori/src/main/java/PR2/HitoriSpiel/GUI/HighscoreDialog.java @@ -6,7 +6,9 @@ import PR2.HitoriSpiel.Utils.Setup; import javax.swing.table.DefaultTableModel; import javax.swing.*; import java.awt.*; +import java.util.Comparator; import java.util.List; +import java.util.concurrent.atomic.AtomicInteger; // aktueller Stand public class HighscoreDialog extends JDialog { @@ -16,11 +18,11 @@ public class HighscoreDialog extends JDialog { public HighscoreDialog(JFrame parentFrame) { super(parentFrame, "Highscoreliste", true); - this.highscoreManager = new HighscoreManager(); - - setLayout(new BorderLayout()); - setSize(500, 400); + setSize(600, 400); setLocationRelativeTo(parentFrame); + + this.highscoreManager = new HighscoreManager(); + setLayout(new BorderLayout()); Setup.stylePanel((JPanel) getContentPane()); // Hintergrundfarbe setzen JLabel titleLabel = new JLabel("Highscores", SwingConstants.CENTER); @@ -28,7 +30,7 @@ public class HighscoreDialog extends JDialog { Setup.styleLabel(titleLabel); // Schriftstil setzen add(titleLabel, BorderLayout.NORTH); - String[] columnNames = {"Name", "Punkte", "Spielfeld"}; + String[] columnNames = {"Platz", "Name", "Zeit (Sek.)", "Spielfeld"}; tableModel = new DefaultTableModel(columnNames, 0); JTable highscoreTable = new JTable(tableModel); highscoreTable.setFillsViewportHeight(true); @@ -36,14 +38,34 @@ public class HighscoreDialog extends JDialog { JScrollPane scrollPane = new JScrollPane(highscoreTable); add(scrollPane, BorderLayout.CENTER); - // Schließen-Button - JButton closeButton = Setup.createButton("Schließen", 120, 40); - closeButton.setFont(new Font(closeButton.getFont().getName(), closeButton.getFont().getStyle(), 14)); // Schriftgröße ändern - closeButton.addActionListener(e -> dispose()); - JPanel buttonPanel = new JPanel(); - Setup.stylePanel(buttonPanel); // Hintergrundstil setzen + + // Schließen-Button + JButton closeButton = Setup.createButton("Schließen", 200, 40); + closeButton.setFont(new Font(closeButton.getFont().getName(), closeButton.getFont().getStyle(), 18)); // Schriftgröße ändern + closeButton.addActionListener(e -> dispose()); buttonPanel.add(closeButton); + + // Button zum Löschen aller Einträge + JButton clearButton = Setup.createButton("Einträge löschen", 200, 40); + clearButton.setFont(new Font(closeButton.getFont().getName(), closeButton.getFont().getStyle(), 18)); + clearButton.addActionListener(e -> { + int confirmation = JOptionPane.showConfirmDialog( + this, + "Möchten Sie wirklich alle Highscores löschen?", + "Highscores löschen", + JOptionPane.YES_NO_OPTION + ); + + if (confirmation == JOptionPane.YES_OPTION) { + highscoreManager.clearHighscores(); + loadHighscores(); // Tabelle aktualisieren + JOptionPane.showMessageDialog(this, "Alle Highscores wurden gelöscht."); + } + }); + buttonPanel.add(clearButton); + + Setup.stylePanel(buttonPanel); // Hintergrundstil setzen add(buttonPanel, BorderLayout.SOUTH); // Highscores laden @@ -54,13 +76,17 @@ public class HighscoreDialog extends JDialog { tableModel.setRowCount(0); // Tabelle zurücksetzen List highscores = highscoreManager.getHighscores(); - highscores.stream() - .sorted((a, b) -> Integer.compare(b.getScore(), a.getScore())) // Sortierung: Höchste Punkte zuerst - .forEach(highscore -> tableModel.addRow(new Object[]{ - highscore.getPlayerName(), - highscore.getScore(), - highscore.getBoardName() - })); + highscores.sort(Comparator.comparingInt(HighscoreManager.Highscore::getScore)); // Sortierung: Kürzeste Zeit zuerst + + int rank = 1; // Platznummer + for (HighscoreManager.Highscore highscore : highscores) { + tableModel.addRow(new Object[]{ + rank++, // Platznummer hochzählen + highscore.getPlayerName(), // Name des Spielers + highscore.getScore(), // Zeit in Sekunden + highscore.getBoardName() // Name des Spielfelds + }); + } } public void refreshHighscores() { diff --git a/Hitori/src/main/java/PR2/HitoriSpiel/Utils/HighscoreManager.java b/Hitori/src/main/java/PR2/HitoriSpiel/Utils/HighscoreManager.java index b2cc067..5f8ea85 100644 --- a/Hitori/src/main/java/PR2/HitoriSpiel/Utils/HighscoreManager.java +++ b/Hitori/src/main/java/PR2/HitoriSpiel/Utils/HighscoreManager.java @@ -19,17 +19,47 @@ public class HighscoreManager { } // Highscore hinzufügen - public synchronized void addHighscore(String playerName, int score, String boardName) { + public synchronized void addHighscore(String playerName, int time, String boardName) { fileLock.lock(); try { - highscoreList.add(new Highscore(playerName, score, boardName)); - highscoreList.sort(Comparator.comparingInt(Highscore::getScore).reversed()); // Sortierung absteigend - saveHighscores(); + // Prüfe, ob es bereits Highscores für das Spielfeld gibt + boolean isShorterTime = highscoreList.stream() + .filter(highscore -> highscore.getBoardName().equals(boardName)) + .allMatch(highscore -> time < highscore.getScore()); + + if (isShorterTime) { + // Entferne alle Highscores für das Spielfeld, die länger oder gleich sind + highscoreList.removeIf(highscore -> highscore.getBoardName().equals(boardName)); + + // Füge den neuen Highscore hinzu + highscoreList.add(new Highscore(playerName, time, boardName)); + + // Sortiere die Liste + highscoreList.sort(Comparator.comparingInt(Highscore::getScore)); // Kürzeste Zeit zuerst + saveHighscores(); + } else { + System.out.println("Neuer Highscore ist nicht kürzer als die bestehenden Einträge."); + } } finally { fileLock.unlock(); } } + // Neue Methode: Überprüfung, ob ein neuer Highscore erreicht wurde + public boolean isNewHighscore(int elapsedTime, String boardName) { + List highscores = getHighscores(); + + // Prüfen, ob das Board bereits einen Highscore-Eintrag hat + for (Highscore highscore : highscores) { + if (highscore.getBoardName().equals(boardName)) { + return elapsedTime < highscore.getScore(); // Neuer Highscore, wenn Zeit besser ist + } + } + + // Wenn das Board keinen Highscore hat, ist dies der erste Eintrag + return true; + } + // Highscores laden private void loadHighscores() { fileLock.lock(); @@ -68,17 +98,15 @@ public class HighscoreManager { // Highscores abrufen public List getHighscores() { - return Collections.unmodifiableList(highscoreList); + return new ArrayList<>(highscoreList); // Modifizierbare Kopie zurückgeben } - - // Alte Highscores bereinigen - public void cleanOldHighscores(int maxEntries) { + + // Löscht alle Highscores + public void clearHighscores() { fileLock.lock(); try { - if (highscoreList.size() > maxEntries) { - highscoreList.subList(maxEntries, highscoreList.size()).clear(); - saveHighscores(); - } + highscoreList.clear(); // Liste leeren + saveHighscores(); // Datei aktualisieren } finally { fileLock.unlock(); } @@ -107,7 +135,7 @@ public class HighscoreManager { public String getBoardName() { return boardName; } - } + } diff --git a/Hitori/src/main/resources/Files/highscores.txt b/Hitori/src/main/resources/Files/highscores.txt index e55f47d..9d2c76f 100644 --- a/Hitori/src/main/resources/Files/highscores.txt +++ b/Hitori/src/main/resources/Files/highscores.txt @@ -1,3 +1 @@ -Name, Zeit (Sekunden), Spielfeld - -NameTest, 123 Sekunden, Hitori4x4_leicht.csv \ No newline at end of file +ame, Zeit (Sekunden), Spielfeld