commit
fa2c1510f5
|
|
@ -8,6 +8,7 @@ public class GameSolver extends HitoriGameMoves {
|
||||||
super(initialBoard);
|
super(initialBoard);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Überprüft, ob das Spiel gelöst wurde
|
||||||
public boolean isSolved() {
|
public boolean isSolved() {
|
||||||
// First check if all cells are marked (either black or white)
|
// First check if all cells are marked (either black or white)
|
||||||
for (int i = 0; i < board.length; i++) {
|
for (int i = 0; i < board.length; i++) {
|
||||||
|
|
@ -55,6 +56,7 @@ public class GameSolver extends HitoriGameMoves {
|
||||||
return isOrthogonallyConnected();
|
return isOrthogonallyConnected();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Überprüft, ob die schwarze Markierung gültig ist
|
||||||
private boolean isValidBlackMark(int row, int col) {
|
private boolean isValidBlackMark(int row, int col) {
|
||||||
if (row > 0 && blackCells[row-1][col] ||
|
if (row > 0 && blackCells[row-1][col] ||
|
||||||
row < board.length-1 && blackCells[row+1][col] ||
|
row < board.length-1 && blackCells[row+1][col] ||
|
||||||
|
|
@ -65,6 +67,7 @@ public class GameSolver extends HitoriGameMoves {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Überprüft, ob weiße Zellen orthogonal verbunden sind
|
||||||
private boolean isOrthogonallyConnected() {
|
private boolean isOrthogonallyConnected() {
|
||||||
if (board.length == 0) return true;
|
if (board.length == 0) return true;
|
||||||
|
|
||||||
|
|
@ -84,6 +87,7 @@ public class GameSolver extends HitoriGameMoves {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Findet die erste weiße Zelle
|
||||||
private int[] findFirstWhiteCell() {
|
private int[] findFirstWhiteCell() {
|
||||||
for (int i = 0; i < board.length; i++) {
|
for (int i = 0; i < board.length; i++) {
|
||||||
for (int j = 0; j < board[0].length; j++) {
|
for (int j = 0; j < board[0].length; j++) {
|
||||||
|
|
@ -95,6 +99,7 @@ public class GameSolver extends HitoriGameMoves {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Tiefensuche, um verbundene weiße Zellen zu finden
|
||||||
private void dfs(int row, int col, boolean[][] visited) {
|
private void dfs(int row, int col, boolean[][] visited) {
|
||||||
if (row < 0 || row >= board.length || col < 0 || col >= board[0].length ||
|
if (row < 0 || row >= board.length || col < 0 || col >= board[0].length ||
|
||||||
visited[row][col] || blackCells[row][col]) {
|
visited[row][col] || blackCells[row][col]) {
|
||||||
|
|
@ -109,6 +114,7 @@ public class GameSolver extends HitoriGameMoves {
|
||||||
dfs(row, col + 1, visited);
|
dfs(row, col + 1, visited);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Findet fehlerhafte schwarze Markierungen
|
||||||
public List<int[]> findIncorrectBlackMarks() {
|
public List<int[]> findIncorrectBlackMarks() {
|
||||||
List<int[]> incorrectMarks = new ArrayList<>();
|
List<int[]> incorrectMarks = new ArrayList<>();
|
||||||
for (int i = 0; i < board.length; i++) {
|
for (int i = 0; i < board.length; i++) {
|
||||||
|
|
|
||||||
|
|
@ -11,12 +11,12 @@ public class HitoriBoardLoader {
|
||||||
public HitoriBoardLoader() {
|
public HitoriBoardLoader() {
|
||||||
availableBoards = new HashMap<>();
|
availableBoards = new HashMap<>();
|
||||||
solutions = new HashMap<>();
|
solutions = new HashMap<>();
|
||||||
loadAllBoards();
|
loadAllBoards(); // Lädt alle verfügbaren Boards
|
||||||
}
|
}
|
||||||
|
|
||||||
private void loadAllBoards() {
|
private void loadAllBoards() {
|
||||||
try {
|
try {
|
||||||
// Define all board file names
|
// Definiere die Board-Dateinamen
|
||||||
String[] boardFiles = {
|
String[] boardFiles = {
|
||||||
"Hitori4x4_leicht.csv",
|
"Hitori4x4_leicht.csv",
|
||||||
"Hitori5x5leicht.csv",
|
"Hitori5x5leicht.csv",
|
||||||
|
|
@ -26,16 +26,12 @@ public class HitoriBoardLoader {
|
||||||
"Hitori15x15_medium.csv"
|
"Hitori15x15_medium.csv"
|
||||||
};
|
};
|
||||||
|
|
||||||
// Try to load each board
|
// Versuche, jedes Board zu laden
|
||||||
for (String fileName : boardFiles) {
|
for (String fileName : boardFiles) {
|
||||||
try {
|
try {
|
||||||
InputStream is = getClass().getResourceAsStream("/" + fileName);
|
InputStream is = getClass().getResourceAsStream("/" + fileName);
|
||||||
if (is == null) {
|
|
||||||
is = getClass().getResourceAsStream("/" + fileName);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (is != null) {
|
if (is != null) {
|
||||||
loadBoard(fileName, is);
|
loadBoard(fileName, is); // Lade das Board
|
||||||
}
|
}
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
System.out.println("Failed to load board: " + fileName);
|
System.out.println("Failed to load board: " + fileName);
|
||||||
|
|
@ -43,6 +39,7 @@ public class HitoriBoardLoader {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Überprüfe, ob Boards geladen wurden
|
||||||
if (availableBoards.isEmpty()) {
|
if (availableBoards.isEmpty()) {
|
||||||
System.out.println("No board files found. Please ensure .csv files are in the resources folder.");
|
System.out.println("No board files found. Please ensure .csv files are in the resources folder.");
|
||||||
} else {
|
} else {
|
||||||
|
|
@ -53,15 +50,16 @@ public class HitoriBoardLoader {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Lädt ein einzelnes Board und seine Lösung
|
||||||
private void loadBoard(String fileName, InputStream inputStream) throws IOException {
|
private void loadBoard(String fileName, InputStream inputStream) throws IOException {
|
||||||
try (BufferedReader reader = new BufferedReader(new InputStreamReader(inputStream))) {
|
try (BufferedReader reader = new BufferedReader(new InputStreamReader(inputStream))) {
|
||||||
List<String> lines = new ArrayList<>();
|
List<String> lines = new ArrayList<>();
|
||||||
String line;
|
String line;
|
||||||
while ((line = reader.readLine()) != null) {
|
while ((line = reader.readLine()) != null) {
|
||||||
lines.add(line);
|
lines.add(line); // Liest jede Zeile der Datei
|
||||||
}
|
}
|
||||||
|
|
||||||
// Find where the solution starts
|
// Finde den Startpunkt der Lösung
|
||||||
int solutionIndex = -1;
|
int solutionIndex = -1;
|
||||||
for (int i = 0; i < lines.size(); i++) {
|
for (int i = 0; i < lines.size(); i++) {
|
||||||
if (lines.get(i).contains("//")) {
|
if (lines.get(i).contains("//")) {
|
||||||
|
|
@ -70,12 +68,12 @@ public class HitoriBoardLoader {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Parse the board
|
// Parsen des Boards
|
||||||
List<String[]> boardRows = new ArrayList<>();
|
List<String[]> boardRows = new ArrayList<>();
|
||||||
for (int i = 0; i < (solutionIndex == -1 ? lines.size() : solutionIndex); i++) {
|
for (int i = 0; i < (solutionIndex == -1 ? lines.size() : solutionIndex); i++) {
|
||||||
line = lines.get(i).trim();
|
line = lines.get(i).trim();
|
||||||
if (!line.isEmpty()) {
|
if (!line.isEmpty()) {
|
||||||
boardRows.add(line.split(","));
|
boardRows.add(line.split(",")); // Trenne die Zeilen in Spalten
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -86,12 +84,12 @@ public class HitoriBoardLoader {
|
||||||
|
|
||||||
for (int i = 0; i < rows; i++) {
|
for (int i = 0; i < rows; i++) {
|
||||||
for (int j = 0; j < cols; j++) {
|
for (int j = 0; j < cols; j++) {
|
||||||
board[i][j] = Integer.parseInt(boardRows.get(i)[j].trim());
|
board[i][j] = Integer.parseInt(boardRows.get(i)[j].trim()); // Konvertiere die Strings in Integers
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
availableBoards.put(fileName, board);
|
availableBoards.put(fileName, board); // Speichere das Board
|
||||||
|
|
||||||
// Parse the solution if available
|
// Wenn eine Lösung vorhanden ist, speichere sie
|
||||||
List<int[]> solutionCoordinates = new ArrayList<>();
|
List<int[]> solutionCoordinates = new ArrayList<>();
|
||||||
if (solutionIndex != -1) {
|
if (solutionIndex != -1) {
|
||||||
for (int i = solutionIndex + 1; i < lines.size(); i++) {
|
for (int i = solutionIndex + 1; i < lines.size(); i++) {
|
||||||
|
|
@ -104,20 +102,23 @@ public class HitoriBoardLoader {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
solutions.put(fileName, solutionCoordinates);
|
solutions.put(fileName, solutionCoordinates); // Speichere die Lösung
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Gibt die Namen der verfügbaren Boards zurück
|
||||||
public Set<String> getAvailableBoardNames() {
|
public Set<String> getAvailableBoardNames() {
|
||||||
return availableBoards.keySet();
|
return availableBoards.keySet();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Gibt ein Board anhand des Namens zurück
|
||||||
public int[][] getBoard(String boardName) {
|
public int[][] getBoard(String boardName) {
|
||||||
return availableBoards.get(boardName);
|
return availableBoards.get(boardName);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Gibt die Lösung für ein Board zurück
|
||||||
public List<int[]> getSolution(String boardName) {
|
public List<int[]> getSolution(String boardName) {
|
||||||
return solutions.get(boardName);
|
return solutions.get(boardName);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -5,9 +5,9 @@ import java.io.*;
|
||||||
public class HitoriGameMain extends GameSolver {
|
public class HitoriGameMain extends GameSolver {
|
||||||
private static final long serialVersionUID = 1L;
|
private static final long serialVersionUID = 1L;
|
||||||
|
|
||||||
private final HitoriGameTimer timer;
|
private final HitoriGameTimer timer; // Timer für das Spiel
|
||||||
private final HitoriGameScores scores;
|
private final HitoriGameScores scores; // Highscore-Verwaltung
|
||||||
private long savedTime;
|
private long savedTime; // Gespeicherte Zeit für den Timer
|
||||||
|
|
||||||
public HitoriGameMain(int[][] initialBoard) {
|
public HitoriGameMain(int[][] initialBoard) {
|
||||||
super(initialBoard);
|
super(initialBoard);
|
||||||
|
|
@ -24,28 +24,26 @@ public class HitoriGameMain extends GameSolver {
|
||||||
return scores;
|
return scores;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Update serialization to handle full game state
|
// Speichert den aktuellen Zustand des Spiels
|
||||||
private void writeObject(ObjectOutputStream out) throws IOException {
|
private void writeObject(ObjectOutputStream out) throws IOException {
|
||||||
out.defaultWriteObject();
|
out.defaultWriteObject();
|
||||||
// Save current state
|
|
||||||
out.writeLong(getElapsedTimeInSeconds());
|
out.writeLong(getElapsedTimeInSeconds());
|
||||||
out.writeInt(mistakeCount);
|
out.writeInt(mistakeCount);
|
||||||
out.writeObject(blackCells);
|
out.writeObject(blackCells);
|
||||||
out.writeObject(whiteCells);
|
out.writeObject(whiteCells);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Stellt den gespeicherten Zustand des Spiels wieder her
|
||||||
private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException {
|
private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException {
|
||||||
in.defaultReadObject();
|
in.defaultReadObject();
|
||||||
// Restore state
|
|
||||||
long savedTime = in.readLong();
|
long savedTime = in.readLong();
|
||||||
this.mistakeCount = in.readInt();
|
this.mistakeCount = in.readInt();
|
||||||
this.blackCells = (boolean[][]) in.readObject();
|
this.blackCells = (boolean[][]) in.readObject();
|
||||||
this.whiteCells = (boolean[][]) in.readObject();
|
this.whiteCells = (boolean[][]) in.readObject();
|
||||||
// Initialize timer with saved time
|
|
||||||
this.timer.setElapsedTime(savedTime);
|
this.timer.setElapsedTime(savedTime);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Timer delegation methods
|
// Steuerung des Timers
|
||||||
public void startTimer() {
|
public void startTimer() {
|
||||||
timer.startTimer();
|
timer.startTimer();
|
||||||
}
|
}
|
||||||
|
|
@ -62,11 +60,12 @@ public class HitoriGameMain extends GameSolver {
|
||||||
timer.resetTimer();
|
timer.resetTimer();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Gibt die verstrichene Zeit zurück
|
||||||
public long getElapsedTimeInSeconds() {
|
public long getElapsedTimeInSeconds() {
|
||||||
return savedTime > 0 ? savedTime : timer.getElapsedTimeInSeconds();
|
return savedTime > 0 ? savedTime : timer.getElapsedTimeInSeconds();
|
||||||
}
|
}
|
||||||
|
|
||||||
// High score delegation methods
|
// Highscore-Verwaltung
|
||||||
public void addHighScore(String playerName, long timeInSeconds) {
|
public void addHighScore(String playerName, long timeInSeconds) {
|
||||||
scores.addHighScore(playerName, timeInSeconds, getMistakeCount());
|
scores.addHighScore(playerName, timeInSeconds, getMistakeCount());
|
||||||
}
|
}
|
||||||
|
|
@ -87,7 +86,7 @@ public class HitoriGameMain extends GameSolver {
|
||||||
scores.saveHighScoresToFile();
|
scores.saveHighScoresToFile();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Game state persistence
|
// Setzt den Spielzustand
|
||||||
public void setGameState(boolean[][] blackCells, boolean[][] whiteCells, int mistakeCount, long elapsedTime) {
|
public void setGameState(boolean[][] blackCells, boolean[][] whiteCells, int mistakeCount, long elapsedTime) {
|
||||||
this.blackCells = new boolean[blackCells.length][blackCells[0].length];
|
this.blackCells = new boolean[blackCells.length][blackCells[0].length];
|
||||||
this.whiteCells = new boolean[whiteCells.length][whiteCells[0].length];
|
this.whiteCells = new boolean[whiteCells.length][whiteCells[0].length];
|
||||||
|
|
@ -101,6 +100,7 @@ public class HitoriGameMain extends GameSolver {
|
||||||
this.savedTime = elapsedTime;
|
this.savedTime = elapsedTime;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Speichert das Spiel in einer Datei
|
||||||
public void saveGameState() {
|
public void saveGameState() {
|
||||||
try (ObjectOutputStream oos = new ObjectOutputStream(
|
try (ObjectOutputStream oos = new ObjectOutputStream(
|
||||||
new FileOutputStream("gamestate.dat"))) {
|
new FileOutputStream("gamestate.dat"))) {
|
||||||
|
|
@ -110,11 +110,11 @@ public class HitoriGameMain extends GameSolver {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Lädt das Spiel aus einer Datei
|
||||||
public static HitoriGameMain loadGameState() {
|
public static HitoriGameMain loadGameState() {
|
||||||
try (ObjectInputStream ois = new ObjectInputStream(
|
try (ObjectInputStream ois = new ObjectInputStream(
|
||||||
new FileInputStream("gamestate.dat"))) {
|
new FileInputStream("gamestate.dat"))) {
|
||||||
HitoriGameMain loadedGame = (HitoriGameMain) ois.readObject();
|
HitoriGameMain loadedGame = (HitoriGameMain) ois.readObject();
|
||||||
// Initialize transient fields
|
|
||||||
loadedGame.timer.resetTimer();
|
loadedGame.timer.resetTimer();
|
||||||
return loadedGame;
|
return loadedGame;
|
||||||
} catch (IOException | ClassNotFoundException e) {
|
} catch (IOException | ClassNotFoundException e) {
|
||||||
|
|
@ -122,6 +122,7 @@ public class HitoriGameMain extends GameSolver {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Stellt den gespeicherten Zustand des Spiels wieder her
|
||||||
public void restoreGameState(HitoriGameMain savedGame) {
|
public void restoreGameState(HitoriGameMain savedGame) {
|
||||||
if (savedGame != null) {
|
if (savedGame != null) {
|
||||||
this.setGameState(savedGame.blackCells, savedGame.whiteCells,
|
this.setGameState(savedGame.blackCells, savedGame.whiteCells,
|
||||||
|
|
@ -132,7 +133,6 @@ public class HitoriGameMain extends GameSolver {
|
||||||
@Override
|
@Override
|
||||||
public void reset() {
|
public void reset() {
|
||||||
super.reset();
|
super.reset();
|
||||||
// Don't reset timer anymore
|
savedTime = 0; // Timer wird nicht zurückgesetzt
|
||||||
savedTime = 0;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -1,96 +0,0 @@
|
||||||
package domain;
|
|
||||||
|
|
||||||
import java.io.Serializable;
|
|
||||||
import java.util.*;
|
|
||||||
|
|
||||||
public class HitoriGameMoves extends GameBase {
|
|
||||||
private List<GameState> history;
|
|
||||||
private int historyPointer;
|
|
||||||
|
|
||||||
private static class GameState implements Serializable {
|
|
||||||
boolean[][] blackCells;
|
|
||||||
boolean[][] whiteCells;
|
|
||||||
|
|
||||||
GameState(boolean[][] blackCells, boolean[][] whiteCells) {
|
|
||||||
this.blackCells = new boolean[blackCells.length][blackCells[0].length];
|
|
||||||
this.whiteCells = new boolean[whiteCells.length][whiteCells[0].length];
|
|
||||||
for (int i = 0; i < blackCells.length; i++) {
|
|
||||||
this.blackCells[i] = Arrays.copyOf(blackCells[i], blackCells[i].length);
|
|
||||||
this.whiteCells[i] = Arrays.copyOf(whiteCells[i], whiteCells[i].length);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public HitoriGameMoves(int[][] initialBoard) {
|
|
||||||
super(initialBoard);
|
|
||||||
this.history = new ArrayList<>();
|
|
||||||
this.historyPointer = -1;
|
|
||||||
saveState();
|
|
||||||
}
|
|
||||||
|
|
||||||
public void markCellAsBlack(int row, int col) {
|
|
||||||
blackCells[row][col] = true;
|
|
||||||
whiteCells[row][col] = false;
|
|
||||||
saveState();
|
|
||||||
}
|
|
||||||
|
|
||||||
public void markCellAsWhite(int row, int col) {
|
|
||||||
whiteCells[row][col] = true;
|
|
||||||
blackCells[row][col] = false;
|
|
||||||
saveState();
|
|
||||||
}
|
|
||||||
|
|
||||||
protected void saveState() {
|
|
||||||
while (history.size() > historyPointer + 1) {
|
|
||||||
history.remove(history.size() - 1);
|
|
||||||
}
|
|
||||||
history.add(new GameState(blackCells, whiteCells));
|
|
||||||
historyPointer++;
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean undo() {
|
|
||||||
if (historyPointer > 0) {
|
|
||||||
historyPointer--;
|
|
||||||
GameState state = history.get(historyPointer);
|
|
||||||
restoreState(state);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean redo() {
|
|
||||||
if (historyPointer < history.size() - 1) {
|
|
||||||
historyPointer++;
|
|
||||||
GameState state = history.get(historyPointer);
|
|
||||||
restoreState(state);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
private void restoreState(GameState state) {
|
|
||||||
for (int i = 0; i < board.length; i++) {
|
|
||||||
blackCells[i] = Arrays.copyOf(state.blackCells[i], state.blackCells[i].length);
|
|
||||||
whiteCells[i] = Arrays.copyOf(state.whiteCells[i], state.whiteCells[i].length);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void reset() {
|
|
||||||
// Save mistake count before reset
|
|
||||||
int currentMistakes = mistakeCount;
|
|
||||||
|
|
||||||
// Call parent reset which resets the board state
|
|
||||||
super.reset();
|
|
||||||
|
|
||||||
// Clear history
|
|
||||||
history.clear();
|
|
||||||
historyPointer = -1;
|
|
||||||
|
|
||||||
// Restore mistake count
|
|
||||||
mistakeCount = currentMistakes;
|
|
||||||
|
|
||||||
// Save initial state
|
|
||||||
saveState();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -8,6 +8,7 @@ public class HitoriGameScores implements Serializable {
|
||||||
|
|
||||||
private Map<String, List<HighScoreEntry>> highScores;
|
private Map<String, List<HighScoreEntry>> highScores;
|
||||||
|
|
||||||
|
// Speichert einzelne Highscore-Einträge
|
||||||
private static class HighScoreEntry implements Serializable {
|
private static class HighScoreEntry implements Serializable {
|
||||||
String playerName;
|
String playerName;
|
||||||
long time;
|
long time;
|
||||||
|
|
@ -24,17 +25,20 @@ public class HitoriGameScores implements Serializable {
|
||||||
this.highScores = new HashMap<>();
|
this.highScores = new HashMap<>();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Fügt einen neuen Highscore hinzu
|
||||||
public void addHighScore(String playerName, long timeInSeconds, int mistakes) {
|
public void addHighScore(String playerName, long timeInSeconds, int mistakes) {
|
||||||
highScores.putIfAbsent(playerName, new ArrayList<>());
|
highScores.putIfAbsent(playerName, new ArrayList<>());
|
||||||
highScores.get(playerName).add(new HighScoreEntry(playerName, timeInSeconds, mistakes));
|
highScores.get(playerName).add(new HighScoreEntry(playerName, timeInSeconds, mistakes));
|
||||||
saveHighScoresToFile();
|
saveHighScoresToFile();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Löscht alle Highscores
|
||||||
public void deleteHighScores() {
|
public void deleteHighScores() {
|
||||||
highScores.clear();
|
highScores.clear();
|
||||||
saveHighScoresToFile();
|
saveHighScoresToFile();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Gibt die besten Highscores mit Durchschnittszeit zurück
|
||||||
public List<String> getHighScoresWithAverage() {
|
public List<String> getHighScoresWithAverage() {
|
||||||
List<String> result = new ArrayList<>();
|
List<String> result = new ArrayList<>();
|
||||||
List<HighScoreEntry> allEntries = new ArrayList<>();
|
List<HighScoreEntry> allEntries = new ArrayList<>();
|
||||||
|
|
@ -43,24 +47,27 @@ public class HitoriGameScores implements Serializable {
|
||||||
allEntries.addAll(entries);
|
allEntries.addAll(entries);
|
||||||
}
|
}
|
||||||
|
|
||||||
allEntries.sort((a, b) -> Long.compare(a.time, b.time));
|
allEntries.sort((a, b) -> Long.compare(a.time, b.time)); // Sortiert nach Zeit
|
||||||
|
|
||||||
|
// Berechnet den Durchschnitt
|
||||||
double avgTime = allEntries.stream()
|
double avgTime = allEntries.stream()
|
||||||
.mapToLong(e -> e.time)
|
.mapToLong(e -> e.time)
|
||||||
.average()
|
.average()
|
||||||
.orElse(0);
|
.orElse(0);
|
||||||
|
|
||||||
|
// Fügt die besten 10 Einträge hinzu
|
||||||
for (int i = 0; i < Math.min(10, allEntries.size()); i++) {
|
for (int i = 0; i < Math.min(10, allEntries.size()); i++) {
|
||||||
HighScoreEntry entry = allEntries.get(i);
|
HighScoreEntry entry = allEntries.get(i);
|
||||||
result.add(String.format("%s - Time: %ds - Mistakes: %d",
|
result.add(String.format("%s - Time: %ds - Mistakes: %d",
|
||||||
entry.playerName, entry.time, entry.mistakes));
|
entry.playerName, entry.time, entry.mistakes));
|
||||||
}
|
}
|
||||||
|
|
||||||
result.add(String.format("Average Time: %.1fs", avgTime));
|
result.add(String.format("Average Time: %.1fs", avgTime)); // Durchschnittszeit hinzufügen
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Speichert die Highscores in einer Datei
|
||||||
public void saveHighScoresToFile() {
|
public void saveHighScoresToFile() {
|
||||||
try (ObjectOutputStream oos = new ObjectOutputStream(
|
try (ObjectOutputStream oos = new ObjectOutputStream(
|
||||||
new FileOutputStream("highscores.dat"))) {
|
new FileOutputStream("highscores.dat"))) {
|
||||||
|
|
@ -70,13 +77,14 @@ public class HitoriGameScores implements Serializable {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Lädt die Highscores aus einer Datei
|
||||||
@SuppressWarnings("unchecked")
|
@SuppressWarnings("unchecked")
|
||||||
public void loadHighScoresFromFile() {
|
public void loadHighScoresFromFile() {
|
||||||
try (ObjectInputStream ois = new ObjectInputStream(
|
try (ObjectInputStream ois = new ObjectInputStream(
|
||||||
new FileInputStream("highscores.dat"))) {
|
new FileInputStream("highscores.dat"))) {
|
||||||
highScores = (Map<String, List<HighScoreEntry>>) ois.readObject();
|
highScores = (Map<String, List<HighScoreEntry>>) ois.readObject();
|
||||||
} catch (IOException | ClassNotFoundException e) {
|
} catch (IOException | ClassNotFoundException e) {
|
||||||
highScores = new HashMap<>();
|
highScores = new HashMap<>(); // Leert die Highscores bei Fehler
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -8,29 +8,31 @@ import java.io.Serializable;
|
||||||
public class HitoriGameTimer implements Serializable {
|
public class HitoriGameTimer implements Serializable {
|
||||||
private static final long serialVersionUID = 1L;
|
private static final long serialVersionUID = 1L;
|
||||||
|
|
||||||
private transient long startTime; // Time when timer was last started
|
private transient long startTime;
|
||||||
private long elapsedTime; // Total accumulated time
|
private long elapsedTime;
|
||||||
private boolean isPaused; // Current pause state
|
private boolean isPaused;
|
||||||
private long lastPauseTime; // When the timer was last paused
|
private long lastPauseTime;
|
||||||
|
|
||||||
public HitoriGameTimer() {
|
public HitoriGameTimer() {
|
||||||
this.startTime = 0;
|
this.startTime = 0;
|
||||||
this.elapsedTime = 0;
|
this.elapsedTime = 0;
|
||||||
this.isPaused = true; // Start paused
|
this.isPaused = true; // Timer beginnt pausiert
|
||||||
this.lastPauseTime = 0;
|
this.lastPauseTime = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Timer starten
|
||||||
public void startTimer() {
|
public void startTimer() {
|
||||||
if (isPaused) {
|
if (isPaused) {
|
||||||
startTime = System.currentTimeMillis();
|
startTime = System.currentTimeMillis();
|
||||||
isPaused = false;
|
isPaused = false;
|
||||||
// If this is a resume after pause, handle accumulated time
|
|
||||||
if (lastPauseTime > 0) {
|
if (lastPauseTime > 0) {
|
||||||
startTime = System.currentTimeMillis();
|
startTime = System.currentTimeMillis();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Timer pausieren
|
||||||
public void pauseTimer() {
|
public void pauseTimer() {
|
||||||
if (!isPaused && startTime > 0) {
|
if (!isPaused && startTime > 0) {
|
||||||
lastPauseTime = System.currentTimeMillis();
|
lastPauseTime = System.currentTimeMillis();
|
||||||
|
|
@ -40,6 +42,7 @@ public class HitoriGameTimer implements Serializable {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Timer stoppen
|
||||||
public void stopTimer() {
|
public void stopTimer() {
|
||||||
if (!isPaused && startTime > 0) {
|
if (!isPaused && startTime > 0) {
|
||||||
long stopTime = System.currentTimeMillis();
|
long stopTime = System.currentTimeMillis();
|
||||||
|
|
@ -50,6 +53,7 @@ public class HitoriGameTimer implements Serializable {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Timer zurücksetzen
|
||||||
public void resetTimer() {
|
public void resetTimer() {
|
||||||
startTime = 0;
|
startTime = 0;
|
||||||
elapsedTime = 0;
|
elapsedTime = 0;
|
||||||
|
|
@ -57,11 +61,13 @@ public class HitoriGameTimer implements Serializable {
|
||||||
lastPauseTime = 0;
|
lastPauseTime = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Setzt die vergangene Zeit manuell
|
||||||
public void setElapsedTime(long timeInSeconds) {
|
public void setElapsedTime(long timeInSeconds) {
|
||||||
this.elapsedTime = timeInSeconds * 1000; // Convert to milliseconds
|
this.elapsedTime = timeInSeconds * 1000; // Umrechnung in Millisekunden
|
||||||
this.lastPauseTime = System.currentTimeMillis();
|
this.lastPauseTime = System.currentTimeMillis();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Gibt die vergangene Zeit in Sekunden zurück
|
||||||
public long getElapsedTimeInSeconds() {
|
public long getElapsedTimeInSeconds() {
|
||||||
if (isPaused) {
|
if (isPaused) {
|
||||||
return elapsedTime / 1000;
|
return elapsedTime / 1000;
|
||||||
|
|
@ -70,23 +76,25 @@ public class HitoriGameTimer implements Serializable {
|
||||||
return (elapsedTime + (currentTime - startTime)) / 1000;
|
return (elapsedTime + (currentTime - startTime)) / 1000;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Gibt zurück, ob der Timer pausiert ist
|
||||||
public boolean isPaused() {
|
public boolean isPaused() {
|
||||||
return isPaused;
|
return isPaused;
|
||||||
}
|
}
|
||||||
|
|
||||||
// For serialization
|
// Für die Serialisierung: Speichert den aktuellen Zustand
|
||||||
private void writeObject(ObjectOutputStream out) throws IOException {
|
private void writeObject(ObjectOutputStream out) throws IOException {
|
||||||
out.defaultWriteObject();
|
out.defaultWriteObject();
|
||||||
// Save current elapsed time if timer is running
|
|
||||||
if (!isPaused && startTime > 0) {
|
if (!isPaused && startTime > 0) {
|
||||||
elapsedTime += System.currentTimeMillis() - startTime;
|
elapsedTime += System.currentTimeMillis() - startTime;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException {
|
private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException {
|
||||||
in.defaultReadObject();
|
in.defaultReadObject();
|
||||||
// Initialize transient fields
|
|
||||||
startTime = 0;
|
startTime = 0;
|
||||||
isPaused = true; // Start paused when restored
|
isPaused = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -31,12 +31,14 @@ class HitoriBoardPanelTest {
|
||||||
boardPanel = new HitoriBoardPanel(gameMoves, gameSolver, controller);
|
boardPanel = new HitoriBoardPanel(gameMoves, gameSolver, controller);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Testet, ob das Board korrekt initialisiert wurde
|
||||||
@Test
|
@Test
|
||||||
void testInitialization() {
|
void testInitialization() {
|
||||||
assertNotNull(boardPanel);
|
assertNotNull(boardPanel);
|
||||||
assertEquals(9, boardPanel.getChildren().size()); // 3x3 board = 9 buttons
|
assertEquals(9, boardPanel.getChildren().size()); // 3x3 board = 9 buttons
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Testet, ob die Buttons korrekt erstellt wurden
|
||||||
@Test
|
@Test
|
||||||
void testCellCreation() {
|
void testCellCreation() {
|
||||||
var children = boardPanel.getChildren();
|
var children = boardPanel.getChildren();
|
||||||
|
|
@ -44,6 +46,7 @@ class HitoriBoardPanelTest {
|
||||||
assertEquals("1", firstButton.getText());
|
assertEquals("1", firstButton.getText());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Testet das Styling der Buttons
|
||||||
@Test
|
@Test
|
||||||
void testButtonStyling() {
|
void testButtonStyling() {
|
||||||
var children = boardPanel.getChildren();
|
var children = boardPanel.getChildren();
|
||||||
|
|
@ -51,21 +54,23 @@ class HitoriBoardPanelTest {
|
||||||
assertEquals("-fx-background-color: lightgray; -fx-text-fill: black;", button.getStyle());
|
assertEquals("-fx-background-color: lightgray; -fx-text-fill: black;", button.getStyle());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Testet das Aktualisieren des Boards
|
||||||
@Test
|
@Test
|
||||||
void testUpdateBoard() {
|
void testUpdateBoard() {
|
||||||
boardPanel.updateBoard();
|
boardPanel.updateBoard();
|
||||||
assertEquals(9, boardPanel.getChildren().size());
|
assertEquals(9, boardPanel.getChildren().size());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Testet die Anzeige von Fehlern auf dem Board
|
||||||
@Test
|
@Test
|
||||||
void testShowErrors() {
|
void testShowErrors() {
|
||||||
// Mark some cells as black to create errors
|
|
||||||
gameMoves.markCellAsBlack(0, 0);
|
gameMoves.markCellAsBlack(0, 0);
|
||||||
gameMoves.markCellAsBlack(0, 1);
|
gameMoves.markCellAsBlack(0, 1);
|
||||||
|
|
||||||
boardPanel.showErrors();
|
boardPanel.showErrors();
|
||||||
|
|
||||||
// Verify that error cells are marked red
|
// Verifiziere, dass fehlerhafte Zellen rot markiert werden
|
||||||
var children = boardPanel.getChildren();
|
var children = boardPanel.getChildren();
|
||||||
for (var child : children) {
|
for (var child : children) {
|
||||||
Button button = (Button) child;
|
Button button = (Button) child;
|
||||||
|
|
|
||||||
|
|
@ -19,12 +19,14 @@ class HitoriControlPanelTest {
|
||||||
controlPanel = new HitoriControlPanel(controller);
|
controlPanel = new HitoriControlPanel(controller);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Testet, ob das Control-Panel korrekt initialisiert wurde
|
||||||
@Test
|
@Test
|
||||||
void testInitialization() {
|
void testInitialization() {
|
||||||
assertNotNull(controlPanel);
|
assertNotNull(controlPanel);
|
||||||
assertTrue(controlPanel.getChildren().size() > 0);
|
assertTrue(controlPanel.getChildren().size() > 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Testet das Aktualisieren des Timer-Labels
|
||||||
@Test
|
@Test
|
||||||
void testUpdateTimerLabel() {
|
void testUpdateTimerLabel() {
|
||||||
controlPanel.updateTimerLabel(42);
|
controlPanel.updateTimerLabel(42);
|
||||||
|
|
@ -32,6 +34,7 @@ class HitoriControlPanelTest {
|
||||||
assertNotNull(42);
|
assertNotNull(42);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Testet das Aktualisieren des Fehler-Labels
|
||||||
@Test
|
@Test
|
||||||
void testUpdateMistakeLabel() {
|
void testUpdateMistakeLabel() {
|
||||||
controlPanel.updateMistakeLabel(5);
|
controlPanel.updateMistakeLabel(5);
|
||||||
|
|
@ -39,6 +42,7 @@ class HitoriControlPanelTest {
|
||||||
assertNotNull(5);
|
assertNotNull(5);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Testet das Setzen des Textes für den Pause-Button
|
||||||
@Test
|
@Test
|
||||||
void testSetPauseButtonText() {
|
void testSetPauseButtonText() {
|
||||||
controlPanel.setPauseButtonText("Test");
|
controlPanel.setPauseButtonText("Test");
|
||||||
|
|
@ -46,6 +50,7 @@ class HitoriControlPanelTest {
|
||||||
assertNotNull(pauseButton);
|
assertNotNull(pauseButton);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Testet die Aktion des Pause-Buttons
|
||||||
@Test
|
@Test
|
||||||
void testPauseButtonAction() {
|
void testPauseButtonAction() {
|
||||||
var pauseButton = findButtonByText(controlPanel, "Pause");
|
var pauseButton = findButtonByText(controlPanel, "Pause");
|
||||||
|
|
@ -55,6 +60,7 @@ class HitoriControlPanelTest {
|
||||||
verify(controller, times(1)).togglePause();
|
verify(controller, times(1)).togglePause();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Testet die Aktion des Reset-Buttons
|
||||||
@Test
|
@Test
|
||||||
void testResetButtonAction() {
|
void testResetButtonAction() {
|
||||||
var resetButton = findButtonByText(controlPanel, "Reset");
|
var resetButton = findButtonByText(controlPanel, "Reset");
|
||||||
|
|
@ -64,6 +70,7 @@ class HitoriControlPanelTest {
|
||||||
verify(controller, times(1)).resetGame();
|
verify(controller, times(1)).resetGame();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Testet die Aktion des Undo-Buttons
|
||||||
@Test
|
@Test
|
||||||
void testUndoButtonAction() {
|
void testUndoButtonAction() {
|
||||||
var undoButton = findButtonByText(controlPanel, "Undo");
|
var undoButton = findButtonByText(controlPanel, "Undo");
|
||||||
|
|
@ -73,6 +80,7 @@ class HitoriControlPanelTest {
|
||||||
verify(controller, times(1)).undo();
|
verify(controller, times(1)).undo();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Testet die Aktion des Redo-Buttons
|
||||||
@Test
|
@Test
|
||||||
void testRedoButtonAction() {
|
void testRedoButtonAction() {
|
||||||
var redoButton = findButtonByText(controlPanel, "Redo");
|
var redoButton = findButtonByText(controlPanel, "Redo");
|
||||||
|
|
@ -82,6 +90,7 @@ class HitoriControlPanelTest {
|
||||||
verify(controller, times(1)).redo();
|
verify(controller, times(1)).redo();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Testet die Aktion des Check-Solution-Buttons
|
||||||
@Test
|
@Test
|
||||||
void testCheckSolutionButtonAction() {
|
void testCheckSolutionButtonAction() {
|
||||||
var checkButton = findButtonByText(controlPanel, "Check Solution");
|
var checkButton = findButtonByText(controlPanel, "Check Solution");
|
||||||
|
|
@ -91,6 +100,7 @@ class HitoriControlPanelTest {
|
||||||
verify(controller, times(1)).checkSolution();
|
verify(controller, times(1)).checkSolution();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Testet die Aktion des New-Game-Buttons
|
||||||
@Test
|
@Test
|
||||||
void testNewGameButtonAction() {
|
void testNewGameButtonAction() {
|
||||||
var newGameButton = findButtonByText(controlPanel, "New Game");
|
var newGameButton = findButtonByText(controlPanel, "New Game");
|
||||||
|
|
@ -100,6 +110,7 @@ class HitoriControlPanelTest {
|
||||||
verify(controller, times(1)).newGame();
|
verify(controller, times(1)).newGame();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Testet die Aktion des Show-Errors-Buttons
|
||||||
@Test
|
@Test
|
||||||
void testShowErrorsButtonAction() {
|
void testShowErrorsButtonAction() {
|
||||||
var showErrorsButton = findButtonByText(controlPanel, "Show Errors");
|
var showErrorsButton = findButtonByText(controlPanel, "Show Errors");
|
||||||
|
|
@ -109,6 +120,7 @@ class HitoriControlPanelTest {
|
||||||
verify(controller, times(1)).showErrors();
|
verify(controller, times(1)).showErrors();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Hilfsmethode: Sucht ein Label mit einem bestimmten Text im Panel
|
||||||
private Label findLabelByText(HitoriControlPanel panel, String text) {
|
private Label findLabelByText(HitoriControlPanel panel, String text) {
|
||||||
return (Label) panel.getChildren().stream()
|
return (Label) panel.getChildren().stream()
|
||||||
.filter(node -> node instanceof Label && ((Label) node).getText().equals(text))
|
.filter(node -> node instanceof Label && ((Label) node).getText().equals(text))
|
||||||
|
|
@ -116,6 +128,7 @@ class HitoriControlPanelTest {
|
||||||
.orElse(null);
|
.orElse(null);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Hilfsmethode: Sucht einen Button mit einem bestimmten Text im Panel
|
||||||
private Button findButtonByText(HitoriControlPanel panel, String text) {
|
private Button findButtonByText(HitoriControlPanel panel, String text) {
|
||||||
return (Button) panel.getChildren().stream()
|
return (Button) panel.getChildren().stream()
|
||||||
.flatMap(node -> node.lookupAll("Button").stream())
|
.flatMap(node -> node.lookupAll("Button").stream())
|
||||||
|
|
|
||||||
|
|
@ -16,14 +16,16 @@ class HitoriGameSolverTest {
|
||||||
game = new GameSolver(TEST_BOARD);
|
game = new GameSolver(TEST_BOARD);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Testet den Anfangszustand: Das Puzzle sollte nicht gelöst sein
|
||||||
@Test
|
@Test
|
||||||
void testUnsolvedInitialState() {
|
void testUnsolvedInitialState() {
|
||||||
assertFalse(game.isSolved());
|
assertFalse(game.isSolved());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Testet das Lösen des Puzzles mit einer bekannten Lösung
|
||||||
@Test
|
@Test
|
||||||
void testSolvingPuzzle() {
|
void testSolvingPuzzle() {
|
||||||
// Apply known solution
|
|
||||||
game.markCellAsBlack(0, 2);
|
game.markCellAsBlack(0, 2);
|
||||||
game.markCellAsWhite(0, 0);
|
game.markCellAsWhite(0, 0);
|
||||||
game.markCellAsWhite(0, 1);
|
game.markCellAsWhite(0, 1);
|
||||||
|
|
@ -37,19 +39,21 @@ class HitoriGameSolverTest {
|
||||||
assertFalse(game.isSolved());
|
assertFalse(game.isSolved());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Testet eine falsche Lösung, bei der alle Zellen weiß markiert sind
|
||||||
@Test
|
@Test
|
||||||
void testIncorrectSolution() {
|
void testIncorrectSolution() {
|
||||||
// Mark all cells white
|
|
||||||
for (int i = 0; i < TEST_BOARD.length; i++) {
|
for (int i = 0; i < TEST_BOARD.length; i++) {
|
||||||
for (int j = 0; j < TEST_BOARD[0].length; j++) {
|
for (int j = 0; j < TEST_BOARD[0].length; j++) {
|
||||||
game.markCellAsWhite(i, j);
|
game.markCellAsWhite(i, j);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Should not be solved due to duplicate numbers
|
|
||||||
assertFalse(game.isSolved());
|
assertFalse(game.isSolved());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Testet, ob das Puzzle nicht gelöst ist, wenn weiße Zellen nicht verbunden sind
|
||||||
@Test
|
@Test
|
||||||
void testDisconnectedWhiteCells() {
|
void testDisconnectedWhiteCells() {
|
||||||
// Create a solution with disconnected white cells
|
// Create a solution with disconnected white cells
|
||||||
|
|
@ -59,21 +63,22 @@ class HitoriGameSolverTest {
|
||||||
game.markCellAsBlack(1, 1);
|
game.markCellAsBlack(1, 1);
|
||||||
game.markCellAsWhite(2, 2);
|
game.markCellAsWhite(2, 2);
|
||||||
|
|
||||||
// Should not be solved due to disconnected white cells
|
|
||||||
assertFalse(game.isSolved());
|
assertFalse(game.isSolved());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Testet die Erkennung von ungültigen schwarzen Markierungen (benachbarte schwarze Zellen)
|
||||||
@Test
|
@Test
|
||||||
void testFindIncorrectBlackMarks() {
|
void testFindIncorrectBlackMarks() {
|
||||||
// Create adjacent black cells
|
|
||||||
game.markCellAsBlack(0, 0);
|
game.markCellAsBlack(0, 0);
|
||||||
game.markCellAsBlack(0, 1); // This creates an invalid situation
|
game.markCellAsBlack(0, 1);
|
||||||
|
|
||||||
List<int[]> errors = game.findIncorrectBlackMarks();
|
List<int[]> errors = game.findIncorrectBlackMarks();
|
||||||
assertFalse(errors.isEmpty());
|
assertFalse(errors.isEmpty());
|
||||||
assertEquals(2, errors.size()); // Both cells should be reported
|
assertEquals(2, errors.size());
|
||||||
|
|
||||||
|
|
||||||
// Verify error coordinates
|
|
||||||
boolean foundFirst = false;
|
boolean foundFirst = false;
|
||||||
boolean foundSecond = false;
|
boolean foundSecond = false;
|
||||||
for (int[] error : errors) {
|
for (int[] error : errors) {
|
||||||
|
|
@ -83,9 +88,10 @@ class HitoriGameSolverTest {
|
||||||
assertTrue(foundFirst && foundSecond);
|
assertTrue(foundFirst && foundSecond);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Testet den Fall, dass es keine ungültigen schwarzen Markierungen gibt
|
||||||
@Test
|
@Test
|
||||||
void testNoIncorrectBlackMarks() {
|
void testNoIncorrectBlackMarks() {
|
||||||
// Make valid black marks
|
|
||||||
game.markCellAsBlack(0, 0);
|
game.markCellAsBlack(0, 0);
|
||||||
game.markCellAsBlack(2, 2);
|
game.markCellAsBlack(2, 2);
|
||||||
|
|
||||||
|
|
@ -93,34 +99,37 @@ class HitoriGameSolverTest {
|
||||||
assertTrue(errors.isEmpty());
|
assertTrue(errors.isEmpty());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Testet, ob das Puzzle nicht gelöst ist, wenn einige Zellen unmarkiert bleiben
|
||||||
@Test
|
@Test
|
||||||
void testUnmarkedCellsNotSolved() {
|
void testUnmarkedCellsNotSolved() {
|
||||||
// Leave some cells unmarked
|
|
||||||
game.markCellAsWhite(0, 0);
|
game.markCellAsWhite(0, 0);
|
||||||
game.markCellAsBlack(0, 1);
|
game.markCellAsBlack(0, 1);
|
||||||
// Don't mark other cells
|
|
||||||
|
|
||||||
assertFalse(game.isSolved());
|
assertFalse(game.isSolved());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Testet den Fall von doppelten Zahlen in einer Zeile
|
||||||
@Test
|
@Test
|
||||||
void testDuplicateNumbersInRows() {
|
void testDuplicateNumbersInRows() {
|
||||||
// Mark cells to create duplicate numbers in a row
|
|
||||||
game.markCellAsWhite(0, 0);
|
game.markCellAsWhite(0, 0);
|
||||||
game.markCellAsWhite(0, 1);
|
game.markCellAsWhite(0, 1);
|
||||||
game.markCellAsWhite(0, 2);
|
game.markCellAsWhite(0, 2);
|
||||||
// Row now has duplicate numbers
|
|
||||||
|
|
||||||
assertFalse(game.isSolved());
|
assertFalse(game.isSolved());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Testet den Fall von doppelten Zahlen in einer Spalte
|
||||||
@Test
|
@Test
|
||||||
void testDuplicateNumbersInColumns() {
|
void testDuplicateNumbersInColumns() {
|
||||||
// Mark cells to create duplicate numbers in a column
|
|
||||||
game.markCellAsWhite(0, 0);
|
game.markCellAsWhite(0, 0);
|
||||||
game.markCellAsWhite(1, 0);
|
game.markCellAsWhite(1, 0);
|
||||||
game.markCellAsWhite(2, 0);
|
game.markCellAsWhite(2, 0);
|
||||||
// Column now has duplicate numbers
|
|
||||||
|
|
||||||
assertFalse(game.isSolved());
|
assertFalse(game.isSolved());
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -14,19 +14,24 @@ class HitoriGameTest {
|
||||||
@BeforeEach
|
@BeforeEach
|
||||||
void setUp() {
|
void setUp() {
|
||||||
game = new HitoriGameMain(TEST_BOARD);
|
game = new HitoriGameMain(TEST_BOARD);
|
||||||
|
|
||||||
|
// Löscht alte Spielstand- und Highscore-Dateien (falls vorhanden)
|
||||||
new File("gamestate.dat").delete();
|
new File("gamestate.dat").delete();
|
||||||
new File("highscores.dat").delete();
|
new File("highscores.dat").delete();
|
||||||
}
|
}
|
||||||
|
|
||||||
@AfterEach
|
@AfterEach
|
||||||
void tearDown() {
|
void tearDown() {
|
||||||
|
// Löscht nach jedem Test die erstellten Dateien
|
||||||
new File("gamestate.dat").delete();
|
new File("gamestate.dat").delete();
|
||||||
new File("highscores.dat").delete();
|
new File("highscores.dat").delete();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
void testGameIntegration() {
|
void testGameIntegration() {
|
||||||
// Test timer functionality
|
// Testet die Integration verschiedener Spielfunktionen
|
||||||
|
|
||||||
|
// Timer starten und prüfen, ob Zeit gezählt wird
|
||||||
game.startTimer();
|
game.startTimer();
|
||||||
try {
|
try {
|
||||||
Thread.sleep(1100);
|
Thread.sleep(1100);
|
||||||
|
|
@ -35,31 +40,33 @@ class HitoriGameTest {
|
||||||
}
|
}
|
||||||
assertTrue(game.getElapsedTimeInSeconds() >= 1);
|
assertTrue(game.getElapsedTimeInSeconds() >= 1);
|
||||||
|
|
||||||
// Test game moves
|
// Testet das Markieren von Zellen
|
||||||
game.markCellAsBlack(0, 2);
|
game.markCellAsBlack(0, 2);
|
||||||
assertTrue(game.getBlackCells()[0][2]);
|
assertTrue(game.getBlackCells()[0][2]);
|
||||||
|
|
||||||
// Test scoring
|
// Testet das Hinzufügen von Highscores
|
||||||
game.addHighScore("TestPlayer", 100);
|
game.addHighScore("TestPlayer", 100);
|
||||||
assertFalse(game.getHighScoresWithAverage().isEmpty());
|
assertFalse(game.getHighScoresWithAverage().isEmpty());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
void testSaveAndLoadGameState() {
|
void testSaveAndLoadGameState() {
|
||||||
// Make some moves
|
// Testet das Speichern und Laden des Spielstands
|
||||||
|
|
||||||
|
// Einige Zellen markieren und Timer starten
|
||||||
game.markCellAsWhite(0, 0);
|
game.markCellAsWhite(0, 0);
|
||||||
game.markCellAsBlack(1, 1);
|
game.markCellAsBlack(1, 1);
|
||||||
game.startTimer();
|
game.startTimer();
|
||||||
try {
|
try {
|
||||||
Thread.sleep(1000);
|
Thread.sleep(1000); // 1 Sekunde warten
|
||||||
} catch (InterruptedException e) {
|
} catch (InterruptedException e) {
|
||||||
fail("Timer test interrupted");
|
fail("Timer test interrupted");
|
||||||
}
|
}
|
||||||
|
|
||||||
// Save game state
|
|
||||||
game.saveGameState();
|
game.saveGameState();
|
||||||
|
|
||||||
// Load game state
|
// Spielstand laden und prüfen
|
||||||
HitoriGameMain loadedGame = HitoriGameMain.loadGameState();
|
HitoriGameMain loadedGame = HitoriGameMain.loadGameState();
|
||||||
assertNotNull(loadedGame);
|
assertNotNull(loadedGame);
|
||||||
assertTrue(loadedGame.getWhiteCells()[0][0]);
|
assertTrue(loadedGame.getWhiteCells()[0][0]);
|
||||||
|
|
@ -69,15 +76,17 @@ class HitoriGameTest {
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
void testResetAll() {
|
void testResetAll() {
|
||||||
// Setup some game state
|
// Testet das vollständige Zurücksetzen des Spiels
|
||||||
|
|
||||||
|
// Spielzustand einrichten
|
||||||
game.markCellAsBlack(0, 0);
|
game.markCellAsBlack(0, 0);
|
||||||
game.startTimer();
|
game.startTimer();
|
||||||
game.addHighScore("TestPlayer", 100);
|
game.addHighScore("TestPlayer", 100);
|
||||||
|
|
||||||
// Reset everything
|
|
||||||
game.reset();
|
game.reset();
|
||||||
|
|
||||||
// Verify reset
|
// Prüfen, ob das Spiel zurückgesetzt wurde
|
||||||
assertFalse(game.getBlackCells()[0][0]);
|
assertFalse(game.getBlackCells()[0][0]);
|
||||||
assertEquals(0, game.getElapsedTimeInSeconds());
|
assertEquals(0, game.getElapsedTimeInSeconds());
|
||||||
assertEquals(0, game.getMistakeCount());
|
assertEquals(0, game.getMistakeCount());
|
||||||
|
|
@ -85,10 +94,11 @@ class HitoriGameTest {
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
void testCompleteGameFlow() {
|
void testCompleteGameFlow() {
|
||||||
// Start game
|
// Testet einen kompletten Spielablauf
|
||||||
|
|
||||||
game.startTimer();
|
game.startTimer();
|
||||||
|
|
||||||
// Make some moves towards solution
|
// Zellen markieren, um das Spiel zu lösen
|
||||||
game.markCellAsBlack(0, 2);
|
game.markCellAsBlack(0, 2);
|
||||||
game.markCellAsWhite(0, 0);
|
game.markCellAsWhite(0, 0);
|
||||||
game.markCellAsWhite(0, 1);
|
game.markCellAsWhite(0, 1);
|
||||||
|
|
@ -99,14 +109,14 @@ class HitoriGameTest {
|
||||||
game.markCellAsWhite(2, 1);
|
game.markCellAsWhite(2, 1);
|
||||||
game.markCellAsBlack(2, 2);
|
game.markCellAsBlack(2, 2);
|
||||||
|
|
||||||
// Verify solution
|
|
||||||
assertFalse(game.isSolved());
|
assertFalse(game.isSolved());
|
||||||
|
|
||||||
// Add score
|
|
||||||
game.stopTimer();
|
game.stopTimer();
|
||||||
game.addHighScore("Winner", game.getElapsedTimeInSeconds());
|
game.addHighScore("Winner", game.getElapsedTimeInSeconds());
|
||||||
|
|
||||||
// Verify score was recorded
|
// Prüfen, ob der Highscore gespeichert wurde
|
||||||
boolean found = false;
|
boolean found = false;
|
||||||
for (String score : game.getHighScoresWithAverage()) {
|
for (String score : game.getHighScoresWithAverage()) {
|
||||||
if (score.contains("Winner")) {
|
if (score.contains("Winner")) {
|
||||||
|
|
@ -119,6 +129,9 @@ class HitoriGameTest {
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
void testTimerPauseResume() {
|
void testTimerPauseResume() {
|
||||||
|
// Testet das Pausieren und Fortsetzen des Timers
|
||||||
|
|
||||||
|
|
||||||
game.startTimer();
|
game.startTimer();
|
||||||
try {
|
try {
|
||||||
Thread.sleep(1000);
|
Thread.sleep(1000);
|
||||||
|
|
@ -126,6 +139,7 @@ class HitoriGameTest {
|
||||||
fail("Timer test interrupted");
|
fail("Timer test interrupted");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Timer pausieren und aktuelle Zeit speichern
|
||||||
game.pauseTimer();
|
game.pauseTimer();
|
||||||
long pausedTime = game.getElapsedTimeInSeconds();
|
long pausedTime = game.getElapsedTimeInSeconds();
|
||||||
|
|
||||||
|
|
@ -135,17 +149,18 @@ class HitoriGameTest {
|
||||||
fail("Timer test interrupted");
|
fail("Timer test interrupted");
|
||||||
}
|
}
|
||||||
|
|
||||||
// Time should not increase while paused
|
// Zeit sollte während der Pause nicht weiterlaufen
|
||||||
assertEquals(pausedTime, game.getElapsedTimeInSeconds());
|
assertEquals(pausedTime, game.getElapsedTimeInSeconds());
|
||||||
|
|
||||||
game.startTimer(); // Resume
|
// Timer fortsetzen und prüfen, ob Zeit weiterläuft
|
||||||
|
game.startTimer();
|
||||||
try {
|
try {
|
||||||
Thread.sleep(1000);
|
Thread.sleep(1000);
|
||||||
} catch (InterruptedException e) {
|
} catch (InterruptedException e) {
|
||||||
fail("Timer test interrupted");
|
fail("Timer test interrupted");
|
||||||
}
|
}
|
||||||
|
|
||||||
// Time should increase after resume
|
|
||||||
assertTrue(game.getElapsedTimeInSeconds() > pausedTime);
|
assertTrue(game.getElapsedTimeInSeconds() > pausedTime);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -10,17 +10,19 @@ class HitoriGameTimerTest {
|
||||||
timer = new HitoriGameTimer();
|
timer = new HitoriGameTimer();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Testet den Anfangszustand des Timers
|
||||||
@Test
|
@Test
|
||||||
void testInitialState() {
|
void testInitialState() {
|
||||||
assertEquals(0, timer.getElapsedTimeInSeconds());
|
assertEquals(0, timer.getElapsedTimeInSeconds());
|
||||||
assertFalse(timer.isPaused());
|
assertTrue(timer.isPaused());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Testet das Starten des Timers
|
||||||
@Test
|
@Test
|
||||||
void testStartTimer() {
|
void testStartTimer() {
|
||||||
timer.startTimer();
|
timer.startTimer();
|
||||||
try {
|
try {
|
||||||
Thread.sleep(1100); // Wait a bit more than 1 second
|
Thread.sleep(1100);
|
||||||
} catch (InterruptedException e) {
|
} catch (InterruptedException e) {
|
||||||
fail("Timer test interrupted");
|
fail("Timer test interrupted");
|
||||||
}
|
}
|
||||||
|
|
@ -29,6 +31,7 @@ class HitoriGameTimerTest {
|
||||||
assertFalse(timer.isPaused());
|
assertFalse(timer.isPaused());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Testet das Pausieren des Timers
|
||||||
@Test
|
@Test
|
||||||
void testPauseTimer() {
|
void testPauseTimer() {
|
||||||
timer.startTimer();
|
timer.startTimer();
|
||||||
|
|
@ -48,10 +51,11 @@ class HitoriGameTimerTest {
|
||||||
fail("Timer test interrupted");
|
fail("Timer test interrupted");
|
||||||
}
|
}
|
||||||
|
|
||||||
// Time should not have increased while paused
|
|
||||||
assertEquals(pausedTime, timer.getElapsedTimeInSeconds());
|
assertEquals(pausedTime, timer.getElapsedTimeInSeconds());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Testet das Fortsetzen des Timers nach einer Pause
|
||||||
@Test
|
@Test
|
||||||
void testResumeTimer() {
|
void testResumeTimer() {
|
||||||
timer.startTimer();
|
timer.startTimer();
|
||||||
|
|
@ -64,7 +68,7 @@ class HitoriGameTimerTest {
|
||||||
timer.pauseTimer();
|
timer.pauseTimer();
|
||||||
long pausedTime = timer.getElapsedTimeInSeconds();
|
long pausedTime = timer.getElapsedTimeInSeconds();
|
||||||
|
|
||||||
timer.startTimer(); // Resume
|
timer.startTimer();
|
||||||
try {
|
try {
|
||||||
Thread.sleep(1000);
|
Thread.sleep(1000);
|
||||||
} catch (InterruptedException e) {
|
} catch (InterruptedException e) {
|
||||||
|
|
@ -74,6 +78,7 @@ class HitoriGameTimerTest {
|
||||||
assertTrue(timer.getElapsedTimeInSeconds() > pausedTime);
|
assertTrue(timer.getElapsedTimeInSeconds() > pausedTime);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Testet das Stoppen des Timers
|
||||||
@Test
|
@Test
|
||||||
void testStopTimer() {
|
void testStopTimer() {
|
||||||
timer.startTimer();
|
timer.startTimer();
|
||||||
|
|
@ -95,6 +100,7 @@ class HitoriGameTimerTest {
|
||||||
assertEquals(stoppedTime, timer.getElapsedTimeInSeconds());
|
assertEquals(stoppedTime, timer.getElapsedTimeInSeconds());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Testet das Zurücksetzen des Timers
|
||||||
@Test
|
@Test
|
||||||
void testResetTimer() {
|
void testResetTimer() {
|
||||||
timer.startTimer();
|
timer.startTimer();
|
||||||
|
|
@ -106,9 +112,10 @@ class HitoriGameTimerTest {
|
||||||
|
|
||||||
timer.resetTimer();
|
timer.resetTimer();
|
||||||
assertEquals(0, timer.getElapsedTimeInSeconds());
|
assertEquals(0, timer.getElapsedTimeInSeconds());
|
||||||
assertFalse(timer.isPaused());
|
assertTrue(timer.isPaused());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Testet das mehrfache Pausieren und Fortsetzen des Timers
|
||||||
@Test
|
@Test
|
||||||
void testMultiplePauseResume() {
|
void testMultiplePauseResume() {
|
||||||
timer.startTimer();
|
timer.startTimer();
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue