Redo/Undo Logik implementiert
parent
dcf9c95a99
commit
75f04b51cc
|
@ -0,0 +1,63 @@
|
|||
package PR2.HitoriSpiel.Domain;
|
||||
|
||||
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
|
||||
|
||||
public Action(int row, int col, String oldState, String newState) {
|
||||
this.row = row;
|
||||
this.col = col;
|
||||
this.oldState = oldState;
|
||||
this.newState = newState;
|
||||
}
|
||||
|
||||
// Alternative Konstruktor für Standardwerte
|
||||
public Action(int row, int col, String newState) {
|
||||
this(row, col, "GRAY", newState);
|
||||
}
|
||||
|
||||
public int getRow() {
|
||||
return row;
|
||||
}
|
||||
|
||||
public int getCol() {
|
||||
return col;
|
||||
}
|
||||
|
||||
public String getOldState() {
|
||||
return oldState;
|
||||
}
|
||||
|
||||
public String getNewState() {
|
||||
return newState;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return row + "," + col + "," + oldState + "," + newState;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (this == o) return true;
|
||||
if (o == null || getClass() != o.getClass()) return false;
|
||||
|
||||
Action action = (Action) o;
|
||||
|
||||
return row == action.row &&
|
||||
col == action.col &&
|
||||
oldState.equals(action.oldState) &&
|
||||
newState.equals(action.newState);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
int result = row;
|
||||
result = 31 * result + col;
|
||||
result = 31 * result + oldState.hashCode();
|
||||
result = 31 * result + newState.hashCode();
|
||||
return result;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,83 @@
|
|||
package PR2.HitoriSpiel.Domain;
|
||||
|
||||
import java.io.*;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.nio.file.Paths;
|
||||
import java.util.Stack;
|
||||
|
||||
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
|
||||
private static void ensureFileExists() {
|
||||
try {
|
||||
// Erstellt den Ordner, falls er nicht existiert
|
||||
Path directoryPath = Paths.get(BASE_DIR);
|
||||
if (!Files.exists(directoryPath)) {
|
||||
Files.createDirectories(directoryPath);
|
||||
System.out.println("Ordner erstellt: " + BASE_DIR);
|
||||
}
|
||||
|
||||
// Erstellt die Datei, falls sie nicht existiert
|
||||
Path filePath = Paths.get(FILE_NAME);
|
||||
if (!Files.exists(filePath)) {
|
||||
Files.createFile(filePath);
|
||||
System.out.println("Datei erstellt: " + FILE_NAME);
|
||||
}
|
||||
} catch (IOException e) {
|
||||
System.err.println("Fehler beim Erstellen von Ordner oder Datei: " + e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
// Speichert den Zustand in der Datei
|
||||
public static void saveState(Stack<Action> undoStack, Stack<Action> redoStack) {
|
||||
ensureFileExists(); // Stellt sicher, dass die Datei existiert
|
||||
try (BufferedWriter writer = new BufferedWriter(new FileWriter(FILE_NAME))) {
|
||||
writer.write("UNDO"); // Kennzeichnung für Undo-Stack
|
||||
writer.newLine();
|
||||
for (Action action : undoStack) {
|
||||
writer.write(action.toString());
|
||||
writer.newLine();
|
||||
}
|
||||
|
||||
writer.write("REDO"); // Kennzeichnung für Redo-Stack
|
||||
writer.newLine();
|
||||
for (Action action : redoStack) {
|
||||
writer.write(action.toString());
|
||||
writer.newLine();
|
||||
}
|
||||
} catch (IOException e) {
|
||||
System.err.println("Fehler beim Speichern der Zustände: " + e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
// Lädt den Zustand aus der Datei
|
||||
public static void loadState(Stack<Action> undoStack, Stack<Action> redoStack) {
|
||||
ensureFileExists(); // Stellt sicher, dass die Datei existiert
|
||||
try (BufferedReader reader = new BufferedReader(new FileReader(FILE_NAME))) {
|
||||
String line;
|
||||
Stack<Action> currentStack = undoStack; // Standard: Undo-Stack
|
||||
while ((line = reader.readLine()) != null) {
|
||||
if (line.equals("UNDO")) {
|
||||
currentStack = undoStack;
|
||||
} else if (line.equals("REDO")) {
|
||||
currentStack = redoStack;
|
||||
} else {
|
||||
String[] parts = line.split(",");
|
||||
int row = Integer.parseInt(parts[0]);
|
||||
int col = Integer.parseInt(parts[1]);
|
||||
String oldState = parts[2];
|
||||
String newState = parts[3];
|
||||
currentStack.push(new Action(row, col, oldState, newState));
|
||||
}
|
||||
}
|
||||
} catch (FileNotFoundException e) {
|
||||
System.out.println("Keine Undo/Redo-Datei gefunden. Es werden leere Stacks verwendet.");
|
||||
} catch (IOException e) {
|
||||
System.err.println("Fehler beim Laden der Zustände: " + e.getMessage());
|
||||
}
|
||||
}
|
||||
}
|
|
@ -4,74 +4,37 @@ import java.io.*;
|
|||
import java.util.Stack;
|
||||
|
||||
public class StateManager implements Serializable {
|
||||
private final Stack<int[][]> undoStack = new Stack<>();
|
||||
private final Stack<int[][]> redoStack = new Stack<>();
|
||||
private final Stack<Action> undoStack = new Stack<>();
|
||||
private final Stack<Action> redoStack = new Stack<>();
|
||||
|
||||
public void saveState(int[][] state) {
|
||||
undoStack.push(copyState(state));
|
||||
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
|
||||
}
|
||||
|
||||
// Macht die letzte Änderung rückgängig
|
||||
public int[][] undo(int[][] currentState) {
|
||||
public Action undo() {
|
||||
if (!undoStack.isEmpty()) {
|
||||
redoStack.push(copyState(currentState)); // Speichere aktuellen Zustand für Redo
|
||||
return undoStack.pop(); // Gib den vorherigen Zustand zurück
|
||||
Action action = undoStack.pop();
|
||||
redoStack.push(action);
|
||||
StateFileManager.saveState(undoStack, redoStack); // Aktuellen Zustand speichern
|
||||
return action;
|
||||
}
|
||||
return null; // Kein Zustand mehr verfügbar
|
||||
return null;
|
||||
}
|
||||
|
||||
// Wiederholt die letzte rückgängig gemachte Änderung
|
||||
public int[][] redo(int[][] currentState) {
|
||||
public Action redo() {
|
||||
if (!redoStack.isEmpty()) {
|
||||
undoStack.push(copyState(currentState)); // Speichere aktuellen Zustand für Undo
|
||||
return redoStack.pop(); // Gib den Redo-Zustand zurück
|
||||
Action action = redoStack.pop();
|
||||
undoStack.push(action);
|
||||
StateFileManager.saveState(undoStack, redoStack); // Aktuellen Zustand speichern
|
||||
return action;
|
||||
}
|
||||
return null; // Kein Zustand verfügbar
|
||||
return null;
|
||||
}
|
||||
|
||||
// Hilfsmethode, um eine Kopie des Zustands zu erstellen
|
||||
private int[][] copyState(int[][] state) {
|
||||
int[][] copy = new int[state.length][state[0].length];
|
||||
for (int i = 0; i < state.length; i++) {
|
||||
System.arraycopy(state[i], 0, copy[i], 0, state[i].length);
|
||||
}
|
||||
return copy;
|
||||
}
|
||||
|
||||
// Speichert die gesamte StateManager-Instanz in einer Datei
|
||||
public void saveStateToFile() {
|
||||
try (ObjectOutputStream out = new ObjectOutputStream(new FileOutputStream("undoRedoState.dat"))) {
|
||||
out.writeObject(undoStack); // Schreibe den Undo-Stack
|
||||
out.writeObject(redoStack); // Schreibe den Redo-Stack
|
||||
System.out.println("Zustände wurden erfolgreich gespeichert.");
|
||||
} catch (IOException e) {
|
||||
System.err.println("Fehler beim Speichern der Zustände: " + e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
// Lädt den StateManager aus einer Datei
|
||||
public static StateManager loadStateFromFile() {
|
||||
try (ObjectInputStream in = new ObjectInputStream(new FileInputStream("undoRedoState.dat"))) {
|
||||
StateManager stateManager = new StateManager();
|
||||
stateManager.undoStack.addAll((Stack<int[][]>) in.readObject());
|
||||
stateManager.redoStack.addAll((Stack<int[][]>) in.readObject());
|
||||
System.out.println("Zustände wurden erfolgreich geladen.");
|
||||
return stateManager;
|
||||
} catch (IOException | ClassNotFoundException e) {
|
||||
System.err.println("Fehler beim Laden der Zustände: " + e.getMessage());
|
||||
return new StateManager(); // Gibt eine neue Instanz zurück, falls ein Fehler auftritt
|
||||
}
|
||||
}
|
||||
|
||||
// Überprüft, ob Undo-Operationen verfügbar sind
|
||||
public boolean canUndo() {
|
||||
return !undoStack.isEmpty();
|
||||
}
|
||||
|
||||
// Überprüft, ob Redo-Operationen verfügbar sind
|
||||
public boolean canRedo() {
|
||||
return !redoStack.isEmpty();
|
||||
|
||||
public void loadStateFromFile() {
|
||||
StateFileManager.loadState(undoStack, redoStack); // Stacks aus Datei laden
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
package PR2.HitoriSpiel.GUI;
|
||||
|
||||
import PR2.HitoriSpiel.Domain.Action;
|
||||
import PR2.HitoriSpiel.Domain.HitoriValidator;
|
||||
import PR2.HitoriSpiel.Domain.StateManager;
|
||||
import PR2.HitoriSpiel.Domain.HitoriBoard;
|
||||
|
@ -75,7 +76,7 @@ public class GameBoard extends JPanel {
|
|||
private JButton createResetButton() {
|
||||
JButton resetButton = Setup.createGameBoardButton("Zurücksetzen", 150, 30);
|
||||
resetButton.addActionListener(e -> {
|
||||
saveStateForUndo();
|
||||
//saveStateForUndo();
|
||||
resetBoard();
|
||||
});
|
||||
return resetButton;
|
||||
|
@ -84,24 +85,29 @@ public class GameBoard extends JPanel {
|
|||
private JButton createUndoButton() {
|
||||
JButton undoButton = Setup.createGameBoardButton("Undo", 80, 30);
|
||||
undoButton.addActionListener(e -> {
|
||||
int[][] previousState = stateManager.undo(board.getNumbers());
|
||||
if (previousState != null) {
|
||||
board.setNumbers(previousState);
|
||||
updateBoard();
|
||||
Action action = stateManager.undo();
|
||||
if (action != null) {
|
||||
HitoriCell cell = board.getCell(action.getRow(), action.getCol());
|
||||
cell.setState(HitoriCell.CellState.valueOf(action.getOldState()));
|
||||
JButton button = (JButton) gamePanel.getComponent(action.getRow() * board.getSize() + action.getCol());
|
||||
updateButtonState(button, cell);
|
||||
} else {
|
||||
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);
|
||||
updateBoard();
|
||||
Action action = stateManager.redo();
|
||||
if (action != null) {
|
||||
HitoriCell cell = board.getCell(action.getRow(), action.getCol());
|
||||
cell.setState(HitoriCell.CellState.valueOf(action.getNewState()));
|
||||
JButton button = (JButton) gamePanel.getComponent(action.getRow() * board.getSize() + action.getCol());
|
||||
updateButtonState(button, cell);
|
||||
} else {
|
||||
JOptionPane.showMessageDialog(this, "Kein Zustand zum Wiederholen vorhanden.", "Redo", JOptionPane.INFORMATION_MESSAGE);
|
||||
}
|
||||
|
@ -164,45 +170,62 @@ public class GameBoard extends JPanel {
|
|||
JButton button = new JButton(String.valueOf(cell.getNumber()));
|
||||
button.setBackground(Color.LIGHT_GRAY);
|
||||
button.addActionListener(e -> {
|
||||
toggleCellState(cell);
|
||||
toggleCellState(cell, row, col);
|
||||
updateButtonState(button, cell);
|
||||
});
|
||||
return button;
|
||||
}
|
||||
|
||||
private void toggleCellState(HitoriCell cell) {
|
||||
private void toggleCellState(HitoriCell cell, int row, int col) {
|
||||
if (cell == null) {
|
||||
System.err.println("Ungültige Zelle! Der Zustand kann nicht geändert werden.");
|
||||
return;
|
||||
}
|
||||
String oldState = cell.getState().toString();
|
||||
String newState;
|
||||
|
||||
switch (cell.getState()) {
|
||||
case GRAY -> cell.setState(HitoriCell.CellState.BLACK);
|
||||
case BLACK -> cell.setState(HitoriCell.CellState.WHITE);
|
||||
case WHITE -> cell.setState(HitoriCell.CellState.GRAY);
|
||||
case GRAY -> {
|
||||
cell.setState(HitoriCell.CellState.BLACK);
|
||||
newState = HitoriCell.CellState.BLACK.toString();
|
||||
}
|
||||
case BLACK -> {
|
||||
cell.setState(HitoriCell.CellState.WHITE);
|
||||
newState = HitoriCell.CellState.WHITE.toString();
|
||||
}
|
||||
case WHITE -> {
|
||||
cell.setState(HitoriCell.CellState.GRAY);
|
||||
newState = HitoriCell.CellState.GRAY.toString();
|
||||
}
|
||||
default -> throw new IllegalStateException("Unerwarteter Zustand: " + cell.getState());
|
||||
}
|
||||
|
||||
stateManager.saveAction(row, col, oldState, newState);
|
||||
|
||||
// Debug-Ausgabe
|
||||
System.out.println("Aktion gespeichert: " + oldState + " -> " + newState);
|
||||
}
|
||||
|
||||
private void updateButtonState(JButton button, HitoriCell cell) {
|
||||
switch (cell.getState()) {
|
||||
case GRAY -> {
|
||||
button.setBackground(Color.LIGHT_GRAY);
|
||||
button.setText(String.valueOf(cell.getNumber()));
|
||||
button.setBackground(Color.LIGHT_GRAY); // Hintergrund grau
|
||||
button.setForeground(Color.BLACK); // Textfarbe schwarz
|
||||
button.setText(String.valueOf(cell.getNumber())); // Zeigt die Zahl an
|
||||
}
|
||||
case BLACK -> {
|
||||
button.setBackground(Color.BLACK);
|
||||
button.setForeground(Color.WHITE);
|
||||
button.setBackground(Color.BLACK); // Hintergrund schwarz
|
||||
button.setForeground(Color.WHITE); // Textfarbe weiß
|
||||
button.setText(String.valueOf(cell.getNumber())); // Zeigt die Zahl an
|
||||
}
|
||||
case WHITE -> {
|
||||
button.setBackground(Color.WHITE);
|
||||
button.setForeground(Color.BLACK);
|
||||
button.setBackground(Color.WHITE); // Hintergrund weiß
|
||||
button.setForeground(Color.BLACK); // Textfarbe schwarz
|
||||
button.setText(String.valueOf(cell.getNumber())); // Zeigt die Zahl an
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void saveStateForUndo() {
|
||||
stateManager.saveState(board.getNumbers());
|
||||
}
|
||||
|
||||
private void addHighscore(int elapsedTime, String boardName) {
|
||||
String playerName = JOptionPane.showInputDialog(this,
|
||||
"Neuer Highscore! Bitte Namen eingeben:",
|
||||
|
@ -306,10 +329,10 @@ public class GameBoard extends JPanel {
|
|||
for (int i = 0; i < board.getSize(); i++) {
|
||||
for (int j = 0; j < board.getSize(); j++) {
|
||||
HitoriCell cell = board.getCell(i, j);
|
||||
JButton button = (JButton) gamePanel.getComponent(i * board.getSize() + j); // Hole den Button
|
||||
updateButtonState(button, cell); // Aktualisiere den Button basierend auf dem Zustand
|
||||
JButton button = (JButton) gamePanel.getComponent(i * board.getSize() + j); // Holt den Button
|
||||
updateButtonState(button, cell); // Aktualisiert den Button basierend auf dem Zustand
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
|
|
@ -3,13 +3,11 @@ package PR2.HitoriSpiel.GUI;
|
|||
import PR2.HitoriSpiel.Utils.HighscoreManager;
|
||||
import PR2.HitoriSpiel.Utils.Setup;
|
||||
|
||||
import javax.swing.table.DefaultTableCellRenderer;
|
||||
import javax.swing.table.DefaultTableModel;
|
||||
import javax.swing.*;
|
||||
import java.awt.*;
|
||||
import java.util.Comparator;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.atomic.AtomicInteger;
|
||||
|
||||
// aktueller Stand
|
||||
|
@ -20,11 +18,11 @@ public class HighscoreDialog extends JDialog {
|
|||
|
||||
public HighscoreDialog(JFrame parentFrame) {
|
||||
super(parentFrame, "Highscoreliste", true);
|
||||
this.highscoreManager = new HighscoreManager();
|
||||
|
||||
setLayout(new BorderLayout());
|
||||
setSize(700, 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);
|
||||
|
@ -32,84 +30,46 @@ public class HighscoreDialog extends JDialog {
|
|||
Setup.styleLabel(titleLabel); // Schriftstil setzen
|
||||
add(titleLabel, BorderLayout.NORTH);
|
||||
|
||||
String[] columnNames = {"Platz", "Name", "Zeit (Sek.)", "Spielfeld", "Durchschnittszeit des Spielfelds"};
|
||||
String[] columnNames = {"Platz", "Name", "Zeit (Sek.)", "Spielfeld"};
|
||||
tableModel = new DefaultTableModel(columnNames, 0);
|
||||
JTable highscoreTable = new JTable(tableModel);
|
||||
highscoreTable.setFillsViewportHeight(true);
|
||||
highscoreTable.setEnabled(false); // Tabelle nur zur Anzeige
|
||||
|
||||
// Renderer, um Text in der Mitte der Zellen zu platzieren
|
||||
DefaultTableCellRenderer centerRenderer = new DefaultTableCellRenderer();
|
||||
centerRenderer.setHorizontalAlignment(SwingConstants.CENTER);
|
||||
|
||||
for (int i = 0; i < highscoreTable.getColumnCount(); i++) {
|
||||
highscoreTable.getColumnModel().getColumn(i).setCellRenderer(centerRenderer);
|
||||
}
|
||||
|
||||
// Automatische Spaltenbreitenanpassung und individuelle Breiten setzen
|
||||
highscoreTable.setAutoResizeMode(JTable.AUTO_RESIZE_OFF);
|
||||
highscoreTable.getColumnModel().getColumn(0).setPreferredWidth(50); // Platz
|
||||
highscoreTable.getColumnModel().getColumn(1).setPreferredWidth(150); // Name
|
||||
highscoreTable.getColumnModel().getColumn(2).setPreferredWidth(100); // Punkte
|
||||
highscoreTable.getColumnModel().getColumn(3).setPreferredWidth(150); // Spielfeld
|
||||
highscoreTable.getColumnModel().getColumn(4).setPreferredWidth(230); // Durchschnittszeit
|
||||
|
||||
JScrollPane scrollPane = new JScrollPane(highscoreTable);
|
||||
add(scrollPane, BorderLayout.CENTER);
|
||||
|
||||
JPanel buttonPanel = new JPanel();
|
||||
|
||||
// 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();
|
||||
loadHighscoresWithAverages(); // Tabelle aktualisieren
|
||||
JOptionPane.showMessageDialog(this, "Alle Highscores wurden gelöscht.");
|
||||
}
|
||||
});
|
||||
buttonPanel.add(clearButton);
|
||||
|
||||
Setup.stylePanel(buttonPanel); // Hintergrundstil setzen
|
||||
add(buttonPanel, BorderLayout.SOUTH);
|
||||
|
||||
// Highscores laden
|
||||
loadHighscoresWithAverages();
|
||||
loadHighscores();
|
||||
}
|
||||
|
||||
private void loadHighscoresWithAverages() {
|
||||
private void loadHighscores() {
|
||||
tableModel.setRowCount(0); // Tabelle zurücksetzen
|
||||
List<HighscoreManager.Highscore> highscores = highscoreManager.getSortedHighscores();
|
||||
Map<String, Double> averageTimes = highscoreManager.getAverageTimesByBoard();
|
||||
List<HighscoreManager.Highscore> highscores = highscoreManager.getHighscores();
|
||||
|
||||
int rank = 1;
|
||||
highscores.sort(Comparator.comparingInt(HighscoreManager.Highscore::getScore)); // Sortierung: Kürzeste Zeit zuerst
|
||||
|
||||
int rank = 1; // Platznummer
|
||||
for (HighscoreManager.Highscore highscore : highscores) {
|
||||
double averageTime = averageTimes.getOrDefault(highscore.getBoardName(), 0.0);
|
||||
tableModel.addRow(new Object[]{
|
||||
rank++, // Platzierung
|
||||
highscore.getPlayerName(), // Name
|
||||
highscore.getScore(), // Punkte
|
||||
highscore.getBoardName(), // Spielfeld
|
||||
String.format("%.2f", averageTime) // Durchschnittszeit
|
||||
rank++, // Platznummer hochzählen
|
||||
highscore.getPlayerName(), // Name des Spielers
|
||||
highscore.getScore(), // Zeit in Sekunden
|
||||
highscore.getBoardName() // Name des Spielfelds
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
public void refreshHighscores() {
|
||||
loadHighscoresWithAverages();
|
||||
loadHighscores();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -19,7 +19,7 @@ public class Main {
|
|||
|
||||
// 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
|
||||
//stateManager.saveStateToFile(); // Speichert die aktuellen Zustände in einer Datei
|
||||
System.out.println("Spielzustände wurden gespeichert.");
|
||||
}));
|
||||
|
||||
|
|
|
@ -1,12 +1,15 @@
|
|||
package PR2.HitoriSpiel.Utils;
|
||||
|
||||
import java.io.*;
|
||||
import java.util.*;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.Comparator;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.locks.ReentrantLock;
|
||||
|
||||
public class HighscoreManager {
|
||||
|
||||
private static final String HIGHSCORE_FILE = "Files/highscores.txt";
|
||||
private static final String HIGHSCORE_FILE = "highscores.txt";
|
||||
private static final ReentrantLock fileLock = new ReentrantLock();
|
||||
// Highscore-Datenstruktur
|
||||
private final List<Highscore> highscoreList = new ArrayList<>();
|
||||
|
@ -44,7 +47,7 @@ public class HighscoreManager {
|
|||
|
||||
// Neue Methode: Überprüfung, ob ein neuer Highscore erreicht wurde
|
||||
public boolean isNewHighscore(int elapsedTime, String boardName) {
|
||||
List<Highscore> highscores = getSortedHighscores();
|
||||
List<Highscore> highscores = getHighscores();
|
||||
|
||||
// Prüfen, ob das Board bereits einen Highscore-Eintrag hat
|
||||
for (Highscore highscore : highscores) {
|
||||
|
@ -60,25 +63,16 @@ public class HighscoreManager {
|
|||
// Highscores laden
|
||||
private void loadHighscores() {
|
||||
fileLock.lock();
|
||||
try (InputStream inputStream = getClass().getClassLoader().getResourceAsStream(HIGHSCORE_FILE)) {
|
||||
if (inputStream == null) {
|
||||
System.out.println("Datei highscores.txt nicht im Classpath gefunden.");
|
||||
return;
|
||||
}
|
||||
|
||||
try (BufferedReader reader = new BufferedReader(new InputStreamReader(inputStream))) {
|
||||
highscoreList.clear(); // Liste zurücksetzen
|
||||
String line;
|
||||
while ((line = reader.readLine()) != null) {
|
||||
String[] parts = line.split(",");
|
||||
if (parts.length == 3) { // Name, Punkte, Spielfeld
|
||||
String playerName = parts[0].trim();
|
||||
int score = Integer.parseInt(parts[1].trim());
|
||||
String boardName = parts[2].trim();
|
||||
highscoreList.add(new Highscore(playerName, score, boardName));
|
||||
}
|
||||
try (BufferedReader reader = new BufferedReader(new FileReader(HIGHSCORE_FILE))) {
|
||||
String line;
|
||||
while ((line = reader.readLine()) != null) {
|
||||
String[] parts = line.split(",");
|
||||
if (parts.length == 3) { // Name, Punkte, Spielfeld
|
||||
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 {
|
||||
|
@ -102,40 +96,11 @@ public class HighscoreManager {
|
|||
}
|
||||
}
|
||||
|
||||
// Highscores abrufen (sortiert nach kürzester Zeit)
|
||||
public List<Highscore> getSortedHighscores() {
|
||||
fileLock.lock();
|
||||
try {
|
||||
highscoreList.sort(Comparator.comparingInt(Highscore::getScore)); // Kürzeste Zeit zuerst
|
||||
return new ArrayList<>(highscoreList); // Kopie der Liste zurückgeben
|
||||
} finally {
|
||||
fileLock.unlock();
|
||||
}
|
||||
// Highscores abrufen
|
||||
public List<Highscore> getHighscores() {
|
||||
return new ArrayList<>(highscoreList); // Modifizierbare Kopie zurückgeben
|
||||
}
|
||||
|
||||
// Durchschnittszeit für jedes Spielfeld berechnen
|
||||
public Map<String, Double> getAverageTimesByBoard() {
|
||||
fileLock.lock();
|
||||
try {
|
||||
Map<String, List<Integer>> boardScores = new HashMap<>();
|
||||
|
||||
for (Highscore highscore : highscoreList) {
|
||||
boardScores.computeIfAbsent(highscore.getBoardName(), k -> new ArrayList<>()).add(highscore.getScore());
|
||||
}
|
||||
|
||||
Map<String, Double> averageTimes = new HashMap<>();
|
||||
for (Map.Entry<String, List<Integer>> entry : boardScores.entrySet()) {
|
||||
List<Integer> scores = entry.getValue();
|
||||
double average = scores.stream().mapToInt(Integer::intValue).average().orElse(0.0);
|
||||
averageTimes.put(entry.getKey(), average);
|
||||
}
|
||||
|
||||
return averageTimes;
|
||||
} finally {
|
||||
fileLock.unlock();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Löscht alle Highscores
|
||||
public void clearHighscores() {
|
||||
fileLock.lock();
|
||||
|
|
Loading…
Reference in New Issue