Compare commits

...

2 Commits

Author SHA1 Message Date
Vickvick2002 3d0f808daf Lösenanzeige verbessert 2025-01-05 14:18:05 +01:00
Vickvick2002 4cb6b12814 Code mit Highscoreliste erweitert 2025-01-05 13:52:30 +01:00
7 changed files with 252 additions and 139 deletions

View File

@ -9,25 +9,22 @@ import java.util.List;
public class HitoriBoard { public class HitoriBoard {
private final HitoriCell[][] board; private final HitoriCell[][] board;
private final List<String> solutionCoordinates; private final List<String> solutionCoordinates;
private int[][] originalBoardData; private final String boardName; // Name des Spielfelds
public HitoriBoard(int[][] numbers, List<String> solutionCoordinates) {
this.originalBoardData = numbers; // Oginaldaten speichern public HitoriBoard(int[][] numbers, List<String> solutionCoordinates, String boardName) {
this.board = new HitoriCell[numbers.length][numbers[0].length]; this.board = new HitoriCell[numbers.length][numbers[0].length];
this.solutionCoordinates = solutionCoordinates; this.solutionCoordinates = solutionCoordinates;
this.boardName = boardName;
initializeBoard(numbers); initializeBoard(numbers);
} }
public List<String> getSolutionCoordinates() { /**
return solutionCoordinates; * Initialisiert das Spielfeld mit den übergebenen Zahlen.
} *
* @param numbers 2D-Array mit den Zahlen des Spielfelds.
public HitoriCell[][] getBoard() { */
return board; private void initializeBoard(int[][] numbers) {
}
private void initializeBoard(int[][] numbers){
for (int i = 0; i < numbers.length; i++) { for (int i = 0; i < numbers.length; i++) {
for (int j = 0; j < numbers[i].length; j++) { for (int j = 0; j < numbers[i].length; j++) {
board[i][j] = new HitoriCell(numbers[i][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<String> 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) { public HitoriCell getCell(int row, int col) {
return board[row][col]; return board[row][col];
} }
/**
* Gibt die Größe des Spielfelds zurück.
*
* @return Anzahl der Zeilen im Spielfeld.
*/
public int getSize() { public int getSize() {
return board.length; 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() { public void resetBoard() {
//initializeBoard(originalBoardData);
for (int i = 0; i < board.length; i++) { for (int i = 0; i < board.length; i++) {
for (int j = 0; j < board[i].length; j++) { for (int j = 0; j < board[i].length; j++) {
board[i][j].setState(HitoriCell.CellState.GRAY); // Zurücksetzen board[i][j].setState(HitoriCell.CellState.GRAY); // Standardzustand
}
}
}
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]);
} }
} }
} }
/**
* Gibt das gesamte Spielfeld als 2D-Array zurück.
*
* @return 2D-Array mit den Zahlen des Spielfelds.
*/
public int[][] getNumbers() { public int[][] getNumbers() {
int[][] numbers = new int[board.length][board[0].length]; int[][] numbers = new int[board.length][board[0].length];
for (int i = 0; i < board.length; i++) { for (int i = 0; i < board.length; i++) {
@ -71,4 +96,17 @@ public class HitoriBoard {
return numbers; 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]);
}
}
}
} }

View File

@ -9,30 +9,42 @@ import java.util.*;
public class HitoriSolutionLoader { public class HitoriSolutionLoader {
public static List<String> loadSolution(String resourcePath) throws IOException { public static List<String> loadSolution(String resourcePath) throws IOException {
InputStream inputStream = HitoriSolutionLoader.class.getResourceAsStream(resourcePath);
if (inputStream == null) {
throw new IOException("Ressourcendatei nicht gefunden: " + resourcePath);
}
List<String> solutionCoordinates = new ArrayList<>(); List<String> solutionCoordinates = new ArrayList<>();
try (BufferedReader reader = new BufferedReader(new InputStreamReader(inputStream))) { boolean solutionSectionFound = false;
String line;
boolean isSolutionSection = 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) { 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")) { if (line.startsWith("//Lösung")) {
isSolutionSection = true; solutionSectionFound = true;
continue; // Überspringe die Kommentarzeile continue;
} }
if (isSolutionSection) { if (solutionSectionFound) {
solutionCoordinates.add(line.trim()); 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; return solutionCoordinates;
} }
} }

View File

@ -5,7 +5,6 @@ import java.util.List;
/** /**
* Validates the Hitori board against the solution. * Validates the Hitori board against the solution.
*/ */
public class HitoriValidator { public class HitoriValidator {
private final HitoriBoard board; private final HitoriBoard board;
@ -19,7 +18,6 @@ public class HitoriValidator {
* @param solutionCoordinates The coordinates of the correct black cells in "row,column" format. * @param solutionCoordinates The coordinates of the correct black cells in "row,column" format.
* @return true if the current board matches the solution, false otherwise. * @return true if the current board matches the solution, false otherwise.
*/ */
public boolean validateBoard(List<String> solutionCoordinates) { public boolean validateBoard(List<String> solutionCoordinates) {
for (String coordinate : solutionCoordinates) { for (String coordinate : solutionCoordinates) {
String[] parts = coordinate.split(","); String[] parts = coordinate.split(",");
@ -33,9 +31,15 @@ public class HitoriValidator {
for (int i = 0; i < board.getSize(); i++) { for (int i = 0; i < board.getSize(); i++) {
for (int j = 0; j < board.getSize(); j++) { for (int j = 0; j < board.getSize(); j++) {
if (board.getCell(i,j).getState() == HitoriCell.CellState.BLACK && HitoriCell cell = board.getCell(i, j);
if (cell.getState() == HitoriCell.CellState.BLACK &&
!solutionCoordinates.contains((i + 1) + "," + (j + 1))) { !solutionCoordinates.contains((i + 1) + "," + (j + 1))) {
return false; return false; // Ein schwarzes Feld gehört nicht zur Lösung
}
// Überprüfe, ob alle nicht schwarzen Felder weiß sind
if (cell.getState() != HitoriCell.CellState.BLACK && cell.getState() != HitoriCell.CellState.WHITE) {
return false; // Es gibt noch graue Felder
} }
} }
} }

View File

@ -27,6 +27,7 @@ public class GameBoard extends JPanel {
// Timer-Label oben hinzufügen // Timer-Label oben hinzufügen
timerLabel = new JLabel("Zeit: 0 Sekunden"); timerLabel = new JLabel("Zeit: 0 Sekunden");
timerLabel.setHorizontalAlignment(SwingConstants.CENTER); timerLabel.setHorizontalAlignment(SwingConstants.CENTER);
Setup.styleLabel(timerLabel);
add(timerLabel, BorderLayout.NORTH); add(timerLabel, BorderLayout.NORTH);
// Timer starten // Timer starten
@ -153,13 +154,7 @@ public class GameBoard extends JPanel {
public boolean validateCurrentBoard() { public boolean validateCurrentBoard() {
HitoriValidator validator = new HitoriValidator(board); HitoriValidator validator = new HitoriValidator(board);
if (validator.validateBoard(board.getSolutionCoordinates())) { return validator.validateBoard(board.getSolutionCoordinates());
JOptionPane.showMessageDialog(this, "Das Spielfeld ist korrekt gelöst!", "Erfolg", JOptionPane.INFORMATION_MESSAGE);
return true;
} else {
JOptionPane.showMessageDialog(this, "Das Spielfeld enthält Fehler!", "Fehler", JOptionPane.ERROR_MESSAGE);
return false;
}
} }
private void showPauseMenu() { private void showPauseMenu() {
@ -234,13 +229,12 @@ public class GameBoard extends JPanel {
} }
} }
private void saveHighscore() { private void addHighscore() {
String playerName = JOptionPane.showInputDialog(this, String playerName = JOptionPane.showInputDialog(this,
"Bitte geben Sie Ihren Namen ein:", "Bitte geben Sie Ihren Namen ein:",
"Highscore speichern", "Highscore speichern",
JOptionPane.PLAIN_MESSAGE); JOptionPane.PLAIN_MESSAGE);
// Überprüfen, ob ein Name eingegeben wurde
if (playerName == null || playerName.trim().isEmpty()) { if (playerName == null || playerName.trim().isEmpty()) {
JOptionPane.showMessageDialog(this, JOptionPane.showMessageDialog(this,
"Highscore wurde nicht gespeichert. Kein Name eingegeben.", "Highscore wurde nicht gespeichert. Kein Name eingegeben.",
@ -249,22 +243,27 @@ public class GameBoard extends JPanel {
return; return;
} }
// Berechne die verstrichene Zeit int elapsedTime = (int) ((System.currentTimeMillis() - startTime) / 1000);
int elapsedTime = (int) ((System.currentTimeMillis() - startTime) / 1000); // Zeit in Sekunden
// Spielfeldname (oder eine Beschreibung) String boardName = board.getBoardName();
String boardName = "Aktuelles Spielfeld"; // Falls ein spezifischer Name verfügbar ist, ersetzen
// Speichere den Highscore mit dem HighscoreManager try {
HighscoreManager.saveHighscore(playerName, elapsedTime, boardName); HighscoreManager manager = new HighscoreManager();
manager.addHighscore(playerName, elapsedTime, boardName);
// Zeige eine Bestätigung an JOptionPane.showMessageDialog(this,
JOptionPane.showMessageDialog(this, "Highscore erfolgreich gespeichert!",
"Highscore erfolgreich gespeichert!", "Erfolg",
"Erfolg", JOptionPane.INFORMATION_MESSAGE);
JOptionPane.INFORMATION_MESSAGE); } catch (Exception e) {
JOptionPane.showMessageDialog(this,
"Fehler beim Speichern des Highscores: " + e.getMessage(),
"Fehler",
JOptionPane.ERROR_MESSAGE);
}
} }
private void returnToMainMenu() { private void returnToMainMenu() {
/// Eltern-Frame abrufen /// Eltern-Frame abrufen
JFrame parentFrame = (JFrame) SwingUtilities.getWindowAncestor(this); JFrame parentFrame = (JFrame) SwingUtilities.getWindowAncestor(this);

View File

@ -1,6 +1,8 @@
package PR2.HitoriSpiel.GUI; package PR2.HitoriSpiel.GUI;
import PR2.HitoriSpiel.Utils.HighscoreManager; import PR2.HitoriSpiel.Utils.HighscoreManager;
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.*;
@ -9,36 +11,59 @@ import java.util.List;
// aktueller Stand // aktueller Stand
public class HighscoreDialog extends JDialog { public class HighscoreDialog extends JDialog {
public HighscoreDialog(JFrame parent) { private final HighscoreManager highscoreManager;
super(parent, "Highscoreliste", true); private final DefaultTableModel tableModel;
public HighscoreDialog(JFrame parentFrame) {
super(parentFrame, "Highscoreliste", true);
this.highscoreManager = new HighscoreManager();
setLayout(new BorderLayout());
setSize(500, 400); setSize(500, 400);
setLocationRelativeTo(parent); setLocationRelativeTo(parentFrame);
Setup.stylePanel((JPanel) getContentPane()); // Hintergrundfarbe setzen
// Tabelle erstellen JLabel titleLabel = new JLabel("Highscores", SwingConstants.CENTER);
String[] columnNames = {"Name", "Zeit (Sek.)", "Spielfeld"}; titleLabel.setFont(new Font("Arial", Font.BOLD, 20));
DefaultTableModel tableModel = new DefaultTableModel(columnNames, 0); Setup.styleLabel(titleLabel); // Schriftstil setzen
add(titleLabel, BorderLayout.NORTH);
// Highscores laden String[] columnNames = {"Name", "Punkte", "Spielfeld"};
List<HighscoreManager.Highscore> highscores = HighscoreManager.loadHighscores(); tableModel = new DefaultTableModel(columnNames, 0);
for (HighscoreManager.Highscore highscore : highscores) { JTable highscoreTable = new JTable(tableModel);
tableModel.addRow(new Object[]{highscore.getName(), highscore.getTime(), highscore.getBoard()}); highscoreTable.setFillsViewportHeight(true);
} highscoreTable.setEnabled(false); // Tabelle nur zur Anzeige
JScrollPane scrollPane = new JScrollPane(highscoreTable);
add(scrollPane, BorderLayout.CENTER);
JTable table = new JTable(tableModel); // Schließen-Button
table.setEnabled(false); // Tabelle nur lesbar JButton closeButton = Setup.createButton("Schließen", 120, 40);
table.setFillsViewportHeight(true); closeButton.setFont(new Font(closeButton.getFont().getName(), closeButton.getFont().getStyle(), 14)); // Schriftgröße ändern
JScrollPane scrollPane = new JScrollPane(table);
// Button zum Schließen des Dialogs
JButton closeButton = new JButton("Schließen");
closeButton.addActionListener(e -> dispose()); closeButton.addActionListener(e -> dispose());
JPanel buttonPanel = new JPanel(); JPanel buttonPanel = new JPanel();
Setup.stylePanel(buttonPanel); // Hintergrundstil setzen
buttonPanel.add(closeButton); buttonPanel.add(closeButton);
setLayout(new BorderLayout());
add(scrollPane, BorderLayout.CENTER);
add(buttonPanel, BorderLayout.SOUTH); add(buttonPanel, BorderLayout.SOUTH);
// Highscores laden
loadHighscores();
}
private void loadHighscores() {
tableModel.setRowCount(0); // Tabelle zurücksetzen
List<HighscoreManager.Highscore> 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();
} }
} }

View File

@ -111,8 +111,9 @@ public class StartMenu extends JPanel {
new HighscoreDialog((JFrame) SwingUtilities.getWindowAncestor(this)).setVisible(true); new HighscoreDialog((JFrame) SwingUtilities.getWindowAncestor(this)).setVisible(true);
} }
// Hilfsmethoden
// Hilfsmethoden
private void loadGameBoard(GameBoard gameBoard, List<String> solutionCoordinates) { private void loadGameBoard(GameBoard gameBoard, List<String> solutionCoordinates) {
removeAll(); removeAll();
setLayout(new BorderLayout()); setLayout(new BorderLayout());
@ -129,9 +130,8 @@ public class StartMenu extends JPanel {
int[][] boardData = loadBoard(resourcePath); int[][] boardData = loadBoard(resourcePath);
List<String> solutionCoordinates = HitoriSolutionLoader.loadSolution(resourcePath); List<String> 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(hitoriBoard);
//GameBoard gameBoard = new GameBoard(new HitoriBoard(boardData, solutionCoordinates));
loadGameBoard(gameBoard, solutionCoordinates); loadGameBoard(gameBoard, solutionCoordinates);
System.out.println("Ausgewählte Datei: " + selectedFile); System.out.println("Ausgewählte Datei: " + selectedFile);
@ -141,9 +141,4 @@ public class StartMenu extends JPanel {
JOptionPane.showMessageDialog(this, "Fehler beim Laden des Spielfelds: " + e.getMessage(), "Fehler", JOptionPane.ERROR_MESSAGE); JOptionPane.showMessageDialog(this, "Fehler beim Laden des Spielfelds: " + e.getMessage(), "Fehler", JOptionPane.ERROR_MESSAGE);
} }
} }
} }

View File

@ -2,72 +2,112 @@ 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;
// aktueller Stand
public class HighscoreManager { public class HighscoreManager {
private static final String HIGHSCORE_FILE = "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<>();
public static class Highscore { public HighscoreManager() {
private final String name; loadHighscores();
private final int time; }
private final String board;
public Highscore(String name, int time, String board) { // Highscore hinzufügen
this.name = name; public synchronized void addHighscore(String playerName, int score, String boardName) {
this.time = time; fileLock.lock();
this.board = board; try {
} highscoreList.add(new Highscore(playerName, score, boardName));
highscoreList.sort(Comparator.comparingInt(Highscore::getScore).reversed()); // Sortierung absteigend
public String getName() { saveHighscores();
return name; } finally {
} fileLock.unlock();
public int getTime() {
return time;
}
public String getBoard() {
return board;
} }
} }
public static List<Highscore> loadHighscores() { // Highscores laden
List<Highscore> highscores = new ArrayList<>(); private void loadHighscores() {
File file = new File(HIGHSCORE_FILE); fileLock.lock();
try (BufferedReader reader = new BufferedReader(new FileReader(HIGHSCORE_FILE))) {
if (!file.exists()) {
return highscores;
}
try (BufferedReader reader = new BufferedReader(new FileReader(file))) {
String line; String line;
while ((line = reader.readLine()) != null) { while ((line = reader.readLine()) != null) {
String[] parts = line.split(", "); String[] parts = line.split(",");
if (parts.length == 3) { if (parts.length == 3) { // Name, Punkte, Spielfeld
String name = parts[0]; highscoreList.add(new Highscore(parts[0], Integer.parseInt(parts[1]), parts[2]));
int time = Integer.parseInt(parts[1]);
String board = parts[2];
highscores.add(new Highscore(name, time, board));
} }
} }
} catch (IOException e) { } catch (FileNotFoundException e) {
e.printStackTrace(); 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))) { // Highscores speichern
writer.write(name + ", " + time + ", " + board); private void saveHighscores() {
writer.newLine(); 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) { } catch (IOException e) {
e.printStackTrace(); System.err.println("Fehler beim Speichern der Highscores: " + e.getMessage());
} finally {
fileLock.unlock();
} }
} }
// Highscores abrufen
public List<Highscore> 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;
}
}
} }