Compare commits

..

No commits in common. "main" and "resourcesfix" have entirely different histories.

22 changed files with 337 additions and 440 deletions

Binary file not shown.

Before

Width:  |  Height:  |  Size: 44 KiB

BIN
gamestate.dat 100644

Binary file not shown.

View File

@ -2,11 +2,9 @@ package GUI;
import domain.*; import domain.*;
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 HitoriGameTimer gameTimer;
@ -18,58 +16,38 @@ public class GameUIController {
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 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.boardPanel = new HitoriBoardPanel(gameMoves, gameSolver, this);
this.controlPanel = new HitoriControlPanel(this); this.controlPanel = new HitoriControlPanel(this);
this.scorePanel = new HitoriScorePanel(this); this.scorePanel = new 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();
} checkWin();
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();
checkWin();
}
private void checkWin() {
if (gameSolver.isSolved()) {
handleWin();
}
} }
public void togglePause() { public void togglePause() {
@ -87,44 +65,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();
// Main application will handle 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 +111,8 @@ public class GameUIController {
} }
public void saveGame() { public void saveGame() {
HitoriGameMain saveState = new HitoriGameMain(gameMoves.getBoard()); HitoriGameMain gameState = new HitoriGameMain(gameMoves.getBoard());
// Copy current state to save gameState.saveGameState();
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 +128,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 +175,7 @@ public class GameUIController {
private void updateUI() { private void updateUI() {
boardPanel.updateBoard(); boardPanel.updateBoard();
updateMistakeLabel(); updateMistakeLabel();
if (gameSolver.isSolved()) { checkWin();
handleWin();
}
} }
private void updateTimerLabel() { private void updateTimerLabel() {
@ -228,7 +183,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 +195,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 +208,8 @@ public class GameUIController {
} }
public void cleanup() { public void cleanup() {
saveGame();
stopTimer(); stopTimer();
saveGame();
} }
public HitoriBoardPanel getBoardPanel() { public HitoriBoardPanel getBoardPanel() {

View File

@ -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()) {

View File

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

View File

@ -3,11 +3,11 @@ package Main;
import GUI.HitoriDialogManager; import GUI.HitoriDialogManager;
import domain.HitoriBoardLoader; import domain.HitoriBoardLoader;
import domain.HitoriGameMain; import domain.HitoriGameMain;
import GUI.GameUIController;
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;
import javafx.stage.Stage; import javafx.stage.Stage;
import GUI.GameUIController;
public class MainMethod extends Application { public class MainMethod extends Application {
private HitoriBoardLoader boardLoader; private HitoriBoardLoader boardLoader;
@ -24,15 +24,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 +46,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);
} }

View File

@ -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() {
@ -43,4 +45,4 @@ public class GameBase implements Serializable {
public int getMistakeCount() { public int getMistakeCount() {
return mistakeCount; return mistakeCount;
} }
} }

View File

@ -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++) {

View File

@ -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,24 +104,21 @@ 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);
} }
} }

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -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);
@ -111,7 +113,6 @@ class GameUIControllerTest {
@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 +129,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);

View File

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

View File

@ -19,22 +19,19 @@ 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(5);
} }
// Testet das Aktualisieren des Fehler-Labels
@Test @Test
void testUpdateMistakeLabel() { void testUpdateMistakeLabel() {
controlPanel.updateMistakeLabel(5); controlPanel.updateMistakeLabel(5);
@ -42,7 +39,6 @@ class HitoriControlPanelTest {
assertNotNull(5); assertNotNull(5);
} }
// Testet das Setzen des Textes für den Pause-Button
@Test @Test
void testSetPauseButtonText() { void testSetPauseButtonText() {
controlPanel.setPauseButtonText("Test"); controlPanel.setPauseButtonText("Test");
@ -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())

View File

@ -0,0 +1,63 @@
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 testConfirmLoadSavedGame() {
// Cannot directly test confirmation dialogs in headless mode
assertDoesNotThrow(() ->
dialogManager.confirmLoadSavedGame()
);
}
}

View File

@ -19,12 +19,12 @@ class HitoriGameMovesTest {
@Test @Test
void testMarkCellAsBlack() { void testMarkCellAsBlack() {
// Testet schwarze Markierung // Test valid black marking
game.markCellAsBlack(0, 1); game.markCellAsBlack(0, 1);
assertFalse(game.getBlackCells()[0][2]); assertFalse(game.getBlackCells()[0][2]);
assertFalse(game.getWhiteCells()[0][2]); assertFalse(game.getWhiteCells()[0][2]);
// Test invalid black marking (adjacent to existing black cell)
} }
@ -42,49 +42,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 +103,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,7 +121,7 @@ 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());
} }

View File

@ -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);
@ -39,21 +37,19 @@ class HitoriGameSolverTest {
assertFalse(game.isSolved()); assertFalse(game.isSolved());
} }
// Testet eine falsche Lösung, bei der alle Zellen weiß markiert sind
@Test @Test
void testIncorrectSolution() { void testIncorrectSolution() {
// Mark all cells white
for (int i = 0; i < TEST_BOARD.length; i++) { for (int i = 0; i < TEST_BOARD.length; i++) {
for (int j = 0; j < TEST_BOARD[0].length; j++) { for (int j = 0; j < TEST_BOARD[0].length; j++) {
game.markCellAsWhite(i, j); game.markCellAsWhite(i, j);
} }
} }
// Should not be solved due to duplicate numbers
assertFalse(game.isSolved()); assertFalse(game.isSolved());
} }
// Testet, ob das Puzzle nicht gelöst ist, wenn weiße Zellen nicht verbunden sind
@Test @Test
void testDisconnectedWhiteCells() { void testDisconnectedWhiteCells() {
// Create a solution with disconnected white cells // Create a solution with disconnected white cells
@ -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());
} }

View File

@ -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,33 +35,31 @@ 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]);
@ -76,17 +69,15 @@ class HitoriGameTest {
@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
assertFalse(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);
} }
} }

View File

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