Compare commits

...

64 Commits

Author SHA1 Message Date
Vickvick2002 af277a5fab Letzte Änderungen 2025-01-07 09:56:46 +01:00
Simona-Ioana Purdila 4284c262e2 GUI Testklassen erstellt, außer für BoardLoader 2025-01-06 22:40:00 +01:00
Simona-Ioana Purdila 2bb0a5bbef GUI Testklassen erstellt, außer für BoardLoader 2025-01-06 22:39:30 +01:00
Simona-Ioana Purdila ed886565fb Aktuellsten Branch nach merge von Improvements_Ioana und Improvements_Vicky 2025-01-06 22:21:06 +01:00
Simona-Ioana Purdila f7a65be2c4 Merge remote-tracking branch 'origin/Improvements_Vick' into Improvements_Together
# Conflicts:
#	Hitori/src/main/highscores/highscores.txt
2025-01-06 22:18:49 +01:00
Simona-Ioana Purdila c474b457b6 JUnit Tests für Domain und Fassade 2025-01-06 22:13:32 +01:00
Vickvick2002 da801b75b0 Logik für Zeit beim Pausieren verbessert 2025-01-06 21:53:05 +01:00
Simona-Ioana Purdila 8da0e90a5c Anpassung der Spielfeldernamen (Endung .csv entfernt) 2025-01-06 21:26:59 +01:00
Simona-Ioana Purdila ffbd2dab10 Durchschnitszeit-Funktion verbessert 2025-01-06 20:09:07 +01:00
Simona-Ioana Purdila d88e35b4e2 Durchschnitszeit-Funktion verbessert 2025-01-06 19:49:08 +01:00
Simona-Ioana Purdila a4ce98a837 README.md aktualisiert 2025-01-06 19:39:15 +01:00
Simona-Ioana Purdila 2122bfc521 README.md aktualisiert 2025-01-06 16:12:00 +01:00
Simona-Ioana Purdila 2418e2aed7 HighscoreListe verschoben 2025-01-06 16:04:27 +01:00
Simona-Ioana Purdila e77359160d HighscoreListe verschoben 2025-01-06 16:04:14 +01:00
Simona-Ioana Purdila 5f41bda301 Fassade-Klassen verschoben 2025-01-06 14:35:13 +01:00
Simona-Ioana Purdila 30f11647bb Fassade-Klassen verschoben, Test-Klassen entfernt, Umbennenung einige Spielfelder 2025-01-06 13:05:54 +01:00
Simona-Ioana Purdila e7e306642f README.md Datei aktualisiert 2025-01-06 12:46:28 +01:00
Vickvick2002 b0f1c46a8c HighscoreLogik verbessert, für jedes Spielfeld 2025-01-05 19:45:05 +01:00
Vickvick2002 75f04b51cc Redo/Undo Logik implementiert 2025-01-05 18:56:42 +01:00
Simona-Ioana Purdila dcf9c95a99 Highscore Liste wird angezeigt, Eintrag speichern noch nicht richtig 2025-01-05 17:10:02 +01:00
Vickvick2002 f7868e042f Highscore Eintrag für Name hinzugefügt 2025-01-05 16:22:30 +01:00
Vickvick2002 eb30f5cd13 Änderungen für Redo und Undo Button vorgenommen 2025-01-05 15:18:52 +01:00
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
Vickvick2002 3742dac038 pom.xml angepasst 2025-01-05 12:34:34 +01:00
Vickvick2002 bb28a136b4 pom.xml angepasst 2025-01-05 11:58:51 +01:00
Vickvick2002 a92ddc2099 loadBoardAsList Methode verändert 2025-01-05 11:34:20 +01:00
Vickvick2002 99fe1f30c4 loadBoardAsList Methode verändert 2025-01-05 11:01:43 +01:00
Vickvick2002 4f9c1f7734 Aktueller Stand der Klassen 2025-01-05 10:47:53 +01:00
Vickvick2002 cf3085b177 Code erweitert 2025-01-05 10:36:47 +01:00
Vickvick2002 f440ecb839 Änderung an Hintergund und Buttonfarbe 2025-01-04 16:07:21 +01:00
Vickvick2002 7139741018 Fehler beim Laden des Hauptmenüs behoben 2025-01-04 14:16:41 +01:00
Vickvick2002 078d653921 GameBoard Code erweitert und verbessert 2025-01-04 13:50:22 +01:00
Vickvick2002 6462424563 HitoriBoard Code verändert 2025-01-04 13:50:11 +01:00
Vickvick2002 152b50fc69 HitoriSolutionLoader Code verändert 2025-01-04 13:49:54 +01:00
Vickvick2002 43c73b0289 Main Code verbessert 2025-01-04 13:49:40 +01:00
Vickvick2002 3b6e3a45a7 StartMenu Code erweitert 2025-01-04 13:49:29 +01:00
Vickvick2002 1b64e31951 StateManager Klasse erstellt für Redo/ Undo Logik 2025-01-03 21:01:39 +01:00
Vickvick2002 2205f1bf04 Code erweitert 2025-01-03 21:01:18 +01:00
Vickvick2002 9267aec8e4 PauseMenu erstellt und Optionen implementiert 2025-01-03 21:01:11 +01:00
Vickvick2002 27f1951fb5 final bei private int number entfernt 2025-01-03 21:00:54 +01:00
Vickvick2002 9d30065f9a Setter hinzugefügt 2025-01-03 21:00:30 +01:00
Vickvick2002 9df1c5e421 Timer und Redo/Undo Button hinzugefügt 2025-01-03 21:00:09 +01:00
Vickvick2002 8f7d815eb5 ResetButton implementiert 2025-01-03 19:16:18 +01:00
Vickvick2002 a4c98bc5d9 ResetMethode verändert 2025-01-03 19:16:05 +01:00
Vickvick2002 24100d209b selectBoard Methode vollständig implementiert 2025-01-03 19:15:44 +01:00
Vickvick2002 b07fcb0ff5 Fehlerabfang hinzugefügt 2025-01-03 18:19:30 +01:00
Vickvick2002 ca2b8a8921 Code erweitert 2025-01-03 18:19:09 +01:00
Vickvick2002 44c80e9779 Code erweitert 2025-01-03 18:19:06 +01:00
Vickvick2002 0b615ba4cc Getter-Methode hinzugefügt 2025-01-03 18:18:59 +01:00
Vickvick2002 99f0b2627b Methode verbessert wegen Fehler 2025-01-03 18:18:41 +01:00
Vickvick2002 cb97bd32eb Klasse erweitert 2025-01-03 18:18:25 +01:00
Vickvick2002 b14d044443 Main Klasse geändert 2025-01-03 15:25:50 +01:00
Vickvick2002 dd778e7841 selectedBoard Methode erweitert 2025-01-03 15:25:35 +01:00
Vickvick2002 6515ea54c4 BoardLoader Klasse erstellt und Spielfelder implementiert 2025-01-03 15:25:12 +01:00
Vickvick2002 9a8fe119e0 In resource Ordner verschoben 2025-01-03 15:24:39 +01:00
Vickvick2002 c626927a39 GameBoard Klasse erstellt 2025-01-03 13:45:27 +01:00
Vickvick2002 12d66335f6 Klasse gelöscht 2025-01-03 13:40:46 +01:00
Vickvick2002 f3481c5b96 Klasse gelöscht 2025-01-03 13:40:15 +01:00
Vickvick2002 936967e809 StartMenu Klasse verbessert 2025-01-03 13:39:40 +01:00
Vickvick2002 9c3fdf9406 Merge branch 'dev_Ioana' of https://gitty.informatik.hs-mannheim.de/3015825/HitoriTeamProjekt into dev_vic 2025-01-03 13:37:42 +01:00
Simona-Ioana Purdila ef5efa7880 Domain Klassen und HitoriSpielfeld 15x15 hinzugefügt, Basis-Funktionalitäten der Klassen erstellt 2024-12-29 17:42:59 +00:00
Vickvick2002 1244cb333d Setze Namen für Buttons in StartMenu und passe Tests entsprechend an 2024-12-19 08:38:10 +01:00
Vickvick2002 cd94bc7db0 Ändere HitoriApp zu einer Instanzmethode und implementiere Main-Klasse als Einstiegspunkt 2024-12-19 08:13:38 +01:00
45 changed files with 2590 additions and 118 deletions

View File

@ -7,11 +7,65 @@
<groupId>org.example</groupId>
<artifactId>HitoriTeamProjekt</artifactId>
<version>1.0-SNAPSHOT</version>
<packaging>jar</packaging>
<properties>
<maven.compiler.source>22</maven.compiler.source>
<maven.compiler.target>22</maven.compiler.target>
<maven.compiler.source>21</maven.compiler.source>
<maven.compiler.target>21</maven.compiler.target>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>
<dependencies>
<!-- AssertJ Swing Test-Framework -->
<dependency>
<groupId>org.assertj</groupId>
<artifactId>assertj-swing</artifactId>
<version>3.17.1</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.13.1</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter</artifactId>
<version>5.8.2</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.mockito</groupId>
<artifactId>mockito-core</artifactId>
<version>4.5.1</version>
<scope>test</scope>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.11.0</version>
<configuration>
<source>21</source> <!-- Java-Version -->
<target>21</target> <!-- Java-Version -->
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-jar-plugin</artifactId>
<version>3.2.0</version>
<configuration>
<archive>
<manifest>
<mainClass>PR2.HitoriSpiel.Main.Main</mainClass> <!-- Vollqualifizierter Name deiner Main-Klasse -->
</manifest>
</archive>
</configuration>
</plugin>
</plugins>
</build>
</project>

View File

@ -0,0 +1,8 @@
Ioana,25,Hitori4x4_leicht.csv,0
test,22,Hitori4x4_leicht.csv,0
Test2,72,Hitori5x5_leicht.csv,0
Test3,100,Hitori8x8_medium.csv,0
Test4,200,Hitori15x15_medium.csv,10
IOANA VERSUCH 156,105,Hitori5x5_leicht.csv,0
IOANA VERSUCH 439,44,Hitori5x5_leicht.csv,0
Yovu,46,Hitori4x4_leicht.csv,0

View File

@ -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;
}
}

View File

@ -1,4 +0,0 @@
package PR2.HitoriSpiel.Domain;
public class DomainTest {
}

View File

@ -0,0 +1,112 @@
package PR2.HitoriSpiel.Domain;
import java.util.List;
/**
* Represents the Hitori game board.
*/
public class HitoriBoard {
private final HitoriCell[][] board;
private final List<String> solutionCoordinates;
private final String boardName; // Name des Spielfelds
public HitoriBoard(int[][] numbers, List<String> solutionCoordinates, String boardName) {
this.board = new HitoriCell[numbers.length][numbers[0].length];
this.solutionCoordinates = solutionCoordinates;
this.boardName = boardName;
initializeBoard(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]);
}
}
}
/**
* 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) {
return board[row][col];
}
/**
* Gibt die Größe des Spielfelds zurück.
*
* @return Anzahl der Zeilen im Spielfeld.
*/
public int getSize() {
return board.length;
}
/**
* Setzt das Spielfeld zurück, indem alle Zellen in den Standardzustand gesetzt werden.
*/
public void resetBoard() {
for (int i = 0; i < board.length; i++) {
for (int j = 0; j < board[i].length; 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++) {
for (int j = 0; j < board[i].length; j++) {
numbers[i][j] = board[i][j].getNumber();
}
}
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

@ -0,0 +1,36 @@
package PR2.HitoriSpiel.Domain;
/**
* Represents a single cell on the Hitori board.
*/
public class HitoriCell {
public enum CellState {
GRAY, WHITE, BLACK
}
private int number;
private CellState state;
public HitoriCell(int number) {
this.number = number;
this.state = CellState.GRAY;
}
public int getNumber() {
return number;
}
public CellState getState() {
return state;
}
public void setState(CellState state) {
this.state = state;
}
public void setNumber(int number) {
this.number = number;
}
}

View File

@ -0,0 +1,50 @@
package PR2.HitoriSpiel.Domain;
import java.util.List;
/**
* Validates the Hitori board against the solution.
*/
public class HitoriValidator {
private final HitoriBoard board;
public HitoriValidator(HitoriBoard board) {
this.board = board;
}
/**
* Validates the current board against the solution.
* @param solutionCoordinates The coordinates of the correct black cells in "row,column" format.
* @return true if the current board matches the solution, false otherwise.
*/
public boolean validateBoard(List<String> solutionCoordinates) {
for (String coordinate : solutionCoordinates) {
String[] parts = coordinate.split(",");
int row = Integer.parseInt(parts[0]) - 1;
int col = Integer.parseInt(parts[1]) - 1;
if (board.getCell(row,col).getState() != HitoriCell.CellState.BLACK){
return false;
}
}
for (int i = 0; i < board.getSize(); i++) {
for (int j = 0; j < board.getSize(); j++) {
HitoriCell cell = board.getCell(i, j);
if (cell.getState() == HitoriCell.CellState.BLACK &&
!solutionCoordinates.contains((i + 1) + "," + (j + 1))) {
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
}
}
}
return true;
}
}

View File

@ -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());
}
}
}

View File

@ -1,4 +0,0 @@
package PR2.HitoriSpiel.Fassade;
public class FassadeTest {
}

View File

@ -0,0 +1,384 @@
package PR2.HitoriSpiel.Fassade;
import PR2.HitoriSpiel.Domain.Action;
import PR2.HitoriSpiel.Domain.HitoriBoard;
import PR2.HitoriSpiel.Domain.HitoriValidator;
import PR2.HitoriSpiel.Domain.HitoriCell;
import PR2.HitoriSpiel.GUI.PauseMenu;
import PR2.HitoriSpiel.GUI.StartMenu;
import javax.swing.*;
import java.awt.*;
public class GameBoard extends JPanel {
private final HitoriBoard board;
private Timer timer;
private long startTime;
private JLabel timerLabel;
private long pausedTime = 0; // Zeit, die beim Pausieren bereits abgelaufen ist
private JPanel gamePanel; // Das Spielfeld als JPanel
private final StateManager stateManager = new StateManager();
public GameBoard(HitoriBoard board) {
this.board = board;
setLayout(new BorderLayout());
// Timer-Label hinzufügen
initializeTimerLabel();
// Timer starten
startTimer();
// Spielfeld erstellen
gamePanel = createGamePanel();
add(gamePanel, BorderLayout.CENTER);
// Kontroll-Buttons unten hinzufügen
JPanel controlPanel = createControlPanel();
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() {
if (timer == null) { // Timer nur beim ersten Start erstellen
timer = new Timer(1000, e -> {
long elapsedTime = (System.currentTimeMillis() - startTime + pausedTime) / 1000; // Zeit berechnen
timerLabel.setText("Zeit: " + elapsedTime + " Sekunden");
});
}
startTime = System.currentTimeMillis(); // Startzeit setzen, bevor der Timer gestartet wird
timer.start(); // Timer starten
System.out.println("Startzeit: " + startTime);
System.out.println("Pausierte Zeit: " + pausedTime);
}
private void stopTimer() {
if (timer != null && timer.isRunning()) {
timer.stop(); // Timer anhalten
pausedTime += System.currentTimeMillis() - startTime; // Zeit während der Pause speichern
System.out.println("Timer gestoppt. Pausierte Zeit: " + pausedTime);
}
}
public void resumeTimer() {
startTime = System.currentTimeMillis(); // Startzeit neu setzen
startTimer(); // Timer erneut starten
System.out.println("Timer fortgesetzt. Startzeit: " + startTime + ", Pausierte Zeit: " + pausedTime);
}
private void resetTimer() {
if (timer != null) {
timer.stop();
}
startTime = 0;
pausedTime = 0;
timerLabel.setText("Zeit: 0 Sekunden");
}
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();
});
return resetButton;
}
private JButton createUndoButton() {
JButton undoButton = Setup.createGameBoardButton("Undo", 80, 30);
undoButton.addActionListener(e -> {
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 -> {
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);
}
});
return redoButton;
}
private JButton createValidateButton() {
JButton validateButton = Setup.createGameBoardButton("Lösen", 80, 30);
validateButton.addActionListener(e -> {
if (validateCurrentBoard()) {
stopTimer();
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();
});
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); // Spielzeit in Sekunden
String boardName = board.getBoardName();
int errors = 0; // Aktuelle Fehlerzahl (falls vorhanden, muss noch angepasst werden)
HighscoreManager manager = new HighscoreManager();
boolean isNewHighscore = manager.isNewHighscore(elapsedTime, boardName);
// Zeige ein Dialogfenster zur Namenseingabe
String playerName = JOptionPane.showInputDialog(this,
isNewHighscore
? "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() {
stopTimer(); // Timer pausieren
PauseMenu pauseMenu = new PauseMenu(
(JFrame) SwingUtilities.getWindowAncestor(this),
this, // Das aktuelle GameBoard-Objekt übergeben
e -> startTimer(), // Spiel fortsetzen
e -> returnToMainMenu(), // Zum Hauptmenü
e -> System.exit(0) // Spiel beenden
);
pauseMenu.setVisible(true);
}
private JButton createCellButton(HitoriCell cell, int row, int col) {
JButton button = new JButton(String.valueOf(cell.getNumber()));
button.setBackground(Color.LIGHT_GRAY);
button.addActionListener(e -> {
toggleCellState(cell, row, col);
updateButtonState(button, cell);
});
return button;
}
public 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);
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); // Hintergrund grau
button.setForeground(Color.BLACK); // Textfarbe schwarz
button.setText(String.valueOf(cell.getNumber())); // Zeigt die Zahl an
}
case BLACK -> {
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); // Hintergrund weiß
button.setForeground(Color.BLACK); // Textfarbe schwarz
button.setText(String.valueOf(cell.getNumber())); // Zeigt die Zahl an
}
}
}
private void addHighscore(int elapsedTime, String boardName, int errors) {
String playerName = JOptionPane.showInputDialog(this,
"Neuer Highscore! Bitte Namen eingeben:",
"Highscore speichern",
JOptionPane.PLAIN_MESSAGE);
if (playerName == null || playerName.trim().isEmpty()) return;
HighscoreManager manager = new HighscoreManager();
manager.addHighscore(playerName, elapsedTime, boardName, errors);
JOptionPane.showMessageDialog(this,
"Highscore erfolgreich gespeichert!",
"Erfolg",
JOptionPane.INFORMATION_MESSAGE);
}
private void returnToMainMenu() {
/// Eltern-Frame abrufen
JFrame parentFrame = (JFrame) SwingUtilities.getWindowAncestor(this);
if (parentFrame != null) {
// Hauptmenü erstellen und im Frame setzen
StartMenu startMenu = new StartMenu(parentFrame);
parentFrame.getContentPane().removeAll(); // Entferne alle aktuellen Inhalte
parentFrame.add(startMenu); // Füge das Hauptmenü hinzu
parentFrame.revalidate(); // Layout aktualisieren
parentFrame.repaint(); // Oberfläche neu zeichnen
} else {
System.err.println("Fehler: Kein übergeordnetes JFrame gefunden.");
}
}
public void resetBoard() {
// Spiellogik zurücksetzen
board.resetBoard();
// Spielfeld (CENTER) entfernen und neu erstellen
if (getLayout() instanceof BorderLayout) {
BorderLayout layout = (BorderLayout) getLayout();
// Komponente im CENTER entfernen
Component centerComponent = layout.getLayoutComponent(BorderLayout.CENTER);
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) {
remove(southComponent);
}
add(createControlPanel(), BorderLayout.SOUTH);
}
// Oberfläche aktualisieren
revalidate();
repaint();
}
private void refreshBoard() {
remove(1); // Entferne das aktuelle Spielfeld im CENTER
if (getLayout() instanceof BorderLayout) {
BorderLayout layout = (BorderLayout) getLayout();
// Komponente im CENTER entfernen
Component centerComponent = layout.getLayoutComponent(BorderLayout.CENTER);
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) {
remove(southComponent);
}
add(createControlPanel(), BorderLayout.SOUTH);
}
// Oberfläche aktualisieren
revalidate();
repaint();
}
private JPanel createGamePanel() {
JPanel gamePanel = new JPanel(new GridLayout(board.getSize(), board.getSize()));
for (int i = 0; i < board.getSize(); i++) {
for (int j = 0; j < board.getSize(); j++) {
HitoriCell cell = board.getCell(i, j);
JButton button = createCellButton(cell, i, j);
gamePanel.add(button);
}
}
System.out.println("Spielpanel erstellt mit " + (board.getSize() * board.getSize()) + " Buttons.");
return gamePanel;
}
private void updateBoard() {
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); // Holt den Button
updateButtonState(button, cell); // Aktualisiert den Button basierend auf dem Zustand
}
}
}
}

View File

@ -0,0 +1,15 @@
package PR2.HitoriSpiel.Fassade;
public class GameManager {
private static GameBoard gameBoard;
public static void setGameBoard(GameBoard gb) {
gameBoard = gb;
}
public static void resumeTimer() {
if (gameBoard != null) {
gameBoard.resumeTimer();
}
}
}

View File

@ -0,0 +1,174 @@
package PR2.HitoriSpiel.Fassade;
import java.io.*;
import java.util.*;
import java.util.concurrent.locks.ReentrantLock;
public class HighscoreManager {
private static final String HIGHSCORE_FILE = "Hitori/src/main/highscores/highscores.txt";
private static final ReentrantLock fileLock = new ReentrantLock();
// Highscore-Datenstruktur
private final List<Highscore> highscoreList = new ArrayList<>();
public HighscoreManager() {
loadHighscores();
}
// Prüft, ob die gegebene Zeit ein neuer Highscore ist
public boolean isNewHighscore(int elapsedTime, String boardName) {
// Filtere die Highscores für das gegebene Spielfeld
List<Highscore> highscoresForBoard = getHighscoresForBoard(boardName);
// Falls es keinen Highscore für das Spielfeld gibt, ist es automatisch ein neuer Highscore
if (highscoresForBoard.isEmpty()) {
return true;
}
// Finde die kürzeste Zeit im Highscore
int bestTime = highscoresForBoard.stream()
.mapToInt(Highscore::getTime)
.min()
.orElse(Integer.MAX_VALUE);
// Überprüfe, ob die aktuelle Zeit besser ist
return elapsedTime < bestTime;
}
// 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
private void saveHighscores() {
try (BufferedWriter writer = new BufferedWriter(new FileWriter(HIGHSCORE_FILE))) {
for (Highscore highscore : highscoreList) {
writer.write(highscore.toString());
writer.newLine();
}
} catch (IOException e) {
System.err.println("Fehler beim Speichern der Highscores: " + e.getMessage());
}
}
// 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.");
}
}
// 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();
}
}
// Highscores abrufen
public List<Highscore> getHighscores() {
return new ArrayList<>(highscoreList); // Modifizierbare Kopie zurückgeben
}
// Löscht alle Highscores
public void clearHighscores() {
fileLock.lock();
try {
highscoreList.clear(); // Liste leeren
saveHighscores(); // Datei aktualisieren
} finally {
fileLock.unlock();
}
}
// Innere Highscore-Klasse
public static class Highscore {
private final String playerName;
private final int time;
private final String boardName;
private final int errors;
public Highscore(String playerName, int score, String boardName, int errors) {
this.playerName = playerName;
this.time = score;
this.boardName = boardName;
this.errors = errors;
}
public String getPlayerName() {
return playerName;
}
public int getTime() {
return time;
}
public String getBoardName() {
return boardName;
}
public int getErrors() {
return errors;
}
public int getScore() {return time;}
@Override
public String toString() {
return playerName + "," + time + "," + boardName + "," + errors;
}
}
}

View File

@ -0,0 +1,50 @@
package PR2.HitoriSpiel.Fassade;
import java.io.*;
import java.util.*;
/**
* Utility class to load the solution from a CSV file.
*/
public class HitoriSolutionLoader {
public static List<String> loadSolution(String resourcePath) throws IOException {
List<String> solutionCoordinates = new ArrayList<>();
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) {
line = line.trim();
// Überprüfen, ob wir im Lösungsteil sind
if (line.startsWith("//Lösung")) {
solutionSectionFound = true;
continue;
}
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;
}
}

View File

@ -0,0 +1,113 @@
package PR2.HitoriSpiel.Fassade;
import javax.swing.*;
import java.awt.*;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
public class Setup {
// Standardfarben
public static final Color BACKGROUND_COLOR = new Color(230, 230, 250);
public static final Color BUTTON_COLOR = new Color(75, 0, 130);
public static final Color BUTTON_TEXT_COLOR = new Color(230, 230, 250);
public static final Color BUTTON_HOVER_COLOR = new Color(64, 224, 208);
// Schriftart für Buttons
public static final Font BUTTON_FONT = new Font("Monospaced", Font.PLAIN, 18);
/**
* Erstellt einen standardisierten Button mit den voreingestellten Farben und Effekten.
*
* @param text Der Text des Buttons.
* @param width Breite des Buttons.
* @param height Höhe des Buttons.
* @return Der konfigurierte JButton.
*/
public static JButton createButton(String text, int width, int height) {
JButton button = new JButton(text);
button.setPreferredSize(new Dimension(width, height));
button.setBackground(BUTTON_COLOR);
button.setForeground(BUTTON_TEXT_COLOR);
button.setFocusPainted(false);
button.setFont(BUTTON_FONT);
// Hover-Effekt hinzufügen
button.addMouseListener(new MouseAdapter() {
@Override
public void mouseEntered(MouseEvent e) {
button.setBackground(BUTTON_HOVER_COLOR);
button.setForeground(Color.BLACK); // Schriftfarbe ändern
}
@Override
public void mouseExited(MouseEvent e) {
button.setBackground(BUTTON_COLOR); // Hintergrundfarbe zurücksetzen
button.setForeground(BUTTON_TEXT_COLOR); // Schriftfarbe zurücksetzen
}
});
return button;
}
// Spezielle Farben für GameBoard
public static final Color GAME_BUTTON_COLOR = new Color(75, 0, 130);
public static final Color GAME_BUTTON_HOVER_COLOR = new Color(64, 224, 208);
public static final Color GAME_BUTTON_TEXT_COLOR = new Color(230, 230, 250);
// Schriftart für Buttons
public static final Font GAME_BOARD_BUTTON_FONT = new Font("Monospaced", Font.PLAIN, 14);
/**
* Erstellt einen Button mit Stil für GameBoard.
*
* @param text Der Text des Buttons.
* @param width Breite des Buttons.
* @param height Höhe des Buttons.
* @return Der konfigurierte JButton.
*/
public static JButton createGameBoardButton(String text, int width, int height) {
JButton button = new JButton(text);
button.setPreferredSize(new Dimension(width, height));
button.setBackground(GAME_BUTTON_COLOR);
button.setForeground(GAME_BUTTON_TEXT_COLOR);
button.setFont(GAME_BOARD_BUTTON_FONT);
button.setFocusPainted(false);
// Hover-Effekt
button.addMouseListener(new MouseAdapter() {
@Override
public void mouseEntered(MouseEvent e) {
button.setBackground(GAME_BUTTON_HOVER_COLOR);
button.setForeground(Color.BLACK); // Schriftfarbe ändern
}
@Override
public void mouseExited(MouseEvent e) {
button.setBackground(GAME_BUTTON_COLOR);
button.setForeground(GAME_BUTTON_TEXT_COLOR); // Schriftfarbe zurücksetzen
}
});
return button;
}
/**
* Setzt den Hintergrund und die Schriftfarbe für ein JPanel.
*
* @param panel Das Panel, dessen Stil angepasst wird.
*/
public static void stylePanel(JPanel panel) {
panel.setBackground(BACKGROUND_COLOR);
}
/**
* Setzt die Farbe und Schriftart eines JLabels.
*
* @param label Das Label, dessen Stil angepasst wird.
*/
public static void styleLabel(JLabel label) {
label.setForeground(new Color(75, 0, 130));
label.setFont(new Font("Monospaced", Font.PLAIN, 30));
}
}

View File

@ -0,0 +1,43 @@
package PR2.HitoriSpiel.Fassade;
import PR2.HitoriSpiel.Domain.Action;
import PR2.HitoriSpiel.Domain.StateFileManager;
import java.io.*;
import java.util.Stack;
public class StateManager implements Serializable {
private final Stack<Action> undoStack = new Stack<>();
private final Stack<Action> redoStack = new Stack<>();
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
}
public Action undo() {
if (!undoStack.isEmpty()) {
Action action = undoStack.pop();
redoStack.push(action);
StateFileManager.saveState(undoStack, redoStack); // Aktuellen Zustand speichern
return action;
}
return null;
}
public Action redo() {
if (!redoStack.isEmpty()) {
Action action = redoStack.pop();
undoStack.push(action);
StateFileManager.saveState(undoStack, redoStack); // Aktuellen Zustand speichern
return action;
}
return null;
}
public void loadStateFromFile() {
StateFileManager.loadState(undoStack, redoStack); // Stacks aus Datei laden
}
}

View File

@ -0,0 +1,154 @@
package PR2.HitoriSpiel.GUI;
import java.io.*;
import java.net.URLDecoder;
import java.util.*;
import java.util.jar.*;
public class BoardLoader {
public static class BoardData {
private final int[][] board;
private final List<String> solution;
public BoardData(int[][] board, List<String> solution) {
this.board = board;
this.solution = solution;
}
public int[][] getBoard() {
return board;
}
public List<String> getSolution() {
return solution;
}
}
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().contains("_") && 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());
}
// Sortiere die Dateien nach Schwierigkeitsgrad und Größe
boardFiles.sort((a, b) -> {
// 1. Schwierigkeitsgrad
boolean aIsLeicht = a.contains("leicht");
boolean bIsLeicht = b.contains("leicht");
boolean aIsMedium = a.contains("medium");
boolean bIsMedium = b.contains("medium");
if (aIsLeicht && bIsMedium) return -1;
if (aIsMedium && bIsLeicht) return 1;
// 2. Größe (z. B. 8x8, 10x10)
int sizeA = extractSize(a);
int sizeB = extractSize(b);
return Integer.compare(sizeA, sizeB);
});
} catch (Exception e) {
System.err.println("Fehler beim Laden der Spielfelder: " + e.getMessage());
}
return boardFiles;
}
public static int[][] loadBoard(String resourcePath) throws IOException {
List<int[]> rows = new ArrayList<>();
try (InputStream inputStream = BoardLoader.class.getResourceAsStream(resourcePath);
BufferedReader reader = new BufferedReader(new InputStreamReader(inputStream))) {
if (inputStream == null) {
throw new IOException("Ressourcendatei nicht gefunden: " + resourcePath);
}
System.out.println("Lade Datei: " + resourcePath);
String line;
int rowCount = 0; // Zähler für die gelesenen Zeilen
// Lies die Zeilen bis zur Spielfeldgröße (n Zeilen)
while ((line = reader.readLine()) != null) {
if (line.trim().isEmpty() || line.startsWith("//")) {
continue; // Ignoriere leere Zeilen oder Kommentare
}
System.out.println("Gelesene Zeile: " + line);
String[] values = line.split(",");
int[] row = new int[values.length];
for (int i = 0; i < values.length; i++) {
try {
row[i] = Integer.parseInt(values[i].trim());
} catch (NumberFormatException e) {
throw new IOException("Ungültiger Wert in der Datei: " + values[i]);
}
}
rows.add(row);
rowCount++;
// Beende das Lesen, wenn die gewünschte Anzahl von Zeilen erreicht ist
if (rowCount == values.length) {
break;
}
}
}
if (rows.isEmpty()) {
throw new IOException("Die Datei " + resourcePath + " enthält keine Daten.");
}
// Konvertiere die Liste von Zeilen in ein 2D-Array
return rows.toArray(new int[0][0]);
}
// Hilfsmethode zum Extrahieren der Größe aus dem Dateinamen
private static int extractSize(String fileName) {
try {
String sizePart = fileName.split("_")[0].replaceAll("\\D", ""); // Entfernt Nicht-Ziffern
return Integer.parseInt(sizePart);
} catch (Exception e) {
return Integer.MAX_VALUE; // Fehlerhafte Dateinamen landen am Ende
}
}
}

View File

@ -1,51 +0,0 @@
package PR2.HitoriSpiel.GUI;
import javax.swing.*;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
public class GameBoardView extends JPanel {
private final JButton[][] cells; // Spielfeld als Buttons
public GameBoardView(int rows, int cols) {
this.setLayout(new GridLayout(rows, cols)); // Grid-Layout für das Spielfeld
cells = new JButton[rows][cols];
// Spielfeld-Buttons initialisieren
for (int row = 0; row < rows; row++) {
for (int col = 0; col < cols; col++) {
cells[row][col] = new JButton();
cells[row][col].setBackground(Color.LIGHT_GRAY);
int finalRow = row;
int finalCol = col;
// ActionListener für Button-Klick
cells[row][col].addActionListener(e -> toggleCellColor(finalRow, finalCol));
this.add(cells[row][col]);
}
}
}
// Methode zum Umschalten der Zellenfarbe
private void toggleCellColor(int row, int col) {
JButton button = cells[row][col];
if (button.getBackground() == Color.LIGHT_GRAY) {
button.setBackground(Color.BLACK);
} else if (button.getBackground() == Color.BLACK) {
button.setBackground(Color.WHITE);
} else {
button.setBackground(Color.LIGHT_GRAY);
}
}
// Methode zum Aktualisieren des Spielfelds (optional)
public void render(int[][] board) {
for (int row = 0; row < board.length; row++) {
for (int col = 0; col < board[row].length; col++) {
cells[row][col].setText(String.valueOf(board[row][col]));
}
}
}
}

View File

@ -0,0 +1,107 @@
package PR2.HitoriSpiel.GUI;
import PR2.HitoriSpiel.Fassade.HighscoreManager;
import PR2.HitoriSpiel.Fassade.Setup;
import javax.swing.table.DefaultTableModel;
import javax.swing.*;
import java.awt.*;
import java.util.ArrayList;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
// aktueller Stand
public class HighscoreDialog extends JDialog {
private final HighscoreManager highscoreManager;
private final DefaultTableModel tableModel;
private final JComboBox<String> boardSelector;
public HighscoreDialog(JFrame parentFrame, List<String> boardNames) {
super(parentFrame, "Highscoreliste", true);
this.highscoreManager = new HighscoreManager();
this.tableModel = new DefaultTableModel(new String[]{"Platz", "Name", "Zeit (Sek.)", "Fehler", "Spielfeld", "Durchschnittszeit"}, 0);
setLayout(new BorderLayout());
setSize(600, 400);
setLocationRelativeTo(parentFrame);
Setup.stylePanel((JPanel) getContentPane()); // Hintergrundfarbe setzen
JLabel titleLabel = new JLabel("Highscores", SwingConstants.CENTER);
titleLabel.setFont(new Font("Arial", Font.BOLD, 20));
Setup.styleLabel(titleLabel); // Schriftstil setzen
add(titleLabel, BorderLayout.NORTH);
// Map für angezeigte Namen und tatsächliche Dateinamen
Map<String, String> displayToFileNameMap = new LinkedHashMap<>();
for (String fileName : boardNames) {
String displayName = fileName.endsWith(".csv") ? fileName.substring(0, fileName.lastIndexOf(".csv")) : fileName;
displayToFileNameMap.put(displayName, fileName);
}
// Spielfeld-Auswahl (ComboBox) mit angezeigten Namen
List<String> displayBoardNames = new ArrayList<>(displayToFileNameMap.keySet());
boardSelector = new JComboBox<>(displayBoardNames.toArray(new String[0]));
boardSelector.addActionListener(e -> {
String selectedDisplayName = (String) boardSelector.getSelectedItem();
if (selectedDisplayName != null) {
String actualFileName = displayToFileNameMap.get(selectedDisplayName);
loadHighscoresForBoard(actualFileName);
}
});
add(boardSelector, BorderLayout.NORTH);
// Tabelle für Highscores
JTable table = new JTable(tableModel);
JScrollPane scrollPane = new JScrollPane(table);
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);
Setup.stylePanel(buttonPanel); // Hintergrundstil setzen
add(buttonPanel, BorderLayout.SOUTH);
// Lade Highscores für das erste Spielfeld
if (!boardNames.isEmpty()) {
String firstFileName = displayToFileNameMap.get(displayBoardNames.get(0));
loadHighscoresForBoard(firstFileName);
}
}
private void loadHighscoresForBoard(String boardName) {
tableModel.setRowCount(0); // Tabelle zurücksetzen
List<HighscoreManager.Highscore> highscores = highscoreManager.getHighscoresForBoard(boardName);
Map<String, Double> averageTimes = highscoreManager.getAverageTimesByBoard();
if (highscores.isEmpty()) {
JOptionPane.showMessageDialog(this,
"Keine Highscores für das ausgewählte Spielfeld vorhanden.",
"Info",
JOptionPane.INFORMATION_MESSAGE);
return;
}
int rank = 1;
for (HighscoreManager.Highscore highscore : highscores) {
String bName = highscore.getBoardName().replaceAll("\\.csv$", ""); // .csv entfernen
double averageTime = averageTimes.getOrDefault(highscore.getBoardName(), 0.0);
tableModel.addRow(new Object[]{
rank++, // Platzierung
highscore.getPlayerName(), // Name
highscore.getScore(), // Punkte
highscore.getErrors(), //Errors
bName, // Spielfeld
String.format("%.2f", averageTime) // Durchschnittszeit
});
}
}
}

View File

@ -1,21 +0,0 @@
package PR2.HitoriSpiel.GUI;
import javax.swing.*;
public class HitoriApp {
public static void start() {
SwingUtilities.invokeLater(() -> {
// Hauptfenster erstellen
JFrame frame = new JFrame("Hitori - Das Spiel");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setSize(400, 400);
// Startmenü hinzufügen
StartMenu startMenu = new StartMenu(frame);
frame.add(startMenu);
frame.setVisible(true);
frame.setLocationRelativeTo(null);
});
}
}

View File

@ -0,0 +1,54 @@
package PR2.HitoriSpiel.GUI;
import PR2.HitoriSpiel.Fassade.Setup;
import PR2.HitoriSpiel.Fassade.GameBoard;
import javax.swing.*;
import java.awt.*;
import java.awt.event.ActionListener;
public class PauseMenu extends JDialog {
private final GameBoard gameBoard;
public PauseMenu(JFrame parent, GameBoard gameBoard, ActionListener resumeAction, ActionListener mainMenuAction, ActionListener exitAction) {
super(parent, "Pause", true);
this.gameBoard = gameBoard; // Instanz speichern
setLayout(new GridLayout(3, 1));
setSize(300, 200);
setLocationRelativeTo(parent);
// "Spiel fortsetzen"-Button
JButton resumeButton = Setup.createButton("Spiel fortsetzen", 200, 40);
resumeButton.addActionListener(e -> {
dispose();
if (resumeAction != null) {
resumeAction.actionPerformed(e);
}
// Timer fortsetzen
gameBoard.resumeTimer();
});
// "Zum Hauptmenü"-Button
JButton mainMenuButton = Setup.createButton("Zum Hauptmenü", 200, 40);
mainMenuButton.addActionListener(e -> {
dispose();
if (mainMenuAction != null) {
mainMenuAction.actionPerformed(e);
}
});
// "Spiel beenden"-Button
JButton exitButton = Setup.createButton("Spiel beenden", 200, 40);
exitButton.addActionListener(e -> {
dispose();
if (exitAction != null) {
exitAction.actionPerformed(e);
}
});
// Buttons hinzufügen
add(resumeButton);
add(mainMenuButton);
add(exitButton);
}
}

View File

@ -1,45 +1,167 @@
package PR2.HitoriSpiel.GUI;
import PR2.HitoriSpiel.Domain.HitoriBoard;
import PR2.HitoriSpiel.Fassade.GameBoard;
import PR2.HitoriSpiel.Fassade.HitoriSolutionLoader;
import PR2.HitoriSpiel.Fassade.Setup;
import javax.swing.*;
import java.awt.*;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Random;
import static PR2.HitoriSpiel.GUI.BoardLoader.loadBoard;
public class StartMenu extends JPanel {
private final JFrame parentFrame;
public StartMenu(JFrame parentFrame) {
// Layout auf FlowLayout setzen
this.setLayout(new FlowLayout(FlowLayout.CENTER, 10, 10)); // Zentriert mit Abständen
this.parentFrame = parentFrame;
setLayout(new GridBagLayout());
Setup.stylePanel(this); // Hintergrundfarbe setzen
//mainPanel = new JPanel(new GridBagLayout());
GridBagConstraints gbc = new GridBagConstraints();
gbc.gridx = 0;
gbc.gridy = GridBagConstraints.RELATIVE;
gbc.insets = new Insets(10, 10, 10, 10);
gbc.anchor = GridBagConstraints.CENTER; // Buttons zentrieren
JLabel titleLabel = new JLabel("Willkommen im Hitori-Spiel!");
Setup.styleLabel(titleLabel);
add(titleLabel, gbc);
// Buttons erstellen
JButton continueButton = createButton("Spiel fortsetzen", 200, 30);
JButton selectBoardButton = createButton("Spielfeld aussuchen", 200, 30);
JButton randomBoardButton = createButton("Zufälliges Spielfeld", 200, 30);
JButton highscoreButton = createButton("Highscore anzeigen", 200, 30);
JButton exitButton = createButton("Spiel beenden", 200, 30);
JButton continueButton = Setup.createButton("Spiel fortsetzen", 300, 50);
JButton selectBoardButton = Setup.createButton("Spielfeld aussuchen", 300, 50);
JButton randomBoardButton = Setup.createButton("Zufälliges Spielfeld", 300, 50);
JButton highscorelistButton = Setup.createButton("Highscoreliste anschauen", 300, 50);
JButton exitButton = Setup.createButton("Spiel beenden", 300, 50);
// ActionListener hinzufügen
continueButton.addActionListener(e -> showMessage("Spiel fortsetzen wird implementiert."));
selectBoardButton.addActionListener(e -> showMessage("Spielfeld auswählen wird implementiert."));
randomBoardButton.addActionListener(e -> showMessage("Zufälliges Spielfeld wird gestartet."));
highscoreButton.addActionListener(e -> showMessage("Highscore-Liste wird angezeigt."));
add(continueButton, gbc);
add(selectBoardButton, gbc);
add(randomBoardButton, gbc);
add(highscorelistButton, gbc);
add(exitButton, gbc);
continueButton.addActionListener(e -> continueGame());
selectBoardButton.addActionListener(e -> selectBoard());
randomBoardButton.addActionListener(e -> randomBoard());
highscorelistButton.addActionListener(e -> highscorelist());
exitButton.addActionListener(e -> System.exit(0));
// Buttons zum Panel hinzufügen
this.add(continueButton);
this.add(selectBoardButton);
this.add(randomBoardButton);
this.add(highscoreButton);
this.add(exitButton);
}
// Methode zum Anzeigen von Nachrichten
private void showMessage(String message) {
JOptionPane.showMessageDialog(this, message, "Info", JOptionPane.INFORMATION_MESSAGE);
public void continueGame() {
// TODO: Logik zum Fortsetzen des Spiels implementieren
JOptionPane.showMessageDialog(this, "Spiel fortsetzen wurde angeklickt");
}
// Methode zum Erstellen von Buttons mit fester Größe
private JButton createButton(String text, int width, int height) {
JButton button = new JButton(text);
button.setPreferredSize(new Dimension(width, height)); // Feste Größe setzen
return button;
public void selectBoard() {
// Lade die Liste der Dateinamen
List<String> boardFileNames = BoardLoader.loadBoardsAsList();
System.out.println("Verfügbare Spielfelder: " + boardFileNames);
if (boardFileNames == null || boardFileNames.isEmpty()) {
JOptionPane.showMessageDialog(this, "Keine Spielfelder gefunden.", "Fehler", JOptionPane.ERROR_MESSAGE);
return;
}
// Map für angezeigte Namen und tatsächliche Dateinamen
Map<String, String> displayToFileNameMap = new LinkedHashMap<>();
for (String fileName : boardFileNames) {
String displayName = fileName.endsWith(".csv") ? fileName.substring(0, fileName.lastIndexOf(".csv")) : fileName;
displayToFileNameMap.put(displayName, fileName);
}
// JComboBox mit den angezeigten Namen füllen
JComboBox<String> boardSelector = new JComboBox<>(displayToFileNameMap.keySet().toArray(new String[0]));
boardSelector.setPreferredSize(new Dimension(250, 30));
JPanel selectionPanel = new JPanel(new BorderLayout());
selectionPanel.add(new JLabel("Wähle ein Spielfeld:"), BorderLayout.NORTH);
selectionPanel.add(boardSelector, BorderLayout.CENTER);
int option = JOptionPane.showConfirmDialog(
this,
selectionPanel,
"Spielfeld auswählen",
JOptionPane.OK_CANCEL_OPTION,
JOptionPane.PLAIN_MESSAGE
);
if (option == JOptionPane.OK_OPTION) {
String selectedDisplayName = (String) boardSelector.getSelectedItem();
System.out.println("Ausgewähltes Spielfeld (Angezeigter Name): " + selectedDisplayName);
if (selectedDisplayName != null) {
// Hole den tatsächlichen Dateinamen
String selectedFileName = displayToFileNameMap.get(selectedDisplayName);
System.out.println("Ausgewählte Datei (mit .csv): " + selectedFileName);
// Lade das ausgewählte Spielfeld
loadAndDisplayBoard(selectedFileName);
}
}
}
public void randomBoard() {
List<String> boardFileNames = BoardLoader.loadBoardsAsList();
if (boardFileNames == null || boardFileNames.isEmpty()) {
JOptionPane.showMessageDialog(this, "Keine Spielfelder gefunden.", "Fehler", JOptionPane.ERROR_MESSAGE);
return;
}
String randomFile = boardFileNames.get(new Random().nextInt(boardFileNames.size()));
System.out.println("Zufällige Datei gewählt: " + randomFile);
loadAndDisplayBoard(randomFile);
}
public void highscorelist() {
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);
}
private void loadAndDisplayBoard(String selectedFile) {
try {
String resourcePath = "/persistent/Hitori_Spielfelder/" + selectedFile;
System.out.println("Lade Datei von Pfad: " + resourcePath);
int[][] boardData = loadBoard(resourcePath);
java.util.List<String> solutionCoordinates = HitoriSolutionLoader.loadSolution(resourcePath);
HitoriBoard hitoriBoard = new HitoriBoard(boardData, solutionCoordinates, selectedFile); // Stelle sicher, dass die Lösung korrekt geladen wird
GameBoard gameBoard = new GameBoard(hitoriBoard);
loadGameBoard(gameBoard, solutionCoordinates);
System.out.println("Ausgewählte Datei: " + selectedFile);
System.out.println("Lade Datei von Pfad: " + resourcePath);
} catch (Exception e) {
JOptionPane.showMessageDialog(this, "Fehler beim Laden des Spielfelds: " + e.getMessage(), "Fehler", JOptionPane.ERROR_MESSAGE);
}
}
// Hilfsmethoden
private void loadGameBoard(GameBoard gameBoard, java.util.List<String> solutionCoordinates) {
removeAll();
setLayout(new BorderLayout());
add(gameBoard, BorderLayout.CENTER);
revalidate();
repaint();
}
}

View File

@ -1,10 +1,41 @@
package PR2.HitoriSpiel.Main;
import PR2.HitoriSpiel.GUI.HitoriApp;
import PR2.HitoriSpiel.GUI.StartMenu;
import PR2.HitoriSpiel.Fassade.StateManager;
import javax.swing.*;
/**
* Einstiegspunkt des Hitori-Spiels. Initialisiert die GUI und startet das Programm.
*/
public class Main {
public static void main(String[] args) {
HitoriApp.start();
// Initialisiere den StateManager
StateManager stateManager = new StateManager();
// 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
System.out.println("Spielzustände wurden gespeichert.");
}));
// Starte das Hauptmenü der Anwendung
SwingUtilities.invokeLater(() -> {
try {
JFrame frame = new JFrame("Hitori - Hauptmenü");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setSize(800, 600);
// Lade das Startmenü
frame.add(new StartMenu(frame));
frame.setVisible(true);
frame.setLocationRelativeTo(null);
} catch (Exception e) {
e.printStackTrace();
JOptionPane.showMessageDialog(null, "Ein schwerer Fehler ist aufgetreten: " + e.getMessage(), "Fehler", JOptionPane.ERROR_MESSAGE);
}
});
}
}

View File

@ -0,0 +1,113 @@
@startuml
package PR2.HitoriSpiel.Domain {
class Action {
- int row
- int col
- String oldState
- String newState
+ getRow(): int
+ getCol(): int
+ getOldState(): String
+ getNewState(): String
}
class HitoriBoard {
- int[][] numbers
- List<String> solutionCoordinates
- String boardName
+ getNumbers(): int[][]
+ setNumbers(int[][] numbers): void
+ getCell(int row, int col): HitoriCell
+ resetBoard(): void
}
class HitoriCell {
- int number
- CellState state
+ getNumber(): int
+ getState(): CellState
+ setState(CellState state): void
}
class HitoriValidator {
- HitoriBoard board
+ validateBoard(List<String> solution): boolean
}
class StateFileManager {
+ saveState(Stack<Action> undoStack, Stack<Action> redoStack): void
+ loadState(Stack<Action> undoStack, Stack<Action> redoStack): void
}
}
package PR2.HitoriSpiel.Fassade {
class GameBoard {
- HitoriBoard board
- Timer timer
- long startTime
- long pausedTime
+ startTimer(): void
+ stopTimer(): void
+ resumeTimer(): void
+ resetBoard(): void
}
class StateManager {
- Stack<Action> undoStack
- Stack<Action> redoStack
+ saveAction(int row, int col, String oldState, String newState): void
+ undo(): Action
+ redo(): Action
}
class Setup {
+ stylePanel(JPanel panel): void
+ styleLabel(JLabel label): void
+ createButton(String text, int width, int height): JButton
}
class HighscoreManager {
- List<Highscore> highscoreList
+ addHighscore(String playerName, int score, String boardName, int errors): void
+ getHighscoresForBoard(String boardName): List<Highscore>
}
}
package PR2.HitoriSpiel.GUI {
class BoardLoader {
+ loadBoardsAsList(): List<String>
+ loadBoard(String resourcePath): int[][]
}
class HighscoreDialog {
- HighscoreManager highscoreManager
- DefaultTableModel tableModel
+ HighscoreDialog(JFrame parentFrame, List<String> boardNames)
}
class PauseMenu {
- GameBoard gameBoard
+ PauseMenu(JFrame parent, GameBoard gameBoard, ActionListener resumeAction, ActionListener mainMenuAction, ActionListener exitAction)
}
class StartMenu {
+ selectBoard(): void
+ randomBoard(): void
+ highscorelist(): void
}
}
package PR2.HitoriSpiel.Main {
class Main {
+ main(String[] args): void
}
}
PR2.HitoriSpiel.Domain.HitoriBoard "1" *-- "many" PR2.HitoriSpiel.Domain.HitoriCell
PR2.HitoriSpiel.Domain.StateManager "1" *-- "many" PR2.HitoriSpiel.Domain.Action
PR2.HitoriSpiel.Fassade.GameBoard "1" *-- "1" PR2.HitoriSpiel.Domain.HitoriBoard
PR2.HitoriSpiel.GUI.BoardLoader ..> PR2.HitoriSpiel.Domain.HitoriBoard
PR2.HitoriSpiel.GUI.HighscoreDialog ..> PR2.HitoriSpiel.Fassade.HighscoreManager
PR2.HitoriSpiel.GUI.PauseMenu --> PR2.HitoriSpiel.Fassade.GameBoard
PR2.HitoriSpiel.GUI.StartMenu --> PR2.HitoriSpiel.GUI.BoardLoader
@enduml

View File

@ -0,0 +1,83 @@
7,1,2,9,12,15,8,11,11,9,11,14,13,6,3
2,3,8,1,2,11,10,9,5,8,14,3,12,13,15
4,14,13,9,4,15,9,10,12,6,5,3,11,5,12
15,9,5,6,10,15,1,15,8,3,5,4,6,2,8
5,11,7,9,15,1,4,3,8,1,9,2,10,13,2
15,15,10,3,1,14,8,12,11,1,9,8,2,7,2
10,7,7,12,9,3,15,2,5,2,10,5,1,7,4
3,8,9,14,1,6,12,4,15,2,13,11,5,10,11
8,6,7,15,11,4,5,11,2,10,3,13,8,12,9
2,2,3,3,4,13,5,6,5,11,5,15,8,9,12
2,15,15,11,13,7,6,5,3,13,8,10,5,1,11
12,5,11,13,13,2,2,8,8,4,10,9,3,2,5
1,13,8,2,1,7,11,4,9,15,4,12,9,3,10
13,10,12,5,15,3,2,7,13,14,12,12,9,11,6
7,12,4,8,14,10,13,13,7,4,2,6,15,15,11
//Lösung
1,4
1,6
1,8
1,11
2,1
2,3
2,9
2,12
2,14
3,5
3,7
3,11
3,15
4,1
4,3
4,6
4,9
4,13
5,4
5,10
5,15
6,2
6,5
6,7
6,9
6,11
6,13
7,1
7,3
7,6
7,8
7,12
7,14
8,5
8,9
8,15
9,3
9,8
9,13
10,1
10,4
10,7
10,9
10,11
11,3
11,10
11,13
11,15
12,2
12,5
12,7
12,9
12,11
12,14
13,1
13,6
13,8
13,13
14,3
14,5
14,9
14,12
15,1
15,7
15,10
15,14
Can't render this file because it has a wrong number of fields in line 17.

View File

@ -3,7 +3,7 @@
1,3,4,2
3,4,3,2
//Lösung (schwarze Felder)
//Lösung
1,2
2,4
3,2
1 3,3,1,4
3 1,3,4,2
4 3,4,3,2
5 //Lösung (schwarze Felder) //Lösung
6 1,2
7 2,4
8 3,2
9 4,1

View File

@ -0,0 +1,31 @@
package Domain;
import PR2.HitoriSpiel.Domain.Action;
import org.junit.jupiter.api.Test;
import static org.junit.jupiter.api.Assertions.*;
public class ActionTest {
@Test
public void testConstructorAndGetters() {
Action action = new Action(2, 3, "WHITE", "BLACK");
assertEquals(2, action.getRow());
assertEquals(3, action.getCol());
assertEquals("WHITE", action.getOldState());
assertEquals("BLACK", action.getNewState());
}
@Test
public void testEqualsAndHashCode() {
Action action1 = new Action(1, 2, "GRAY", "WHITE");
Action action2 = new Action(1, 2, "GRAY", "WHITE");
assertEquals(action1, action2);
assertEquals(action1.hashCode(), action2.hashCode());
}
@Test
public void testToString() {
Action action = new Action(4, 5, "GRAY", "BLACK");
assertEquals("4,5,GRAY,BLACK", action.toString());
}
}

View File

@ -0,0 +1,36 @@
package Domain;
import PR2.HitoriSpiel.Domain.HitoriBoard;
import PR2.HitoriSpiel.Domain.HitoriCell;
import org.junit.jupiter.api.Test;
import java.util.Arrays;
import static org.junit.jupiter.api.Assertions.*;
public class HitoriBoardTest {
@Test
public void testBoardInitialization() {
int[][] numbers = {{1, 2}, {3, 4}};
HitoriBoard board = new HitoriBoard(numbers, Arrays.asList("1,1", "2,2"), "TestBoard");
assertEquals(2, board.getSize());
assertEquals("TestBoard", board.getBoardName());
assertEquals(1, board.getCell(0, 0).getNumber());
}
@Test
public void testResetBoard() {
int[][] numbers = {{5, 6}, {7, 8}};
HitoriBoard board = new HitoriBoard(numbers, Arrays.asList("1,1", "2,2"), "ResetTest");
board.resetBoard();
assertEquals(HitoriCell.CellState.GRAY, board.getCell(0, 0).getState());
}
@Test
public void testSetAndGetNumbers() {
int[][] initialNumbers = {{9, 10}, {11, 12}};
HitoriBoard board = new HitoriBoard(initialNumbers, Arrays.asList(), "SetNumbersTest");
int[][] newNumbers = {{1, 2}, {3, 4}};
board.setNumbers(newNumbers);
assertArrayEquals(newNumbers, board.getNumbers());
}
}

View File

@ -0,0 +1,23 @@
package Domain;
import PR2.HitoriSpiel.Domain.HitoriCell;
import org.junit.jupiter.api.Test;
import static org.junit.jupiter.api.Assertions.*;
public class HitoriCellTest {
@Test
public void testCellInitialization() {
HitoriCell cell = new HitoriCell(7);
assertEquals(7, cell.getNumber());
assertEquals(HitoriCell.CellState.GRAY, cell.getState());
}
@Test
public void testSetState() {
HitoriCell cell = new HitoriCell(8);
cell.setState(HitoriCell.CellState.BLACK);
assertEquals(HitoriCell.CellState.BLACK, cell.getState());
}
}

View File

@ -0,0 +1,89 @@
package Domain;
import PR2.HitoriSpiel.Domain.HitoriBoard;
import PR2.HitoriSpiel.Domain.HitoriValidator;
import PR2.HitoriSpiel.Domain.HitoriCell;
import org.junit.jupiter.api.Test;
import java.util.Arrays;
import static org.junit.jupiter.api.Assertions.*;
public class HitoriValidatorTest {
@Test
public void testValidateBoardValidSolution() {
// Spielfeld-Setup
int[][] numbers = {{1, 2, 3}, {4, 1, 6}, {7, 8, 1}};
HitoriBoard board = new HitoriBoard(numbers, Arrays.asList("1,1", "2,2", "3,3"), "ValidSolutionTest");
// Lösung manuell setzen (alle Zellen aus der Lösungsliste auf BLACK setzen)
board.getCell(0, 0).setState(HitoriCell.CellState.BLACK); // Koordinaten 1,1
board.getCell(1, 1).setState(HitoriCell.CellState.BLACK); // Koordinaten 2,2
board.getCell(2, 2).setState(HitoriCell.CellState.BLACK); // Koordinaten 3,3
// Alle anderen Zellen auf WHITE setzen
for (int i = 0; i < board.getSize(); i++) {
for (int j = 0; j < board.getSize(); j++) {
if (!Arrays.asList("1,1", "2,2", "3,3").contains((i + 1) + "," + (j + 1))) {
board.getCell(i, j).setState(HitoriCell.CellState.WHITE);
}
}
}
// Validator initialisieren und prüfen
HitoriValidator validator = new HitoriValidator(board);
assertTrue(validator.validateBoard(Arrays.asList("1,1", "2,2", "3,3")));
}
@Test
public void testValidateBoardInvalidSolution() {
// Spielfeld-Setup
int[][] numbers = {{1, 2, 3}, {4, 1, 6}, {7, 8, 1}};
HitoriBoard board = new HitoriBoard(numbers, Arrays.asList("1,1", "2,2", "3,3"), "InvalidSolutionTest");
// Ungültige Lösung setzen (eine Zelle aus der Lösungsliste bleibt nicht BLACK)
board.getCell(0, 0).setState(HitoriCell.CellState.BLACK); // Koordinaten 1,1
board.getCell(1, 1).setState(HitoriCell.CellState.WHITE); // Koordinaten 2,2 (falsch)
board.getCell(2, 2).setState(HitoriCell.CellState.BLACK); // Koordinaten 3,3
// Alle anderen Zellen auf WHITE setzen
for (int i = 0; i < board.getSize(); i++) {
for (int j = 0; j < board.getSize(); j++) {
if (!Arrays.asList("1,1", "2,2", "3,3").contains((i + 1) + "," + (j + 1))) {
board.getCell(i, j).setState(HitoriCell.CellState.WHITE);
}
}
}
// Validator initialisieren und prüfen
HitoriValidator validator = new HitoriValidator(board);
assertFalse(validator.validateBoard(Arrays.asList("1,1", "2,2", "3,3")));
}
@Test
public void testValidateBoardExtraBlackCells() {
// Spielfeld-Setup
int[][] numbers = {{1, 2, 3}, {4, 1, 6}, {7, 8, 1}};
HitoriBoard board = new HitoriBoard(numbers, Arrays.asList("1,1", "2,2", "3,3"), "ExtraBlackCellsTest");
// Lösung setzen
board.getCell(0, 0).setState(HitoriCell.CellState.BLACK); // Koordinaten 1,1
board.getCell(1, 1).setState(HitoriCell.CellState.BLACK); // Koordinaten 2,2
board.getCell(2, 2).setState(HitoriCell.CellState.BLACK); // Koordinaten 3,3
// Zusätzliche schwarze Zelle setzen (ungültig)
board.getCell(0, 1).setState(HitoriCell.CellState.BLACK); // Koordinaten 1,2 (nicht Teil der Lösung)
// Alle anderen Zellen auf WHITE setzen
for (int i = 0; i < board.getSize(); i++) {
for (int j = 0; j < board.getSize(); j++) {
if (!Arrays.asList("1,1", "2,2", "3,3", "1,2").contains((i + 1) + "," + (j + 1))) {
board.getCell(i, j).setState(HitoriCell.CellState.WHITE);
}
}
}
// Validator initialisieren und prüfen
HitoriValidator validator = new HitoriValidator(board);
assertFalse(validator.validateBoard(Arrays.asList("1,1", "2,2", "3,3")));
}
}

View File

@ -0,0 +1,29 @@
package Domain;
import PR2.HitoriSpiel.Domain.StateFileManager;
import PR2.HitoriSpiel.Domain.Action;
import org.junit.jupiter.api.Test;
import java.util.Stack;
import static org.junit.jupiter.api.Assertions.*;
public class StateFileManagerTest {
@Test
public void testSaveAndLoadState() {
Stack<Action> undoStack = new Stack<>();
Stack<Action> redoStack = new Stack<>();
undoStack.push(new Action(1, 1, "GRAY", "BLACK"));
redoStack.push(new Action(2, 2, "WHITE", "GRAY"));
StateFileManager.saveState(undoStack, redoStack);
Stack<Action> loadedUndo = new Stack<>();
Stack<Action> loadedRedo = new Stack<>();
StateFileManager.loadState(loadedUndo, loadedRedo);
assertEquals(undoStack, loadedUndo);
assertEquals(redoStack, loadedRedo);
}
}

View File

@ -0,0 +1,95 @@
package Fassade;
import PR2.HitoriSpiel.Domain.HitoriBoard;
import PR2.HitoriSpiel.Domain.HitoriCell;
import PR2.HitoriSpiel.Fassade.GameBoard;
import org.junit.jupiter.api.Test;
import javax.swing.*;
import java.util.Arrays;
import static org.junit.jupiter.api.Assertions.*;
public class GameBoardTest {
@Test
public void testGameBoardInitialization() {
int[][] numbers = {{1, 2, 3}, {4, 5, 6}, {7, 8, 9}};
HitoriBoard board = new HitoriBoard(numbers, Arrays.asList("1,1", "2,2", "3,3"), "TestBoard");
GameBoard gameBoard = new GameBoard(board);
assertNotNull(gameBoard, "GameBoard sollte erfolgreich initialisiert werden.");
assertNotNull(gameBoard.validateCurrentBoard(), "Das Spielfeld sollte validierbar sein.");
}
@Test
public void testResetBoard() {
int[][] numbers = {{1, 2, 3}, {4, 5, 6}, {7, 8, 9}};
HitoriBoard board = new HitoriBoard(numbers, Arrays.asList("1,1", "2,2", "3,3"), "TestBoard");
GameBoard gameBoard = new GameBoard(board);
// Setze einige Zellen auf unterschiedliche Zustände
board.getCell(0, 0).setState(HitoriCell.CellState.BLACK);
board.getCell(1, 1).setState(HitoriCell.CellState.WHITE);
// Führe das Zurücksetzen durch
gameBoard.resetBoard();
// Verifiziere, dass alle Zellen zurückgesetzt wurden
for (int i = 0; i < numbers.length; i++) {
for (int j = 0; j < numbers[i].length; j++) {
assertEquals(HitoriCell.CellState.GRAY, board.getCell(i, j).getState(),
"Alle Zellen sollten nach dem Zurücksetzen grau sein.");
}
}
}
@Test
public void testValidateCurrentBoard() {
int[][] numbers = {{1, 2, 3}, {4, 5, 6}, {7, 8, 9}};
HitoriBoard board = new HitoriBoard(numbers, Arrays.asList("1,1", "2,2", "3,3"), "TestBoard");
GameBoard gameBoard = new GameBoard(board);
// Setze Zellen auf die Lösung
board.getCell(0, 0).setState(HitoriCell.CellState.BLACK);
board.getCell(1, 1).setState(HitoriCell.CellState.BLACK);
board.getCell(2, 2).setState(HitoriCell.CellState.BLACK);
// Alle anderen Zellen auf weiß setzen
for (int i = 0; i < numbers.length; i++) {
for (int j = 0; j < numbers[i].length; j++) {
if (!Arrays.asList("1,1", "2,2", "3,3").contains((i + 1) + "," + (j + 1))) {
board.getCell(i, j).setState(HitoriCell.CellState.WHITE);
}
}
}
assertTrue(gameBoard.validateCurrentBoard(), "Das Board sollte als gültig erkannt werden.");
}
@Test
public void testToggleCellState() {
int[][] numbers = {{1, 2, 3}, {4, 5, 6}, {7, 8, 9}};
HitoriBoard board = new HitoriBoard(numbers, Arrays.asList("1,1", "2,2", "3,3"), "TestBoard");
GameBoard gameBoard = new GameBoard(board);
HitoriCell cell = board.getCell(0, 0);
// Initialer Zustand: GRAY
assertEquals(HitoriCell.CellState.GRAY, cell.getState(), "Die Zelle sollte initial grau sein.");
// Zustand wechseln: BLACK
gameBoard.toggleCellState(cell, 0, 0);
assertEquals(HitoriCell.CellState.BLACK, cell.getState(), "Die Zelle sollte schwarz sein.");
// Zustand wechseln: WHITE
gameBoard.toggleCellState(cell, 0, 0);
assertEquals(HitoriCell.CellState.WHITE, cell.getState(), "Die Zelle sollte weiß sein.");
// Zustand wechseln: GRAY
gameBoard.toggleCellState(cell, 0, 0);
assertEquals(HitoriCell.CellState.GRAY, cell.getState(), "Die Zelle sollte wieder grau sein.");
}
}

View File

@ -0,0 +1,44 @@
package Fassade;
import PR2.HitoriSpiel.Fassade.HighscoreManager;
import org.junit.jupiter.api.Test;
import java.util.List;
import static org.junit.jupiter.api.Assertions.*;
public class HighscoreManagerTest {
@Test
public void testAddHighscore() {
HighscoreManager manager = new HighscoreManager();
manager.addHighscore("Alice", 120, "TestBoard", 0);
List<HighscoreManager.Highscore> highscores = manager.getHighscoresForBoard("TestBoard");
assertEquals(1, highscores.size());
assertEquals("Alice", highscores.get(0).getPlayerName());
assertEquals(120, highscores.get(0).getTime());
assertEquals("TestBoard", highscores.get(0).getBoardName());
}
@Test
public void testIsNewHighscore() {
HighscoreManager manager = new HighscoreManager();
manager.addHighscore("Bob", 150, "TestBoard", 0);
assertTrue(manager.isNewHighscore(140, "TestBoard"));
assertFalse(manager.isNewHighscore(160, "TestBoard"));
}
@Test
public void testClearHighscores() {
HighscoreManager manager = new HighscoreManager();
manager.addHighscore("Alice", 100, "TestBoard", 0);
manager.clearHighscores();
List<HighscoreManager.Highscore> highscores = manager.getHighscores();
assertTrue(highscores.isEmpty(), "Alle Highscores sollten gelöscht sein.");
}
}

View File

@ -0,0 +1,102 @@
package Fassade;
import PR2.HitoriSpiel.Fassade.HitoriSolutionLoader;
import org.junit.jupiter.api.Test;
import java.io.*;
import java.util.ArrayList;
import java.util.List;
import static org.junit.jupiter.api.Assertions.*;
public class HitoriSolutionLoaderTest {
@Test
public void testLoadSolutionValidFile() throws IOException {
// Simuliere eine valide Lösung im InputStream
String solutionContent = """
//Lösung
1,1
2,2
3,3
""";
InputStream inputStream = new ByteArrayInputStream(solutionContent.getBytes());
// Mock den Aufruf von getResourceAsStream
List<String> solution = loadSolutionFromStream(inputStream);
assertNotNull(solution, "Die Lösungsliste sollte nicht null sein.");
assertFalse(solution.isEmpty(), "Die Lösungsliste sollte nicht leer sein.");
assertEquals("1,1", solution.get(0), "Die erste Koordinate sollte korrekt geladen werden.");
assertEquals("3,3", solution.get(2), "Die letzte Koordinate sollte korrekt geladen werden.");
}
@Test
public void testLoadSolutionNoSolutionSection() throws IOException {
// Simuliere eine Datei ohne "//Lösung"
String solutionContent = """
1,1
2,2
3,3
""";
InputStream inputStream = new ByteArrayInputStream(solutionContent.getBytes());
// Mock den Aufruf von getResourceAsStream
List<String> solution = loadSolutionFromStream(inputStream);
assertNotNull(solution, "Die Lösungsliste sollte nicht null sein.");
assertTrue(solution.isEmpty(), "Die Lösungsliste sollte leer sein, wenn kein Lösungsteil gefunden wird.");
}
@Test
public void testLoadSolutionWithEmptyLines() throws IOException {
// Simuliere eine Datei mit leeren Zeilen
String solutionContent = """
//Lösung
1,1
2,2
3,3
""";
InputStream inputStream = new ByteArrayInputStream(solutionContent.getBytes());
// Mock den Aufruf von getResourceAsStream
List<String> solution = loadSolutionFromStream(inputStream);
assertNotNull(solution, "Die Lösungsliste sollte nicht null sein.");
assertFalse(solution.isEmpty(), "Die Lösungsliste sollte nicht leer sein.");
assertEquals(3, solution.size(), "Die Lösungsliste sollte nur 3 gültige Einträge enthalten.");
assertEquals("1,1", solution.get(0), "Die erste Koordinate sollte korrekt geladen werden.");
}
// Hilfsmethode: Simuliert die Verarbeitung des InputStreams
private List<String> loadSolutionFromStream(InputStream inputStream) throws IOException {
BufferedReader reader = new BufferedReader(new InputStreamReader(inputStream));
List<String> solutionCoordinates = new ArrayList<>();
boolean solutionSectionFound = false;
String line;
while ((line = reader.readLine()) != null) {
line = line.trim();
if (line.startsWith("//Lösung")) {
solutionSectionFound = true;
continue;
}
if (solutionSectionFound) {
if (!line.isEmpty()) {
solutionCoordinates.add(line);
}
}
}
if (!solutionSectionFound) {
System.err.println("Warnung: Lösungsteil wurde in der Datei nicht gefunden.");
}
return solutionCoordinates;
}
}

View File

@ -0,0 +1,35 @@
package Fassade;
import PR2.HitoriSpiel.Fassade.Setup;
import org.junit.jupiter.api.Test;
import javax.swing.*;
import java.awt.*;
import static org.junit.jupiter.api.Assertions.*;
public class SetupTest {
@Test
public void testCreateButton() {
JButton button = Setup.createButton("TestButton", 100, 50);
assertNotNull(button);
assertEquals("TestButton", button.getText());
assertEquals(new Dimension(100, 50), button.getPreferredSize());
assertEquals(Setup.BUTTON_COLOR, button.getBackground());
assertEquals(Setup.BUTTON_TEXT_COLOR, button.getForeground());
}
@Test
public void testCreateGameBoardButton() {
JButton button = Setup.createGameBoardButton("GameButton", 150, 60);
assertNotNull(button);
assertEquals("GameButton", button.getText());
assertEquals(new Dimension(150, 60), button.getPreferredSize());
assertEquals(Setup.GAME_BUTTON_COLOR, button.getBackground());
assertEquals(Setup.GAME_BUTTON_TEXT_COLOR, button.getForeground());
}
}

View File

@ -0,0 +1,50 @@
package Fassade;
import PR2.HitoriSpiel.Fassade.StateManager;
import PR2.HitoriSpiel.Domain.Action;
import org.junit.jupiter.api.Test;
import static org.junit.jupiter.api.Assertions.*;
public class StateManagerTest {
@Test
public void testSaveActionAndUndo() {
StateManager stateManager = new StateManager();
stateManager.saveAction(0, 0, "GRAY", "BLACK");
Action undoAction = stateManager.undo();
assertNotNull(undoAction);
assertEquals(0, undoAction.getRow());
assertEquals(0, undoAction.getCol());
assertEquals("GRAY", undoAction.getOldState());
assertEquals("BLACK", undoAction.getNewState());
}
@Test
public void testRedo() {
StateManager stateManager = new StateManager();
stateManager.saveAction(1, 1, "WHITE", "BLACK");
stateManager.undo();
Action redoAction = stateManager.redo();
assertNotNull(redoAction);
assertEquals(1, redoAction.getRow());
assertEquals(1, redoAction.getCol());
assertEquals("WHITE", redoAction.getOldState());
assertEquals("BLACK", redoAction.getNewState());
}
@Test
public void testLoadStateFromFile() {
StateManager stateManager = new StateManager();
stateManager.saveAction(0, 0, "GRAY", "BLACK");
stateManager.saveAction(1, 1, "WHITE", "BLACK");
stateManager.loadStateFromFile();
assertNotNull(stateManager.undo(), "Der Undo-Stack sollte geladen werden.");
assertNotNull(stateManager.redo(), "Der Redo-Stack sollte geladen werden.");
}
}

View File

@ -0,0 +1,5 @@
package GUI;
public class BoardLoaderTest {
}

View File

@ -0,0 +1,42 @@
package GUI;
import PR2.HitoriSpiel.GUI.HighscoreDialog;
import org.junit.jupiter.api.Test;
import javax.swing.*;
import java.util.List;
import static org.junit.jupiter.api.Assertions.*;
public class HighscoreDialogTest {
@Test
public void testHighscoreDialogInitialization() {
SwingUtilities.invokeLater(() -> {
JFrame parentFrame = new JFrame();
List<String> boardNames = List.of("leicht_8x8.csv", "medium_10x10.csv");
HighscoreDialog dialog = new HighscoreDialog(parentFrame, boardNames);
assertNotNull(dialog, "Der HighscoreDialog sollte erfolgreich erstellt werden.");
assertEquals("Highscoreliste", dialog.getTitle(), "Der Titel des Dialogs sollte korrekt sein.");
assertEquals(600, dialog.getWidth(), "Die Breite des Dialogs sollte 600 Pixel betragen.");
assertEquals(400, dialog.getHeight(), "Die Höhe des Dialogs sollte 400 Pixel betragen.");
});
}
@Test
public void testLoadHighscoresForBoard() {
SwingUtilities.invokeLater(() -> {
JFrame parentFrame = new JFrame();
List<String> boardNames = List.of("leicht_8x8.csv", "medium_10x10.csv");
HighscoreDialog dialog = new HighscoreDialog(parentFrame, boardNames);
JComboBox<?> comboBox = (JComboBox<?>) dialog.getContentPane().getComponent(1); // ComboBox ist das 2. Element
assertNotNull(comboBox, "Die Spielfeld-Auswahl sollte existieren.");
assertEquals(2, comboBox.getItemCount(), "Die ComboBox sollte zwei Einträge enthalten.");
JTable table = (JTable) ((JScrollPane) dialog.getContentPane().getComponent(2)).getViewport().getView();
assertNotNull(table, "Die Tabelle für Highscores sollte existieren.");
});
}
}

View File

@ -0,0 +1,61 @@
package GUI;
import PR2.HitoriSpiel.GUI.PauseMenu;
import PR2.HitoriSpiel.Fassade.GameBoard;
import org.junit.jupiter.api.Test;
import javax.swing.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import static org.junit.jupiter.api.Assertions.*;
public class PauseMenuTest {
@Test
public void testPauseMenuInitialization() {
SwingUtilities.invokeLater(() -> {
JFrame parentFrame = new JFrame();
GameBoard gameBoard = new GameBoard(null); // GameBoard-Mock
ActionListener resumeAction = e -> System.out.println("Resume Action Triggered");
ActionListener mainMenuAction = e -> System.out.println("Main Menu Action Triggered");
ActionListener exitAction = e -> System.out.println("Exit Action Triggered");
PauseMenu pauseMenu = new PauseMenu(parentFrame, gameBoard, resumeAction, mainMenuAction, exitAction);
assertNotNull(pauseMenu, "Das PauseMenu sollte erfolgreich erstellt werden.");
assertEquals("Pause", pauseMenu.getTitle(), "Der Titel des Dialogs sollte 'Pause' sein.");
assertEquals(300, pauseMenu.getWidth(), "Die Breite des Dialogs sollte 300 Pixel betragen.");
assertEquals(200, pauseMenu.getHeight(), "Die Höhe des Dialogs sollte 200 Pixel betragen.");
});
}
@Test
public void testPauseMenuButtonActions() {
SwingUtilities.invokeLater(() -> {
JFrame parentFrame = new JFrame();
GameBoard gameBoard = new GameBoard(null); // GameBoard-Mock
boolean[] actionTriggered = {false, false, false};
ActionListener resumeAction = e -> actionTriggered[0] = true;
ActionListener mainMenuAction = e -> actionTriggered[1] = true;
ActionListener exitAction = e -> actionTriggered[2] = true;
PauseMenu pauseMenu = new PauseMenu(parentFrame, gameBoard, resumeAction, mainMenuAction, exitAction);
// Teste Buttons
JButton resumeButton = (JButton) pauseMenu.getContentPane().getComponent(0);
JButton mainMenuButton = (JButton) pauseMenu.getContentPane().getComponent(1);
JButton exitButton = (JButton) pauseMenu.getContentPane().getComponent(2);
resumeButton.doClick();
assertTrue(actionTriggered[0], "Resume-Action sollte ausgelöst werden.");
mainMenuButton.doClick();
assertTrue(actionTriggered[1], "MainMenu-Action sollte ausgelöst werden.");
exitButton.doClick();
assertTrue(actionTriggered[2], "Exit-Action sollte ausgelöst werden.");
});
}
}

View File

@ -0,0 +1,46 @@
package GUI;
import PR2.HitoriSpiel.GUI.StartMenu;
import org.junit.jupiter.api.Test;
import javax.swing.*;
import static org.junit.jupiter.api.Assertions.*;
public class StartMenuTest {
@Test
public void testStartMenuInitialization() {
SwingUtilities.invokeLater(() -> {
JFrame parentFrame = new JFrame();
StartMenu startMenu = new StartMenu(parentFrame);
assertNotNull(startMenu, "Das StartMenu sollte erfolgreich erstellt werden.");
assertEquals(5, startMenu.getComponentCount(), "Das StartMenu sollte fünf Buttons enthalten.");
// Überprüfe Buttons
JButton continueButton = (JButton) startMenu.getComponent(1);
assertEquals("Spiel fortsetzen", continueButton.getText(), "Der Text des ersten Buttons sollte korrekt sein.");
JButton selectBoardButton = (JButton) startMenu.getComponent(2);
assertEquals("Spielfeld aussuchen", selectBoardButton.getText(), "Der Text des zweiten Buttons sollte korrekt sein.");
});
}
@Test
public void testButtonActions() {
SwingUtilities.invokeLater(() -> {
JFrame parentFrame = new JFrame();
StartMenu startMenu = new StartMenu(parentFrame);
// Simuliere Button-Klicks
JButton continueButton = (JButton) startMenu.getComponent(1);
continueButton.doClick();
JButton exitButton = (JButton) startMenu.getComponent(4);
exitButton.doClick();
// Die tatsächliche Logik muss separat getestet werden (z. B. via Mocking).
});
}
}

View File

@ -4,7 +4,22 @@
* Simona-Ioana Purdila - 3015825
* Victoria Petropoulos - 3014866
## Plan für die Bearbeitung der Aufgabe:
- [ ] Aufgabestellung durchgehen und Issues erstellen
- [ ] Klassendiagramme erstellen
- [ ]
## Plan für die Bearbeitung der Aufgabenstellung:
- [x] Aufteilung des Produktiv-Codes in Domain, Fassade und GUI
- [x] Spielfelder von den Profs hochladen
- [x] Verwendung von Maven
- [x] Verwendung von Git
- [x] Verwendung von Feature-Branches
- [x] Erstellung Unit-Tests mit JUnit
## Die Aufgabenstellung:
- [x] GUI: GUI, in der beliebige Spielfelder angezeigt und bespielt werden können.
- [x] GUI: Die Möglichkeit ein bestimmtes Spielfeld auszuwählen oder zufällig eines ausgesucht zu bekommen.
- [x] Domain + GUI: Die Felder des Spielfelds sollen zu Beginn grau hinterlegt sein und auf schwarz (gestrichen) oder weiß gesetzt werden können, um einen besseren Überblick zu behalten (vgl. janko.at)
- [x] Domain + GUI: Alle gesetzten Farb-Markierungen sollen gespeichert werden und beliebig vor und zurück geklickt werden können (Undo/Redo-Funktion).
- [x] GUI: Ferner soll es einen Reset-Button geben, der das laufende Spiel wieder komplett auf den Anfangsstand zurücksetzt; die Zeit soll aber weiterlaufen.
- [x] GUI: Eine Zeitmessung, die während des Spiels mitläuft.
- [x] Domain: Ein Highscore für jedes Spielfeld, in dem die Zeiten zusammen mit einem vom Spieler einzugebenden Namen (auf der Platte) gespeichert werden.
- [x] GUI + Domain: Sobald das Spielfeld komplett korrekt gelöst ist (die geschwärzten Zahlen alle korrekt gesetzt wurden), stoppt das Spiel die Zeit und gibt die Möglichkeit einen Namen für den Highscore einzutragen.
- [ ] GUI + Domain: Das Spiel soll eine Markierung der fälschlich schwarz markierten Felder als Hilfestellung anzeigen können, es soll beim Highscore mitgespeichert werden, wie viele Fehler dabei insgesamt über das Spiel angezeigt wurden.
- [x] GUI + Domain: Beim Highscore soll für jedes Spielfeld auch die Durchschnittszeit aller bisherigen Einträge angezeigt werden.