Compare commits
64 Commits
a7e92f5a6f
...
af277a5fab
Author | SHA1 | Date |
---|---|---|
|
af277a5fab | |
|
4284c262e2 | |
|
2bb0a5bbef | |
|
ed886565fb | |
|
f7a65be2c4 | |
|
c474b457b6 | |
|
da801b75b0 | |
|
8da0e90a5c | |
|
ffbd2dab10 | |
|
d88e35b4e2 | |
|
a4ce98a837 | |
|
2122bfc521 | |
|
2418e2aed7 | |
|
e77359160d | |
|
5f41bda301 | |
|
30f11647bb | |
|
e7e306642f | |
|
b0f1c46a8c | |
|
75f04b51cc | |
|
dcf9c95a99 | |
|
f7868e042f | |
|
eb30f5cd13 | |
|
3d0f808daf | |
|
4cb6b12814 | |
|
3742dac038 | |
|
bb28a136b4 | |
|
a92ddc2099 | |
|
99fe1f30c4 | |
|
4f9c1f7734 | |
|
cf3085b177 | |
|
f440ecb839 | |
|
7139741018 | |
|
078d653921 | |
|
6462424563 | |
|
152b50fc69 | |
|
43c73b0289 | |
|
3b6e3a45a7 | |
|
1b64e31951 | |
|
2205f1bf04 | |
|
9267aec8e4 | |
|
27f1951fb5 | |
|
9d30065f9a | |
|
9df1c5e421 | |
|
8f7d815eb5 | |
|
a4c98bc5d9 | |
|
24100d209b | |
|
b07fcb0ff5 | |
|
ca2b8a8921 | |
|
44c80e9779 | |
|
0b615ba4cc | |
|
99f0b2627b | |
|
cb97bd32eb | |
|
b14d044443 | |
|
dd778e7841 | |
|
6515ea54c4 | |
|
9a8fe119e0 | |
|
c626927a39 | |
|
12d66335f6 | |
|
f3481c5b96 | |
|
936967e809 | |
|
9c3fdf9406 | |
|
ef5efa7880 | |
|
1244cb333d | |
|
cd94bc7db0 |
|
@ -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>
|
|
@ -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
|
|
@ -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;
|
||||
}
|
||||
}
|
|
@ -1,4 +0,0 @@
|
|||
package PR2.HitoriSpiel.Domain;
|
||||
|
||||
public class DomainTest {
|
||||
}
|
|
@ -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]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
|
||||
}
|
|
@ -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());
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,4 +0,0 @@
|
|||
package PR2.HitoriSpiel.Fassade;
|
||||
|
||||
public class FassadeTest {
|
||||
}
|
|
@ -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
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
|
@ -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();
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -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;
|
||||
}
|
||||
}
|
|
@ -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));
|
||||
}
|
||||
}
|
|
@ -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
|
||||
}
|
||||
}
|
||||
|
|
@ -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
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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]));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -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
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -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);
|
||||
});
|
||||
}
|
||||
}
|
|
@ -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);
|
||||
}
|
||||
}
|
|
@ -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();
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
|
@ -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
|
|
@ -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.
|
|
@ -3,7 +3,7 @@
|
|||
1,3,4,2
|
||||
3,4,3,2
|
||||
|
||||
//Lösung (schwarze Felder)
|
||||
//Lösung
|
||||
1,2
|
||||
2,4
|
||||
3,2
|
|
|
@ -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());
|
||||
}
|
||||
}
|
|
@ -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());
|
||||
}
|
||||
}
|
|
@ -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());
|
||||
}
|
||||
}
|
||||
|
|
@ -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")));
|
||||
}
|
||||
}
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
|
@ -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.");
|
||||
}
|
||||
|
||||
}
|
|
@ -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.");
|
||||
}
|
||||
}
|
||||
|
|
@ -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;
|
||||
}
|
||||
}
|
|
@ -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());
|
||||
}
|
||||
}
|
||||
|
|
@ -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.");
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,5 @@
|
|||
package GUI;
|
||||
|
||||
public class BoardLoaderTest {
|
||||
|
||||
}
|
|
@ -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.");
|
||||
});
|
||||
}
|
||||
}
|
|
@ -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.");
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
@ -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).
|
||||
});
|
||||
}
|
||||
}
|
23
README.md
23
README.md
|
@ -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.
|
Loading…
Reference in New Issue