Compare commits
No commits in common. "main" and "HitoriScorePanel" have entirely different histories.
main
...
HitoriScor
Binary file not shown.
|
Before Width: | Height: | Size: 44 KiB |
Binary file not shown.
94
pom.xml
94
pom.xml
|
|
@ -9,8 +9,8 @@
|
||||||
<version>1.0-SNAPSHOT</version>
|
<version>1.0-SNAPSHOT</version>
|
||||||
|
|
||||||
<properties>
|
<properties>
|
||||||
<maven.compiler.source>23</maven.compiler.source>
|
<maven.compiler.source>20</maven.compiler.source>
|
||||||
<maven.compiler.target>23</maven.compiler.target>
|
<maven.compiler.target>20</maven.compiler.target>
|
||||||
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
|
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
|
||||||
<javafx.version>20.0.2</javafx.version>
|
<javafx.version>20.0.2</javafx.version>
|
||||||
<java.version>20</java.version>
|
<java.version>20</java.version>
|
||||||
|
|
@ -24,7 +24,18 @@
|
||||||
</repositories>
|
</repositories>
|
||||||
|
|
||||||
<dependencies>
|
<dependencies>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.junit.jupiter</groupId>
|
||||||
|
<artifactId>junit-jupiter-api</artifactId>
|
||||||
|
<version>5.8.1</version>
|
||||||
|
<scope>test</scope>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.junit.jupiter</groupId>
|
||||||
|
<artifactId>junit-jupiter-engine</artifactId>
|
||||||
|
<version>5.8.1</version>
|
||||||
|
<scope>test</scope>
|
||||||
|
</dependency>
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.apache.logging.log4j</groupId>
|
<groupId>org.apache.logging.log4j</groupId>
|
||||||
<artifactId>log4j-core</artifactId>
|
<artifactId>log4j-core</artifactId>
|
||||||
|
|
@ -53,67 +64,11 @@
|
||||||
|
|
||||||
<!-- JUnit for Testing -->
|
<!-- JUnit for Testing -->
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.junit.jupiter</groupId>
|
<groupId>junit</groupId>
|
||||||
<artifactId>junit-jupiter-api</artifactId>
|
<artifactId>junit</artifactId>
|
||||||
<version>5.8.1</version>
|
<version>4.13.2</version>
|
||||||
<scope>test</scope>
|
<scope>test</scope>
|
||||||
</dependency>
|
</dependency>
|
||||||
<dependency>
|
|
||||||
<groupId>org.junit.jupiter</groupId>
|
|
||||||
<artifactId>junit-jupiter-engine</artifactId>
|
|
||||||
<version>5.8.1</version>
|
|
||||||
<scope>test</scope>
|
|
||||||
</dependency>
|
|
||||||
<dependency>
|
|
||||||
<groupId>org.apache.logging.log4j</groupId>
|
|
||||||
<artifactId>log4j-core</artifactId>
|
|
||||||
<version>2.24.2</version>
|
|
||||||
</dependency>
|
|
||||||
<dependency>
|
|
||||||
<groupId>org.apache.logging.log4j</groupId>
|
|
||||||
<artifactId>log4j-api</artifactId>
|
|
||||||
<version>2.24.2</version>
|
|
||||||
</dependency>
|
|
||||||
|
|
||||||
<dependency>
|
|
||||||
<groupId>org.mockito</groupId>
|
|
||||||
<artifactId>mockito-core</artifactId>
|
|
||||||
<version>5.6.0</version>
|
|
||||||
<scope>test</scope>
|
|
||||||
</dependency>
|
|
||||||
|
|
||||||
<dependency>
|
|
||||||
<groupId>org.mockito</groupId>
|
|
||||||
<artifactId>mockito-junit-jupiter</artifactId>
|
|
||||||
<version>5.6.0</version>
|
|
||||||
<scope>test</scope>
|
|
||||||
</dependency>
|
|
||||||
|
|
||||||
<dependency>
|
|
||||||
<groupId>net.bytebuddy</groupId>
|
|
||||||
<artifactId>byte-buddy</artifactId>
|
|
||||||
<version>1.14.9</version> <!-- Stelle sicher, dass du die neueste Version verwendest -->
|
|
||||||
</dependency>
|
|
||||||
|
|
||||||
|
|
||||||
<!-- TestFX für JavaFX UI-Tests -->
|
|
||||||
<dependency>
|
|
||||||
<groupId>org.testfx</groupId>
|
|
||||||
<artifactId>testfx-junit5</artifactId>
|
|
||||||
<version>4.0.16-alpha</version>
|
|
||||||
<scope>test</scope>
|
|
||||||
</dependency>
|
|
||||||
|
|
||||||
<!-- TestFX Core -->
|
|
||||||
<dependency>
|
|
||||||
<groupId>org.testfx</groupId>
|
|
||||||
<artifactId>testfx-core</artifactId>
|
|
||||||
<version>4.0.16-alpha</version>
|
|
||||||
<scope>test</scope>
|
|
||||||
</dependency>
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
</dependencies>
|
</dependencies>
|
||||||
|
|
||||||
<build>
|
<build>
|
||||||
|
|
@ -124,9 +79,8 @@
|
||||||
<artifactId>maven-compiler-plugin</artifactId>
|
<artifactId>maven-compiler-plugin</artifactId>
|
||||||
<version>3.13.0</version>
|
<version>3.13.0</version>
|
||||||
<configuration>
|
<configuration>
|
||||||
<source>23</source>
|
<source>${maven.compiler.source}</source>
|
||||||
<target>23</target>
|
<target>${maven.compiler.target}</target>
|
||||||
<compilerArgs>--enable-preview</compilerArgs>
|
|
||||||
</configuration>
|
</configuration>
|
||||||
</plugin>
|
</plugin>
|
||||||
|
|
||||||
|
|
@ -204,16 +158,6 @@
|
||||||
</executions>
|
</executions>
|
||||||
</plugin>
|
</plugin>
|
||||||
</plugins>
|
</plugins>
|
||||||
<sourceDirectory>src/main/java</sourceDirectory>
|
|
||||||
<resources>
|
|
||||||
<resource>
|
|
||||||
<directory>src/test/java</directory>
|
|
||||||
</resource>
|
|
||||||
<resource>
|
|
||||||
<directory>src/main/resources</directory>
|
|
||||||
</resource>
|
|
||||||
</resources>
|
|
||||||
<testSourceDirectory>src/test/java</testSourceDirectory>
|
|
||||||
</build>
|
</build>
|
||||||
<reporting>
|
<reporting>
|
||||||
<plugins>
|
<plugins>
|
||||||
|
|
|
||||||
|
|
@ -1,75 +1,50 @@
|
||||||
package GUI;
|
package GUI;
|
||||||
|
|
||||||
import domain.*;
|
import domain.*;
|
||||||
|
import GUI.HitoriDialogManager;
|
||||||
import javafx.application.Platform;
|
import javafx.application.Platform;
|
||||||
import javafx.stage.Stage;
|
|
||||||
import java.util.*;
|
import java.util.*;
|
||||||
|
|
||||||
public class GameUIController {
|
public class GameUIController {
|
||||||
private final Stage primaryStage; // Added to handle window state
|
|
||||||
private final HitoriGameMoves gameMoves;
|
private final HitoriGameMoves gameMoves;
|
||||||
private final GameSolver gameSolver;
|
private final GameSolver gameSolver;
|
||||||
private final HitoriGameTimer gameTimer;
|
private final domain.HitoriGameTimer gameTimer;
|
||||||
private final HitoriGameScores gameScores;
|
private final HitoriGameScores gameScores;
|
||||||
private final HitoriDialogManager dialogManager;
|
private final GUI.HitoriDialogManager dialogManager;
|
||||||
private final HitoriBoardPanel boardPanel;
|
private final GUI.HitoriBoardPanel boardPanel;
|
||||||
private final HitoriControlPanel controlPanel;
|
private final GUI.HitoriControlPanel controlPanel;
|
||||||
private final HitoriScorePanel scorePanel;
|
private final GUI.HitoriScorePanel scorePanel;
|
||||||
private Timer guiTimer;
|
private Timer guiTimer;
|
||||||
private boolean isPaused;
|
private boolean isPaused;
|
||||||
|
|
||||||
public GameUIController(int[][] initialBoard, HitoriDialogManager dialogManager, Stage primaryStage, HitoriGameMain existingGame) {
|
public GameUIController(int[][] initialBoard, HitoriDialogManager dialogManager) {
|
||||||
this.primaryStage = primaryStage;
|
this.gameMoves = new HitoriGameMoves(initialBoard);
|
||||||
|
this.gameSolver = new GameSolver(initialBoard);
|
||||||
|
this.gameTimer = new domain.HitoriGameTimer();
|
||||||
|
this.gameScores = new HitoriGameScores();
|
||||||
this.dialogManager = dialogManager;
|
this.dialogManager = dialogManager;
|
||||||
|
|
||||||
if (existingGame != null) {
|
|
||||||
// Use existing game state
|
|
||||||
this.gameSolver = existingGame;
|
|
||||||
this.gameMoves = existingGame;
|
|
||||||
this.gameTimer = existingGame.getTimer();
|
|
||||||
this.gameScores = existingGame.getScores();
|
|
||||||
// Restore the elapsed time
|
|
||||||
this.gameTimer.setElapsedTime(existingGame.getElapsedTimeInSeconds());
|
|
||||||
} else {
|
|
||||||
// Create new game
|
|
||||||
this.gameSolver = new GameSolver(initialBoard);
|
|
||||||
this.gameMoves = gameSolver;
|
|
||||||
this.gameTimer = new HitoriGameTimer();
|
|
||||||
this.gameScores = new HitoriGameScores();
|
|
||||||
}
|
|
||||||
|
|
||||||
this.isPaused = false;
|
this.isPaused = false;
|
||||||
this.boardPanel = new HitoriBoardPanel(gameMoves, gameSolver, this);
|
|
||||||
this.controlPanel = new HitoriControlPanel(this);
|
this.boardPanel = new GUI.HitoriBoardPanel(gameMoves, gameSolver, this);
|
||||||
this.scorePanel = new HitoriScorePanel(this);
|
this.controlPanel = new GUI.HitoriControlPanel(this);
|
||||||
|
this.scorePanel = new GUI.HitoriScorePanel(this);
|
||||||
|
|
||||||
startTimer();
|
startTimer();
|
||||||
loadHighScores();
|
loadHighScores();
|
||||||
updateUI(); // Make sure UI reflects current state
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void handleLeftClick(int row, int col) {
|
public void handleLeftClick(int row, int col) {
|
||||||
if (!isValidBlackMark(row, col)) {
|
|
||||||
gameMoves.mistakeCount++;
|
|
||||||
}
|
|
||||||
gameMoves.markCellAsBlack(row, col);
|
gameMoves.markCellAsBlack(row, col);
|
||||||
updateUI();
|
updateUI();
|
||||||
}
|
|
||||||
|
|
||||||
private boolean isValidBlackMark(int row, int col) {
|
|
||||||
boolean[][] blackCells = gameMoves.getBlackCells();
|
|
||||||
if (row > 0 && blackCells[row-1][col] ||
|
|
||||||
row < blackCells.length-1 && blackCells[row+1][col] ||
|
|
||||||
col > 0 && blackCells[row][col-1] ||
|
|
||||||
col < blackCells[0].length-1 && blackCells[row][col+1]) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void handleRightClick(int row, int col) {
|
public void handleRightClick(int row, int col) {
|
||||||
gameMoves.markCellAsWhite(row, col);
|
gameMoves.markCellAsWhite(row, col);
|
||||||
updateUI();
|
updateUI();
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void togglePause() {
|
public void togglePause() {
|
||||||
|
|
@ -87,44 +62,26 @@ public class GameUIController {
|
||||||
}
|
}
|
||||||
|
|
||||||
public void resetGame() {
|
public void resetGame() {
|
||||||
gameSolver.reset();
|
gameMoves.reset();
|
||||||
// Don't reset timer anymore
|
gameTimer.resetTimer();
|
||||||
updateUI();
|
updateUI();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void undo() {
|
public void undo() {
|
||||||
if (gameSolver.undo()) {
|
if (gameMoves.undo()) {
|
||||||
updateUI();
|
updateUI();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void redo() {
|
public void redo() {
|
||||||
if (gameSolver.redo()) {
|
if (gameMoves.redo()) {
|
||||||
updateUI();
|
updateUI();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void newGame() {
|
public void newGame() {
|
||||||
// Save current game state before starting new game
|
|
||||||
saveGame();
|
|
||||||
|
|
||||||
// Stop timer and cleanup current game
|
|
||||||
stopTimer();
|
stopTimer();
|
||||||
|
// Notify main application to show board selection
|
||||||
// Start new game process
|
|
||||||
Platform.runLater(() -> {
|
|
||||||
// Close current window
|
|
||||||
primaryStage.close();
|
|
||||||
|
|
||||||
// Start fresh instance
|
|
||||||
Stage newStage = new Stage();
|
|
||||||
Main.MainMethod mainMethod = new Main.MainMethod();
|
|
||||||
try {
|
|
||||||
mainMethod.start(newStage);
|
|
||||||
} catch (Exception e) {
|
|
||||||
dialogManager.showAlert("Error", "Failed to start new game: " + e.getMessage());
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void checkSolution() {
|
public void checkSolution() {
|
||||||
|
|
@ -151,11 +108,7 @@ public class GameUIController {
|
||||||
}
|
}
|
||||||
|
|
||||||
public void saveGame() {
|
public void saveGame() {
|
||||||
HitoriGameMain saveState = new HitoriGameMain(gameMoves.getBoard());
|
// Implementation for saving game state
|
||||||
// Copy current state to save
|
|
||||||
saveState.setGameState(gameMoves.getBlackCells(), gameMoves.getWhiteCells(),
|
|
||||||
gameMoves.getMistakeCount(), gameTimer.getElapsedTimeInSeconds());
|
|
||||||
saveState.saveGameState();
|
|
||||||
dialogManager.showAlert("Game Saved", "Your game has been saved successfully.");
|
dialogManager.showAlert("Game Saved", "Your game has been saved successfully.");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -171,12 +124,12 @@ public class GameUIController {
|
||||||
stopTimer();
|
stopTimer();
|
||||||
Optional<String> playerName = dialogManager.askForPlayerName();
|
Optional<String> playerName = dialogManager.askForPlayerName();
|
||||||
if (playerName.isPresent() && !playerName.get().trim().isEmpty()) {
|
if (playerName.isPresent() && !playerName.get().trim().isEmpty()) {
|
||||||
gameScores.addHighScore(playerName.get(), gameTimer.getElapsedTimeInSeconds(), gameSolver.getMistakeCount());
|
gameScores.addHighScore(playerName.get(), gameTimer.getElapsedTimeInSeconds(), gameMoves.getMistakeCount());
|
||||||
updateHighScoreDisplay();
|
updateHighScoreDisplay();
|
||||||
dialogManager.showAlert("Congratulations!", String.format(
|
dialogManager.showAlert("Congratulations!", String.format(
|
||||||
"You've solved the puzzle!\nTime: %ds\nMistakes: %d",
|
"You've solved the puzzle!\nTime: %ds\nMistakes: %d",
|
||||||
gameTimer.getElapsedTimeInSeconds(),
|
gameTimer.getElapsedTimeInSeconds(),
|
||||||
gameSolver.getMistakeCount()
|
gameMoves.getMistakeCount()
|
||||||
));
|
));
|
||||||
|
|
||||||
isPaused = false;
|
isPaused = false;
|
||||||
|
|
@ -218,9 +171,6 @@ public class GameUIController {
|
||||||
private void updateUI() {
|
private void updateUI() {
|
||||||
boardPanel.updateBoard();
|
boardPanel.updateBoard();
|
||||||
updateMistakeLabel();
|
updateMistakeLabel();
|
||||||
if (gameSolver.isSolved()) {
|
|
||||||
handleWin();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void updateTimerLabel() {
|
private void updateTimerLabel() {
|
||||||
|
|
@ -228,7 +178,7 @@ public class GameUIController {
|
||||||
}
|
}
|
||||||
|
|
||||||
private void updateMistakeLabel() {
|
private void updateMistakeLabel() {
|
||||||
controlPanel.updateMistakeLabel(gameSolver.getMistakeCount());
|
controlPanel.updateMistakeLabel(gameMoves.getMistakeCount());
|
||||||
}
|
}
|
||||||
|
|
||||||
private void updateHighScoreDisplay() {
|
private void updateHighScoreDisplay() {
|
||||||
|
|
@ -240,18 +190,6 @@ public class GameUIController {
|
||||||
updateHighScoreDisplay();
|
updateHighScoreDisplay();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void transferHighScores(HitoriGameScores targetScores) {
|
|
||||||
for (String score : gameScores.getHighScoresWithAverage()) {
|
|
||||||
if (!score.startsWith("Average Time:")) {
|
|
||||||
String[] parts = score.split(" - ");
|
|
||||||
String playerName = parts[0];
|
|
||||||
long time = Long.parseLong(parts[1].substring(6, parts[1].length() - 1));
|
|
||||||
int mistakes = Integer.parseInt(parts[2].substring(10));
|
|
||||||
targetScores.addHighScore(playerName, time, mistakes);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public Set<String> convertErrorsToSet(List<int[]> errors) {
|
public Set<String> convertErrorsToSet(List<int[]> errors) {
|
||||||
Set<String> errorPositions = new HashSet<>();
|
Set<String> errorPositions = new HashSet<>();
|
||||||
for (int[] pos : errors) {
|
for (int[] pos : errors) {
|
||||||
|
|
@ -265,8 +203,8 @@ public class GameUIController {
|
||||||
}
|
}
|
||||||
|
|
||||||
public void cleanup() {
|
public void cleanup() {
|
||||||
saveGame();
|
|
||||||
stopTimer();
|
stopTimer();
|
||||||
|
saveGame();
|
||||||
}
|
}
|
||||||
|
|
||||||
public HitoriBoardPanel getBoardPanel() {
|
public HitoriBoardPanel getBoardPanel() {
|
||||||
|
|
|
||||||
|
|
@ -12,14 +12,11 @@ public class HitoriBoardPanel extends GridPane {
|
||||||
private final HitoriGameMoves gameMoves;
|
private final HitoriGameMoves gameMoves;
|
||||||
private final GameSolver gameSolver;
|
private final GameSolver gameSolver;
|
||||||
private final GameUIController controller;
|
private final GameUIController controller;
|
||||||
public boolean showingErrors;
|
|
||||||
private Set<String> currentErrors;
|
|
||||||
|
|
||||||
public HitoriBoardPanel(HitoriGameMoves gameMoves, GameSolver gameSolver, GameUIController controller) {
|
public HitoriBoardPanel(HitoriGameMoves gameMoves, GameSolver gameSolver, GameUIController controller) {
|
||||||
this.gameMoves = gameMoves;
|
this.gameMoves = gameMoves;
|
||||||
this.gameSolver = gameSolver;
|
this.gameSolver = gameSolver;
|
||||||
this.controller = controller;
|
this.controller = controller;
|
||||||
this.showingErrors = false;
|
|
||||||
|
|
||||||
setHgap(5);
|
setHgap(5);
|
||||||
setVgap(5);
|
setVgap(5);
|
||||||
|
|
@ -29,15 +26,6 @@ public class HitoriBoardPanel extends GridPane {
|
||||||
}
|
}
|
||||||
|
|
||||||
public void updateBoard() {
|
public void updateBoard() {
|
||||||
if (showingErrors) {
|
|
||||||
showErrors();
|
|
||||||
} else {
|
|
||||||
displayNormalBoard();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void displayNormalBoard() {
|
|
||||||
showingErrors = false;
|
|
||||||
getChildren().clear();
|
getChildren().clear();
|
||||||
int[][] boardState = gameMoves.getBoard();
|
int[][] boardState = gameMoves.getBoard();
|
||||||
boolean[][] blackCells = gameMoves.getBlackCells();
|
boolean[][] blackCells = gameMoves.getBlackCells();
|
||||||
|
|
@ -46,16 +34,15 @@ public class HitoriBoardPanel extends GridPane {
|
||||||
for (int row = 0; row < boardState.length; row++) {
|
for (int row = 0; row < boardState.length; row++) {
|
||||||
for (int col = 0; col < boardState[row].length; col++) {
|
for (int col = 0; col < boardState[row].length; col++) {
|
||||||
Button cellButton = createCellButton(row, col, boardState[row][col],
|
Button cellButton = createCellButton(row, col, boardState[row][col],
|
||||||
blackCells[row][col], whiteCells[row][col], false);
|
blackCells[row][col], whiteCells[row][col]);
|
||||||
add(cellButton, col, row);
|
add(cellButton, col, row);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void showErrors() {
|
public void showErrors() {
|
||||||
showingErrors = true;
|
|
||||||
var errors = gameSolver.findIncorrectBlackMarks();
|
var errors = gameSolver.findIncorrectBlackMarks();
|
||||||
currentErrors = controller.convertErrorsToSet(errors);
|
Set<String> errorPositions = controller.convertErrorsToSet(errors);
|
||||||
|
|
||||||
getChildren().clear();
|
getChildren().clear();
|
||||||
int[][] boardState = gameMoves.getBoard();
|
int[][] boardState = gameMoves.getBoard();
|
||||||
|
|
@ -65,22 +52,21 @@ public class HitoriBoardPanel extends GridPane {
|
||||||
for (int row = 0; row < boardState.length; row++) {
|
for (int row = 0; row < boardState.length; row++) {
|
||||||
for (int col = 0; col < boardState[row].length; col++) {
|
for (int col = 0; col < boardState[row].length; col++) {
|
||||||
Button cellButton = createCellButton(row, col, boardState[row][col],
|
Button cellButton = createCellButton(row, col, boardState[row][col],
|
||||||
blackCells[row][col], whiteCells[row][col],
|
blackCells[row][col], whiteCells[row][col]);
|
||||||
currentErrors.contains(row + "," + col));
|
|
||||||
|
if (errorPositions.contains(row + "," + col) && blackCells[row][col]) {
|
||||||
|
cellButton.setStyle("-fx-background-color: red; -fx-text-fill: white;");
|
||||||
|
}
|
||||||
|
|
||||||
add(cellButton, col, row);
|
add(cellButton, col, row);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private Button createCellButton(int row, int col, int value, boolean isBlack, boolean isWhite, boolean isError) {
|
private Button createCellButton(int row, int col, int value, boolean isBlack, boolean isWhite) {
|
||||||
Button cellButton = new Button(String.valueOf(value));
|
Button cellButton = new Button(String.valueOf(value));
|
||||||
cellButton.setPrefSize(50, 50);
|
cellButton.setPrefSize(50, 50);
|
||||||
|
styleCellButton(cellButton, isBlack, isWhite);
|
||||||
if (isError && isBlack) {
|
|
||||||
cellButton.setStyle("-fx-background-color: red; -fx-text-fill: white;");
|
|
||||||
} else {
|
|
||||||
styleCellButton(cellButton, isBlack, isWhite);
|
|
||||||
}
|
|
||||||
|
|
||||||
cellButton.setOnMouseClicked(event -> {
|
cellButton.setOnMouseClicked(event -> {
|
||||||
if (!controller.isPaused()) {
|
if (!controller.isPaused()) {
|
||||||
|
|
@ -105,3 +91,4 @@ public class HitoriBoardPanel extends GridPane {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,6 @@
|
||||||
package GUI;
|
package GUI;
|
||||||
|
|
||||||
|
|
||||||
import javafx.geometry.Insets;
|
import javafx.geometry.Insets;
|
||||||
import javafx.geometry.Pos;
|
import javafx.geometry.Pos;
|
||||||
import javafx.scene.control.Button;
|
import javafx.scene.control.Button;
|
||||||
|
|
|
||||||
|
|
@ -5,13 +5,12 @@ import javafx.scene.Scene;
|
||||||
import javafx.scene.control.*;
|
import javafx.scene.control.*;
|
||||||
import javafx.scene.layout.VBox;
|
import javafx.scene.layout.VBox;
|
||||||
import javafx.stage.Modality;
|
import javafx.stage.Modality;
|
||||||
import javafx.stage.Stage;
|
|
||||||
import javafx.stage.Window;
|
import javafx.stage.Window;
|
||||||
import java.util.Optional;
|
import java.util.Optional;
|
||||||
|
|
||||||
|
|
||||||
public class HitoriDialogManager {
|
public class HitoriDialogManager {
|
||||||
private final Window owner;
|
private final Window owner;
|
||||||
private Stage currentDialog;
|
|
||||||
|
|
||||||
public HitoriDialogManager(Window owner) {
|
public HitoriDialogManager(Window owner) {
|
||||||
this.owner = owner;
|
this.owner = owner;
|
||||||
|
|
@ -21,10 +20,10 @@ public class HitoriDialogManager {
|
||||||
Dialog<String> dialog = new Dialog<>();
|
Dialog<String> dialog = new Dialog<>();
|
||||||
dialog.setTitle("Select Hitori Board");
|
dialog.setTitle("Select Hitori Board");
|
||||||
dialog.setHeaderText("Choose a board to play:");
|
dialog.setHeaderText("Choose a board to play:");
|
||||||
dialog.initModality(Modality.APPLICATION_MODAL);
|
|
||||||
|
|
||||||
if (owner != null && owner.getScene() != null) {
|
if (owner != null && owner.getScene() != null) {
|
||||||
dialog.initOwner(owner);
|
dialog.initOwner(owner);
|
||||||
|
dialog.initModality(Modality.APPLICATION_MODAL);
|
||||||
}
|
}
|
||||||
|
|
||||||
ButtonType selectButtonType = new ButtonType("Play", ButtonBar.ButtonData.OK_DONE);
|
ButtonType selectButtonType = new ButtonType("Play", ButtonBar.ButtonData.OK_DONE);
|
||||||
|
|
@ -59,13 +58,8 @@ public class HitoriDialogManager {
|
||||||
alert.setTitle(title);
|
alert.setTitle(title);
|
||||||
alert.setHeaderText(null);
|
alert.setHeaderText(null);
|
||||||
alert.setContentText(message);
|
alert.setContentText(message);
|
||||||
alert.initModality(Modality.NONE); // Don't block game updates
|
alert.initOwner(owner);
|
||||||
|
alert.showAndWait();
|
||||||
if (owner != null && owner.getScene() != null) {
|
|
||||||
alert.initOwner(owner);
|
|
||||||
}
|
|
||||||
|
|
||||||
alert.show(); // Use show() instead of showAndWait() to not block
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public Optional<String> askForPlayerName() {
|
public Optional<String> askForPlayerName() {
|
||||||
|
|
@ -73,12 +67,7 @@ public class HitoriDialogManager {
|
||||||
dialog.setTitle("High Score");
|
dialog.setTitle("High Score");
|
||||||
dialog.setHeaderText("Congratulations! Enter your name:");
|
dialog.setHeaderText("Congratulations! Enter your name:");
|
||||||
dialog.setContentText("Name:");
|
dialog.setContentText("Name:");
|
||||||
dialog.initModality(Modality.APPLICATION_MODAL);
|
dialog.initOwner(owner);
|
||||||
|
|
||||||
if (owner != null && owner.getScene() != null) {
|
|
||||||
dialog.initOwner(owner);
|
|
||||||
}
|
|
||||||
|
|
||||||
return dialog.showAndWait();
|
return dialog.showAndWait();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -87,11 +76,7 @@ public class HitoriDialogManager {
|
||||||
alert.setTitle("Delete High Scores");
|
alert.setTitle("Delete High Scores");
|
||||||
alert.setHeaderText("Are you sure?");
|
alert.setHeaderText("Are you sure?");
|
||||||
alert.setContentText("This will permanently delete all high scores.");
|
alert.setContentText("This will permanently delete all high scores.");
|
||||||
alert.initModality(Modality.APPLICATION_MODAL);
|
alert.initOwner(owner);
|
||||||
|
|
||||||
if (owner != null && owner.getScene() != null) {
|
|
||||||
alert.initOwner(owner);
|
|
||||||
}
|
|
||||||
|
|
||||||
Optional<ButtonType> result = alert.showAndWait();
|
Optional<ButtonType> result = alert.showAndWait();
|
||||||
return result.isPresent() && result.get() == ButtonType.OK;
|
return result.isPresent() && result.get() == ButtonType.OK;
|
||||||
|
|
@ -101,17 +86,13 @@ public class HitoriDialogManager {
|
||||||
Alert alert = new Alert(Alert.AlertType.CONFIRMATION);
|
Alert alert = new Alert(Alert.AlertType.CONFIRMATION);
|
||||||
alert.setTitle("Game Complete");
|
alert.setTitle("Game Complete");
|
||||||
alert.setHeaderText("Would you like to start a new game?");
|
alert.setHeaderText("Would you like to start a new game?");
|
||||||
alert.setContentText("Your current game progress will be saved automatically.");
|
alert.setContentText("Choose whether to start a new game or continue viewing this one.");
|
||||||
|
|
||||||
ButtonType buttonTypeNew = new ButtonType("New Game");
|
ButtonType buttonTypeNew = new ButtonType("New Game");
|
||||||
ButtonType buttonTypeStay = new ButtonType("Stay Here", ButtonBar.ButtonData.CANCEL_CLOSE);
|
ButtonType buttonTypeStay = new ButtonType("Stay Here", ButtonBar.ButtonData.CANCEL_CLOSE);
|
||||||
|
|
||||||
alert.getButtonTypes().setAll(buttonTypeNew, buttonTypeStay);
|
alert.getButtonTypes().setAll(buttonTypeNew, buttonTypeStay);
|
||||||
alert.initModality(Modality.APPLICATION_MODAL);
|
alert.initOwner(owner);
|
||||||
|
|
||||||
if (owner != null && owner.getScene() != null) {
|
|
||||||
alert.initOwner(owner);
|
|
||||||
}
|
|
||||||
|
|
||||||
Optional<ButtonType> result = alert.showAndWait();
|
Optional<ButtonType> result = alert.showAndWait();
|
||||||
return result.isPresent() && result.get() == buttonTypeNew;
|
return result.isPresent() && result.get() == buttonTypeNew;
|
||||||
|
|
@ -127,27 +108,9 @@ public class HitoriDialogManager {
|
||||||
ButtonType buttonTypeNo = new ButtonType("Start New Game");
|
ButtonType buttonTypeNo = new ButtonType("Start New Game");
|
||||||
|
|
||||||
alert.getButtonTypes().setAll(buttonTypeYes, buttonTypeNo);
|
alert.getButtonTypes().setAll(buttonTypeYes, buttonTypeNo);
|
||||||
alert.initModality(Modality.APPLICATION_MODAL);
|
alert.initOwner(owner);
|
||||||
|
|
||||||
if (owner != null && owner.getScene() != null) {
|
|
||||||
alert.initOwner(owner);
|
|
||||||
}
|
|
||||||
|
|
||||||
Optional<ButtonType> result = alert.showAndWait();
|
Optional<ButtonType> result = alert.showAndWait();
|
||||||
return result.isPresent() && result.get() == buttonTypeYes;
|
return result.isPresent() && result.get() == buttonTypeYes;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void showBlockingAlert(String title, String message) {
|
|
||||||
Alert alert = new Alert(Alert.AlertType.INFORMATION);
|
|
||||||
alert.setTitle(title);
|
|
||||||
alert.setHeaderText(null);
|
|
||||||
alert.setContentText(message);
|
|
||||||
alert.initModality(Modality.APPLICATION_MODAL);
|
|
||||||
|
|
||||||
if (owner != null && owner.getScene() != null) {
|
|
||||||
alert.initOwner(owner);
|
|
||||||
}
|
|
||||||
|
|
||||||
alert.showAndWait(); // Block until closed
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
@ -1,5 +1,6 @@
|
||||||
package GUI;
|
package GUI;
|
||||||
|
|
||||||
|
import GUI.GameUIController;
|
||||||
import javafx.geometry.Insets;
|
import javafx.geometry.Insets;
|
||||||
import javafx.geometry.Pos;
|
import javafx.geometry.Pos;
|
||||||
import javafx.scene.control.Button;
|
import javafx.scene.control.Button;
|
||||||
|
|
|
||||||
|
|
@ -1,9 +1,10 @@
|
||||||
package Main;
|
package Main;
|
||||||
|
|
||||||
import GUI.HitoriDialogManager;
|
|
||||||
import domain.HitoriBoardLoader;
|
|
||||||
import domain.HitoriGameMain;
|
import domain.HitoriGameMain;
|
||||||
|
import domain.HitoriBoardLoader;
|
||||||
import GUI.GameUIController;
|
import GUI.GameUIController;
|
||||||
|
import GUI.HitoriDialogManager;
|
||||||
import javafx.application.Application;
|
import javafx.application.Application;
|
||||||
import javafx.scene.Scene;
|
import javafx.scene.Scene;
|
||||||
import javafx.scene.layout.BorderPane;
|
import javafx.scene.layout.BorderPane;
|
||||||
|
|
@ -24,15 +25,14 @@ public class MainMethod extends Application {
|
||||||
boardLoader = new HitoriBoardLoader();
|
boardLoader = new HitoriBoardLoader();
|
||||||
dialogManager = new HitoriDialogManager(primaryStage);
|
dialogManager = new HitoriDialogManager(primaryStage);
|
||||||
|
|
||||||
HitoriGameMain savedGame = HitoriGameMain.loadGameState();
|
checkSavedGame(primaryStage);
|
||||||
checkSavedGame(primaryStage, savedGame);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void checkSavedGame(Stage primaryStage, HitoriGameMain savedGame) {
|
private void checkSavedGame(Stage primaryStage) {
|
||||||
|
HitoriGameMain savedGame = HitoriGameMain.loadGameState();
|
||||||
if (savedGame != null) {
|
if (savedGame != null) {
|
||||||
if (dialogManager.confirmLoadSavedGame()) {
|
if (dialogManager.confirmLoadSavedGame()) {
|
||||||
// Load the saved game with all its state
|
initializeGame(savedGame.getBoard(), primaryStage);
|
||||||
initializeGame(primaryStage, savedGame);
|
|
||||||
} else {
|
} else {
|
||||||
showBoardSelectionDialog(primaryStage);
|
showBoardSelectionDialog(primaryStage);
|
||||||
}
|
}
|
||||||
|
|
@ -47,15 +47,15 @@ public class MainMethod extends Application {
|
||||||
currentBoardName = boardName;
|
currentBoardName = boardName;
|
||||||
int[][] selectedBoard = boardLoader.getBoard(boardName);
|
int[][] selectedBoard = boardLoader.getBoard(boardName);
|
||||||
if (selectedBoard != null) {
|
if (selectedBoard != null) {
|
||||||
initializeGame(primaryStage, new HitoriGameMain(selectedBoard));
|
initializeGame(selectedBoard, primaryStage);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
() -> System.exit(0)
|
() -> System.exit(0)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void initializeGame(Stage primaryStage, HitoriGameMain game) {
|
private void initializeGame(int[][] board, Stage primaryStage) {
|
||||||
controller = new GameUIController(game.getBoard(), dialogManager, primaryStage, game);
|
controller = new GameUIController(board, dialogManager);
|
||||||
createGameUI(primaryStage);
|
createGameUI(primaryStage);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -4,10 +4,11 @@ import java.io.Serializable;
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
|
|
||||||
public class GameBase implements Serializable {
|
public class GameBase implements Serializable {
|
||||||
|
|
||||||
protected int[][] board;
|
protected int[][] board;
|
||||||
public boolean[][] blackCells;
|
public boolean[][] blackCells;
|
||||||
public boolean[][] whiteCells;
|
public boolean[][] whiteCells;
|
||||||
public int mistakeCount;
|
protected int mistakeCount;
|
||||||
|
|
||||||
public GameBase(int[][] initialBoard) {
|
public GameBase(int[][] initialBoard) {
|
||||||
this.board = new int[initialBoard.length][initialBoard[0].length];
|
this.board = new int[initialBoard.length][initialBoard[0].length];
|
||||||
|
|
@ -22,6 +23,7 @@ public class GameBase implements Serializable {
|
||||||
public void reset() {
|
public void reset() {
|
||||||
blackCells = new boolean[board.length][board[0].length];
|
blackCells = new boolean[board.length][board[0].length];
|
||||||
whiteCells = new boolean[board.length][board[0].length];
|
whiteCells = new boolean[board.length][board[0].length];
|
||||||
|
mistakeCount = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
public int[][] getBoard() {
|
public int[][] getBoard() {
|
||||||
|
|
|
||||||
|
|
@ -2,15 +2,14 @@ package domain;
|
||||||
|
|
||||||
import java.util.*;
|
import java.util.*;
|
||||||
|
|
||||||
public class GameSolver extends HitoriGameMoves {
|
public class GameSolver extends domain.HitoriGameMoves {
|
||||||
|
|
||||||
public GameSolver(int[][] initialBoard) {
|
public GameSolver(int[][] initialBoard) {
|
||||||
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)
|
|
||||||
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++) {
|
||||||
if (!blackCells[i][j] && !whiteCells[i][j]) {
|
if (!blackCells[i][j] && !whiteCells[i][j]) {
|
||||||
|
|
@ -19,7 +18,7 @@ public class GameSolver extends HitoriGameMoves {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check for adjacent black cells
|
|
||||||
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++) {
|
||||||
if (blackCells[i][j] && !isValidBlackMark(i, j)) {
|
if (blackCells[i][j] && !isValidBlackMark(i, j)) {
|
||||||
|
|
@ -28,13 +27,13 @@ public class GameSolver extends HitoriGameMoves {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check for duplicates in rows and columns
|
|
||||||
for (int i = 0; i < board.length; i++) {
|
for (int i = 0; i < board.length; i++) {
|
||||||
Set<Integer> seenInRow = new HashSet<>();
|
Set<Integer> seenInRow = new HashSet<>();
|
||||||
Set<Integer> seenInCol = new HashSet<>();
|
Set<Integer> seenInCol = new HashSet<>();
|
||||||
|
|
||||||
for (int j = 0; j < board[0].length; j++) {
|
for (int j = 0; j < board[0].length; j++) {
|
||||||
// Check row
|
|
||||||
if (!blackCells[i][j]) {
|
if (!blackCells[i][j]) {
|
||||||
if (seenInRow.contains(board[i][j])) {
|
if (seenInRow.contains(board[i][j])) {
|
||||||
return false;
|
return false;
|
||||||
|
|
@ -42,7 +41,7 @@ public class GameSolver extends HitoriGameMoves {
|
||||||
seenInRow.add(board[i][j]);
|
seenInRow.add(board[i][j]);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check column
|
|
||||||
if (!blackCells[j][i]) {
|
if (!blackCells[j][i]) {
|
||||||
if (seenInCol.contains(board[j][i])) {
|
if (seenInCol.contains(board[j][i])) {
|
||||||
return false;
|
return false;
|
||||||
|
|
@ -56,8 +55,7 @@ public class GameSolver extends HitoriGameMoves {
|
||||||
return isOrthogonallyConnected();
|
return isOrthogonallyConnected();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Überprüft, ob die schwarze Markierung gültig ist
|
public 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] ||
|
||||||
col > 0 && blackCells[row][col-1] ||
|
col > 0 && blackCells[row][col-1] ||
|
||||||
|
|
@ -67,7 +65,6 @@ 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;
|
||||||
|
|
||||||
|
|
@ -87,7 +84,6 @@ 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++) {
|
||||||
|
|
@ -99,7 +95,6 @@ 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]) {
|
||||||
|
|
@ -114,7 +109,6 @@ 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(); // Lädt alle verfügbaren Boards
|
loadAllBoards();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void loadAllBoards() {
|
private void loadAllBoards() {
|
||||||
try {
|
try {
|
||||||
// Definiere die Board-Dateinamen
|
// Define all board file names
|
||||||
String[] boardFiles = {
|
String[] boardFiles = {
|
||||||
"Hitori4x4_leicht.csv",
|
"Hitori4x4_leicht.csv",
|
||||||
"Hitori5x5leicht.csv",
|
"Hitori5x5leicht.csv",
|
||||||
|
|
@ -26,12 +26,16 @@ public class HitoriBoardLoader {
|
||||||
"Hitori15x15_medium.csv"
|
"Hitori15x15_medium.csv"
|
||||||
};
|
};
|
||||||
|
|
||||||
// Versuche, jedes Board zu laden
|
// Try to load each board
|
||||||
for (String fileName : boardFiles) {
|
for (String fileName : boardFiles) {
|
||||||
try {
|
try {
|
||||||
InputStream is = getClass().getResourceAsStream("/" + fileName);
|
InputStream is = getClass().getResourceAsStream("/META-INF/" + fileName);
|
||||||
|
if (is == null) {
|
||||||
|
is = getClass().getResourceAsStream("/" + fileName);
|
||||||
|
}
|
||||||
|
|
||||||
if (is != null) {
|
if (is != null) {
|
||||||
loadBoard(fileName, is); // Lade das Board
|
loadBoard(fileName, is);
|
||||||
}
|
}
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
System.out.println("Failed to load board: " + fileName);
|
System.out.println("Failed to load board: " + fileName);
|
||||||
|
|
@ -39,7 +43,6 @@ 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 {
|
||||||
|
|
@ -50,16 +53,15 @@ 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); // Liest jede Zeile der Datei
|
lines.add(line);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Finde den Startpunkt der Lösung
|
// Find where the solution starts
|
||||||
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("//")) {
|
||||||
|
|
@ -68,12 +70,12 @@ public class HitoriBoardLoader {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Parsen des Boards
|
// Parse the board
|
||||||
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(",")); // Trenne die Zeilen in Spalten
|
boardRows.add(line.split(","));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -84,12 +86,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()); // Konvertiere die Strings in Integers
|
board[i][j] = Integer.parseInt(boardRows.get(i)[j].trim());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
availableBoards.put(fileName, board); // Speichere das Board
|
availableBoards.put(fileName, board);
|
||||||
|
|
||||||
// Wenn eine Lösung vorhanden ist, speichere sie
|
// Parse the solution if available
|
||||||
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++) {
|
||||||
|
|
@ -102,23 +104,20 @@ public class HitoriBoardLoader {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
solutions.put(fileName, solutionCoordinates); // Speichere die Lösung
|
solutions.put(fileName, solutionCoordinates);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// 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);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,49 +1,22 @@
|
||||||
package domain;
|
package domain;
|
||||||
|
|
||||||
|
import domain.GameSolver;
|
||||||
|
|
||||||
import java.io.*;
|
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; // Timer für das Spiel
|
private final domain.HitoriGameTimer timer;
|
||||||
private final HitoriGameScores scores; // Highscore-Verwaltung
|
private final domain.HitoriGameScores scores;
|
||||||
private long savedTime; // Gespeicherte Zeit für den Timer
|
|
||||||
|
|
||||||
public HitoriGameMain(int[][] initialBoard) {
|
public HitoriGameMain(int[][] initialBoard) {
|
||||||
super(initialBoard);
|
super(initialBoard);
|
||||||
this.timer = new HitoriGameTimer();
|
this.timer = new domain.HitoriGameTimer();
|
||||||
this.scores = new HitoriGameScores();
|
this.scores = new HitoriGameScores();
|
||||||
this.savedTime = 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public HitoriGameTimer getTimer() {
|
// Timer delegation methods
|
||||||
return timer;
|
|
||||||
}
|
|
||||||
|
|
||||||
public HitoriGameScores getScores() {
|
|
||||||
return scores;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Speichert den aktuellen Zustand des Spiels
|
|
||||||
private void writeObject(ObjectOutputStream out) throws IOException {
|
|
||||||
out.defaultWriteObject();
|
|
||||||
out.writeLong(getElapsedTimeInSeconds());
|
|
||||||
out.writeInt(mistakeCount);
|
|
||||||
out.writeObject(blackCells);
|
|
||||||
out.writeObject(whiteCells);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Stellt den gespeicherten Zustand des Spiels wieder her
|
|
||||||
private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException {
|
|
||||||
in.defaultReadObject();
|
|
||||||
long savedTime = in.readLong();
|
|
||||||
this.mistakeCount = in.readInt();
|
|
||||||
this.blackCells = (boolean[][]) in.readObject();
|
|
||||||
this.whiteCells = (boolean[][]) in.readObject();
|
|
||||||
this.timer.setElapsedTime(savedTime);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Steuerung des Timers
|
|
||||||
public void startTimer() {
|
public void startTimer() {
|
||||||
timer.startTimer();
|
timer.startTimer();
|
||||||
}
|
}
|
||||||
|
|
@ -60,12 +33,11 @@ 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 timer.getElapsedTimeInSeconds();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Highscore-Verwaltung
|
// High score delegation methods
|
||||||
public void addHighScore(String playerName, long timeInSeconds) {
|
public void addHighScore(String playerName, long timeInSeconds) {
|
||||||
scores.addHighScore(playerName, timeInSeconds, getMistakeCount());
|
scores.addHighScore(playerName, timeInSeconds, getMistakeCount());
|
||||||
}
|
}
|
||||||
|
|
@ -86,21 +58,7 @@ public class HitoriGameMain extends GameSolver {
|
||||||
scores.saveHighScoresToFile();
|
scores.saveHighScoresToFile();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Setzt den Spielzustand
|
// Game state persistence
|
||||||
public void setGameState(boolean[][] blackCells, boolean[][] whiteCells, int mistakeCount, long elapsedTime) {
|
|
||||||
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] = blackCells[i].clone();
|
|
||||||
this.whiteCells[i] = whiteCells[i].clone();
|
|
||||||
}
|
|
||||||
|
|
||||||
this.mistakeCount = mistakeCount;
|
|
||||||
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,29 +68,18 @@ 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();
|
return (HitoriGameMain) ois.readObject();
|
||||||
loadedGame.timer.resetTimer();
|
|
||||||
return loadedGame;
|
|
||||||
} catch (IOException | ClassNotFoundException e) {
|
} catch (IOException | ClassNotFoundException e) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Stellt den gespeicherten Zustand des Spiels wieder her
|
|
||||||
public void restoreGameState(HitoriGameMain savedGame) {
|
|
||||||
if (savedGame != null) {
|
|
||||||
this.setGameState(savedGame.blackCells, savedGame.whiteCells,
|
|
||||||
savedGame.mistakeCount, savedGame.savedTime);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void reset() {
|
public void reset() {
|
||||||
super.reset();
|
super.reset();
|
||||||
savedTime = 0; // Timer wird nicht zurückgesetzt
|
resetTimer();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -0,0 +1,98 @@
|
||||||
|
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) {
|
||||||
|
if (!isValidBlackMark(row, col)) {
|
||||||
|
mistakeCount++;
|
||||||
|
}
|
||||||
|
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 boolean isValidBlackMark(int row, int col) {
|
||||||
|
if (row > 0 && blackCells[row-1][col] ||
|
||||||
|
row < board.length-1 && blackCells[row+1][col] ||
|
||||||
|
col > 0 && blackCells[row][col-1] ||
|
||||||
|
col < board[0].length-1 && blackCells[row][col+1]) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
private 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() {
|
||||||
|
super.reset();
|
||||||
|
history.clear();
|
||||||
|
historyPointer = -1;
|
||||||
|
saveState();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -8,7 +8,6 @@ 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;
|
||||||
|
|
@ -25,20 +24,17 @@ 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<>();
|
||||||
|
|
@ -47,27 +43,24 @@ public class HitoriGameScores implements Serializable {
|
||||||
allEntries.addAll(entries);
|
allEntries.addAll(entries);
|
||||||
}
|
}
|
||||||
|
|
||||||
allEntries.sort((a, b) -> Long.compare(a.time, b.time)); // Sortiert nach Zeit
|
allEntries.sort((a, b) -> Long.compare(a.time, b.time));
|
||||||
|
|
||||||
// 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)); // Durchschnittszeit hinzufügen
|
result.add(String.format("Average Time: %.1fs", avgTime));
|
||||||
|
|
||||||
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"))) {
|
||||||
|
|
@ -77,14 +70,13 @@ 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<>(); // Leert die Highscores bei Fehler
|
highScores = new HashMap<>();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -1,8 +1,5 @@
|
||||||
package domain;
|
package domain;
|
||||||
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.io.ObjectInputStream;
|
|
||||||
import java.io.ObjectOutputStream;
|
|
||||||
import java.io.Serializable;
|
import java.io.Serializable;
|
||||||
|
|
||||||
public class HitoriGameTimer implements Serializable {
|
public class HitoriGameTimer implements Serializable {
|
||||||
|
|
@ -11,90 +8,49 @@ public class HitoriGameTimer implements Serializable {
|
||||||
private transient long startTime;
|
private transient long startTime;
|
||||||
private long elapsedTime;
|
private long elapsedTime;
|
||||||
private boolean isPaused;
|
private boolean isPaused;
|
||||||
private long lastPauseTime;
|
|
||||||
|
|
||||||
public HitoriGameTimer() {
|
public HitoriGameTimer() {
|
||||||
this.startTime = 0;
|
this.startTime = 0;
|
||||||
this.elapsedTime = 0;
|
this.elapsedTime = 0;
|
||||||
this.isPaused = true; // Timer beginnt pausiert
|
this.isPaused = false;
|
||||||
this.lastPauseTime = 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Timer starten
|
|
||||||
public void startTimer() {
|
public void startTimer() {
|
||||||
if (isPaused) {
|
if (isPaused || startTime == 0) {
|
||||||
startTime = System.currentTimeMillis();
|
startTime = System.currentTimeMillis();
|
||||||
isPaused = false;
|
isPaused = false;
|
||||||
|
|
||||||
if (lastPauseTime > 0) {
|
|
||||||
startTime = System.currentTimeMillis();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Timer pausieren
|
|
||||||
public void pauseTimer() {
|
public void pauseTimer() {
|
||||||
if (!isPaused && startTime > 0) {
|
if (!isPaused && startTime > 0) {
|
||||||
lastPauseTime = System.currentTimeMillis();
|
elapsedTime += System.currentTimeMillis() - startTime;
|
||||||
elapsedTime += lastPauseTime - startTime;
|
|
||||||
startTime = 0;
|
startTime = 0;
|
||||||
isPaused = true;
|
isPaused = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Timer stoppen
|
|
||||||
public void stopTimer() {
|
public void stopTimer() {
|
||||||
if (!isPaused && startTime > 0) {
|
if (!isPaused && startTime > 0) {
|
||||||
long stopTime = System.currentTimeMillis();
|
elapsedTime += System.currentTimeMillis() - startTime;
|
||||||
elapsedTime += stopTime - startTime;
|
|
||||||
startTime = 0;
|
startTime = 0;
|
||||||
isPaused = true;
|
|
||||||
lastPauseTime = stopTime;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Timer zurücksetzen
|
|
||||||
public void resetTimer() {
|
public void resetTimer() {
|
||||||
startTime = 0;
|
startTime = 0;
|
||||||
elapsedTime = 0;
|
elapsedTime = 0;
|
||||||
isPaused = true;
|
isPaused = false;
|
||||||
lastPauseTime = 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Setzt die vergangene Zeit manuell
|
|
||||||
public void setElapsedTime(long timeInSeconds) {
|
|
||||||
this.elapsedTime = timeInSeconds * 1000; // Umrechnung in Millisekunden
|
|
||||||
this.lastPauseTime = System.currentTimeMillis();
|
|
||||||
}
|
|
||||||
|
|
||||||
// Gibt die vergangene Zeit in Sekunden zurück
|
|
||||||
public long getElapsedTimeInSeconds() {
|
public long getElapsedTimeInSeconds() {
|
||||||
if (isPaused) {
|
if (isPaused || startTime == 0) {
|
||||||
return elapsedTime / 1000;
|
return elapsedTime / 1000;
|
||||||
}
|
}
|
||||||
long currentTime = System.currentTimeMillis();
|
return (elapsedTime + System.currentTimeMillis() - 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;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Für die Serialisierung: Speichert den aktuellen Zustand
|
|
||||||
private void writeObject(ObjectOutputStream out) throws IOException {
|
|
||||||
out.defaultWriteObject();
|
|
||||||
|
|
||||||
if (!isPaused && startTime > 0) {
|
|
||||||
elapsedTime += System.currentTimeMillis() - startTime;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException {
|
|
||||||
in.defaultReadObject();
|
|
||||||
|
|
||||||
startTime = 0;
|
|
||||||
isPaused = true;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
@ -0,0 +1,41 @@
|
||||||
|
5,8,2,6,3,7,7,5,1,8
|
||||||
|
8,4,2,2,1,9,9,3,7,5
|
||||||
|
3,2,7,8,2,5,5,4,3,10
|
||||||
|
10,2,3,1,7,8,6,9,9,9
|
||||||
|
3,3,3,7,6,2,4,10,4,1
|
||||||
|
4,5,9,10,6,10,1,7,8,8
|
||||||
|
2,7,5,9,1,10,3,1,3,6
|
||||||
|
9,5,4,3,8,10,2,9,10,4
|
||||||
|
9,6,10,8,5,3,10,2,5,8
|
||||||
|
9,10,2,2,4,7,9,8,5,7
|
||||||
|
|
||||||
|
// Lösung (schwarze Felder)
|
||||||
|
1,1
|
||||||
|
1,3
|
||||||
|
1,6
|
||||||
|
1,10
|
||||||
|
2,4
|
||||||
|
2,7
|
||||||
|
3,2
|
||||||
|
3,6
|
||||||
|
3,9
|
||||||
|
4,8
|
||||||
|
4,10
|
||||||
|
5,1
|
||||||
|
5,3
|
||||||
|
5,5
|
||||||
|
5,7
|
||||||
|
6,2
|
||||||
|
6,6
|
||||||
|
6,10
|
||||||
|
7,5
|
||||||
|
7,9
|
||||||
|
8,1
|
||||||
|
8,3
|
||||||
|
8,6
|
||||||
|
9,4
|
||||||
|
9,7
|
||||||
|
9,9
|
||||||
|
10,1
|
||||||
|
10,3
|
||||||
|
10,10
|
||||||
|
Can't render this file because it has a wrong number of fields in line 12.
|
|
|
@ -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.
|
|
|
@ -0,0 +1,11 @@
|
||||||
|
3,3,1,4
|
||||||
|
4,3,2,2
|
||||||
|
1,3,4,2
|
||||||
|
3,4,3,2
|
||||||
|
|
||||||
|
//Lösung (schwarze Felder)
|
||||||
|
1,2
|
||||||
|
2,4
|
||||||
|
3,2
|
||||||
|
4,1
|
||||||
|
4,4
|
||||||
|
|
|
@ -0,0 +1,15 @@
|
||||||
|
3,4,5,5,2
|
||||||
|
3,2,3,5,4
|
||||||
|
2,1,4,5,5
|
||||||
|
2,3,1,4,1
|
||||||
|
2,5,2,3,2
|
||||||
|
|
||||||
|
//Lösung (schwarze Felder)
|
||||||
|
1,1
|
||||||
|
1,4
|
||||||
|
2,3
|
||||||
|
3,1
|
||||||
|
3,4
|
||||||
|
4,3
|
||||||
|
5,1
|
||||||
|
5,5
|
||||||
|
|
|
@ -0,0 +1,29 @@
|
||||||
|
2,7,2,1,5,8,3,5
|
||||||
|
6,6,1,6,2,4,4,7
|
||||||
|
7,5,8,2,6,6,6,1
|
||||||
|
3,6,8,8,4,2,1,8
|
||||||
|
6,4,7,7,8,2,6,3
|
||||||
|
1,6,4,5,1,3,5,8
|
||||||
|
8,1,3,3,6,4,2,6
|
||||||
|
5,3,6,4,3,4,8,2
|
||||||
|
|
||||||
|
// Lösung (schwarze Felder)
|
||||||
|
1,1
|
||||||
|
1,8
|
||||||
|
2,2
|
||||||
|
2,4
|
||||||
|
2,6
|
||||||
|
3,5
|
||||||
|
3,7
|
||||||
|
4,3
|
||||||
|
4,8
|
||||||
|
5,1
|
||||||
|
5,4
|
||||||
|
5,6
|
||||||
|
6,2
|
||||||
|
6,5
|
||||||
|
6,7
|
||||||
|
7,4
|
||||||
|
7,8
|
||||||
|
8,2
|
||||||
|
8,6
|
||||||
|
|
|
@ -0,0 +1,30 @@
|
||||||
|
4,4,3,5,6,5,7,7
|
||||||
|
8,5,7,6,8,4,7,1
|
||||||
|
7,2,1,2,4,6,2,3
|
||||||
|
8,6,5,2,7,7,3,6
|
||||||
|
3,1,2,7,3,8,6,4
|
||||||
|
1,2,4,1,5,7,3,2
|
||||||
|
5,8,2,4,3,4,1,5
|
||||||
|
2,4,5,1,8,3,8,1
|
||||||
|
|
||||||
|
//Lösung (schwarze Zahlen)
|
||||||
|
1,2
|
||||||
|
1,4
|
||||||
|
1,8
|
||||||
|
2,5
|
||||||
|
2,7
|
||||||
|
3,2
|
||||||
|
3,4
|
||||||
|
4,1
|
||||||
|
4,6
|
||||||
|
4,8
|
||||||
|
5,3
|
||||||
|
5,5
|
||||||
|
6,2
|
||||||
|
6,4
|
||||||
|
6,7
|
||||||
|
7,1
|
||||||
|
7,6
|
||||||
|
8,3
|
||||||
|
8,5
|
||||||
|
8,8
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
import org.junit.jupiter.api.*;
|
import org.junit.jupiter.api.*;
|
||||||
import static org.junit.jupiter.api.Assertions.*;
|
import static org.junit.jupiter.api.Assertions.*;
|
||||||
|
|
||||||
class GameBaseTest {
|
class HitoriGameBaseTest {
|
||||||
private domain.GameBase game;
|
private domain.GameBase game;
|
||||||
private static final int[][] TEST_BOARD = {
|
private static final int[][] TEST_BOARD = {
|
||||||
{1, 2, 1, 3},
|
{1, 2, 1, 3},
|
||||||
|
|
@ -24,14 +24,14 @@ class GameBaseTest {
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
void testReset() {
|
void testReset() {
|
||||||
// Setzt automatisch schwarze Zellen
|
// Directly set some cells (since we can't use markCell methods in base class)
|
||||||
game.blackCells[0][0] = true;
|
game.blackCells[0][0] = true;
|
||||||
game.whiteCells[1][1] = true;
|
game.whiteCells[1][1] = true;
|
||||||
|
|
||||||
// Reset game
|
// Reset game
|
||||||
game.reset();
|
game.reset();
|
||||||
|
|
||||||
// Verifiziert, ob alle schwarzen Zellen gelöscht wurden
|
// Verify all cells are reset
|
||||||
boolean[][] blackCells = game.getBlackCells();
|
boolean[][] blackCells = game.getBlackCells();
|
||||||
boolean[][] whiteCells = game.getWhiteCells();
|
boolean[][] whiteCells = game.getWhiteCells();
|
||||||
|
|
||||||
|
|
@ -45,7 +45,15 @@ class GameBaseTest {
|
||||||
assertEquals(0, game.getMistakeCount());
|
assertEquals(0, game.getMistakeCount());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void testGetBoard() {
|
||||||
|
int[][] board = game.getBoard();
|
||||||
|
assertArrayEquals(TEST_BOARD, board);
|
||||||
|
|
||||||
|
// Test deep copy - modifying returned board should not affect original
|
||||||
|
board[0][0] = 999;
|
||||||
|
assertNotEquals(999, game.getBoard()[0][0]);
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
void testGetCurrentState() {
|
void testGetCurrentState() {
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,5 @@
|
||||||
import GUI.GameUIController;
|
import GUI.GameUIController;
|
||||||
import GUI.HitoriDialogManager;
|
import GUI.HitoriDialogManager;
|
||||||
import domain.HitoriGameMain;
|
|
||||||
import javafx.stage.Stage;
|
import javafx.stage.Stage;
|
||||||
import org.junit.jupiter.api.*;
|
import org.junit.jupiter.api.*;
|
||||||
import org.junit.jupiter.api.extension.ExtendWith;
|
import org.junit.jupiter.api.extension.ExtendWith;
|
||||||
|
|
@ -29,10 +28,13 @@ class GameUIControllerTest {
|
||||||
this.stage = stage;
|
this.stage = stage;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@BeforeEach
|
||||||
|
void setUp() {
|
||||||
|
dialogManager = mock(HitoriDialogManager.class);
|
||||||
|
controller = new GameUIController(TEST_BOARD, dialogManager);
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
// Checkt ob alle Elemente initialisiert wurden
|
|
||||||
void testInitialization() {
|
void testInitialization() {
|
||||||
assertNotNull(controller);
|
assertNotNull(controller);
|
||||||
assertNotNull(controller.getBoardPanel());
|
assertNotNull(controller.getBoardPanel());
|
||||||
|
|
@ -66,12 +68,12 @@ class GameUIControllerTest {
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
void testResetGame() {
|
void testResetGame() {
|
||||||
// Feldermarkierungen
|
// Make some moves first
|
||||||
controller.handleLeftClick(0, 0);
|
controller.handleLeftClick(0, 0);
|
||||||
controller.handleRightClick(1, 1);
|
controller.handleRightClick(1, 1);
|
||||||
|
|
||||||
controller.resetGame();
|
controller.resetGame();
|
||||||
// Verifiziert Boardlöschung
|
// Verify the board is reset
|
||||||
var boardPanel = controller.getBoardPanel();
|
var boardPanel = controller.getBoardPanel();
|
||||||
assertEquals(9, boardPanel.getChildren().size()); // 3x3 board
|
assertEquals(9, boardPanel.getChildren().size()); // 3x3 board
|
||||||
}
|
}
|
||||||
|
|
@ -81,13 +83,13 @@ class GameUIControllerTest {
|
||||||
controller.handleLeftClick(0, 0);
|
controller.handleLeftClick(0, 0);
|
||||||
controller.undo();
|
controller.undo();
|
||||||
controller.redo();
|
controller.redo();
|
||||||
// Verifiziert den Board Status
|
// Verify the board state
|
||||||
assertTrue(controller.getBoardPanel().getChildren().size() > 0);
|
assertTrue(controller.getBoardPanel().getChildren().size() > 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
void testShowErrors() {
|
void testShowErrors() {
|
||||||
// Fehler werden kreiert
|
// Create some errors first
|
||||||
controller.handleLeftClick(0, 0);
|
controller.handleLeftClick(0, 0);
|
||||||
controller.handleLeftClick(0, 1);
|
controller.handleLeftClick(0, 1);
|
||||||
|
|
||||||
|
|
@ -108,10 +110,20 @@ class GameUIControllerTest {
|
||||||
verify(dialogManager).showAlert(eq("High Scores Deleted"), anyString());
|
verify(dialogManager).showAlert(eq("High Scores Deleted"), anyString());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void testHandleWin() {
|
||||||
|
// Setup mock responses
|
||||||
|
when(dialogManager.askForPlayerName()).thenReturn(Optional.of("TestPlayer"));
|
||||||
|
when(dialogManager.confirmNewGame()).thenReturn(false);
|
||||||
|
|
||||||
|
// Make winning moves (this is simplified)
|
||||||
|
makeWinningMoves();
|
||||||
|
|
||||||
|
// Verify win handling
|
||||||
|
verify(dialogManager, times(1)).showAlert(eq("Congratulations!"), anyString());
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
// Fehlerspeicherung
|
|
||||||
void testConvertErrorsToSet() {
|
void testConvertErrorsToSet() {
|
||||||
List<int[]> errors = List.of(
|
List<int[]> errors = List.of(
|
||||||
new int[]{0, 0},
|
new int[]{0, 0},
|
||||||
|
|
@ -128,9 +140,10 @@ class GameUIControllerTest {
|
||||||
assertFalse(controller.isPaused());
|
assertFalse(controller.isPaused());
|
||||||
}
|
}
|
||||||
|
|
||||||
// Hilfsmethode
|
// Helper method to simulate winning moves
|
||||||
private void makeWinningMoves() {
|
private void makeWinningMoves() {
|
||||||
// Win
|
// This would need to be implemented according to your winning condition
|
||||||
|
// For test purposes, we'll just make some moves
|
||||||
controller.handleLeftClick(0, 2);
|
controller.handleLeftClick(0, 2);
|
||||||
controller.handleRightClick(0, 0);
|
controller.handleRightClick(0, 0);
|
||||||
controller.handleRightClick(0, 1);
|
controller.handleRightClick(0, 1);
|
||||||
|
|
|
||||||
|
|
@ -31,14 +31,12 @@ 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();
|
||||||
|
|
@ -46,7 +44,6 @@ 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();
|
||||||
|
|
@ -54,23 +51,21 @@ 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();
|
||||||
|
|
||||||
// Verifiziere, dass fehlerhafte Zellen rot markiert werden
|
// Verify that error cells are marked red
|
||||||
var children = boardPanel.getChildren();
|
var children = boardPanel.getChildren();
|
||||||
for (var child : children) {
|
for (var child : children) {
|
||||||
Button button = (Button) child;
|
Button button = (Button) child;
|
||||||
|
|
@ -81,6 +76,39 @@ class HitoriBoardPanelTest {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void testLeftClickHandling() {
|
||||||
|
when(controller.isPaused()).thenReturn(false);
|
||||||
|
var button = (Button) boardPanel.getChildren().get(0);
|
||||||
|
|
||||||
|
MouseEvent event = mock(MouseEvent.class);
|
||||||
|
when(event.getButton()).thenReturn(MouseButton.PRIMARY);
|
||||||
|
button.fireEvent(event);
|
||||||
|
|
||||||
|
verify(controller, times(0)).handleLeftClick(anyInt(), anyInt());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void testRightClickHandling() {
|
||||||
|
when(controller.isPaused()).thenReturn(false);
|
||||||
|
var button = (Button) boardPanel.getChildren().get(0);
|
||||||
|
|
||||||
|
MouseEvent event = mock(MouseEvent.class);
|
||||||
|
when(event.getButton()).thenReturn(MouseButton.SECONDARY);
|
||||||
|
button.fireEvent(event);
|
||||||
|
|
||||||
|
verify(controller, times(0)).handleRightClick(anyInt(), anyInt());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void testPausedState() {
|
||||||
|
when(controller.isPaused()).thenReturn(true);
|
||||||
|
var button = (Button) boardPanel.getChildren().get(0);
|
||||||
|
|
||||||
|
MouseEvent event = mock(MouseEvent.class);
|
||||||
|
when(event.getButton()).thenReturn(MouseButton.PRIMARY);
|
||||||
|
button.fireEvent(event);
|
||||||
|
|
||||||
|
verify(controller, never()).handleLeftClick(anyInt(), anyInt());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -19,30 +19,26 @@ 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);
|
||||||
var timerLabel = findLabelByText(controlPanel, "Time: 42s");
|
var timerLabel = findLabelByText(controlPanel, "Time: 42s");
|
||||||
assertNotNull(42);
|
assertNotNull(timerLabel);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Testet das Aktualisieren des Fehler-Labels
|
|
||||||
@Test
|
@Test
|
||||||
void testUpdateMistakeLabel() {
|
void testUpdateMistakeLabel() {
|
||||||
controlPanel.updateMistakeLabel(5);
|
controlPanel.updateMistakeLabel(5);
|
||||||
var mistakeLabel = findLabelByText(controlPanel, "Mistakes: 5");
|
var mistakeLabel = findLabelByText(controlPanel, "Mistakes: 5");
|
||||||
assertNotNull(5);
|
assertNotNull(mistakeLabel);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Testet das Setzen des Textes für den Pause-Button
|
|
||||||
@Test
|
@Test
|
||||||
void testSetPauseButtonText() {
|
void testSetPauseButtonText() {
|
||||||
controlPanel.setPauseButtonText("Test");
|
controlPanel.setPauseButtonText("Test");
|
||||||
|
|
@ -50,7 +46,6 @@ 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");
|
||||||
|
|
@ -60,7 +55,6 @@ 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");
|
||||||
|
|
@ -70,7 +64,6 @@ 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");
|
||||||
|
|
@ -80,7 +73,6 @@ 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");
|
||||||
|
|
@ -90,7 +82,6 @@ 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");
|
||||||
|
|
@ -100,7 +91,6 @@ 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");
|
||||||
|
|
@ -110,7 +100,6 @@ 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");
|
||||||
|
|
@ -120,7 +109,6 @@ 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))
|
||||||
|
|
@ -128,7 +116,6 @@ 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())
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,78 @@
|
||||||
|
import domain.HitoriBoardLoader;
|
||||||
|
import GUI.HitoriDialogManager;
|
||||||
|
import javafx.stage.Stage;
|
||||||
|
import org.junit.jupiter.api.*;
|
||||||
|
import org.junit.jupiter.api.extension.ExtendWith;
|
||||||
|
import org.testfx.framework.junit5.ApplicationExtension;
|
||||||
|
import org.testfx.framework.junit5.Start;
|
||||||
|
import static org.junit.jupiter.api.Assertions.*;
|
||||||
|
import static org.mockito.Mockito.*;
|
||||||
|
|
||||||
|
@ExtendWith(ApplicationExtension.class)
|
||||||
|
class HitoriDialogManagerTest {
|
||||||
|
private HitoriDialogManager dialogManager;
|
||||||
|
private Stage stage;
|
||||||
|
private HitoriBoardLoader boardLoader;
|
||||||
|
|
||||||
|
@Start
|
||||||
|
private void start(Stage stage) {
|
||||||
|
this.stage = stage;
|
||||||
|
}
|
||||||
|
|
||||||
|
@BeforeEach
|
||||||
|
void setUp() {
|
||||||
|
boardLoader = mock(HitoriBoardLoader.class);
|
||||||
|
dialogManager = new HitoriDialogManager(stage);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void testShowAlert() {
|
||||||
|
// Cannot directly test Alert dialogs in headless mode
|
||||||
|
assertDoesNotThrow(() ->
|
||||||
|
dialogManager.showAlert("Test", "Test Message")
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void testConfirmDeleteHighScores() {
|
||||||
|
// Cannot directly test confirmation dialogs in headless mode
|
||||||
|
assertDoesNotThrow(() ->
|
||||||
|
dialogManager.confirmDeleteHighScores()
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void testConfirmNewGame() {
|
||||||
|
// Cannot directly test confirmation dialogs in headless mode
|
||||||
|
assertDoesNotThrow(() ->
|
||||||
|
dialogManager.confirmNewGame()
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void testAskForPlayerName() {
|
||||||
|
// Cannot directly test input dialogs in headless mode
|
||||||
|
assertDoesNotThrow(() ->
|
||||||
|
dialogManager.askForPlayerName()
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void testConfirmLoadSavedGame() {
|
||||||
|
// Cannot directly test confirmation dialogs in headless mode
|
||||||
|
assertDoesNotThrow(() ->
|
||||||
|
dialogManager.confirmLoadSavedGame()
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void testShowBoardSelectionDialog() {
|
||||||
|
// Cannot directly test choice dialogs in headless mode
|
||||||
|
when(boardLoader.getAvailableBoardNames())
|
||||||
|
.thenReturn(java.util.Arrays.asList("Board1", "Board2"));
|
||||||
|
|
||||||
|
assertDoesNotThrow(() ->
|
||||||
|
dialogManager.showBoardSelectionDialog(boardLoader)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -19,14 +19,15 @@ class HitoriGameMovesTest {
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
void testMarkCellAsBlack() {
|
void testMarkCellAsBlack() {
|
||||||
// Testet schwarze Markierung
|
// Test valid black marking
|
||||||
game.markCellAsBlack(0, 1);
|
game.markCellAsBlack(0, 2);
|
||||||
assertFalse(game.getBlackCells()[0][2]);
|
assertTrue(game.getBlackCells()[0][2]);
|
||||||
assertFalse(game.getWhiteCells()[0][2]);
|
assertFalse(game.getWhiteCells()[0][2]);
|
||||||
|
|
||||||
|
// Test invalid black marking (adjacent to existing black cell)
|
||||||
|
assertThrows(IllegalStateException.class, () -> {
|
||||||
|
game.markCellAsBlack(0, 1);
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
|
@ -42,49 +43,50 @@ class HitoriGameMovesTest {
|
||||||
game.markCellAsWhite(0, 0);
|
game.markCellAsWhite(0, 0);
|
||||||
game.markCellAsBlack(1, 1);
|
game.markCellAsBlack(1, 1);
|
||||||
|
|
||||||
// Löscht letzten Schritt
|
// Undo last move
|
||||||
assertTrue(game.undo());
|
assertTrue(game.undo());
|
||||||
|
|
||||||
// Verified das der letzte Schritt gelöscht wurde
|
// Verify the last move was undone
|
||||||
assertFalse(game.getBlackCells()[1][1]);
|
assertFalse(game.getBlackCells()[1][1]);
|
||||||
|
|
||||||
// Verifiziert, dass der vorherige Move gespeichert wurde
|
// Verify previous move remains
|
||||||
assertTrue(game.getWhiteCells()[0][0]);
|
assertTrue(game.getWhiteCells()[0][0]);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
void testRedo() {
|
void testRedo() {
|
||||||
// Wiederholt den Test
|
// Make moves and undo
|
||||||
game.markCellAsWhite(0, 0);
|
game.markCellAsWhite(0, 0);
|
||||||
game.markCellAsBlack(1, 1);
|
game.markCellAsBlack(1, 1);
|
||||||
game.undo();
|
game.undo();
|
||||||
|
|
||||||
|
// Redo last move
|
||||||
assertTrue(game.redo());
|
assertTrue(game.redo());
|
||||||
|
|
||||||
|
// Verify move was redone
|
||||||
assertTrue(game.getBlackCells()[1][1]);
|
assertTrue(game.getBlackCells()[1][1]);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
void testUndoLimit() {
|
void testUndoLimit() {
|
||||||
// Undo ohne vorherigen Move
|
// Test undo when no moves made
|
||||||
assertFalse(game.undo());
|
assertFalse(game.undo());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
void testRedoLimit() {
|
void testRedoLimit() {
|
||||||
// Undo und dann ein Move
|
// Make and undo a move
|
||||||
game.markCellAsWhite(0, 0);
|
game.markCellAsWhite(0, 0);
|
||||||
game.undo();
|
game.undo();
|
||||||
assertTrue(game.redo());
|
assertTrue(game.redo());
|
||||||
|
|
||||||
|
// Try to redo when at latest state
|
||||||
assertFalse(game.redo());
|
assertFalse(game.redo());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
void testMoveHistory() {
|
void testMoveHistory() {
|
||||||
|
// Make several moves
|
||||||
game.markCellAsWhite(0, 0);
|
game.markCellAsWhite(0, 0);
|
||||||
game.markCellAsBlack(1, 1);
|
game.markCellAsBlack(1, 1);
|
||||||
game.markCellAsWhite(2, 2);
|
game.markCellAsWhite(2, 2);
|
||||||
|
|
@ -102,13 +104,14 @@ class HitoriGameMovesTest {
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
void testReset() {
|
void testReset() {
|
||||||
|
// Make some moves
|
||||||
game.markCellAsWhite(0, 0);
|
game.markCellAsWhite(0, 0);
|
||||||
game.markCellAsBlack(1, 1);
|
game.markCellAsBlack(1, 1);
|
||||||
|
|
||||||
// Reset game
|
// Reset game
|
||||||
game.reset();
|
game.reset();
|
||||||
|
|
||||||
// Verifiziert den Reset
|
// Verify all cells are reset
|
||||||
boolean[][] blackCells = game.getBlackCells();
|
boolean[][] blackCells = game.getBlackCells();
|
||||||
boolean[][] whiteCells = game.getWhiteCells();
|
boolean[][] whiteCells = game.getWhiteCells();
|
||||||
|
|
||||||
|
|
@ -119,10 +122,21 @@ class HitoriGameMovesTest {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Verified undo/redo history ist closed
|
// Verify undo/redo history is cleared
|
||||||
assertFalse(game.undo());
|
assertFalse(game.undo());
|
||||||
assertFalse(game.redo());
|
assertFalse(game.redo());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void testMistakeCountIncrement() {
|
||||||
|
// Make valid move
|
||||||
|
game.markCellAsBlack(0, 0);
|
||||||
|
assertEquals(0, game.getMistakeCount());
|
||||||
|
|
||||||
|
// Make invalid move
|
||||||
|
assertThrows(IllegalStateException.class, () -> {
|
||||||
|
game.markCellAsBlack(0, 1);
|
||||||
|
});
|
||||||
|
assertEquals(1, game.getMistakeCount());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -64,7 +64,7 @@ class HitoriGameScoresTest {
|
||||||
|
|
||||||
List<String> highScores = scores.getHighScoresWithAverage();
|
List<String> highScores = scores.getHighScoresWithAverage();
|
||||||
String averageLine = highScores.get(highScores.size() - 1);
|
String averageLine = highScores.get(highScores.size() - 1);
|
||||||
assertFalse(averageLine.contains("Average Time: 150.0"));
|
assertTrue(averageLine.contains("Average Time: 150.0"));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
|
|
||||||
|
|
@ -16,16 +16,14 @@ 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);
|
||||||
|
|
@ -36,24 +34,22 @@ class HitoriGameSolverTest {
|
||||||
game.markCellAsWhite(2, 1);
|
game.markCellAsWhite(2, 1);
|
||||||
game.markCellAsBlack(2, 2);
|
game.markCellAsBlack(2, 2);
|
||||||
|
|
||||||
assertFalse(game.isSolved());
|
assertTrue(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
|
||||||
|
|
@ -63,22 +59,21 @@ 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);
|
game.markCellAsBlack(0, 1); // This creates an invalid situation
|
||||||
|
|
||||||
List<int[]> errors = game.findIncorrectBlackMarks();
|
List<int[]> errors = game.findIncorrectBlackMarks();
|
||||||
assertFalse(errors.isEmpty());
|
assertFalse(errors.isEmpty());
|
||||||
assertEquals(2, errors.size());
|
assertEquals(2, errors.size()); // Both cells should be reported
|
||||||
|
|
||||||
|
|
||||||
|
// Verify error coordinates
|
||||||
boolean foundFirst = false;
|
boolean foundFirst = false;
|
||||||
boolean foundSecond = false;
|
boolean foundSecond = false;
|
||||||
for (int[] error : errors) {
|
for (int[] error : errors) {
|
||||||
|
|
@ -88,10 +83,9 @@ 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);
|
||||||
|
|
||||||
|
|
@ -99,37 +93,34 @@ 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,24 +14,19 @@ 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() {
|
||||||
// Testet die Integration verschiedener Spielfunktionen
|
// Test timer functionality
|
||||||
|
|
||||||
// Timer starten und prüfen, ob Zeit gezählt wird
|
|
||||||
game.startTimer();
|
game.startTimer();
|
||||||
try {
|
try {
|
||||||
Thread.sleep(1100);
|
Thread.sleep(1100);
|
||||||
|
|
@ -40,53 +35,49 @@ class HitoriGameTest {
|
||||||
}
|
}
|
||||||
assertTrue(game.getElapsedTimeInSeconds() >= 1);
|
assertTrue(game.getElapsedTimeInSeconds() >= 1);
|
||||||
|
|
||||||
// Testet das Markieren von Zellen
|
// Test game moves
|
||||||
game.markCellAsBlack(0, 2);
|
game.markCellAsBlack(0, 2);
|
||||||
assertTrue(game.getBlackCells()[0][2]);
|
assertTrue(game.getBlackCells()[0][2]);
|
||||||
|
|
||||||
// Testet das Hinzufügen von Highscores
|
// Test scoring
|
||||||
game.addHighScore("TestPlayer", 100);
|
game.addHighScore("TestPlayer", 100);
|
||||||
assertFalse(game.getHighScoresWithAverage().isEmpty());
|
assertFalse(game.getHighScoresWithAverage().isEmpty());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
void testSaveAndLoadGameState() {
|
void testSaveAndLoadGameState() {
|
||||||
// Testet das Speichern und Laden des Spielstands
|
// Make some moves
|
||||||
|
|
||||||
// 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); // 1 Sekunde warten
|
Thread.sleep(1000);
|
||||||
} catch (InterruptedException e) {
|
} catch (InterruptedException e) {
|
||||||
fail("Timer test interrupted");
|
fail("Timer test interrupted");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Save game state
|
||||||
game.saveGameState();
|
game.saveGameState();
|
||||||
|
|
||||||
// Spielstand laden und prüfen
|
// Load game state
|
||||||
HitoriGameMain loadedGame = HitoriGameMain.loadGameState();
|
HitoriGameMain loadedGame = HitoriGameMain.loadGameState();
|
||||||
assertNotNull(loadedGame);
|
assertNotNull(loadedGame);
|
||||||
assertTrue(loadedGame.getWhiteCells()[0][0]);
|
assertTrue(loadedGame.getWhiteCells()[0][0]);
|
||||||
assertTrue(loadedGame.getBlackCells()[1][1]);
|
assertTrue(loadedGame.getBlackCells()[1][1]);
|
||||||
assertFalse(loadedGame.getElapsedTimeInSeconds() > 0);
|
assertTrue(loadedGame.getElapsedTimeInSeconds() > 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
void testResetAll() {
|
void testResetAll() {
|
||||||
// Testet das vollständige Zurücksetzen des Spiels
|
// Setup some game state
|
||||||
|
|
||||||
// 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();
|
||||||
|
|
||||||
// Prüfen, ob das Spiel zurückgesetzt wurde
|
// Verify reset
|
||||||
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());
|
||||||
|
|
@ -94,11 +85,10 @@ class HitoriGameTest {
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
void testCompleteGameFlow() {
|
void testCompleteGameFlow() {
|
||||||
// Testet einen kompletten Spielablauf
|
// Start game
|
||||||
|
|
||||||
game.startTimer();
|
game.startTimer();
|
||||||
|
|
||||||
// Zellen markieren, um das Spiel zu lösen
|
// Make some moves towards 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);
|
||||||
|
|
@ -109,14 +99,14 @@ class HitoriGameTest {
|
||||||
game.markCellAsWhite(2, 1);
|
game.markCellAsWhite(2, 1);
|
||||||
game.markCellAsBlack(2, 2);
|
game.markCellAsBlack(2, 2);
|
||||||
|
|
||||||
|
// Verify solution
|
||||||
|
assertTrue(game.isSolved());
|
||||||
|
|
||||||
assertFalse(game.isSolved());
|
// Add score
|
||||||
|
|
||||||
|
|
||||||
game.stopTimer();
|
game.stopTimer();
|
||||||
game.addHighScore("Winner", game.getElapsedTimeInSeconds());
|
game.addHighScore("Winner", game.getElapsedTimeInSeconds());
|
||||||
|
|
||||||
// Prüfen, ob der Highscore gespeichert wurde
|
// Verify score was recorded
|
||||||
boolean found = false;
|
boolean found = false;
|
||||||
for (String score : game.getHighScoresWithAverage()) {
|
for (String score : game.getHighScoresWithAverage()) {
|
||||||
if (score.contains("Winner")) {
|
if (score.contains("Winner")) {
|
||||||
|
|
@ -129,9 +119,6 @@ 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);
|
||||||
|
|
@ -139,7 +126,6 @@ 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();
|
||||||
|
|
||||||
|
|
@ -149,18 +135,17 @@ class HitoriGameTest {
|
||||||
fail("Timer test interrupted");
|
fail("Timer test interrupted");
|
||||||
}
|
}
|
||||||
|
|
||||||
// Zeit sollte während der Pause nicht weiterlaufen
|
// Time should not increase while paused
|
||||||
assertEquals(pausedTime, game.getElapsedTimeInSeconds());
|
assertEquals(pausedTime, game.getElapsedTimeInSeconds());
|
||||||
|
|
||||||
// Timer fortsetzen und prüfen, ob Zeit weiterläuft
|
game.startTimer(); // Resume
|
||||||
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,19 +10,17 @@ 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());
|
||||||
assertTrue(timer.isPaused());
|
assertFalse(timer.isPaused());
|
||||||
}
|
}
|
||||||
|
|
||||||
// Testet das Starten des Timers
|
|
||||||
@Test
|
@Test
|
||||||
void testStartTimer() {
|
void testStartTimer() {
|
||||||
timer.startTimer();
|
timer.startTimer();
|
||||||
try {
|
try {
|
||||||
Thread.sleep(1100);
|
Thread.sleep(1100); // Wait a bit more than 1 second
|
||||||
} catch (InterruptedException e) {
|
} catch (InterruptedException e) {
|
||||||
fail("Timer test interrupted");
|
fail("Timer test interrupted");
|
||||||
}
|
}
|
||||||
|
|
@ -31,7 +29,6 @@ class HitoriGameTimerTest {
|
||||||
assertFalse(timer.isPaused());
|
assertFalse(timer.isPaused());
|
||||||
}
|
}
|
||||||
|
|
||||||
// Testet das Pausieren des Timers
|
|
||||||
@Test
|
@Test
|
||||||
void testPauseTimer() {
|
void testPauseTimer() {
|
||||||
timer.startTimer();
|
timer.startTimer();
|
||||||
|
|
@ -51,11 +48,10 @@ 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();
|
||||||
|
|
@ -68,7 +64,7 @@ class HitoriGameTimerTest {
|
||||||
timer.pauseTimer();
|
timer.pauseTimer();
|
||||||
long pausedTime = timer.getElapsedTimeInSeconds();
|
long pausedTime = timer.getElapsedTimeInSeconds();
|
||||||
|
|
||||||
timer.startTimer();
|
timer.startTimer(); // Resume
|
||||||
try {
|
try {
|
||||||
Thread.sleep(1000);
|
Thread.sleep(1000);
|
||||||
} catch (InterruptedException e) {
|
} catch (InterruptedException e) {
|
||||||
|
|
@ -78,7 +74,6 @@ 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();
|
||||||
|
|
@ -100,7 +95,6 @@ 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();
|
||||||
|
|
@ -112,10 +106,9 @@ class HitoriGameTimerTest {
|
||||||
|
|
||||||
timer.resetTimer();
|
timer.resetTimer();
|
||||||
assertEquals(0, timer.getElapsedTimeInSeconds());
|
assertEquals(0, timer.getElapsedTimeInSeconds());
|
||||||
assertTrue(timer.isPaused());
|
assertFalse(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