From 4cb6b128144493a6182606e59151c9a25942a779 Mon Sep 17 00:00:00 2001 From: Vickvick2002 Date: Sun, 5 Jan 2025 13:52:30 +0100 Subject: [PATCH] Code mit Highscoreliste erweitert --- .../PR2/HitoriSpiel/Domain/HitoriBoard.java | 86 +++++++---- .../Domain/HitoriSolutionLoader.java | 40 ++++-- .../java/PR2/HitoriSpiel/GUI/GameBoard.java | 31 ++-- .../PR2/HitoriSpiel/GUI/HighscoreDialog.java | 69 ++++++--- .../java/PR2/HitoriSpiel/GUI/StartMenu.java | 3 +- .../HitoriSpiel/Utils/HighscoreManager.java | 134 ++++++++++++------ 6 files changed, 241 insertions(+), 122 deletions(-) diff --git a/Hitori/src/main/java/PR2/HitoriSpiel/Domain/HitoriBoard.java b/Hitori/src/main/java/PR2/HitoriSpiel/Domain/HitoriBoard.java index ef3dfde..cf0280d 100644 --- a/Hitori/src/main/java/PR2/HitoriSpiel/Domain/HitoriBoard.java +++ b/Hitori/src/main/java/PR2/HitoriSpiel/Domain/HitoriBoard.java @@ -9,25 +9,22 @@ import java.util.List; public class HitoriBoard { private final HitoriCell[][] board; private final List solutionCoordinates; - private int[][] originalBoardData; + private final String boardName; // Name des Spielfelds - public HitoriBoard(int[][] numbers, List solutionCoordinates) { - this.originalBoardData = numbers; // Oginaldaten speichern + + public HitoriBoard(int[][] numbers, List solutionCoordinates, String boardName) { this.board = new HitoriCell[numbers.length][numbers[0].length]; this.solutionCoordinates = solutionCoordinates; + this.boardName = boardName; initializeBoard(numbers); } - public List getSolutionCoordinates() { - return solutionCoordinates; - } - - public HitoriCell[][] getBoard() { - return board; - } - - - private void initializeBoard(int[][] numbers){ + /** + * Initialisiert das Spielfeld mit den übergebenen Zahlen. + * + * @param numbers 2D-Array mit den Zahlen des Spielfelds. + */ + private void initializeBoard(int[][] numbers) { for (int i = 0; i < numbers.length; i++) { for (int j = 0; j < numbers[i].length; j++) { board[i][j] = new HitoriCell(numbers[i][j]); @@ -35,32 +32,60 @@ public class HitoriBoard { } } + /** + * Gibt den Namen des Spielfelds zurück. + * + * @return Name des Spielfelds. + */ + public String getBoardName() { + return boardName; + } + + /** + * Gibt die Lösungskonfiguration des Spielfelds zurück. + * + * @return Liste der Koordinaten, die zur Lösung gehören. + */ + public List getSolutionCoordinates() { + return solutionCoordinates; + } + + /** + * Gibt die HitoriCell an einer bestimmten Position zurück. + * + * @param row Zeile der Zelle. + * @param col Spalte der Zelle. + * @return Die HitoriCell an der angegebenen Position. + */ public HitoriCell getCell(int row, int col) { return board[row][col]; } + /** + * Gibt die Größe des Spielfelds zurück. + * + * @return Anzahl der Zeilen im Spielfeld. + */ public int getSize() { return board.length; } - //Board zurücksetzen zu dem Anfangszustand + /** + * Setzt das Spielfeld zurück, indem alle Zellen in den Standardzustand gesetzt werden. + */ public void resetBoard() { - //initializeBoard(originalBoardData); for (int i = 0; i < board.length; i++) { for (int j = 0; j < board[i].length; j++) { - board[i][j].setState(HitoriCell.CellState.GRAY); // Zurücksetzen - } - } - } - - 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]); + board[i][j].setState(HitoriCell.CellState.GRAY); // Standardzustand } } } + /** + * 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++) { @@ -71,4 +96,17 @@ public class HitoriBoard { 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/HitoriSolutionLoader.java b/Hitori/src/main/java/PR2/HitoriSpiel/Domain/HitoriSolutionLoader.java index d18cf81..99b38dc 100644 --- a/Hitori/src/main/java/PR2/HitoriSpiel/Domain/HitoriSolutionLoader.java +++ b/Hitori/src/main/java/PR2/HitoriSpiel/Domain/HitoriSolutionLoader.java @@ -9,30 +9,42 @@ import java.util.*; public class HitoriSolutionLoader { public static List loadSolution(String resourcePath) throws IOException { - InputStream inputStream = HitoriSolutionLoader.class.getResourceAsStream(resourcePath); - if (inputStream == null) { - throw new IOException("Ressourcendatei nicht gefunden: " + resourcePath); - } - List solutionCoordinates = new ArrayList<>(); - try (BufferedReader reader = new BufferedReader(new InputStreamReader(inputStream))) { - String line; - boolean isSolutionSection = false; + boolean solutionSectionFound = false; + try (InputStream inputStream = HitoriSolutionLoader.class.getResourceAsStream(resourcePath); + BufferedReader reader = new BufferedReader(new InputStreamReader(inputStream))) { + + if (inputStream == null) { + throw new IOException("Ressourcendatei nicht gefunden: " + resourcePath); + } + + String line; while ((line = reader.readLine()) != null) { - // Erkenne den Abschnitt für die Lösung + line = line.trim(); + + // Überprüfen, ob wir im Lösungsteil sind if (line.startsWith("//Lösung")) { - isSolutionSection = true; - continue; // Überspringe die Kommentarzeile + solutionSectionFound = true; + continue; } - if (isSolutionSection) { - solutionCoordinates.add(line.trim()); + if (solutionSectionFound) { + if (line.isEmpty()) { + continue; // Ignoriere leere Zeilen + } + solutionCoordinates.add(line); } } + + if (!solutionSectionFound) { + System.err.println("Warnung: Lösungsteil wurde in der Datei " + resourcePath + " nicht gefunden."); + } + } catch (IOException e) { + System.err.println("Fehler beim Laden der Lösung: " + e.getMessage()); + throw e; } return solutionCoordinates; - } } \ No newline at end of file diff --git a/Hitori/src/main/java/PR2/HitoriSpiel/GUI/GameBoard.java b/Hitori/src/main/java/PR2/HitoriSpiel/GUI/GameBoard.java index e45d4ea..ae83aa3 100644 --- a/Hitori/src/main/java/PR2/HitoriSpiel/GUI/GameBoard.java +++ b/Hitori/src/main/java/PR2/HitoriSpiel/GUI/GameBoard.java @@ -27,6 +27,7 @@ public class GameBoard extends JPanel { // Timer-Label oben hinzufügen timerLabel = new JLabel("Zeit: 0 Sekunden"); timerLabel.setHorizontalAlignment(SwingConstants.CENTER); + Setup.styleLabel(timerLabel); add(timerLabel, BorderLayout.NORTH); // Timer starten @@ -234,13 +235,12 @@ public class GameBoard extends JPanel { } } - private void saveHighscore() { + private void addHighscore() { String playerName = JOptionPane.showInputDialog(this, "Bitte geben Sie Ihren Namen ein:", "Highscore speichern", JOptionPane.PLAIN_MESSAGE); - // Überprüfen, ob ein Name eingegeben wurde if (playerName == null || playerName.trim().isEmpty()) { JOptionPane.showMessageDialog(this, "Highscore wurde nicht gespeichert. Kein Name eingegeben.", @@ -249,22 +249,27 @@ public class GameBoard extends JPanel { return; } - // Berechne die verstrichene Zeit - int elapsedTime = (int) ((System.currentTimeMillis() - startTime) / 1000); // Zeit in Sekunden + int elapsedTime = (int) ((System.currentTimeMillis() - startTime) / 1000); - // Spielfeldname (oder eine Beschreibung) - String boardName = "Aktuelles Spielfeld"; // Falls ein spezifischer Name verfügbar ist, ersetzen + String boardName = board.getBoardName(); - // Speichere den Highscore mit dem HighscoreManager - HighscoreManager.saveHighscore(playerName, elapsedTime, boardName); + try { + HighscoreManager manager = new HighscoreManager(); + manager.addHighscore(playerName, elapsedTime, boardName); - // Zeige eine Bestätigung an - JOptionPane.showMessageDialog(this, - "Highscore erfolgreich gespeichert!", - "Erfolg", - JOptionPane.INFORMATION_MESSAGE); + 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); + } } + private void returnToMainMenu() { /// Eltern-Frame abrufen JFrame parentFrame = (JFrame) SwingUtilities.getWindowAncestor(this); diff --git a/Hitori/src/main/java/PR2/HitoriSpiel/GUI/HighscoreDialog.java b/Hitori/src/main/java/PR2/HitoriSpiel/GUI/HighscoreDialog.java index 8734eeb..ce64491 100644 --- a/Hitori/src/main/java/PR2/HitoriSpiel/GUI/HighscoreDialog.java +++ b/Hitori/src/main/java/PR2/HitoriSpiel/GUI/HighscoreDialog.java @@ -1,6 +1,8 @@ package PR2.HitoriSpiel.GUI; import PR2.HitoriSpiel.Utils.HighscoreManager; +import PR2.HitoriSpiel.Utils.Setup; + import javax.swing.table.DefaultTableModel; import javax.swing.*; import java.awt.*; @@ -9,36 +11,59 @@ import java.util.List; // aktueller Stand public class HighscoreDialog extends JDialog { - public HighscoreDialog(JFrame parent) { - super(parent, "Highscoreliste", true); + private final HighscoreManager highscoreManager; + private final DefaultTableModel tableModel; + + public HighscoreDialog(JFrame parentFrame) { + super(parentFrame, "Highscoreliste", true); + this.highscoreManager = new HighscoreManager(); + + setLayout(new BorderLayout()); setSize(500, 400); - setLocationRelativeTo(parent); + setLocationRelativeTo(parentFrame); + Setup.stylePanel((JPanel) getContentPane()); // Hintergrundfarbe setzen - // Tabelle erstellen - String[] columnNames = {"Name", "Zeit (Sek.)", "Spielfeld"}; - DefaultTableModel tableModel = new DefaultTableModel(columnNames, 0); + JLabel titleLabel = new JLabel("Highscores", SwingConstants.CENTER); + titleLabel.setFont(new Font("Arial", Font.BOLD, 20)); + Setup.styleLabel(titleLabel); // Schriftstil setzen + add(titleLabel, BorderLayout.NORTH); - // Highscores laden - List highscores = HighscoreManager.loadHighscores(); - for (HighscoreManager.Highscore highscore : highscores) { - tableModel.addRow(new Object[]{highscore.getName(), highscore.getTime(), highscore.getBoard()}); - } + String[] columnNames = {"Name", "Punkte", "Spielfeld"}; + tableModel = new DefaultTableModel(columnNames, 0); + JTable highscoreTable = new JTable(tableModel); + highscoreTable.setFillsViewportHeight(true); + highscoreTable.setEnabled(false); // Tabelle nur zur Anzeige + JScrollPane scrollPane = new JScrollPane(highscoreTable); + add(scrollPane, BorderLayout.CENTER); - JTable table = new JTable(tableModel); - table.setEnabled(false); // Tabelle nur lesbar - table.setFillsViewportHeight(true); - - JScrollPane scrollPane = new JScrollPane(table); - - // Button zum Schließen des Dialogs - JButton closeButton = new JButton("Schließen"); + // 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 buttonPanel.add(closeButton); - - setLayout(new BorderLayout()); - add(scrollPane, BorderLayout.CENTER); add(buttonPanel, BorderLayout.SOUTH); + + // Highscores laden + loadHighscores(); + } + + private void loadHighscores() { + 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() + })); + } + + public void refreshHighscores() { + loadHighscores(); } } diff --git a/Hitori/src/main/java/PR2/HitoriSpiel/GUI/StartMenu.java b/Hitori/src/main/java/PR2/HitoriSpiel/GUI/StartMenu.java index a5dd347..c0ae5c2 100644 --- a/Hitori/src/main/java/PR2/HitoriSpiel/GUI/StartMenu.java +++ b/Hitori/src/main/java/PR2/HitoriSpiel/GUI/StartMenu.java @@ -129,9 +129,8 @@ public class StartMenu extends JPanel { int[][] boardData = loadBoard(resourcePath); List solutionCoordinates = HitoriSolutionLoader.loadSolution(resourcePath); - HitoriBoard hitoriBoard = new HitoriBoard(boardData, solutionCoordinates); // Stelle sicher, dass die Lösung korrekt geladen wird + HitoriBoard hitoriBoard = new HitoriBoard(boardData, solutionCoordinates, selectedFile); // Stelle sicher, dass die Lösung korrekt geladen wird GameBoard gameBoard = new GameBoard(hitoriBoard); - //GameBoard gameBoard = new GameBoard(new HitoriBoard(boardData, solutionCoordinates)); loadGameBoard(gameBoard, solutionCoordinates); System.out.println("Ausgewählte Datei: " + selectedFile); diff --git a/Hitori/src/main/java/PR2/HitoriSpiel/Utils/HighscoreManager.java b/Hitori/src/main/java/PR2/HitoriSpiel/Utils/HighscoreManager.java index 1d48908..b2cc067 100644 --- a/Hitori/src/main/java/PR2/HitoriSpiel/Utils/HighscoreManager.java +++ b/Hitori/src/main/java/PR2/HitoriSpiel/Utils/HighscoreManager.java @@ -2,72 +2,112 @@ package PR2.HitoriSpiel.Utils; import java.io.*; import java.util.ArrayList; +import java.util.Collections; import java.util.Comparator; import java.util.List; +import java.util.concurrent.locks.ReentrantLock; -// aktueller Stand public class HighscoreManager { private static final String HIGHSCORE_FILE = "highscores.txt"; + private static final ReentrantLock fileLock = new ReentrantLock(); + // Highscore-Datenstruktur + private final List highscoreList = new ArrayList<>(); - public static class Highscore { - private final String name; - private final int time; - private final String board; + public HighscoreManager() { + loadHighscores(); + } - public Highscore(String name, int time, String board) { - this.name = name; - this.time = time; - this.board = board; - } - - public String getName() { - return name; - } - - public int getTime() { - return time; - } - - public String getBoard() { - return board; + // Highscore hinzufügen + public synchronized void addHighscore(String playerName, int score, String boardName) { + fileLock.lock(); + try { + highscoreList.add(new Highscore(playerName, score, boardName)); + highscoreList.sort(Comparator.comparingInt(Highscore::getScore).reversed()); // Sortierung absteigend + saveHighscores(); + } finally { + fileLock.unlock(); } } - public static List loadHighscores() { - List highscores = new ArrayList<>(); - File file = new File(HIGHSCORE_FILE); - - if (!file.exists()) { - return highscores; - } - - try (BufferedReader reader = new BufferedReader(new FileReader(file))) { + // Highscores laden + private void loadHighscores() { + fileLock.lock(); + try (BufferedReader reader = new BufferedReader(new FileReader(HIGHSCORE_FILE))) { String line; while ((line = reader.readLine()) != null) { - String[] parts = line.split(", "); - if (parts.length == 3) { - String name = parts[0]; - int time = Integer.parseInt(parts[1]); - String board = parts[2]; - highscores.add(new Highscore(name, time, board)); + String[] parts = line.split(","); + if (parts.length == 3) { // Name, Punkte, Spielfeld + highscoreList.add(new Highscore(parts[0], Integer.parseInt(parts[1]), parts[2])); } } - } catch (IOException e) { - e.printStackTrace(); + } catch (FileNotFoundException e) { + System.out.println("Highscore-Datei nicht gefunden. Sie wird nach dem ersten Speichern erstellt."); + } catch (IOException | NumberFormatException e) { + System.err.println("Fehler beim Laden der Highscores: " + e.getMessage()); + } finally { + fileLock.unlock(); } - - // Highscores nach Zeit sortieren (kürzeste Zeit zuerst) - highscores.sort(Comparator.comparingInt(Highscore::getTime)); - return highscores; } - public static void saveHighscore(String name, int time, String board) { - try (BufferedWriter writer = new BufferedWriter(new FileWriter(HIGHSCORE_FILE, true))) { - writer.write(name + ", " + time + ", " + board); - writer.newLine(); + + // Highscores speichern + private void saveHighscores() { + fileLock.lock(); + try (BufferedWriter writer = new BufferedWriter(new FileWriter(HIGHSCORE_FILE))) { + for (Highscore highscore : highscoreList) { + writer.write(highscore.getPlayerName() + "," + highscore.getScore() + "," + highscore.getBoardName()); + writer.newLine(); + } } catch (IOException e) { - e.printStackTrace(); + System.err.println("Fehler beim Speichern der Highscores: " + e.getMessage()); + } finally { + fileLock.unlock(); } } + + // Highscores abrufen + public List getHighscores() { + return Collections.unmodifiableList(highscoreList); + } + + // Alte Highscores bereinigen + public void cleanOldHighscores(int maxEntries) { + fileLock.lock(); + try { + if (highscoreList.size() > maxEntries) { + highscoreList.subList(maxEntries, highscoreList.size()).clear(); + saveHighscores(); + } + } finally { + fileLock.unlock(); + } + } + + // Innere Highscore-Klasse + public static class Highscore { + private final String playerName; + private final int score; + private final String boardName; + + public Highscore(String playerName, int score, String boardName) { + this.playerName = playerName; + this.score = score; + this.boardName = boardName; + } + + public String getPlayerName() { + return playerName; + } + + public int getScore() { + return score; + } + + public String getBoardName() { + return boardName; + } + + } } +