Compare commits
No commits in common. "master" and "Improvements_Ioana" have entirely different histories.
master
...
Improvemen
115
Hitori/pom.xml
115
Hitori/pom.xml
|
@ -1,113 +1,62 @@
|
||||||
<?xml version="1.0" encoding="UTF-8"?>
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
|
<project xmlns="http://maven.apache.org/POM/4.0.0"
|
||||||
|
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||||
|
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||||
<modelVersion>4.0.0</modelVersion>
|
<modelVersion>4.0.0</modelVersion>
|
||||||
|
|
||||||
<groupId>org.example</groupId>
|
<groupId>org.example</groupId>
|
||||||
<artifactId>HitoriTeamProjekt</artifactId>
|
<artifactId>HitoriTeamProjekt</artifactId>
|
||||||
<version>1.0-SNAPSHOT</version>
|
<version>1.0-SNAPSHOT</version>
|
||||||
|
|
||||||
<properties>
|
<properties>
|
||||||
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
|
|
||||||
<maven.compiler.source>21</maven.compiler.source>
|
<maven.compiler.source>21</maven.compiler.source>
|
||||||
<maven.compiler.target>21</maven.compiler.target>
|
<maven.compiler.target>21</maven.compiler.target>
|
||||||
|
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
|
||||||
</properties>
|
</properties>
|
||||||
|
|
||||||
<dependencies>
|
<dependencies>
|
||||||
|
<!-- AssertJ Swing Test-Framework -->
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.junit.jupiter</groupId>
|
<groupId>org.assertj</groupId>
|
||||||
<artifactId>junit-jupiter-api</artifactId>
|
<artifactId>assertj-swing</artifactId>
|
||||||
<version>5.8.1</version>
|
<version>3.17.1</version>
|
||||||
|
<scope>test</scope>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>junit</groupId>
|
||||||
|
<artifactId>junit</artifactId>
|
||||||
|
<version>4.13.1</version>
|
||||||
<scope>test</scope>
|
<scope>test</scope>
|
||||||
</dependency>
|
</dependency>
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.junit.jupiter</groupId>
|
<groupId>org.junit.jupiter</groupId>
|
||||||
<artifactId>junit-jupiter-engine</artifactId>
|
<artifactId>junit-jupiter</artifactId>
|
||||||
<version>5.8.1</version>
|
<version>5.8.2</version>
|
||||||
<scope>test</scope>
|
<scope>test</scope>
|
||||||
</dependency>
|
</dependency>
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.apache.logging.log4j</groupId>
|
<groupId>org.mockito</groupId>
|
||||||
<artifactId>log4j-core</artifactId>
|
<artifactId>mockito-core</artifactId>
|
||||||
<version>2.24.2</version>
|
<version>4.5.1</version>
|
||||||
|
<scope>test</scope>
|
||||||
</dependency>
|
</dependency>
|
||||||
</dependencies>
|
</dependencies>
|
||||||
|
|
||||||
<build>
|
<build>
|
||||||
<plugins>
|
<plugins>
|
||||||
<!-- Compiler -->
|
|
||||||
<plugin>
|
<plugin>
|
||||||
<groupId>org.apache.maven.plugins</groupId>
|
<groupId>org.apache.maven.plugins</groupId>
|
||||||
<artifactId>maven-compiler-plugin</artifactId>
|
<artifactId>maven-jar-plugin</artifactId>
|
||||||
<version>3.13.0</version>
|
<version>3.2.0</version>
|
||||||
<configuration>
|
<configuration>
|
||||||
<source>${maven.compiler.source}</source>
|
<archive>
|
||||||
<target>${maven.compiler.target}</target>
|
<manifest>
|
||||||
|
<addClasspath>true</addClasspath>
|
||||||
|
<mainClass>PR2.HitoriSpiel.Main.Main</mainClass> <!-- Vollqualifizierter Name deiner Main-Klasse -->
|
||||||
|
</manifest>
|
||||||
|
</archive>
|
||||||
</configuration>
|
</configuration>
|
||||||
</plugin>
|
</plugin>
|
||||||
<!-- JAR creation -->
|
|
||||||
<plugin>
|
|
||||||
<groupId>org.apache.maven.plugins</groupId>
|
|
||||||
<artifactId>maven-shade-plugin</artifactId>
|
|
||||||
<version>3.6.0</version>
|
|
||||||
<configuration>
|
|
||||||
<createDependencyReducedPom>false</createDependencyReducedPom>
|
|
||||||
</configuration>
|
|
||||||
<executions>
|
|
||||||
<execution>
|
|
||||||
<phase>package</phase>
|
|
||||||
<goals>
|
|
||||||
<goal>shade</goal>
|
|
||||||
</goals>
|
|
||||||
<configuration>
|
|
||||||
<transformers>
|
|
||||||
<transformer implementation="org.apache.maven.plugins.shade.resource.ManifestResourceTransformer">
|
|
||||||
<mainClass> PR2.HitoriSpiel.Main.Main</mainClass>
|
|
||||||
</transformer>
|
|
||||||
</transformers>
|
|
||||||
</configuration>
|
|
||||||
</execution>
|
|
||||||
</executions>
|
|
||||||
</plugin>
|
|
||||||
<!-- Code coverage, cf.: target/site/jacoco -->
|
|
||||||
<plugin>
|
|
||||||
<groupId>org.jacoco</groupId>
|
|
||||||
<artifactId>jacoco-maven-plugin</artifactId>
|
|
||||||
<version>0.8.12</version>
|
|
||||||
<executions>
|
|
||||||
<execution>
|
|
||||||
<goals>
|
|
||||||
<goal>prepare-agent</goal>
|
|
||||||
</goals>
|
|
||||||
</execution>
|
|
||||||
<execution>
|
|
||||||
<id>report</id>
|
|
||||||
<phase>test</phase>
|
|
||||||
<goals>
|
|
||||||
<goal>report</goal>
|
|
||||||
</goals>
|
|
||||||
</execution>
|
|
||||||
</executions>
|
|
||||||
</plugin>
|
|
||||||
<!-- Static code analysis, cf: target/site/pmd.html -->
|
|
||||||
<plugin>
|
|
||||||
<groupId>org.apache.maven.plugins</groupId>
|
|
||||||
<artifactId>maven-pmd-plugin</artifactId>
|
|
||||||
<version>3.26.0</version>
|
|
||||||
<configuration>
|
|
||||||
<failOnViolation>false</failOnViolation>
|
|
||||||
<printFailingErrors>true</printFailingErrors>
|
|
||||||
</configuration>
|
|
||||||
<executions>
|
|
||||||
<execution>
|
|
||||||
<phase>verify</phase>
|
|
||||||
<goals>
|
|
||||||
<goal>check</goal>
|
|
||||||
</goals>
|
|
||||||
</execution>
|
|
||||||
</executions>
|
|
||||||
</plugin>
|
|
||||||
</plugins>
|
</plugins>
|
||||||
</build>
|
</build>
|
||||||
<reporting>
|
|
||||||
<plugins>
|
|
||||||
<!-- generate Javadocs via "mvn site" and find them in the site
|
|
||||||
folder -->
|
|
||||||
</plugins>
|
|
||||||
</reporting>
|
|
||||||
</project>
|
</project>
|
|
@ -6,4 +6,3 @@ Test4,200,Hitori15x15_medium.csv,10
|
||||||
IOANA VERSUCH 156,105,Hitori5x5_leicht.csv,0
|
IOANA VERSUCH 156,105,Hitori5x5_leicht.csv,0
|
||||||
IOANA VERSUCH 439,44,Hitori5x5_leicht.csv,0
|
IOANA VERSUCH 439,44,Hitori5x5_leicht.csv,0
|
||||||
Yovu,46,Hitori4x4_leicht.csv,0
|
Yovu,46,Hitori4x4_leicht.csv,0
|
||||||
hi,18,Hitori4x4_leicht.csv,0
|
|
||||||
|
|
|
@ -1,27 +1,11 @@
|
||||||
package PR2.HitoriSpiel.Domain;
|
package PR2.HitoriSpiel.Domain;
|
||||||
|
|
||||||
/**
|
|
||||||
* Die Klasse Action repräsentiert eine Aktion im Hitori-Spiel, die eine Änderung
|
|
||||||
* an einer bestimmten Zelle des Spielfelds beschreibt, einschließlich der Koordinaten,
|
|
||||||
* des alten Zustands und des neuen Zustands.
|
|
||||||
*/
|
|
||||||
|
|
||||||
public class Action {
|
public class Action {
|
||||||
private final int row; // Zeile, in der die Änderung erfolgt ist
|
private final int row; // Zeile, in der die Änderung erfolgt ist
|
||||||
private final int col; // Spalte, 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 oldState; // Alter Zustand der Zelle
|
||||||
private final String newState; // Neuer Zustand der Zelle
|
private final String newState; // Neuer Zustand der Zelle
|
||||||
|
|
||||||
/**
|
|
||||||
* Erstellt ein neues Action-Objekt mit den angegebenen Koordinaten,
|
|
||||||
* dem alten Zustand und dem neuen Zustand.
|
|
||||||
*
|
|
||||||
* @param row Die Zeile, in der die Änderung erfolgt ist.
|
|
||||||
* @param col Die Spalte, in der die Änderung erfolgt ist.
|
|
||||||
* @param oldState Der alte Zustand der Zelle.
|
|
||||||
* @param newState Der neue Zustand der Zelle.
|
|
||||||
*/
|
|
||||||
|
|
||||||
public Action(int row, int col, String oldState, String newState) {
|
public Action(int row, int col, String oldState, String newState) {
|
||||||
this.row = row;
|
this.row = row;
|
||||||
this.col = col;
|
this.col = col;
|
||||||
|
@ -29,15 +13,6 @@ public class Action {
|
||||||
this.newState = newState;
|
this.newState = newState;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Erstellt ein neues Action-Objekt mit den angegebenen Koordinaten
|
|
||||||
* und dem neuen Zustand; der alte Zustand wird auf "GRAY" gesetzt.
|
|
||||||
*
|
|
||||||
* @param row Die Zeile, in der die Änderung erfolgt ist.
|
|
||||||
* @param col Die Spalte, in der die Änderung erfolgt ist.
|
|
||||||
* @param newState Der neue Zustand der Zelle.
|
|
||||||
*/
|
|
||||||
|
|
||||||
// Alternative Konstruktor für Standardwerte
|
// Alternative Konstruktor für Standardwerte
|
||||||
public Action(int row, int col, String newState) {
|
public Action(int row, int col, String newState) {
|
||||||
this(row, col, "GRAY", newState);
|
this(row, col, "GRAY", newState);
|
||||||
|
@ -77,13 +52,6 @@ public class Action {
|
||||||
newState.equals(action.newState);
|
newState.equals(action.newState);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Berechnet den Hashcode für das Action-Objekt basierend
|
|
||||||
* auf den Attributen row, col, oldState und newState.
|
|
||||||
*
|
|
||||||
* @return Der berechnete Hashcode.
|
|
||||||
*/
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int hashCode() {
|
public int hashCode() {
|
||||||
int result = row;
|
int result = row;
|
||||||
|
|
|
@ -3,8 +3,7 @@ package PR2.HitoriSpiel.Domain;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Die Klasse HitoriBoard repräsentiert das Spielfeld des Hitori-Spiels.
|
* Represents the Hitori game board.
|
||||||
* Sie enthält die Zellen des Spielfelds, die Lösungskonfiguration und den Namen des Spielfelds.
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
public class HitoriBoard {
|
public class HitoriBoard {
|
||||||
|
@ -13,15 +12,6 @@ public class HitoriBoard {
|
||||||
private final String boardName; // Name des Spielfelds
|
private final String boardName; // Name des Spielfelds
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Konstruktor, der das Spielfeld mit den Zahlen, der Lösungskonfiguration
|
|
||||||
* und dem Namen des Spielfelds initialisiert.
|
|
||||||
*
|
|
||||||
* @param numbers 2D-Array mit den Zahlen des Spielfelds.
|
|
||||||
* @param solutionCoordinates Liste der Koordinaten, die zur Lösung gehören.
|
|
||||||
* @param boardName Name des Spielfelds.
|
|
||||||
*/
|
|
||||||
|
|
||||||
public HitoriBoard(int[][] numbers, List<String> solutionCoordinates, String boardName) {
|
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;
|
||||||
|
@ -91,6 +81,32 @@ public class HitoriBoard {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,28 +1,17 @@
|
||||||
package PR2.HitoriSpiel.Domain;
|
package PR2.HitoriSpiel.Domain;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Die Klasse HitoriCell repräsentiert eine einzelne Zelle auf dem Hitori-Spielfeld.
|
* Represents a single cell on the Hitori board.
|
||||||
* Sie speichert die Zahl der Zelle und deren Zustand (GRAY, WHITE, BLACK).
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
public class HitoriCell {
|
public class HitoriCell {
|
||||||
|
|
||||||
/**
|
|
||||||
* Enum zur Darstellung der möglichen Zustände einer Zelle.
|
|
||||||
*/
|
|
||||||
|
|
||||||
public enum CellState {
|
public enum CellState {
|
||||||
GRAY, WHITE, BLACK
|
GRAY, WHITE, BLACK
|
||||||
}
|
}
|
||||||
private int number;
|
private int number;
|
||||||
private CellState state;
|
private CellState state;
|
||||||
|
|
||||||
/**
|
|
||||||
* Konstruktor, der eine Zelle mit einer Zahl erstellt und den Zustand auf GRAY setzt.
|
|
||||||
*
|
|
||||||
* @param number Die Zahl der Zelle.
|
|
||||||
*/
|
|
||||||
|
|
||||||
public HitoriCell(int number) {
|
public HitoriCell(int number) {
|
||||||
this.number = number;
|
this.number = number;
|
||||||
this.state = CellState.GRAY;
|
this.state = CellState.GRAY;
|
||||||
|
|
|
@ -3,44 +3,32 @@ package PR2.HitoriSpiel.Domain;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Die Klasse HitoriValidator überprüft, ob das aktuelle Spielfeld des Hitori-Spiels korrekt gelöst ist,
|
* Validates the Hitori board against the solution.
|
||||||
* indem es mit der angegebenen Lösung verglichen wird.
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
public class HitoriValidator {
|
public class HitoriValidator {
|
||||||
|
|
||||||
private final HitoriBoard board;
|
private final HitoriBoard board;
|
||||||
|
|
||||||
/**
|
|
||||||
* Konstruktor, der den Validator mit einem Hitori-Spielfeld initialisiert.
|
|
||||||
*
|
|
||||||
* @param board Das zu überprüfende Hitori-Spielfeld.
|
|
||||||
*/
|
|
||||||
|
|
||||||
public HitoriValidator(HitoriBoard board) {
|
public HitoriValidator(HitoriBoard board) {
|
||||||
this.board = board;
|
this.board = board;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Überprüft, ob das aktuelle Spielfeld der Lösung entspricht.
|
* Validates the current board against the solution.
|
||||||
*
|
* @param solutionCoordinates The coordinates of the correct black cells in "row,column" format.
|
||||||
* @param solutionCoordinates Die Koordinaten der korrekten schwarzen Felder im Format "row,column".
|
* @return true if the current board matches the solution, false otherwise.
|
||||||
* @return true, wenn das aktuelle Spielfeld der Lösung entspricht, andernfalls false.
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
public boolean validateBoard(List<String> solutionCoordinates) {
|
public boolean validateBoard(List<String> solutionCoordinates) {
|
||||||
// Überprüfe, ob alle Koordinaten der Lösung korrekt schwarz markiert sind
|
|
||||||
for (String coordinate : solutionCoordinates) {
|
for (String coordinate : solutionCoordinates) {
|
||||||
String[] parts = coordinate.split(",");
|
String[] parts = coordinate.split(",");
|
||||||
int row = Integer.parseInt(parts[0]) - 1;
|
int row = Integer.parseInt(parts[0]) - 1;
|
||||||
int col = Integer.parseInt(parts[1]) - 1;
|
int col = Integer.parseInt(parts[1]) - 1;
|
||||||
|
|
||||||
if (board.getCell(row,col).getState() != HitoriCell.CellState.BLACK){
|
if (board.getCell(row,col).getState() != HitoriCell.CellState.BLACK){
|
||||||
return false; // Ein Feld, das schwarz sein sollte, ist aber nicht
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Überprüfe alle Zellen des Spielfelds
|
|
||||||
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++) {
|
||||||
HitoriCell cell = board.getCell(i, j);
|
HitoriCell cell = board.getCell(i, j);
|
||||||
|
@ -56,7 +44,7 @@ public class HitoriValidator {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return true; // Das Spielfeld entspricht der Lösung
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,23 +1,17 @@
|
||||||
package PR2.HitoriSpiel.Domain;
|
package PR2.HitoriSpiel.Domain;
|
||||||
|
|
||||||
import java.io.*;
|
import java.io.*;
|
||||||
import java.nio.file.*;
|
import java.nio.file.Files;
|
||||||
|
import java.nio.file.Path;
|
||||||
|
import java.nio.file.Paths;
|
||||||
import java.util.Stack;
|
import java.util.Stack;
|
||||||
|
|
||||||
/**
|
|
||||||
* Die Klasse StateFileManager verwaltet das Speichern und Laden der Zustände des Undo- und Redo-Stacks
|
|
||||||
* in eine Datei. Sie stellt sicher, dass der Speicherort existiert und ermöglicht so die Persistenz der Spielzustände.
|
|
||||||
*/
|
|
||||||
|
|
||||||
public class StateFileManager {
|
public class StateFileManager {
|
||||||
// Speicherort für die Undo/Redo-Datei im Benutzerverzeichnis
|
// Speicherort für die Undo/Redo-Datei im Benutzerverzeichnis
|
||||||
private static final String BASE_DIR = System.getProperty("user.home") + "/HitoriGame";
|
private static final String BASE_DIR = System.getProperty("user.home") + "/HitoriGame";
|
||||||
private static final String FILE_NAME = BASE_DIR + "/undoRedoLog.txt";
|
private static final String FILE_NAME = BASE_DIR + "/undoRedoLog.txt";
|
||||||
|
|
||||||
/**
|
// Stellt sicher, dass der Ordner und die Datei existieren
|
||||||
* Stellt sicher, dass der Ordner und die Datei existieren.
|
|
||||||
*/
|
|
||||||
|
|
||||||
private static void ensureFileExists() {
|
private static void ensureFileExists() {
|
||||||
try {
|
try {
|
||||||
// Erstellt den Ordner, falls er nicht existiert
|
// Erstellt den Ordner, falls er nicht existiert
|
||||||
|
@ -38,13 +32,7 @@ public class StateFileManager {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
// Speichert den Zustand in der Datei
|
||||||
* Speichert den Zustand der Undo- und Redo-Stacks in der Datei.
|
|
||||||
*
|
|
||||||
* @param undoStack Der aktuelle Undo-Stack.
|
|
||||||
* @param redoStack Der aktuelle Redo-Stack.
|
|
||||||
*/
|
|
||||||
|
|
||||||
public static void saveState(Stack<Action> undoStack, Stack<Action> redoStack) {
|
public static void saveState(Stack<Action> undoStack, Stack<Action> redoStack) {
|
||||||
ensureFileExists(); // Stellt sicher, dass die Datei existiert
|
ensureFileExists(); // Stellt sicher, dass die Datei existiert
|
||||||
try (BufferedWriter writer = new BufferedWriter(new FileWriter(FILE_NAME))) {
|
try (BufferedWriter writer = new BufferedWriter(new FileWriter(FILE_NAME))) {
|
||||||
|
@ -66,13 +54,7 @@ public class StateFileManager {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
// Lädt den Zustand aus der Datei
|
||||||
* Lädt den Zustand der Undo- und Redo-Stacks aus der Datei.
|
|
||||||
*
|
|
||||||
* @param undoStack Der Stack, in den die Undo-Zustände geladen werden.
|
|
||||||
* @param redoStack Der Stack, in den die Redo-Zustände geladen werden.
|
|
||||||
*/
|
|
||||||
|
|
||||||
public static void loadState(Stack<Action> undoStack, Stack<Action> redoStack) {
|
public static void loadState(Stack<Action> undoStack, Stack<Action> redoStack) {
|
||||||
ensureFileExists(); // Stellt sicher, dass die Datei existiert
|
ensureFileExists(); // Stellt sicher, dass die Datei existiert
|
||||||
try (BufferedReader reader = new BufferedReader(new FileReader(FILE_NAME))) {
|
try (BufferedReader reader = new BufferedReader(new FileReader(FILE_NAME))) {
|
||||||
|
|
|
@ -1,24 +0,0 @@
|
||||||
package PR2.HitoriSpiel.Fassade;
|
|
||||||
|
|
||||||
import PR2.HitoriSpiel.Domain.HitoriBoard;
|
|
||||||
|
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Die Klasse BoardManager dient als Fassade, um ein HitoriBoard-Objekt zu erstellen
|
|
||||||
* und die Spielfeld-Initialisierung zu kapseln.
|
|
||||||
*/
|
|
||||||
|
|
||||||
public class BoardManager {
|
|
||||||
/**
|
|
||||||
* Erstellt und gibt ein HitoriBoard-Objekt basierend auf den angegebenen Parametern zurück.
|
|
||||||
*
|
|
||||||
* @param boardData Die Daten des Spielfelds.
|
|
||||||
* @param solutionCoordinates Die Koordinaten der Lösung.
|
|
||||||
* @param selectedFile Die ausgewählte Datei mit den Spielfeldinformationen.
|
|
||||||
* @return Das erstellte HitoriBoard-Objekt.
|
|
||||||
*/
|
|
||||||
public HitoriBoard createBoard(int[][] boardData, List<String> solutionCoordinates, String selectedFile) {
|
|
||||||
return new HitoriBoard(boardData, solutionCoordinates, selectedFile);
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -10,26 +10,14 @@ import PR2.HitoriSpiel.GUI.StartMenu;
|
||||||
import javax.swing.*;
|
import javax.swing.*;
|
||||||
import java.awt.*;
|
import java.awt.*;
|
||||||
|
|
||||||
/**
|
|
||||||
* Die Klasse GameBoard repräsentiert das Spielfeld des Hitori-Spiels mit zugehörigen Steuerungselementen.
|
|
||||||
* Sie bietet Funktionalitäten wie Timer, Spielfeldvalidierung, Undo/Redo und Highscore-Management.
|
|
||||||
*/
|
|
||||||
|
|
||||||
public class GameBoard extends JPanel {
|
public class GameBoard extends JPanel {
|
||||||
private final HitoriBoard board; // Das Hitori-Spielfeld-Objekt
|
private final HitoriBoard board;
|
||||||
private Timer timer; // Timer für die Spielzeitmessung
|
private Timer timer;
|
||||||
private long startTime; // Startzeit des Timers
|
private long startTime;
|
||||||
private JLabel timerLabel; // Anzeigeelement für die aktuelle Spielzeit
|
private JLabel timerLabel;
|
||||||
private long pausedTime = 0; // Zeit, die beim Pausieren bereits abgelaufen ist
|
|
||||||
private JPanel gamePanel; // Das Spielfeld als JPanel
|
private JPanel gamePanel; // Das Spielfeld als JPanel
|
||||||
private final StateManager stateManager = new StateManager(); // Manager für Undo/Redo-Operationen
|
private final StateManager stateManager = new StateManager();
|
||||||
private long elapsedTime = 0;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Konstruktor, der das Spielfeld und die Steuerungselemente initialisiert.
|
|
||||||
*
|
|
||||||
* @param board Das Hitori-Spielfeld.
|
|
||||||
*/
|
|
||||||
|
|
||||||
public GameBoard(HitoriBoard board) {
|
public GameBoard(HitoriBoard board) {
|
||||||
this.board = board;
|
this.board = board;
|
||||||
|
@ -43,17 +31,13 @@ public class GameBoard extends JPanel {
|
||||||
|
|
||||||
// Spielfeld erstellen
|
// Spielfeld erstellen
|
||||||
gamePanel = createGamePanel();
|
gamePanel = createGamePanel();
|
||||||
add(gamePanel, BorderLayout.CENTER); // Spielfeld im Zentrum hinzufügen
|
add(gamePanel, BorderLayout.CENTER);
|
||||||
|
|
||||||
// Kontroll-Buttons unten hinzufügen
|
// Kontroll-Buttons unten hinzufügen
|
||||||
JPanel controlPanel = createControlPanel();
|
JPanel controlPanel = createControlPanel();
|
||||||
add(controlPanel, BorderLayout.SOUTH); // Buttons am unteren Rand platzieren
|
add(controlPanel, BorderLayout.SOUTH);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Initialisiert das Timer-Label.
|
|
||||||
*/
|
|
||||||
|
|
||||||
private void initializeTimerLabel() {
|
private void initializeTimerLabel() {
|
||||||
timerLabel = new JLabel("Zeit: 0 Sekunden");
|
timerLabel = new JLabel("Zeit: 0 Sekunden");
|
||||||
timerLabel.setHorizontalAlignment(SwingConstants.CENTER);
|
timerLabel.setHorizontalAlignment(SwingConstants.CENTER);
|
||||||
|
@ -61,12 +45,20 @@ public class GameBoard extends JPanel {
|
||||||
add(timerLabel, BorderLayout.NORTH);
|
add(timerLabel, BorderLayout.NORTH);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void startTimer() {
|
||||||
|
startTime = System.currentTimeMillis();
|
||||||
|
timer = new Timer(1000, e -> {
|
||||||
|
long elapsedTime = (System.currentTimeMillis() - startTime) / 1000;
|
||||||
|
timerLabel.setText("Zeit: " + elapsedTime + " Sekunden");
|
||||||
|
});
|
||||||
|
timer.start();
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
private void stopTimer() {
|
||||||
* Erstellt das Steuerungspanel mit Kontroll-Buttons.
|
if (timer != null) {
|
||||||
*
|
timer.stop();
|
||||||
* @return Das erstellte Panel.
|
}
|
||||||
*/
|
}
|
||||||
|
|
||||||
private JPanel createControlPanel() {
|
private JPanel createControlPanel() {
|
||||||
JPanel controlPanel = new JPanel();
|
JPanel controlPanel = new JPanel();
|
||||||
|
@ -80,36 +72,24 @@ public class GameBoard extends JPanel {
|
||||||
return controlPanel;
|
return controlPanel;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Erstellt den "Zurücksetzen"-Button.
|
|
||||||
*
|
|
||||||
* @return Der Reset-Button.
|
|
||||||
*/
|
|
||||||
|
|
||||||
private JButton createResetButton() {
|
private JButton createResetButton() {
|
||||||
JButton resetButton = Setup.createGameBoardButton("Zurücksetzen", 150, 30);
|
JButton resetButton = Setup.createGameBoardButton("Zurücksetzen", 150, 30);
|
||||||
resetButton.addActionListener(e -> {
|
resetButton.addActionListener(e -> {
|
||||||
//saveStateForUndo();
|
//saveStateForUndo();
|
||||||
resetBoard(); // Spielfeld zurücksetzen
|
resetBoard();
|
||||||
});
|
});
|
||||||
return resetButton;
|
return resetButton;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Erstellt den "Undo"-Button.
|
|
||||||
*
|
|
||||||
* @return Der Undo-Button.
|
|
||||||
*/
|
|
||||||
|
|
||||||
private JButton createUndoButton() {
|
private JButton createUndoButton() {
|
||||||
JButton undoButton = Setup.createGameBoardButton("Undo", 80, 30);
|
JButton undoButton = Setup.createGameBoardButton("Undo", 80, 30);
|
||||||
undoButton.addActionListener(e -> {
|
undoButton.addActionListener(e -> {
|
||||||
Action action = stateManager.undo(); // Letzte Aktion rückgängig machen
|
Action action = stateManager.undo();
|
||||||
if (action != null) {
|
if (action != null) {
|
||||||
HitoriCell cell = board.getCell(action.getRow(), action.getCol()); // Betroffene Zelle abrufen
|
HitoriCell cell = board.getCell(action.getRow(), action.getCol());
|
||||||
cell.setState(HitoriCell.CellState.valueOf(action.getOldState())); // Zustand der Zelle zurücksetzen
|
cell.setState(HitoriCell.CellState.valueOf(action.getOldState()));
|
||||||
JButton button = (JButton) gamePanel.getComponent(action.getRow() * board.getSize() + action.getCol());
|
JButton button = (JButton) gamePanel.getComponent(action.getRow() * board.getSize() + action.getCol());
|
||||||
updateButtonState(button, cell); // Button-Status aktualisieren
|
updateButtonState(button, cell);
|
||||||
} else {
|
} else {
|
||||||
JOptionPane.showMessageDialog(this, "Kein Zustand zum Zurücksetzen vorhanden.", "Undo", JOptionPane.INFORMATION_MESSAGE);
|
JOptionPane.showMessageDialog(this, "Kein Zustand zum Zurücksetzen vorhanden.", "Undo", JOptionPane.INFORMATION_MESSAGE);
|
||||||
}
|
}
|
||||||
|
@ -118,16 +98,10 @@ public class GameBoard extends JPanel {
|
||||||
return undoButton;
|
return undoButton;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Erstellt den "Redo"-Button.
|
|
||||||
*
|
|
||||||
* @return Der Redo-Button.
|
|
||||||
*/
|
|
||||||
|
|
||||||
private JButton createRedoButton() {
|
private JButton createRedoButton() {
|
||||||
JButton redoButton = Setup.createGameBoardButton("Redo", 80, 30);
|
JButton redoButton = Setup.createGameBoardButton("Redo", 80, 30);
|
||||||
redoButton.addActionListener(e -> {
|
redoButton.addActionListener(e -> {
|
||||||
Action action = stateManager.redo(); // Letzte rückgängig gemachte Aktion wiederherstellen
|
Action action = stateManager.redo();
|
||||||
if (action != null) {
|
if (action != null) {
|
||||||
HitoriCell cell = board.getCell(action.getRow(), action.getCol());
|
HitoriCell cell = board.getCell(action.getRow(), action.getCol());
|
||||||
cell.setState(HitoriCell.CellState.valueOf(action.getNewState()));
|
cell.setState(HitoriCell.CellState.valueOf(action.getNewState()));
|
||||||
|
@ -140,18 +114,12 @@ public class GameBoard extends JPanel {
|
||||||
return redoButton;
|
return redoButton;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Erstellt den "Lösen"-Button.
|
|
||||||
*
|
|
||||||
* @return Der Validate-Button.
|
|
||||||
*/
|
|
||||||
|
|
||||||
private JButton createValidateButton() {
|
private JButton createValidateButton() {
|
||||||
JButton validateButton = Setup.createGameBoardButton("Lösen", 80, 30);
|
JButton validateButton = Setup.createGameBoardButton("Lösen", 80, 30);
|
||||||
validateButton.addActionListener(e -> {
|
validateButton.addActionListener(e -> {
|
||||||
if (validateCurrentBoard()) { // Prüfen, ob das Spielfeld korrekt gelöst ist
|
if (validateCurrentBoard()) {
|
||||||
stopTimer(); // Timer anhalten
|
stopTimer();
|
||||||
handleHighscore(); // Highscore bearbeiten
|
handleHighscore();
|
||||||
} else {
|
} else {
|
||||||
JOptionPane.showMessageDialog(this, "Das Spielfeld enthält Fehler!", "Fehler", JOptionPane.ERROR_MESSAGE);
|
JOptionPane.showMessageDialog(this, "Das Spielfeld enthält Fehler!", "Fehler", JOptionPane.ERROR_MESSAGE);
|
||||||
}
|
}
|
||||||
|
@ -159,12 +127,6 @@ public class GameBoard extends JPanel {
|
||||||
return validateButton;
|
return validateButton;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Erstellt den "Pause"-Button.
|
|
||||||
*
|
|
||||||
* @return Der Pause-Button.
|
|
||||||
*/
|
|
||||||
|
|
||||||
private JButton createPauseButton() {
|
private JButton createPauseButton() {
|
||||||
JButton pauseButton = Setup.createGameBoardButton("Pause", 80, 30);
|
JButton pauseButton = Setup.createGameBoardButton("Pause", 80, 30);
|
||||||
pauseButton.addActionListener(e -> {
|
pauseButton.addActionListener(e -> {
|
||||||
|
@ -174,28 +136,18 @@ public class GameBoard extends JPanel {
|
||||||
return pauseButton;
|
return pauseButton;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Validiert das aktuelle Spielfeld gegen die Lösung.
|
|
||||||
*
|
|
||||||
* @return true, wenn das Spielfeld korrekt ist, sonst false.
|
|
||||||
*/
|
|
||||||
|
|
||||||
public boolean validateCurrentBoard() {
|
public boolean validateCurrentBoard() {
|
||||||
HitoriValidator validator = new HitoriValidator(board);
|
HitoriValidator validator = new HitoriValidator(board);
|
||||||
return validator.validateBoard(board.getSolutionCoordinates()); // Prüfen, ob das Spielfeld korrekt ist
|
return validator.validateBoard(board.getSolutionCoordinates());
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Verarbeitet die Highscore-Logik, einschließlich der Überprüfung, ob ein neuer Highscore erreicht wurde,
|
|
||||||
* und speichert den Highscore, wenn der Spieler seinen Namen eingibt.
|
|
||||||
*/
|
|
||||||
|
|
||||||
private void handleHighscore() {
|
private void handleHighscore() {
|
||||||
|
int elapsedTime = (int) ((System.currentTimeMillis() - startTime) / 1000); // Spielzeit in Sekunden
|
||||||
String boardName = board.getBoardName();
|
String boardName = board.getBoardName();
|
||||||
int errors = 0; // Aktuelle Fehlerzahl (falls vorhanden, muss noch angepasst werden)
|
int errors = 0; // Aktuelle Fehlerzahl (falls vorhanden, muss noch angepasst werden)
|
||||||
|
|
||||||
HighscoreManager manager = new HighscoreManager();
|
HighscoreManager manager = new HighscoreManager();
|
||||||
boolean isNewHighscore = manager.isNewHighscore((int)elapsedTime, boardName); // Prüfen, ob ein neuer Highscore erreicht wurde
|
boolean isNewHighscore = manager.isNewHighscore(elapsedTime, boardName);
|
||||||
|
|
||||||
// Zeige ein Dialogfenster zur Namenseingabe
|
// Zeige ein Dialogfenster zur Namenseingabe
|
||||||
String playerName = JOptionPane.showInputDialog(this,
|
String playerName = JOptionPane.showInputDialog(this,
|
||||||
|
@ -211,7 +163,7 @@ public class GameBoard extends JPanel {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Speichere den Highscore
|
// Speichere den Highscore
|
||||||
manager.addHighscore(playerName, (int)elapsedTime, boardName, errors);
|
manager.addHighscore(playerName, elapsedTime, boardName, errors);
|
||||||
|
|
||||||
JOptionPane.showMessageDialog(this,
|
JOptionPane.showMessageDialog(this,
|
||||||
isNewHighscore
|
isNewHighscore
|
||||||
|
@ -225,15 +177,9 @@ public class GameBoard extends JPanel {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Zeigt das Pausenmenü an.
|
|
||||||
*/
|
|
||||||
|
|
||||||
private void showPauseMenu() {
|
private void showPauseMenu() {
|
||||||
stopTimer(); // Timer pausieren
|
|
||||||
PauseMenu pauseMenu = new PauseMenu(
|
PauseMenu pauseMenu = new PauseMenu(
|
||||||
(JFrame) SwingUtilities.getWindowAncestor(this),
|
(JFrame) SwingUtilities.getWindowAncestor(this),
|
||||||
this, // Das aktuelle GameBoard-Objekt übergeben
|
|
||||||
e -> startTimer(), // Spiel fortsetzen
|
e -> startTimer(), // Spiel fortsetzen
|
||||||
e -> returnToMainMenu(), // Zum Hauptmenü
|
e -> returnToMainMenu(), // Zum Hauptmenü
|
||||||
e -> System.exit(0) // Spiel beenden
|
e -> System.exit(0) // Spiel beenden
|
||||||
|
@ -241,15 +187,6 @@ public class GameBoard extends JPanel {
|
||||||
pauseMenu.setVisible(true);
|
pauseMenu.setVisible(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Erstellt einen Button für eine Zelle des Spielfelds.
|
|
||||||
*
|
|
||||||
* @param cell Die Zelle.
|
|
||||||
* @param row Die Zeile der Zelle.
|
|
||||||
* @param col Die Spalte der Zelle.
|
|
||||||
* @return Der Button.
|
|
||||||
*/
|
|
||||||
|
|
||||||
private JButton createCellButton(HitoriCell cell, int row, int col) {
|
private JButton createCellButton(HitoriCell cell, int row, int col) {
|
||||||
JButton button = new JButton(String.valueOf(cell.getNumber()));
|
JButton button = new JButton(String.valueOf(cell.getNumber()));
|
||||||
button.setBackground(Color.LIGHT_GRAY);
|
button.setBackground(Color.LIGHT_GRAY);
|
||||||
|
@ -260,14 +197,6 @@ public class GameBoard extends JPanel {
|
||||||
return button;
|
return button;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Schaltet den Zustand einer Zelle um.
|
|
||||||
*
|
|
||||||
* @param cell Die zu toggelnde Zelle.
|
|
||||||
* @param row Die Zeile der Zelle.
|
|
||||||
* @param col Die Spalte der Zelle.
|
|
||||||
*/
|
|
||||||
|
|
||||||
public void toggleCellState(HitoriCell cell, int row, int col) {
|
public void toggleCellState(HitoriCell cell, int row, int col) {
|
||||||
if (cell == null) {
|
if (cell == null) {
|
||||||
System.err.println("Ungültige Zelle! Der Zustand kann nicht geändert werden.");
|
System.err.println("Ungültige Zelle! Der Zustand kann nicht geändert werden.");
|
||||||
|
@ -298,13 +227,6 @@ public class GameBoard extends JPanel {
|
||||||
System.out.println("Aktion gespeichert: " + oldState + " -> " + newState);
|
System.out.println("Aktion gespeichert: " + oldState + " -> " + newState);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Aktualisiert die Darstellung eines Buttons basierend auf dem Zustand der Zelle.
|
|
||||||
*
|
|
||||||
* @param button Der Button.
|
|
||||||
* @param cell Die Zelle.
|
|
||||||
*/
|
|
||||||
|
|
||||||
private void updateButtonState(JButton button, HitoriCell cell) {
|
private void updateButtonState(JButton button, HitoriCell cell) {
|
||||||
switch (cell.getState()) {
|
switch (cell.getState()) {
|
||||||
case GRAY -> {
|
case GRAY -> {
|
||||||
|
@ -325,9 +247,22 @@ public class GameBoard extends JPanel {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
private void addHighscore(int elapsedTime, String boardName, int errors) {
|
||||||
* Kehrt ins Hauptmenü zurück.
|
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() {
|
private void returnToMainMenu() {
|
||||||
/// Eltern-Frame abrufen
|
/// Eltern-Frame abrufen
|
||||||
|
@ -344,10 +279,6 @@ public class GameBoard extends JPanel {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Setzt das Spielfeld zurück.
|
|
||||||
*/
|
|
||||||
|
|
||||||
public void resetBoard() {
|
public void resetBoard() {
|
||||||
// Spiellogik zurücksetzen
|
// Spiellogik zurücksetzen
|
||||||
board.resetBoard();
|
board.resetBoard();
|
||||||
|
@ -374,7 +305,6 @@ public class GameBoard extends JPanel {
|
||||||
repaint();
|
repaint();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Aktualisiert das Spielfeld
|
|
||||||
private void refreshBoard() {
|
private void refreshBoard() {
|
||||||
remove(1); // Entferne das aktuelle Spielfeld im CENTER
|
remove(1); // Entferne das aktuelle Spielfeld im CENTER
|
||||||
if (getLayout() instanceof BorderLayout) {
|
if (getLayout() instanceof BorderLayout) {
|
||||||
|
@ -402,12 +332,6 @@ public class GameBoard extends JPanel {
|
||||||
repaint();
|
repaint();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Erstellt das Spielfeld als JPanel.
|
|
||||||
*
|
|
||||||
* @return Das erstellte JPanel mit Spielfeldzellen.
|
|
||||||
*/
|
|
||||||
|
|
||||||
private JPanel createGamePanel() {
|
private JPanel createGamePanel() {
|
||||||
JPanel gamePanel = new JPanel(new GridLayout(board.getSize(), board.getSize()));
|
JPanel gamePanel = new JPanel(new GridLayout(board.getSize(), board.getSize()));
|
||||||
for (int i = 0; i < board.getSize(); i++) {
|
for (int i = 0; i < board.getSize(); i++) {
|
||||||
|
@ -432,47 +356,4 @@ public class GameBoard extends JPanel {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// --------Hilfsmethoden---------
|
|
||||||
|
|
||||||
// Startet den Timer
|
|
||||||
private void startTimer() {
|
|
||||||
if (timer == null) { // Timer nur beim ersten Start erstellen
|
|
||||||
timer = new Timer(1000, e -> {
|
|
||||||
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);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Hält den Timer an
|
|
||||||
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);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Setzt den Timer fort
|
|
||||||
public void resumeTimer() {
|
|
||||||
startTime = System.currentTimeMillis(); // Startzeit neu setzen
|
|
||||||
startTimer(); // Timer erneut starten
|
|
||||||
System.out.println("Timer fortgesetzt. Startzeit: " + startTime + ", Pausierte Zeit: " + pausedTime);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Setzt den Timer zurück
|
|
||||||
private void resetTimer() {
|
|
||||||
if (timer != null) {
|
|
||||||
timer.stop();
|
|
||||||
}
|
|
||||||
startTime = 0;
|
|
||||||
pausedTime = 0;
|
|
||||||
timerLabel.setText("Zeit: 0 Sekunden");
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,16 +0,0 @@
|
||||||
package PR2.HitoriSpiel.Fassade;
|
|
||||||
|
|
||||||
// TODO: Spiel fortsetzen
|
|
||||||
public class GameManager {
|
|
||||||
private static GameBoard gameBoard;
|
|
||||||
|
|
||||||
public static void setGameBoard(GameBoard gb) {
|
|
||||||
gameBoard = gb;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static void resumeTimer() {
|
|
||||||
if (gameBoard != null) {
|
|
||||||
gameBoard.resumeTimer();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -4,12 +4,6 @@ import java.io.*;
|
||||||
import java.util.*;
|
import java.util.*;
|
||||||
import java.util.concurrent.locks.ReentrantLock;
|
import java.util.concurrent.locks.ReentrantLock;
|
||||||
|
|
||||||
/**
|
|
||||||
* Die Klasse HighscoreManager verwaltet die Highscores für das Hitori-Spiel.
|
|
||||||
* Sie unterstützt das Hinzufügen, Speichern, Laden und Analysieren von Highscore-Daten
|
|
||||||
* sowie die Berechnung von Durchschnittszeiten pro Spielfeld.
|
|
||||||
*/
|
|
||||||
|
|
||||||
public class HighscoreManager {
|
public class HighscoreManager {
|
||||||
|
|
||||||
private static final String HIGHSCORE_FILE = "Hitori/src/main/highscores/highscores.txt";
|
private static final String HIGHSCORE_FILE = "Hitori/src/main/highscores/highscores.txt";
|
||||||
|
@ -17,22 +11,11 @@ public class HighscoreManager {
|
||||||
// Highscore-Datenstruktur
|
// Highscore-Datenstruktur
|
||||||
private final List<Highscore> highscoreList = new ArrayList<>();
|
private final List<Highscore> highscoreList = new ArrayList<>();
|
||||||
|
|
||||||
/**
|
|
||||||
* Konstruktor, der Highscores aus der Datei lädt.
|
|
||||||
*/
|
|
||||||
|
|
||||||
public HighscoreManager() {
|
public HighscoreManager() {
|
||||||
loadHighscores();
|
loadHighscores();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
// Prüft, ob die gegebene Zeit ein neuer Highscore ist
|
||||||
* Überprüft, ob die gegebene Zeit ein neuer Highscore für das angegebene Spielfeld ist.
|
|
||||||
*
|
|
||||||
* @param elapsedTime Die benötigte Zeit.
|
|
||||||
* @param boardName Der Name des Spielfelds.
|
|
||||||
* @return true, wenn es ein neuer Highscore ist, sonst false.
|
|
||||||
*/
|
|
||||||
|
|
||||||
public boolean isNewHighscore(int elapsedTime, String boardName) {
|
public boolean isNewHighscore(int elapsedTime, String boardName) {
|
||||||
// Filtere die Highscores für das gegebene Spielfeld
|
// Filtere die Highscores für das gegebene Spielfeld
|
||||||
List<Highscore> highscoresForBoard = getHighscoresForBoard(boardName);
|
List<Highscore> highscoresForBoard = getHighscoresForBoard(boardName);
|
||||||
|
@ -51,27 +34,13 @@ public class HighscoreManager {
|
||||||
return elapsedTime < bestTime;
|
return elapsedTime < bestTime;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
// Highscore hinzufügen
|
||||||
* Fügt einen neuen Highscore hinzu und speichert die aktualisierten Highscores.
|
|
||||||
*
|
|
||||||
* @param playerName Der Name des Spielers.
|
|
||||||
* @param time Die benötigte Zeit.
|
|
||||||
* @param boardName Der Name des Spielfelds.
|
|
||||||
* @param errors Die Anzahl der Fehler.
|
|
||||||
*/
|
|
||||||
|
|
||||||
public synchronized void addHighscore(String playerName, int time, String boardName, int errors) {
|
public synchronized void addHighscore(String playerName, int time, String boardName, int errors) {
|
||||||
highscoreList.add(new Highscore(playerName, time, boardName, errors));
|
highscoreList.add(new Highscore(playerName, time, boardName, errors));
|
||||||
saveHighscores();
|
saveHighscores();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
// Highscores für ein bestimmtes Spielfeld abrufen
|
||||||
* Gibt die Highscores für ein bestimmtes Spielfeld zurück, sortiert nach kürzester Zeit.
|
|
||||||
*
|
|
||||||
* @param boardName Der Name des Spielfelds.
|
|
||||||
* @return Eine Liste der Top 10 Highscores für das Spielfeld.
|
|
||||||
*/
|
|
||||||
|
|
||||||
public List<Highscore> getHighscoresForBoard(String boardName) {
|
public List<Highscore> getHighscoresForBoard(String boardName) {
|
||||||
return highscoreList.stream()
|
return highscoreList.stream()
|
||||||
.filter(highscore -> highscore.getBoardName().equals(boardName))
|
.filter(highscore -> highscore.getBoardName().equals(boardName))
|
||||||
|
@ -80,10 +49,7 @@ public class HighscoreManager {
|
||||||
.toList();
|
.toList();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
// Highscores speichern
|
||||||
* Speichert die Highscores in einer Datei.
|
|
||||||
*/
|
|
||||||
|
|
||||||
private void saveHighscores() {
|
private void saveHighscores() {
|
||||||
try (BufferedWriter writer = new BufferedWriter(new FileWriter(HIGHSCORE_FILE))) {
|
try (BufferedWriter writer = new BufferedWriter(new FileWriter(HIGHSCORE_FILE))) {
|
||||||
for (Highscore highscore : highscoreList) {
|
for (Highscore highscore : highscoreList) {
|
||||||
|
@ -95,10 +61,7 @@ public class HighscoreManager {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
// Highscores laden
|
||||||
* Lädt die Highscores aus einer Datei.
|
|
||||||
*/
|
|
||||||
|
|
||||||
private void loadHighscores() {
|
private void loadHighscores() {
|
||||||
try (BufferedReader reader = new BufferedReader(new FileReader(HIGHSCORE_FILE))) {
|
try (BufferedReader reader = new BufferedReader(new FileReader(HIGHSCORE_FILE))) {
|
||||||
String line;
|
String line;
|
||||||
|
@ -131,12 +94,7 @@ public class HighscoreManager {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
// Durchschnittszeit für jedes Spielfeld berechnen
|
||||||
* Berechnet die Durchschnittszeiten für jedes Spielfeld.
|
|
||||||
*
|
|
||||||
* @return Eine Map mit Spielfeldnamen und deren Durchschnittszeiten.
|
|
||||||
*/
|
|
||||||
|
|
||||||
public Map<String, Double> getAverageTimesByBoard() {
|
public Map<String, Double> getAverageTimesByBoard() {
|
||||||
fileLock.lock();
|
fileLock.lock();
|
||||||
try {
|
try {
|
||||||
|
@ -159,20 +117,12 @@ public class HighscoreManager {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
// Highscores abrufen
|
||||||
* Gibt alle Highscores zurück.
|
|
||||||
*
|
|
||||||
* @return Eine Liste aller Highscores.
|
|
||||||
*/
|
|
||||||
|
|
||||||
public List<Highscore> getHighscores() {
|
public List<Highscore> getHighscores() {
|
||||||
return new ArrayList<>(highscoreList); // Modifizierbare Kopie zurückgeben
|
return new ArrayList<>(highscoreList); // Modifizierbare Kopie zurückgeben
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
// Löscht alle Highscores
|
||||||
* Löscht alle Highscores und aktualisiert die Datei.
|
|
||||||
*/
|
|
||||||
|
|
||||||
public void clearHighscores() {
|
public void clearHighscores() {
|
||||||
fileLock.lock();
|
fileLock.lock();
|
||||||
try {
|
try {
|
||||||
|
@ -183,25 +133,13 @@ public class HighscoreManager {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
// Innere Highscore-Klasse
|
||||||
* Innere Klasse, die einen Highscore repräsentiert.
|
|
||||||
*/
|
|
||||||
|
|
||||||
public static class Highscore {
|
public static class Highscore {
|
||||||
private final String playerName;
|
private final String playerName;
|
||||||
private final int time;
|
private final int time;
|
||||||
private final String boardName;
|
private final String boardName;
|
||||||
private final int errors;
|
private final int errors;
|
||||||
|
|
||||||
/**
|
|
||||||
* Konstruktor für einen Highscore-Eintrag.
|
|
||||||
*
|
|
||||||
* @param playerName Der Name des Spielers.
|
|
||||||
* @param score Die benötigte Zeit.
|
|
||||||
* @param boardName Der Name des Spielfelds.
|
|
||||||
* @param errors Die Anzahl der Fehler.
|
|
||||||
*/
|
|
||||||
|
|
||||||
public Highscore(String playerName, int score, String boardName, int errors) {
|
public Highscore(String playerName, int score, String boardName, int errors) {
|
||||||
this.playerName = playerName;
|
this.playerName = playerName;
|
||||||
this.time = score;
|
this.time = score;
|
||||||
|
|
|
@ -4,20 +4,10 @@ import java.io.*;
|
||||||
import java.util.*;
|
import java.util.*;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Die Klasse HitoriSolutionLoader ist eine Hilfsklasse zum Laden der Lösung für ein Hitori-Spielfeld aus einer CSV-Datei.
|
* Utility class to load the solution from a CSV file.
|
||||||
* Die Lösung wird im Abschnitt "//Lösung" der Datei erwartet und enthält die Koordinaten der schwarzen Zellen.
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
public class HitoriSolutionLoader {
|
public class HitoriSolutionLoader {
|
||||||
|
|
||||||
/**
|
|
||||||
* Lädt die Lösung für ein Hitori-Spielfeld aus einer Ressourcendatei.
|
|
||||||
*
|
|
||||||
* @param resourcePath Der Pfad zur Ressourcendatei.
|
|
||||||
* @return Eine Liste der Koordinaten der schwarzen Zellen im Format "row,column".
|
|
||||||
* @throws IOException Wenn die Datei nicht gefunden wird oder ein Lesefehler auftritt.
|
|
||||||
*/
|
|
||||||
|
|
||||||
public static List<String> loadSolution(String resourcePath) throws IOException {
|
public static List<String> loadSolution(String resourcePath) throws IOException {
|
||||||
List<String> solutionCoordinates = new ArrayList<>();
|
List<String> solutionCoordinates = new ArrayList<>();
|
||||||
boolean solutionSectionFound = false;
|
boolean solutionSectionFound = false;
|
||||||
|
|
|
@ -5,10 +5,6 @@ import java.awt.*;
|
||||||
import java.awt.event.MouseAdapter;
|
import java.awt.event.MouseAdapter;
|
||||||
import java.awt.event.MouseEvent;
|
import java.awt.event.MouseEvent;
|
||||||
|
|
||||||
/**
|
|
||||||
* Die Klasse Setup bietet zentrale Methoden und Konstanten zur Gestaltung und Vereinheitlichung der GUI-Komponenten für das Hitori-Spiel.
|
|
||||||
*/
|
|
||||||
|
|
||||||
public class Setup {
|
public class Setup {
|
||||||
|
|
||||||
// Standardfarben
|
// Standardfarben
|
||||||
|
|
|
@ -6,38 +6,16 @@ import PR2.HitoriSpiel.Domain.StateFileManager;
|
||||||
import java.io.*;
|
import java.io.*;
|
||||||
import java.util.Stack;
|
import java.util.Stack;
|
||||||
|
|
||||||
/**
|
|
||||||
* Die Klasse StateManager verwaltet die Undo- und Redo-Funktionalität für das Hitori-Spiel
|
|
||||||
* und speichert Zustandsänderungen in einer Datei.
|
|
||||||
*/
|
|
||||||
|
|
||||||
public class StateManager implements Serializable {
|
public class StateManager implements Serializable {
|
||||||
private final Stack<Action> undoStack = new Stack<>();
|
private final Stack<Action> undoStack = new Stack<>();
|
||||||
private final Stack<Action> redoStack = new Stack<>();
|
private final Stack<Action> redoStack = new Stack<>();
|
||||||
|
|
||||||
/**
|
|
||||||
* Speichert eine neue Aktion im Undo-Stack und leert den Redo-Stack.
|
|
||||||
* Speichert zudem den aktuellen Zustand in einer Datei.
|
|
||||||
*
|
|
||||||
* @param row Die Zeile der Aktion.
|
|
||||||
* @param col Die Spalte der Aktion.
|
|
||||||
* @param oldState Der alte Zustand.
|
|
||||||
* @param newState Der neue Zustand.
|
|
||||||
*/
|
|
||||||
|
|
||||||
public void saveAction(int row, int col, String oldState, String newState) {
|
public void saveAction(int row, int col, String oldState, String newState) {
|
||||||
undoStack.push(new Action(row, col, oldState, newState));
|
undoStack.push(new Action(row, col, oldState, newState));
|
||||||
redoStack.clear(); // Redo-Stack leeren, da ein neuer Zustand hinzugefügt wurde
|
redoStack.clear(); // Redo-Stack leeren, da ein neuer Zustand hinzugefügt wurde
|
||||||
StateFileManager.saveState(undoStack, redoStack); // Speichern in Datei
|
StateFileManager.saveState(undoStack, redoStack); // Speichern in Datei
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Führt eine Undo-Aktion aus, verschiebt die Aktion in den Redo-Stack
|
|
||||||
* und speichert den aktuellen Zustand in einer Datei.
|
|
||||||
*
|
|
||||||
* @return Die rückgängig gemachte Aktion oder null, wenn der Undo-Stack leer ist.
|
|
||||||
*/
|
|
||||||
|
|
||||||
public Action undo() {
|
public Action undo() {
|
||||||
if (!undoStack.isEmpty()) {
|
if (!undoStack.isEmpty()) {
|
||||||
Action action = undoStack.pop();
|
Action action = undoStack.pop();
|
||||||
|
@ -48,13 +26,6 @@ public class StateManager implements Serializable {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Führt eine Redo-Aktion aus, verschiebt die Aktion in den Undo-Stack
|
|
||||||
* und speichert den aktuellen Zustand in einer Datei.
|
|
||||||
*
|
|
||||||
* @return Die wiederhergestellte Aktion oder null, wenn der Redo-Stack leer ist.
|
|
||||||
*/
|
|
||||||
|
|
||||||
public Action redo() {
|
public Action redo() {
|
||||||
if (!redoStack.isEmpty()) {
|
if (!redoStack.isEmpty()) {
|
||||||
Action action = redoStack.pop();
|
Action action = redoStack.pop();
|
||||||
|
@ -65,10 +36,6 @@ public class StateManager implements Serializable {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Lädt die Undo- und Redo-Stacks aus einer Datei, um den letzten gespeicherten Zustand wiederherzustellen.
|
|
||||||
*/
|
|
||||||
|
|
||||||
public void loadStateFromFile() {
|
public void loadStateFromFile() {
|
||||||
StateFileManager.loadState(undoStack, redoStack); // Stacks aus Datei laden
|
StateFileManager.loadState(undoStack, redoStack); // Stacks aus Datei laden
|
||||||
}
|
}
|
||||||
|
|
|
@ -5,20 +5,60 @@ import java.net.URLDecoder;
|
||||||
import java.util.*;
|
import java.util.*;
|
||||||
import java.util.jar.*;
|
import java.util.jar.*;
|
||||||
|
|
||||||
/**
|
|
||||||
* Die Klasse BoardLoader lädt Spielfeld-Dateien für das Hitori-Spiel aus dem Dateisystem oder einem JAR-Archiv
|
|
||||||
* und bietet Funktionen zum Parsen der Dateien in ein 2D-Array.
|
|
||||||
*/
|
|
||||||
|
|
||||||
public class BoardLoader {
|
public class BoardLoader {
|
||||||
|
|
||||||
/**
|
public static class BoardData {
|
||||||
* Lädt eine Liste von Spielfelddateien aus dem Verzeichnis oder dem JAR-Archiv.
|
private final int[][] board;
|
||||||
* Sortiert die Dateien nach Schwierigkeitsgrad (leicht, medium) und Größe.
|
private final List<String> solution;
|
||||||
*
|
|
||||||
* @return Eine Liste der gefundenen Spielfelddateien.
|
|
||||||
*/
|
|
||||||
|
|
||||||
|
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 {
|
||||||
|
var resource = BoardLoader.class.getClassLoader().getResource("persistent/Hitori_Spielfelder/");
|
||||||
|
if (resource == null) {
|
||||||
|
throw new IOException("Das Verzeichnis 'persistent/Hitori_Spielfelder/' wurde nicht gefunden.");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (resource.getProtocol().equals("file")) {
|
||||||
|
// Zugriff auf das Dateisystem (IDE-Umgebung)
|
||||||
|
File directory = new File(resource.toURI());
|
||||||
|
for (File file : directory.listFiles()) {
|
||||||
|
if (file.isFile() && file.getName().endsWith(".csv")) {
|
||||||
|
boardFiles.add(file.getName());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else if (resource.getProtocol().equals("jar")) {
|
||||||
|
// 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));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch (Exception e) {
|
||||||
|
System.err.println("Fehler beim Laden der Spielfelder: " + e.getMessage());
|
||||||
|
}
|
||||||
|
return boardFiles;
|
||||||
|
}*/
|
||||||
public static List<String> loadBoardsAsList() {
|
public static List<String> loadBoardsAsList() {
|
||||||
List<String> boardFiles = new ArrayList<>();
|
List<String> boardFiles = new ArrayList<>();
|
||||||
try {
|
try {
|
||||||
|
@ -81,13 +121,8 @@ public class BoardLoader {
|
||||||
return boardFiles;
|
return boardFiles;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Lädt ein Spielfeld aus einer Ressourcendatei und gibt es als 2D-Array zurück.
|
|
||||||
*
|
|
||||||
* @param resourcePath Der Pfad zur Ressourcendatei.
|
|
||||||
* @return Ein 2D-Array, das das geladene Spielfeld darstellt.
|
|
||||||
* @throws IOException Wenn die Datei nicht gefunden oder fehlerhaft ist.
|
|
||||||
*/
|
|
||||||
|
|
||||||
public static int[][] loadBoard(String resourcePath) throws IOException {
|
public static int[][] loadBoard(String resourcePath) throws IOException {
|
||||||
List<int[]> rows = new ArrayList<>();
|
List<int[]> rows = new ArrayList<>();
|
||||||
|
@ -141,10 +176,6 @@ public class BoardLoader {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
//--------------------------Hilfsmethoden----------------------------------
|
|
||||||
|
|
||||||
|
|
||||||
// Hilfsmethode zum Extrahieren der Größe aus dem Dateinamen
|
// Hilfsmethode zum Extrahieren der Größe aus dem Dateinamen
|
||||||
private static int extractSize(String fileName) {
|
private static int extractSize(String fileName) {
|
||||||
try {
|
try {
|
||||||
|
|
|
@ -2,34 +2,22 @@ package PR2.HitoriSpiel.GUI;
|
||||||
|
|
||||||
import PR2.HitoriSpiel.Fassade.HighscoreManager;
|
import PR2.HitoriSpiel.Fassade.HighscoreManager;
|
||||||
import PR2.HitoriSpiel.Fassade.Setup;
|
import PR2.HitoriSpiel.Fassade.Setup;
|
||||||
|
|
||||||
import javax.swing.table.DefaultTableModel;
|
import javax.swing.table.DefaultTableModel;
|
||||||
|
|
||||||
import javax.swing.*;
|
import javax.swing.*;
|
||||||
import java.awt.*;
|
import java.awt.*;
|
||||||
import java.util.*;
|
import java.util.ArrayList;
|
||||||
|
import java.util.LinkedHashMap;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
// aktueller Stand
|
||||||
/**
|
|
||||||
* Die Klasse HighscoreDialog erstellt ein Dialogfenster, das die Highscores für verschiedene Spielfelder des Hitori-Spiels
|
|
||||||
* anzeigt und verwaltet. Sie ermöglicht die Auswahl eines Spielfelds, das Anzeigen der zugehörigen Highscores und die
|
|
||||||
* Berechnung der Durchschnittszeiten.
|
|
||||||
*/
|
|
||||||
|
|
||||||
|
|
||||||
public class HighscoreDialog extends JDialog {
|
public class HighscoreDialog extends JDialog {
|
||||||
|
|
||||||
private final HighscoreManager highscoreManager;
|
private final HighscoreManager highscoreManager;
|
||||||
private final DefaultTableModel tableModel;
|
private final DefaultTableModel tableModel;
|
||||||
private final JComboBox<String> boardSelector;
|
private final JComboBox<String> boardSelector;
|
||||||
|
|
||||||
/**
|
|
||||||
* Konstruktor, der das Highscore-Dialogfenster erstellt und initialisiert.
|
|
||||||
*
|
|
||||||
* @param parentFrame Das übergeordnete Fenster, in dem der Dialog angezeigt wird.
|
|
||||||
* @param boardNames Eine Liste von Spielfelddateinamen.
|
|
||||||
*/
|
|
||||||
|
|
||||||
public HighscoreDialog(JFrame parentFrame, List<String> boardNames) {
|
public HighscoreDialog(JFrame parentFrame, List<String> boardNames) {
|
||||||
super(parentFrame, "Highscoreliste", true);
|
super(parentFrame, "Highscoreliste", true);
|
||||||
|
|
||||||
|
@ -76,6 +64,7 @@ public class HighscoreDialog extends JDialog {
|
||||||
closeButton.setFont(new Font(closeButton.getFont().getName(), closeButton.getFont().getStyle(), 18)); // Schriftgröße ändern
|
closeButton.setFont(new Font(closeButton.getFont().getName(), closeButton.getFont().getStyle(), 18)); // Schriftgröße ändern
|
||||||
closeButton.addActionListener(e -> dispose());
|
closeButton.addActionListener(e -> dispose());
|
||||||
buttonPanel.add(closeButton);
|
buttonPanel.add(closeButton);
|
||||||
|
|
||||||
Setup.stylePanel(buttonPanel); // Hintergrundstil setzen
|
Setup.stylePanel(buttonPanel); // Hintergrundstil setzen
|
||||||
add(buttonPanel, BorderLayout.SOUTH);
|
add(buttonPanel, BorderLayout.SOUTH);
|
||||||
|
|
||||||
|
@ -86,11 +75,6 @@ public class HighscoreDialog extends JDialog {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Lädt die Highscores für ein ausgewähltes Spielfeld und aktualisiert die Tabelle.
|
|
||||||
*
|
|
||||||
* @param boardName Der Name des ausgewählten Spielfelds.
|
|
||||||
*/
|
|
||||||
|
|
||||||
private void loadHighscoresForBoard(String boardName) {
|
private void loadHighscoresForBoard(String boardName) {
|
||||||
tableModel.setRowCount(0); // Tabelle zurücksetzen
|
tableModel.setRowCount(0); // Tabelle zurücksetzen
|
||||||
|
|
|
@ -1,33 +1,15 @@
|
||||||
package PR2.HitoriSpiel.GUI;
|
package PR2.HitoriSpiel.GUI;
|
||||||
|
|
||||||
import PR2.HitoriSpiel.Fassade.Setup;
|
import PR2.HitoriSpiel.Fassade.Setup;
|
||||||
import PR2.HitoriSpiel.Fassade.GameBoard;
|
|
||||||
|
|
||||||
import javax.swing.*;
|
import javax.swing.*;
|
||||||
import java.awt.*;
|
import java.awt.*;
|
||||||
import java.awt.event.ActionListener;
|
import java.awt.event.ActionListener;
|
||||||
|
|
||||||
/**
|
|
||||||
* Die Klasse PauseMenu erstellt ein Dialogfenster, das während einer Pause im Hitori-Spiel angezeigt wird.
|
|
||||||
* Sie bietet Optionen, das Spiel fortzusetzen, zum Hauptmenü zurückzukehren oder das Spiel zu beenden.
|
|
||||||
*/
|
|
||||||
|
|
||||||
public class PauseMenu extends JDialog {
|
public class PauseMenu extends JDialog {
|
||||||
private final GameBoard gameBoard;
|
|
||||||
|
|
||||||
/**
|
public PauseMenu(JFrame parent, ActionListener resumeAction, ActionListener mainMenuAction, ActionListener exitAction) {
|
||||||
* Konstruktor, der das Pause-Menü erstellt und die entsprechenden Buttons konfiguriert.
|
|
||||||
*
|
|
||||||
* @param parent Das übergeordnete Fenster, in dem der Dialog angezeigt wird.
|
|
||||||
* @param gameBoard Das aktuelle GameBoard-Objekt, um den Timer fortzusetzen.
|
|
||||||
* @param resumeAction Aktion, die ausgeführt wird, wenn der "Spiel fortsetzen"-Button geklickt wird.
|
|
||||||
* @param mainMenuAction Aktion, die ausgeführt wird, wenn der "Zum Hauptmenü"-Button geklickt wird.
|
|
||||||
* @param exitAction Aktion, die ausgeführt wird, wenn der "Spiel beenden"-Button geklickt wird.
|
|
||||||
*/
|
|
||||||
|
|
||||||
public PauseMenu(JFrame parent, GameBoard gameBoard, ActionListener resumeAction, ActionListener mainMenuAction, ActionListener exitAction) {
|
|
||||||
super(parent, "Pause", true);
|
super(parent, "Pause", true);
|
||||||
this.gameBoard = gameBoard; // Instanz speichern
|
|
||||||
setLayout(new GridLayout(3, 1));
|
setLayout(new GridLayout(3, 1));
|
||||||
setSize(300, 200);
|
setSize(300, 200);
|
||||||
setLocationRelativeTo(parent);
|
setLocationRelativeTo(parent);
|
||||||
|
@ -39,8 +21,6 @@ public class PauseMenu extends JDialog {
|
||||||
if (resumeAction != null) {
|
if (resumeAction != null) {
|
||||||
resumeAction.actionPerformed(e);
|
resumeAction.actionPerformed(e);
|
||||||
}
|
}
|
||||||
// Timer fortsetzen
|
|
||||||
gameBoard.resumeTimer();
|
|
||||||
});
|
});
|
||||||
|
|
||||||
// "Zum Hauptmenü"-Button
|
// "Zum Hauptmenü"-Button
|
||||||
|
|
|
@ -1,31 +1,22 @@
|
||||||
package PR2.HitoriSpiel.GUI;
|
package PR2.HitoriSpiel.GUI;
|
||||||
|
|
||||||
import PR2.HitoriSpiel.Fassade.BoardManager;
|
import PR2.HitoriSpiel.Domain.HitoriBoard;
|
||||||
import PR2.HitoriSpiel.Fassade.GameBoard;
|
import PR2.HitoriSpiel.Fassade.GameBoard;
|
||||||
import PR2.HitoriSpiel.Fassade.HitoriSolutionLoader;
|
import PR2.HitoriSpiel.Fassade.HitoriSolutionLoader;
|
||||||
import PR2.HitoriSpiel.Fassade.Setup;
|
import PR2.HitoriSpiel.Fassade.Setup;
|
||||||
|
|
||||||
import javax.swing.*;
|
import javax.swing.*;
|
||||||
import java.awt.*;
|
import java.awt.*;
|
||||||
import java.util.*;
|
import java.util.LinkedHashMap;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.Random;
|
||||||
|
|
||||||
import static PR2.HitoriSpiel.GUI.BoardLoader.loadBoard;
|
import static PR2.HitoriSpiel.GUI.BoardLoader.loadBoard;
|
||||||
|
|
||||||
/**
|
|
||||||
* Die Klasse StartMenu erstellt das Hauptmenü des Hitori-Spiels und bietet Optionen wie Spielfeldauswahl,
|
|
||||||
* Fortsetzen eines Spiels, Start eines zufälligen Spielfelds, Highscore-Anzeige und Spielbeendigung.
|
|
||||||
*/
|
|
||||||
|
|
||||||
public class StartMenu extends JPanel {
|
public class StartMenu extends JPanel {
|
||||||
private final JFrame parentFrame;
|
private final JFrame parentFrame;
|
||||||
|
|
||||||
/**
|
|
||||||
* Konstruktor, der das Hauptmenü erstellt und alle relevanten Buttons und Aktionen initialisiert.
|
|
||||||
*
|
|
||||||
* @param parentFrame Das übergeordnete JFrame-Fenster, in dem das Menü angezeigt wird.
|
|
||||||
*/
|
|
||||||
|
|
||||||
public StartMenu(JFrame parentFrame) {
|
public StartMenu(JFrame parentFrame) {
|
||||||
this.parentFrame = parentFrame;
|
this.parentFrame = parentFrame;
|
||||||
setLayout(new GridBagLayout());
|
setLayout(new GridBagLayout());
|
||||||
|
@ -65,21 +56,11 @@ public class StartMenu extends JPanel {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Aktion für den "Spiel fortsetzen"-Button.
|
|
||||||
* Zeigt einen Hinweis an, da die Funktion noch nicht implementiert ist.
|
|
||||||
*/
|
|
||||||
|
|
||||||
public void continueGame() {
|
public void continueGame() {
|
||||||
// TODO: Logik zum Fortsetzen des Spiels implementieren
|
// TODO: Logik zum Fortsetzen des Spiels implementieren
|
||||||
JOptionPane.showMessageDialog(this, "Spiel fortsetzen wurde angeklickt");
|
JOptionPane.showMessageDialog(this, "Spiel fortsetzen wurde angeklickt");
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Aktion für den "Spielfeld aussuchen"-Button.
|
|
||||||
* Öffnet ein Dialogfenster zur Auswahl eines Spielfelds aus der verfügbaren Liste.
|
|
||||||
*/
|
|
||||||
|
|
||||||
public void selectBoard() {
|
public void selectBoard() {
|
||||||
|
|
||||||
// Lade die Liste der Dateinamen
|
// Lade die Liste der Dateinamen
|
||||||
|
@ -128,10 +109,6 @@ public class StartMenu extends JPanel {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Aktion für den "Zufälliges Spielfeld"-Button.
|
|
||||||
* Wählt ein zufälliges Spielfeld aus der Liste und lädt es.
|
|
||||||
*/
|
|
||||||
|
|
||||||
public void randomBoard() {
|
public void randomBoard() {
|
||||||
List<String> boardFileNames = BoardLoader.loadBoardsAsList();
|
List<String> boardFileNames = BoardLoader.loadBoardsAsList();
|
||||||
|
@ -144,10 +121,6 @@ public class StartMenu extends JPanel {
|
||||||
loadAndDisplayBoard(randomFile);
|
loadAndDisplayBoard(randomFile);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Aktion für den "Highscoreliste anschauen"-Button.
|
|
||||||
* Öffnet das Highscore-Dialogfenster.
|
|
||||||
*/
|
|
||||||
|
|
||||||
public void highscorelist() {
|
public void highscorelist() {
|
||||||
List<String> boardNames = BoardLoader.loadBoardsAsList(); // Lade die Spielfeldnamen
|
List<String> boardNames = BoardLoader.loadBoardsAsList(); // Lade die Spielfeldnamen
|
||||||
|
@ -159,12 +132,6 @@ public class StartMenu extends JPanel {
|
||||||
new HighscoreDialog((JFrame) SwingUtilities.getWindowAncestor(this), boardNames).setVisible(true);
|
new HighscoreDialog((JFrame) SwingUtilities.getWindowAncestor(this), boardNames).setVisible(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Lädt ein Spielfeld aus einer Datei und zeigt es im Hauptfenster an.
|
|
||||||
*
|
|
||||||
* @param selectedFile Der Name der ausgewählten Datei.
|
|
||||||
*/
|
|
||||||
|
|
||||||
private void loadAndDisplayBoard(String selectedFile) {
|
private void loadAndDisplayBoard(String selectedFile) {
|
||||||
try {
|
try {
|
||||||
String resourcePath = "/persistent/Hitori_Spielfelder/" + selectedFile;
|
String resourcePath = "/persistent/Hitori_Spielfelder/" + selectedFile;
|
||||||
|
@ -173,10 +140,8 @@ public class StartMenu extends JPanel {
|
||||||
int[][] boardData = loadBoard(resourcePath);
|
int[][] boardData = loadBoard(resourcePath);
|
||||||
java.util.List<String> solutionCoordinates = HitoriSolutionLoader.loadSolution(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
|
HitoriBoard hitoriBoard = new HitoriBoard(boardData, solutionCoordinates, selectedFile); // Stelle sicher, dass die Lösung korrekt geladen wird
|
||||||
// BoardManager-Instanz erstellen
|
GameBoard gameBoard = new GameBoard(hitoriBoard);
|
||||||
BoardManager boardManager = new BoardManager();
|
|
||||||
GameBoard gameBoard = new GameBoard(boardManager.createBoard(boardData, solutionCoordinates, selectedFile));
|
|
||||||
loadGameBoard(gameBoard, solutionCoordinates);
|
loadGameBoard(gameBoard, solutionCoordinates);
|
||||||
|
|
||||||
System.out.println("Ausgewählte Datei: " + selectedFile);
|
System.out.println("Ausgewählte Datei: " + selectedFile);
|
||||||
|
@ -187,9 +152,7 @@ public class StartMenu extends JPanel {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// --------------------Hilfsmethoden--------------------------------------------
|
// Hilfsmethoden
|
||||||
|
|
||||||
//Aktualisiert die Benutzeroberfläche, um das geladene Spielfeld anzuzeigen
|
|
||||||
private void loadGameBoard(GameBoard gameBoard, java.util.List<String> solutionCoordinates) {
|
private void loadGameBoard(GameBoard gameBoard, java.util.List<String> solutionCoordinates) {
|
||||||
removeAll();
|
removeAll();
|
||||||
setLayout(new BorderLayout());
|
setLayout(new BorderLayout());
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
package PR2.HitoriSpiel.Main;
|
package PR2.HitoriSpiel.Main;
|
||||||
|
|
||||||
import PR2.HitoriSpiel.GUI.StartMenu;
|
import PR2.HitoriSpiel.GUI.StartMenu;
|
||||||
|
import PR2.HitoriSpiel.Fassade.StateManager;
|
||||||
import javax.swing.*;
|
import javax.swing.*;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -10,6 +11,9 @@ import javax.swing.*;
|
||||||
public class Main {
|
public class Main {
|
||||||
public static void main(String[] args) {
|
public static void main(String[] args) {
|
||||||
|
|
||||||
|
// Initialisiere den StateManager
|
||||||
|
StateManager stateManager = new StateManager();
|
||||||
|
|
||||||
// Füge einen Shutdown-Hook hinzu, um Zustände bei Beendigung zu speichern
|
// Füge einen Shutdown-Hook hinzu, um Zustände bei Beendigung zu speichern
|
||||||
Runtime.getRuntime().addShutdownHook(new Thread(() -> {
|
Runtime.getRuntime().addShutdownHook(new Thread(() -> {
|
||||||
//stateManager.saveStateToFile(); // Speichert die aktuellen Zustände in einer Datei
|
//stateManager.saveStateToFile(); // Speichert die aktuellen Zustände in einer Datei
|
||||||
|
|
|
@ -1,118 +0,0 @@
|
||||||
//Klassendiagramm
|
|
||||||
@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>
|
|
||||||
}
|
|
||||||
|
|
||||||
class BoardManager {
|
|
||||||
+ createBoard(int[][] boardData, List<String> solutionCoordinates, String selectedFile): HitoriBoard
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
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.Fassade.BoardManager ..> PR2.HitoriSpiel.GUI.StartMenu
|
|
||||||
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
|
|
Binary file not shown.
Before Width: | Height: | Size: 228 KiB |
|
@ -25,4 +25,12 @@ public class HitoriBoardTest {
|
||||||
assertEquals(HitoriCell.CellState.GRAY, board.getCell(0, 0).getState());
|
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());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,5 +0,0 @@
|
||||||
package GUI;
|
|
||||||
|
|
||||||
public class BoardLoaderTest {
|
|
||||||
|
|
||||||
}
|
|
|
@ -1,42 +0,0 @@
|
||||||
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.");
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,61 +0,0 @@
|
||||||
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.");
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
|
@ -1,46 +1,53 @@
|
||||||
package GUI;
|
package GUI;
|
||||||
|
|
||||||
import PR2.HitoriSpiel.GUI.StartMenu;
|
import PR2.HitoriSpiel.GUI.StartMenu;
|
||||||
|
import org.assertj.swing.edt.GuiActionRunner;
|
||||||
|
import org.assertj.swing.fixture.FrameFixture;
|
||||||
|
import org.junit.jupiter.api.AfterEach;
|
||||||
|
import org.junit.jupiter.api.BeforeEach;
|
||||||
import org.junit.jupiter.api.Test;
|
import org.junit.jupiter.api.Test;
|
||||||
|
|
||||||
import javax.swing.*;
|
import javax.swing.*;
|
||||||
|
|
||||||
import static org.junit.jupiter.api.Assertions.*;
|
import static org.assertj.core.api.Assertions.assertThat;
|
||||||
|
|
||||||
public class StartMenuTest {
|
public class StartMenuTest {
|
||||||
|
|
||||||
@Test
|
private FrameFixture window;
|
||||||
public void testStartMenuInitialization() {
|
|
||||||
SwingUtilities.invokeLater(() -> {
|
|
||||||
JFrame parentFrame = new JFrame();
|
|
||||||
StartMenu startMenu = new StartMenu(parentFrame);
|
|
||||||
|
|
||||||
assertNotNull(startMenu, "Das StartMenu sollte erfolgreich erstellt werden.");
|
@BeforeEach
|
||||||
assertEquals(5, startMenu.getComponentCount(), "Das StartMenu sollte fünf Buttons enthalten.");
|
public void setUp() {
|
||||||
|
JFrame frame = GuiActionRunner.execute(() -> {
|
||||||
// Überprüfe Buttons
|
JFrame testFrame = new JFrame();
|
||||||
JButton continueButton = (JButton) startMenu.getComponent(1);
|
testFrame.add(new StartMenu(testFrame));
|
||||||
assertEquals("Spiel fortsetzen", continueButton.getText(), "Der Text des ersten Buttons sollte korrekt sein.");
|
testFrame.pack();
|
||||||
|
testFrame.setVisible(true);
|
||||||
JButton selectBoardButton = (JButton) startMenu.getComponent(2);
|
return testFrame;
|
||||||
assertEquals("Spielfeld aussuchen", selectBoardButton.getText(), "Der Text des zweiten Buttons sollte korrekt sein.");
|
|
||||||
});
|
});
|
||||||
|
window = new FrameFixture(frame);
|
||||||
|
}
|
||||||
|
|
||||||
|
@AfterEach
|
||||||
|
public void tearDown() {
|
||||||
|
window.cleanUp();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testButtonsExist() {
|
||||||
|
// Buttons über ihre Namen finden und testen
|
||||||
|
assertThat(window.button("Spiel fortsetzen")).isNotNull();
|
||||||
|
assertThat(window.button("Spielfeld aussuchen")).isNotNull();
|
||||||
|
assertThat(window.button("Zufälliges Spielfeld")).isNotNull();
|
||||||
|
assertThat(window.button("Highscoreliste anschauen")).isNotNull();
|
||||||
|
assertThat(window.button("Spiel beenden")).isNotNull();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testButtonActions() {
|
public void testButtonActions() {
|
||||||
SwingUtilities.invokeLater(() -> {
|
window.button("Spiel fortsetzen").click();
|
||||||
JFrame parentFrame = new JFrame();
|
window.button("Spielfeld aussuchen").click();
|
||||||
StartMenu startMenu = new StartMenu(parentFrame);
|
window.button("Zufälliges Spielfeld").click();
|
||||||
|
window.button("Highscoreliste anschauen").click();
|
||||||
// Simuliere Button-Klicks
|
window.button("Spiel beenden").click();
|
||||||
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).
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -10,7 +10,7 @@
|
||||||
- [x] Verwendung von Maven
|
- [x] Verwendung von Maven
|
||||||
- [x] Verwendung von Git
|
- [x] Verwendung von Git
|
||||||
- [x] Verwendung von Feature-Branches
|
- [x] Verwendung von Feature-Branches
|
||||||
- [x] Erstellung Unit-Tests mit JUnit
|
- [ ] Erstellung Unit-Tests mit JUnit
|
||||||
|
|
||||||
## Die Aufgabenstellung:
|
## Die Aufgabenstellung:
|
||||||
- [x] GUI: GUI, in der beliebige Spielfelder angezeigt und bespielt werden können.
|
- [x] GUI: GUI, in der beliebige Spielfelder angezeigt und bespielt werden können.
|
||||||
|
@ -23,8 +23,3 @@
|
||||||
- [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.
|
- [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.
|
- [ ] 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.
|
- [x] GUI + Domain: Beim Highscore soll für jedes Spielfeld auch die Durchschnittszeit aller bisherigen Einträge angezeigt werden.
|
||||||
|
|
||||||
## Was nicht funktioniert:
|
|
||||||
- [x] Nach Reset funktionieren Undo/Redo Button nicht mehr
|
|
||||||
- [x] Nach Spiel fortsetzen -> Timer speichert nicht richtige Zeit
|
|
||||||
- [x] Jar-Datei -> Einträge aus highscores.txt werden nicht angezeigt und neue Einträge werden nicht gespeichert.
|
|
Loading…
Reference in New Issue