package GUI; import domain.*; import GUI.HitoriDialogManager; import javafx.application.Platform; import java.util.*; public class GameUIController { private final HitoriGameMoves gameMoves; private final GameSolver gameSolver; private final domain.HitoriGameTimer gameTimer; private final HitoriGameScores gameScores; private final GUI.HitoriDialogManager dialogManager; private final GUI.HitoriBoardPanel boardPanel; private final GUI.HitoriControlPanel controlPanel; private final GUI.HitoriScorePanel scorePanel; private Timer guiTimer; private boolean isPaused; public GameUIController(int[][] initialBoard, HitoriDialogManager dialogManager) { this.gameMoves = new HitoriGameMoves(initialBoard); this.gameSolver = new GameSolver(initialBoard); this.gameTimer = new domain.HitoriGameTimer(); this.gameScores = new HitoriGameScores(); this.dialogManager = dialogManager; this.isPaused = false; this.boardPanel = new GUI.HitoriBoardPanel(gameMoves, gameSolver, this); this.controlPanel = new GUI.HitoriControlPanel(this); this.scorePanel = new GUI.HitoriScorePanel(this); startTimer(); loadHighScores(); } public void handleLeftClick(int row, int col) { gameMoves.markCellAsBlack(row, col); updateUI(); } 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() { gameMoves.reset(); gameTimer.resetTimer(); updateUI(); } public void undo() { if (gameMoves.undo()) { updateUI(); } } public void redo() { if (gameMoves.redo()) { updateUI(); } } public void newGame() { stopTimer(); // Notify main application to show board selection } public void checkSolution() { if (gameSolver.isSolved()) { handleWin(); } else { dialogManager.showAlert("Not Solved", "The current solution is not correct. Keep trying!"); } } public void showErrors() { List 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() { // Implementation for saving game state 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 playerName = dialogManager.askForPlayerName(); if (playerName.isPresent() && !playerName.get().trim().isEmpty()) { gameScores.addHighScore(playerName.get(), gameTimer.getElapsedTimeInSeconds(), gameMoves.getMistakeCount()); updateHighScoreDisplay(); dialogManager.showAlert("Congratulations!", String.format( "You've solved the puzzle!\nTime: %ds\nMistakes: %d", gameTimer.getElapsedTimeInSeconds(), gameMoves.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(); } private void updateTimerLabel() { controlPanel.updateTimerLabel(gameTimer.getElapsedTimeInSeconds()); } private void updateMistakeLabel() { controlPanel.updateMistakeLabel(gameMoves.getMistakeCount()); } private void updateHighScoreDisplay() { scorePanel.updateHighScores(String.join("\n", gameScores.getHighScoresWithAverage())); } private void loadHighScores() { gameScores.loadHighScoresFromFile(); updateHighScoreDisplay(); } public Set convertErrorsToSet(List errors) { Set errorPositions = new HashSet<>(); for (int[] pos : errors) { errorPositions.add(pos[0] + "," + pos[1]); } return errorPositions; } public boolean isPaused() { return isPaused; } public void cleanup() { stopTimer(); saveGame(); } public HitoriBoardPanel getBoardPanel() { return boardPanel; } public HitoriControlPanel getControlPanel() { return controlPanel; } public HitoriScorePanel getScorePanel() { return scorePanel; } }