HighscoreLogik verbessert, für jedes Spielfeld

revisionCode
Vickvick2002 2025-01-05 19:45:05 +01:00
parent 75f04b51cc
commit b0f1c46a8c
6 changed files with 196 additions and 105 deletions

View File

@ -28,7 +28,7 @@ public class BoardLoader {
} }
} }
public static List<String> loadBoardsAsList() { /* public static List<String> loadBoardsAsList() {
List<String> boardFiles = new ArrayList<>(); List<String> boardFiles = new ArrayList<>();
try { try {
var resource = BoardLoader.class.getClassLoader().getResource("persistent/Hitori_Spielfelder/"); var resource = BoardLoader.class.getClassLoader().getResource("persistent/Hitori_Spielfelder/");
@ -61,8 +61,52 @@ public class BoardLoader {
System.err.println("Fehler beim Laden der Spielfelder: " + e.getMessage()); System.err.println("Fehler beim Laden der Spielfelder: " + e.getMessage());
} }
return boardFiles; return boardFiles;
}*/
public static List<String> loadBoardsAsList() {
List<String> boardFiles = new ArrayList<>();
try {
// Zugriff auf die Ressource
var resource = BoardLoader.class.getClassLoader().getResource("persistent/Hitori_Spielfelder/");
if (resource == null) {
throw new IOException("Das Verzeichnis 'persistent/Hitori_Spielfelder/' wurde nicht gefunden.");
} }
// Unterscheide zwischen Dateisystem und JAR-Umgebung
if ("file".equals(resource.getProtocol())) {
// Entwicklungsmodus: Zugriff auf das Dateisystem
File directory = new File(resource.toURI());
File[] files = directory.listFiles();
if (files != null) {
for (File file : files) {
if (file.isFile() && file.getName().endsWith(".csv")) {
boardFiles.add(file.getName());
}
}
} else {
System.err.println("Das Verzeichnis ist leer: " + directory.getAbsolutePath());
}
} else if ("jar".equals(resource.getProtocol())) {
// Produktionsmodus: Zugriff im JAR
String path = resource.getPath().substring(5, resource.getPath().indexOf("!")); // JAR-Pfad extrahieren
try (JarFile jar = new JarFile(URLDecoder.decode(path, "UTF-8"))) {
Enumeration<JarEntry> entries = jar.entries();
while (entries.hasMoreElements()) {
String name = entries.nextElement().getName();
if (name.startsWith("persistent/Hitori_Spielfelder/") && name.endsWith(".csv")) {
boardFiles.add(name.substring(name.lastIndexOf("/") + 1));
}
}
}
} else {
throw new IOException("Unbekanntes Protokoll: " + resource.getProtocol());
}
} catch (Exception e) {
System.err.println("Fehler beim Laden der Spielfelder: " + e.getMessage());
}
return boardFiles;
}
public static int[][] loadBoard(String resourcePath) throws IOException { public static int[][] loadBoard(String resourcePath) throws IOException {

View File

@ -143,17 +143,39 @@ public class GameBoard extends JPanel {
} }
private void handleHighscore() { private void handleHighscore() {
int elapsedTime = (int) ((System.currentTimeMillis() - startTime) / 1000); int elapsedTime = (int) ((System.currentTimeMillis() - startTime) / 1000); // Spielzeit in Sekunden
String boardName = board.getBoardName(); String boardName = board.getBoardName();
int errors = 0; // Aktuelle Fehlerzahl (falls vorhanden, muss noch angepasst werden)
HighscoreManager manager = new HighscoreManager(); HighscoreManager manager = new HighscoreManager();
boolean isNewHighscore = manager.isNewHighscore(elapsedTime, boardName); boolean isNewHighscore = manager.isNewHighscore(elapsedTime, boardName);
if (isNewHighscore) { // Zeige ein Dialogfenster zur Namenseingabe
addHighscore(elapsedTime, boardName); String playerName = JOptionPane.showInputDialog(this,
} else { isNewHighscore
JOptionPane.showMessageDialog(this, "Das Spielfeld ist korrekt gelöst!", "Erfolg", JOptionPane.INFORMATION_MESSAGE); ? "Neuer Highscore! Bitte geben Sie Ihren Namen ein:"
: "Das Spielfeld ist korrekt gelöst! Bitte geben Sie Ihren Namen ein:",
"Highscore speichern",
JOptionPane.PLAIN_MESSAGE);
if (playerName == null || playerName.trim().isEmpty()) {
JOptionPane.showMessageDialog(this, "Name wurde nicht eingegeben. Kein Highscore gespeichert.", "Info", JOptionPane.INFORMATION_MESSAGE);
return;
} }
// Speichere den Highscore
manager.addHighscore(playerName, elapsedTime, boardName, errors);
JOptionPane.showMessageDialog(this,
isNewHighscore
? "Glückwunsch! Dein Highscore wurde gespeichert!"
: "Dein Eintrag wurde gespeichert!",
"Highscore",
JOptionPane.INFORMATION_MESSAGE);
// Kehre ins Hauptmenü zurück
returnToMainMenu();
} }
private void showPauseMenu() { private void showPauseMenu() {
@ -226,7 +248,7 @@ public class GameBoard extends JPanel {
} }
} }
private void addHighscore(int elapsedTime, String boardName) { private void addHighscore(int elapsedTime, String boardName, int errors) {
String playerName = JOptionPane.showInputDialog(this, String playerName = JOptionPane.showInputDialog(this,
"Neuer Highscore! Bitte Namen eingeben:", "Neuer Highscore! Bitte Namen eingeben:",
"Highscore speichern", "Highscore speichern",
@ -235,7 +257,7 @@ public class GameBoard extends JPanel {
if (playerName == null || playerName.trim().isEmpty()) return; if (playerName == null || playerName.trim().isEmpty()) return;
HighscoreManager manager = new HighscoreManager(); HighscoreManager manager = new HighscoreManager();
manager.addHighscore(playerName, elapsedTime, boardName); manager.addHighscore(playerName, elapsedTime, boardName, errors);
JOptionPane.showMessageDialog(this, JOptionPane.showMessageDialog(this,
"Highscore erfolgreich gespeichert!", "Highscore erfolgreich gespeichert!",
@ -246,7 +268,6 @@ public class GameBoard extends JPanel {
private void returnToMainMenu() { private void returnToMainMenu() {
/// Eltern-Frame abrufen /// Eltern-Frame abrufen
JFrame parentFrame = (JFrame) SwingUtilities.getWindowAncestor(this); JFrame parentFrame = (JFrame) SwingUtilities.getWindowAncestor(this);
if (parentFrame != null) { if (parentFrame != null) {
// Hauptmenü erstellen und im Frame setzen // Hauptmenü erstellen und im Frame setzen
StartMenu startMenu = new StartMenu(parentFrame); StartMenu startMenu = new StartMenu(parentFrame);

View File

@ -2,27 +2,29 @@ package PR2.HitoriSpiel.GUI;
import PR2.HitoriSpiel.Utils.HighscoreManager; import PR2.HitoriSpiel.Utils.HighscoreManager;
import PR2.HitoriSpiel.Utils.Setup; import PR2.HitoriSpiel.Utils.Setup;
import javax.swing.table.DefaultTableModel; import javax.swing.table.DefaultTableModel;
import javax.swing.*; import javax.swing.*;
import java.awt.*; import java.awt.*;
import java.util.Comparator; import java.util.Comparator;
import java.util.List; import java.util.List;
import java.util.concurrent.atomic.AtomicInteger;
// aktueller Stand // aktueller Stand
public class HighscoreDialog extends JDialog { public class HighscoreDialog extends JDialog {
private final HighscoreManager highscoreManager; private final HighscoreManager highscoreManager;
private final DefaultTableModel tableModel; private final DefaultTableModel tableModel;
private final JComboBox<String> boardSelector;
public HighscoreDialog(JFrame parentFrame) { public HighscoreDialog(JFrame parentFrame, List<String> boardNames) {
super(parentFrame, "Highscoreliste", true); super(parentFrame, "Highscoreliste", true);
setSize(600, 400);
setLocationRelativeTo(parentFrame);
this.highscoreManager = new HighscoreManager(); this.highscoreManager = new HighscoreManager();
this.tableModel = new DefaultTableModel(new String[]{"Platz", "Name", "Zeit (Sek.)", "Fehler", "Spielfeld"}, 0);
setLayout(new BorderLayout()); setLayout(new BorderLayout());
setSize(600, 400);
setLocationRelativeTo(parentFrame);
Setup.stylePanel((JPanel) getContentPane()); // Hintergrundfarbe setzen Setup.stylePanel((JPanel) getContentPane()); // Hintergrundfarbe setzen
JLabel titleLabel = new JLabel("Highscores", SwingConstants.CENTER); JLabel titleLabel = new JLabel("Highscores", SwingConstants.CENTER);
@ -30,12 +32,15 @@ public class HighscoreDialog extends JDialog {
Setup.styleLabel(titleLabel); // Schriftstil setzen Setup.styleLabel(titleLabel); // Schriftstil setzen
add(titleLabel, BorderLayout.NORTH); add(titleLabel, BorderLayout.NORTH);
String[] columnNames = {"Platz", "Name", "Zeit (Sek.)", "Spielfeld"};
tableModel = new DefaultTableModel(columnNames, 0); // Spielfeld-Auswahl (ComboBox)
JTable highscoreTable = new JTable(tableModel); boardSelector = new JComboBox<>(boardNames.toArray(new String[0]));
highscoreTable.setFillsViewportHeight(true); boardSelector.addActionListener(e -> loadHighscoresForBoard((String) boardSelector.getSelectedItem()));
highscoreTable.setEnabled(false); // Tabelle nur zur Anzeige add(boardSelector, BorderLayout.NORTH);
JScrollPane scrollPane = new JScrollPane(highscoreTable);
// Tabelle für Highscores
JTable table = new JTable(tableModel);
JScrollPane scrollPane = new JScrollPane(table);
add(scrollPane, BorderLayout.CENTER); add(scrollPane, BorderLayout.CENTER);
JPanel buttonPanel = new JPanel(); JPanel buttonPanel = new JPanel();
@ -48,28 +53,31 @@ public class HighscoreDialog extends JDialog {
Setup.stylePanel(buttonPanel); // Hintergrundstil setzen Setup.stylePanel(buttonPanel); // Hintergrundstil setzen
add(buttonPanel, BorderLayout.SOUTH); add(buttonPanel, BorderLayout.SOUTH);
// Highscores laden loadHighscoresForBoard(boardNames.get(0));
loadHighscores();
} }
private void loadHighscores() { private void loadHighscoresForBoard(String boardName) {
tableModel.setRowCount(0); // Tabelle zurücksetzen tableModel.setRowCount(0); // Tabelle zurücksetzen
List<HighscoreManager.Highscore> highscores = highscoreManager.getHighscores(); List<HighscoreManager.Highscore> highscores = highscoreManager.getHighscoresForBoard(boardName);
highscores.sort(Comparator.comparingInt(HighscoreManager.Highscore::getScore)); // Sortierung: Kürzeste Zeit zuerst if (highscores.isEmpty()) {
JOptionPane.showMessageDialog(this,
"Keine Highscores für das ausgewählte Spielfeld vorhanden.",
"Info",
JOptionPane.INFORMATION_MESSAGE);
return;
}
int rank = 1; // Platznummer int rank = 1;
for (HighscoreManager.Highscore highscore : highscores) { for (HighscoreManager.Highscore highscore : highscores) {
tableModel.addRow(new Object[]{ tableModel.addRow(new Object[]{
rank++, // Platznummer hochzählen rank++, // Platznummer
highscore.getPlayerName(), // Name des Spielers highscore.getPlayerName(), // Spielername
highscore.getScore(), // Zeit in Sekunden highscore.getTime(), // Zeit in Sekunden
highscore.getBoardName() // Name des Spielfelds highscore.getErrors(), // Anzahl der Fehler
highscore.getBoardName() // Spielfeldname
}); });
} }
} }
public void refreshHighscores() {
loadHighscores();
}
} }

View File

@ -1,5 +1,7 @@
package PR2.HitoriSpiel.GUI; package PR2.HitoriSpiel.GUI;
import PR2.HitoriSpiel.Utils.Setup;
import javax.swing.*; import javax.swing.*;
import java.awt.*; import java.awt.*;
import java.awt.event.ActionListener; import java.awt.event.ActionListener;
@ -13,7 +15,7 @@ public class PauseMenu extends JDialog {
setLocationRelativeTo(parent); setLocationRelativeTo(parent);
// "Spiel fortsetzen"-Button // "Spiel fortsetzen"-Button
JButton resumeButton = new JButton("Spiel fortsetzen"); JButton resumeButton = Setup.createButton("Spiel fortsetzen", 200, 40);
resumeButton.addActionListener(e -> { resumeButton.addActionListener(e -> {
dispose(); dispose();
if (resumeAction != null) { if (resumeAction != null) {
@ -22,7 +24,7 @@ public class PauseMenu extends JDialog {
}); });
// "Zum Hauptmenü"-Button // "Zum Hauptmenü"-Button
JButton mainMenuButton = new JButton("Zum Hauptmenü"); JButton mainMenuButton = Setup.createButton("Zum Hauptmenü", 200, 40);
mainMenuButton.addActionListener(e -> { mainMenuButton.addActionListener(e -> {
dispose(); dispose();
if (mainMenuAction != null) { if (mainMenuAction != null) {
@ -31,7 +33,7 @@ public class PauseMenu extends JDialog {
}); });
// "Spiel beenden"-Button // "Spiel beenden"-Button
JButton exitButton = new JButton("Spiel beenden"); JButton exitButton = Setup.createButton("Spiel beenden", 200, 40);
exitButton.addActionListener(e -> { exitButton.addActionListener(e -> {
dispose(); dispose();
if (exitAction != null) { if (exitAction != null) {

View File

@ -108,7 +108,13 @@ public class StartMenu extends JPanel {
private void highscorelist() { private void highscorelist() {
new HighscoreDialog((JFrame) SwingUtilities.getWindowAncestor(this)).setVisible(true); List<String> boardNames = BoardLoader.loadBoardsAsList(); // Lade die Spielfeldnamen
if (boardNames == null || boardNames.isEmpty()) {
JOptionPane.showMessageDialog(this, "Keine Highscores verfügbar, da keine Spielfelder gefunden wurden.", "Info", JOptionPane.INFORMATION_MESSAGE);
return;
}
new HighscoreDialog((JFrame) SwingUtilities.getWindowAncestor(this), boardNames).setVisible(true);
} }

View File

@ -2,7 +2,6 @@ package PR2.HitoriSpiel.Utils;
import java.io.*; import java.io.*;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator; import java.util.Comparator;
import java.util.List; import java.util.List;
import java.util.concurrent.locks.ReentrantLock; import java.util.concurrent.locks.ReentrantLock;
@ -18,81 +17,82 @@ public class HighscoreManager {
loadHighscores(); loadHighscores();
} }
// Highscore hinzufügen // Prüft, ob die gegebene Zeit ein neuer Highscore ist
public synchronized void addHighscore(String playerName, int time, String boardName) {
fileLock.lock();
try {
// 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) { public boolean isNewHighscore(int elapsedTime, String boardName) {
List<Highscore> highscores = getHighscores(); // Filtere die Highscores für das gegebene Spielfeld
List<Highscore> highscoresForBoard = getHighscoresForBoard(boardName);
// Prüfen, ob das Board bereits einen Highscore-Eintrag hat // Falls es keinen Highscore für das Spielfeld gibt, ist es automatisch ein neuer Highscore
for (Highscore highscore : highscores) { if (highscoresForBoard.isEmpty()) {
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; return true;
} }
// Highscores laden // Finde die kürzeste Zeit im Highscore
private void loadHighscores() { int bestTime = highscoresForBoard.stream()
fileLock.lock(); .mapToInt(Highscore::getTime)
try (BufferedReader reader = new BufferedReader(new FileReader(HIGHSCORE_FILE))) { .min()
String line; .orElse(Integer.MAX_VALUE);
while ((line = reader.readLine()) != null) {
String[] parts = line.split(","); // Überprüfe, ob die aktuelle Zeit besser ist
if (parts.length == 3) { // Name, Punkte, Spielfeld return elapsedTime < bestTime;
highscoreList.add(new Highscore(parts[0], Integer.parseInt(parts[1]), parts[2]));
}
}
} 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();
}
} }
// Highscore hinzufügen
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
public List<Highscore> getHighscoresForBoard(String boardName) {
return highscoreList.stream()
.filter(highscore -> highscore.getBoardName().equals(boardName))
.sorted(Comparator.comparingInt(Highscore::getTime)) // Sortiere nach kürzester Zeit
.limit(10) // Zeige nur die Top 10
.toList();
}
// Highscores speichern // Highscores speichern
private void saveHighscores() { private void saveHighscores() {
fileLock.lock();
try (BufferedWriter writer = new BufferedWriter(new FileWriter(HIGHSCORE_FILE))) { try (BufferedWriter writer = new BufferedWriter(new FileWriter(HIGHSCORE_FILE))) {
for (Highscore highscore : highscoreList) { for (Highscore highscore : highscoreList) {
writer.write(highscore.getPlayerName() + "," + highscore.getScore() + "," + highscore.getBoardName()); writer.write(highscore.toString());
writer.newLine(); writer.newLine();
} }
} catch (IOException e) { } catch (IOException e) {
System.err.println("Fehler beim Speichern der Highscores: " + e.getMessage()); System.err.println("Fehler beim Speichern der Highscores: " + e.getMessage());
} finally { }
fileLock.unlock(); }
// Highscores laden
private void loadHighscores() {
try (BufferedReader reader = new BufferedReader(new FileReader(HIGHSCORE_FILE))) {
String line;
while ((line = reader.readLine()) != null) {
String[] parts = line.split(",");
// Validierung der Datenstruktur
if (parts.length < 4) {
System.err.println("Fehlerhafter Eintrag in Highscore-Datei: " + line);
String[] fixedParts = new String[4];
System.arraycopy(parts, 0, fixedParts, 0, parts.length);
fixedParts[3] = "0"; // Standardwert für fehlende Fehleranzahl
parts = fixedParts;
}
try {
String playerName = parts[0];
int time = Integer.parseInt(parts[1]);
String boardName = parts[2];
int errors = Integer.parseInt(parts[3]);
// Füge den Eintrag der Liste hinzu
highscoreList.add(new Highscore(playerName, time, boardName, errors));
} catch (NumberFormatException e) {
System.err.println("Ungültiges Zahlenformat in Zeile: " + line);
}
}
} catch (IOException e) {
System.out.println("Highscore-Datei nicht gefunden. Eine neue wird erstellt.");
} }
} }
@ -115,27 +115,37 @@ public class HighscoreManager {
// Innere Highscore-Klasse // Innere Highscore-Klasse
public static class Highscore { public static class Highscore {
private final String playerName; private final String playerName;
private final int score; private final int time;
private final String boardName; private final String boardName;
private final int errors;
public Highscore(String playerName, int score, String boardName) { public Highscore(String playerName, int score, String boardName, int errors) {
this.playerName = playerName; this.playerName = playerName;
this.score = score; this.time = score;
this.boardName = boardName; this.boardName = boardName;
this.errors = errors;
} }
public String getPlayerName() { public String getPlayerName() {
return playerName; return playerName;
} }
public int getScore() { public int getTime() {
return score; return time;
} }
public String getBoardName() { public String getBoardName() {
return boardName; return boardName;
} }
public int getErrors() {
return errors;
} }
@Override
public String toString() {
return playerName + "," + time + "," + boardName + "," + errors;
}
}
} }