283 lines
8.8 KiB
Java
283 lines
8.8 KiB
Java
package GUI;
|
|
|
|
import domain.*;
|
|
import javafx.application.Platform;
|
|
import javafx.stage.Stage;
|
|
import java.util.*;
|
|
|
|
public class GameUIController {
|
|
private final Stage primaryStage; // Added to handle window state
|
|
private final HitoriGameMoves gameMoves;
|
|
private final GameSolver gameSolver;
|
|
private final HitoriGameTimer gameTimer;
|
|
private final HitoriGameScores gameScores;
|
|
private final HitoriDialogManager dialogManager;
|
|
private final HitoriBoardPanel boardPanel;
|
|
private final HitoriControlPanel controlPanel;
|
|
private final HitoriScorePanel scorePanel;
|
|
private Timer guiTimer;
|
|
private boolean isPaused;
|
|
|
|
public GameUIController(int[][] initialBoard, HitoriDialogManager dialogManager, Stage primaryStage, HitoriGameMain existingGame) {
|
|
this.primaryStage = primaryStage;
|
|
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.boardPanel = new HitoriBoardPanel(gameMoves, gameSolver, this);
|
|
this.controlPanel = new HitoriControlPanel(this);
|
|
this.scorePanel = new HitoriScorePanel(this);
|
|
|
|
startTimer();
|
|
loadHighScores();
|
|
updateUI(); // Make sure UI reflects current state
|
|
}
|
|
|
|
public void handleLeftClick(int row, int col) {
|
|
if (!isValidBlackMark(row, col)) {
|
|
gameMoves.mistakeCount++;
|
|
}
|
|
gameMoves.markCellAsBlack(row, col);
|
|
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) {
|
|
gameMoves.markCellAsWhite(row, col);
|
|
updateUI();
|
|
}
|
|
|
|
public void togglePause() {
|
|
isPaused = !isPaused;
|
|
if (isPaused) {
|
|
gameTimer.pauseTimer();
|
|
controlPanel.setPauseButtonText("Resume");
|
|
boardPanel.setDisable(true);
|
|
} else {
|
|
gameTimer.startTimer();
|
|
controlPanel.setPauseButtonText("Pause");
|
|
boardPanel.setDisable(false);
|
|
}
|
|
updateTimerLabel();
|
|
}
|
|
|
|
public void resetGame() {
|
|
gameSolver.reset();
|
|
// Don't reset timer anymore
|
|
updateUI();
|
|
}
|
|
|
|
public void undo() {
|
|
if (gameSolver.undo()) {
|
|
updateUI();
|
|
}
|
|
}
|
|
|
|
public void redo() {
|
|
if (gameSolver.redo()) {
|
|
updateUI();
|
|
}
|
|
}
|
|
|
|
public void newGame() {
|
|
// Save current game state before starting new game
|
|
saveGame();
|
|
|
|
// Stop timer and cleanup current game
|
|
stopTimer();
|
|
|
|
// 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() {
|
|
if (gameSolver.isSolved()) {
|
|
handleWin();
|
|
} else {
|
|
dialogManager.showAlert("Not Solved", "The current solution is not correct. Keep trying!");
|
|
}
|
|
}
|
|
|
|
public void showErrors() {
|
|
List<int[]> errors = gameSolver.findIncorrectBlackMarks();
|
|
if (errors.isEmpty()) {
|
|
dialogManager.showAlert("No Errors", "No rule violations found in current black markings.");
|
|
return;
|
|
}
|
|
|
|
boardPanel.showErrors();
|
|
StringBuilder message = new StringBuilder("Found " + errors.size() + " error(s):\n");
|
|
for (int[] pos : errors) {
|
|
message.append(String.format("Row %d, Column %d\n", pos[0] + 1, pos[1] + 1));
|
|
}
|
|
dialogManager.showAlert("Errors Found", message.toString());
|
|
}
|
|
|
|
public void saveGame() {
|
|
HitoriGameMain saveState = new HitoriGameMain(gameMoves.getBoard());
|
|
// 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.");
|
|
}
|
|
|
|
public void deleteHighScores() {
|
|
if (dialogManager.confirmDeleteHighScores()) {
|
|
gameScores.deleteHighScores();
|
|
updateHighScoreDisplay();
|
|
dialogManager.showAlert("High Scores Deleted", "All high scores have been deleted successfully.");
|
|
}
|
|
}
|
|
|
|
private void handleWin() {
|
|
stopTimer();
|
|
Optional<String> playerName = dialogManager.askForPlayerName();
|
|
if (playerName.isPresent() && !playerName.get().trim().isEmpty()) {
|
|
gameScores.addHighScore(playerName.get(), gameTimer.getElapsedTimeInSeconds(), gameSolver.getMistakeCount());
|
|
updateHighScoreDisplay();
|
|
dialogManager.showAlert("Congratulations!", String.format(
|
|
"You've solved the puzzle!\nTime: %ds\nMistakes: %d",
|
|
gameTimer.getElapsedTimeInSeconds(),
|
|
gameSolver.getMistakeCount()
|
|
));
|
|
|
|
isPaused = false;
|
|
boardPanel.setDisable(false);
|
|
controlPanel.setPauseButtonText("Pause");
|
|
|
|
if (dialogManager.confirmNewGame()) {
|
|
newGame();
|
|
}
|
|
}
|
|
}
|
|
|
|
private void startTimer() {
|
|
if (guiTimer != null) {
|
|
guiTimer.cancel();
|
|
}
|
|
gameTimer.startTimer();
|
|
guiTimer = new Timer(true);
|
|
guiTimer.scheduleAtFixedRate(new TimerTask() {
|
|
@Override
|
|
public void run() {
|
|
Platform.runLater(() -> {
|
|
if (!isPaused) {
|
|
updateTimerLabel();
|
|
}
|
|
});
|
|
}
|
|
}, 0, 1000);
|
|
}
|
|
|
|
private void stopTimer() {
|
|
if (guiTimer != null) {
|
|
guiTimer.cancel();
|
|
guiTimer = null;
|
|
}
|
|
gameTimer.stopTimer();
|
|
}
|
|
|
|
private void updateUI() {
|
|
boardPanel.updateBoard();
|
|
updateMistakeLabel();
|
|
if (gameSolver.isSolved()) {
|
|
handleWin();
|
|
}
|
|
}
|
|
|
|
private void updateTimerLabel() {
|
|
controlPanel.updateTimerLabel(gameTimer.getElapsedTimeInSeconds());
|
|
}
|
|
|
|
private void updateMistakeLabel() {
|
|
controlPanel.updateMistakeLabel(gameSolver.getMistakeCount());
|
|
}
|
|
|
|
private void updateHighScoreDisplay() {
|
|
scorePanel.updateHighScores(String.join("\n", gameScores.getHighScoresWithAverage()));
|
|
}
|
|
|
|
private void loadHighScores() {
|
|
gameScores.loadHighScoresFromFile();
|
|
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) {
|
|
Set<String> errorPositions = new HashSet<>();
|
|
for (int[] pos : errors) {
|
|
errorPositions.add(pos[0] + "," + pos[1]);
|
|
}
|
|
return errorPositions;
|
|
}
|
|
|
|
public boolean isPaused() {
|
|
return isPaused;
|
|
}
|
|
|
|
public void cleanup() {
|
|
saveGame();
|
|
stopTimer();
|
|
}
|
|
|
|
public HitoriBoardPanel getBoardPanel() {
|
|
return boardPanel;
|
|
}
|
|
|
|
public HitoriControlPanel getControlPanel() {
|
|
return controlPanel;
|
|
}
|
|
|
|
public HitoriScorePanel getScorePanel() {
|
|
return scorePanel;
|
|
}
|
|
} |