import javafx.application.Platform; import javafx.scene.control.Alert; import javafx.scene.control.ButtonType; import javafx.scene.control.MenuItem; import javafx.scene.layout.ColumnConstraints; import javafx.scene.layout.GridPane; import javafx.scene.layout.RowConstraints; import javafx.scene.text.Font; import javafx.scene.text.FontWeight; import java.util.ArrayList; import java.util.HashMap; import java.util.Optional; import java.util.Stack; public class GameManager extends GridPane { public ArrayList cages; private KonKon konkon; private Integer n = 0; private HashMap cellMap; private boolean showMistakes = false; private Cell currentlySelected; public Stack history = new Stack<>(), future = new Stack<>(); private Alert alert, unsolve; private ButtonType loadFromFile, loadFromText, generate, tryAgain, closeProgram; MenuItem undo, redo; GameManager(KonKon konkon) { this.konkon = konkon; alert = new Alert(Alert.AlertType.CONFIRMATION, "What do you want to do next?"); alert.setTitle("You did it"); loadFromFile = new ButtonType("Load new from file"); loadFromText = new ButtonType("Load new from text"); generate = new ButtonType("Generate new"); tryAgain = new ButtonType("Try again"); closeProgram = new ButtonType("Quit"); unsolve = new Alert(Alert.AlertType.CONFIRMATION, "Select an option"); unsolve.setTitle("Please try a new puzzle"); unsolve.getButtonTypes().setAll(loadFromFile, loadFromText, generate, closeProgram); alert.getButtonTypes().setAll(loadFromFile, loadFromText, generate, tryAgain, closeProgram); } void makeGameFromConfig(ArrayList cages) { konkon.evenMoreRoot.getChildren().remove(konkon.winAnim); konkon.winSound.stop(); this.getChildren().clear(); this.cages = new ArrayList<>(); for (CageConfig cageConfig : cages) { this.cages.add(new Cage(this, cageConfig)); } putCellsOnBoard(); } public void updateFontSize(int mainSize, int overlaySize) { for(Cell cell : cellMap.values()) { cell.getCurrentValueLabel().setFont(Font.font("Courier New", FontWeight.BOLD, mainSize)); } for(Cage cage : cages) { cage.idOverlay.setFont(Font.font("Courier New", FontWeight.BOLD, overlaySize)); } } public void checkGameWon() { if (checkIfGameOver()) { try { konkon.evenMoreRoot.getChildren().add(konkon.winAnim); } catch(IllegalArgumentException e) { konkon.evenMoreRoot.getChildren().remove(konkon.winAnim); konkon.evenMoreRoot.getChildren().add(konkon.winAnim); } konkon.winSound.play(); Platform.runLater(() -> { alert.setHeaderText("Congratulations, you've solved this " + this.n + "x" + this.n + " KonKon puzzle"); Optional result = alert.showAndWait(); if (result.get() == loadFromFile) { konkon.loadFromFile(); } else if (result.get() == loadFromText) { konkon.loadFromText(); } else if (result.get() == generate){ konkon.generatePuzzlePrompt(); } else if (result.get() == tryAgain) { for (Cell cell : getCellMap().values()) { cell.clearCell(); } } else { Platform.exit(); System.exit(0); } konkon.evenMoreRoot.getChildren().remove(konkon.winAnim); alert.close(); }); } } public boolean checkIfGameOver() { for (Cage cage : cages) { if (!cage.isFilledCorrectly(true)) { return false; } } for (int i = 0; i < this.n; i++) { if (!checkColumnCorrect(i, true) || !checkRowCorrect(i, true)) { return false; } } return true; } void putCellsOnBoard() { cellMap = new HashMap<>(); for (Cage cage : cages) { cellMap.putAll(cage.getCellMap()); } this.n = (int) Math.sqrt(cellMap.size()); for (Cage cage : cages) { cage.setBorders(); for (Cell cell : cage.getCells()) { cell.fillComboBox(); } } getColumnConstraints().clear(); getRowConstraints().clear(); for (int i = 0; i < n; i++) { ColumnConstraints col = new ColumnConstraints(); col.setPercentWidth(100.0 / n); getColumnConstraints().add(col); RowConstraints row = new RowConstraints(); row.setPercentHeight(100.0 / n); getRowConstraints().add(row); } int count = 1; for (int i = 0; i < n; i++) { for (int j = 0; j < n; j++) { Cell cellToAdd = cellMap.get(count); cellToAdd.setXY(j, i); add(cellToAdd, j, i); count++; } } Solver solver = new Solver(this); if(!solver.solve(1)) { Platform.runLater(() -> { unsolve.setHeaderText("Unsolvable Puzzle Warning"); Optional result = unsolve.showAndWait(); if (result.get() == loadFromFile) { konkon.loadFromFile(); } else if (result.get() == loadFromText) { konkon.loadFromText(); } else if (result.get() == generate) { konkon.generatePuzzlePrompt(); } else { Platform.exit(); System.exit(0); } unsolve.close(); }); } } public Boolean checkColumnCorrect(int col, boolean victoryCheck) { ArrayList currentValues = new ArrayList<>(); for (int i = 0; i < this.n; i++) { int value = cellMap.get((col + 1) + i * this.n).getCurrentValue(); if (currentValues.contains(value) || value > this.n) { return false; } else { if (victoryCheck || value != 0) { currentValues.add(value); } } } return true; } public Boolean checkRowCorrect(int row, boolean victoryCheck) { ArrayList currentValues = new ArrayList<>(); for (int i = 0; i < this.n; i++) { int cellID = ((row * this.n) + 1) + i; int value = cellMap.get(cellID).getCurrentValue(); if (currentValues.contains(value) || value > this.n) { return false; } else { if (victoryCheck || value != 0) { currentValues.add(value); } } } return true; } public void checkAllCellsForMistakes() { for (Cell cell : cellMap.values()) { if (!checkRowCorrect(cell.getY(), false) || !checkColumnCorrect(cell.getX(), false) || !cell.cage.isFilledCorrectly(false)) { cell.setBackground(cell.mistakeBG); } else { cell.setBackground(cell.normalBG); } } } public void logHistory(Cell cell) { history.push(new HistoricCell(cell, cell.getCurrentValue())); undo.setDisable(false); future.clear(); } public void undoLastMove() { if (!history.isEmpty()) { redo.setDisable(false); HistoricCell cellToAdd = history.pop(); Cell cellToRemove = this.cellMap.get(cellToAdd.cell.getCellID()); future.push(new HistoricCell(cellToRemove, cellToRemove.getCurrentValue())); cellToRemove.setCurrentValue(cellToAdd.newValue); } } public void redoLastMove() { if (!future.empty()) { HistoricCell cellToAdd = future.pop(); Cell cellToRemove = this.cellMap.get(cellToAdd.cell.getCellID()); history.push(new HistoricCell(cellToRemove, cellToRemove.getCurrentValue())); cellToRemove.setCurrentValue(cellToAdd.newValue); } } public Integer getN() { return n; } public Cell getCurrentlySelected() { return currentlySelected; } public void setCurrentlySelected(Cell cell) { this.currentlySelected = cell; } public boolean isShowMistakes() { return showMistakes; } public void setShowMistakes(boolean mistake) { showMistakes = mistake; } public HashMap getCellMap() { return cellMap; } public void setUndoRedo(MenuItem undo, MenuItem redo) { this.undo = undo; this.redo = redo; } }