From 6c2255ea1c006af1a53678ec1a9f0f495ab6c7bc Mon Sep 17 00:00:00 2001 From: SowinskiBraeden Date: Thu, 27 Nov 2025 11:56:48 -0800 Subject: [PATCH] impliment something from each lesson --- scores.txt | 0 .../ca/bcit/comp2522/project/GameBoard.java | 25 + .../project/InvalidMoveException.java | 9 + src/code/ca/bcit/comp2522/project/Mines.java | 745 ++++++++---------- .../ca/bcit/comp2522/project/MinesUI.java | 471 +++++++++++ src/code/ca/bcit/comp2522/project/MyGame.java | 25 + .../ca/bcit/comp2522/project/MinesTest.java | 61 ++ 7 files changed, 903 insertions(+), 433 deletions(-) create mode 100644 scores.txt create mode 100644 src/code/ca/bcit/comp2522/project/GameBoard.java create mode 100644 src/code/ca/bcit/comp2522/project/InvalidMoveException.java create mode 100644 src/code/ca/bcit/comp2522/project/MinesUI.java create mode 100644 src/code/ca/bcit/comp2522/project/MyGame.java create mode 100644 src/tests/ca/bcit/comp2522/project/MinesTest.java diff --git a/scores.txt b/scores.txt new file mode 100644 index 0000000..e69de29 diff --git a/src/code/ca/bcit/comp2522/project/GameBoard.java b/src/code/ca/bcit/comp2522/project/GameBoard.java new file mode 100644 index 0000000..b2c1193 --- /dev/null +++ b/src/code/ca/bcit/comp2522/project/GameBoard.java @@ -0,0 +1,25 @@ +package ca.bcit.comp2522.project; + +public abstract class GameBoard +{ + protected int width; + protected int height; + + protected GameBoard(final int width, final int height) + { + this.width = width; + this.height = height; + } + + public final int getWidth() + { + return this.width; + } + + public final int getHeight() + { + return this.height; + } + + public abstract void reset(); +} diff --git a/src/code/ca/bcit/comp2522/project/InvalidMoveException.java b/src/code/ca/bcit/comp2522/project/InvalidMoveException.java new file mode 100644 index 0000000..93f64a2 --- /dev/null +++ b/src/code/ca/bcit/comp2522/project/InvalidMoveException.java @@ -0,0 +1,9 @@ +package ca.bcit.comp2522.project; + +public class InvalidMoveException extends Exception +{ + public InvalidMoveException(final String message) + { + super(message); + } +} diff --git a/src/code/ca/bcit/comp2522/project/Mines.java b/src/code/ca/bcit/comp2522/project/Mines.java index bd4739b..0df0fb2 100644 --- a/src/code/ca/bcit/comp2522/project/Mines.java +++ b/src/code/ca/bcit/comp2522/project/Mines.java @@ -1,45 +1,17 @@ package ca.bcit.comp2522.project; -import javafx.animation.Timeline; -import javafx.application.Application; -import javafx.geometry.Insets; -import javafx.geometry.Pos; -import javafx.scene.Scene; -import javafx.scene.control.Alert; -import javafx.scene.control.Button; -import javafx.scene.control.Label; -import javafx.scene.input.MouseButton; -import javafx.scene.layout.GridPane; -import javafx.scene.layout.VBox; -import javafx.scene.text.Font; -import javafx.scene.text.FontWeight; -import javafx.stage.Stage; - -import java.util.HashMap; -import java.util.Map; +import java.io.BufferedReader; +import java.io.BufferedWriter; +import java.io.File; +import java.io.FileReader; +import java.io.FileWriter; +import java.io.IOException; import java.util.Random; +import java.util.Scanner; import java.util.function.Consumer; -public class Mines extends Application +public class Mines extends GameBoard { - private static final int FONT_SIZE = 18; - private static final Font FONT = Font.font("Arial", FontWeight.BOLD, FONT_SIZE); - - private static final int WINDOW_WIDTH = 1920; - private static final int WINDOW_HEIGHT = 1080; - private static final int BUTTON_WIDTH = 60; - private static final int BUTTON_HEIGHT = 60; - private static final int MENU_BUTTON_WIDTH = 180; - private static final int EASY_WIDTH = 8; - private static final int EASY_HEIGHT = 8; - private static final int HARD_WIDTH = 36; - private static final int HARD_HEIGHT = 16; - private static final int PADDING = 20; - private static final int GAME_PADDING = 5; - private static final int VERTICAL_MARGIN = 15; - - private static final int EASY_MINES = 10; - private static final int HARD_MINES = 99; private static final int MINE = -1; private static final int NO_MINE = 0; @@ -49,109 +21,131 @@ public class Mines extends Application private static final int FIRST_ROW = 0; private static final int FIRST_COL = 0; - private static final int NO_FLAG = 0; - private static final int FLAG = 1; - private static final int FLAG_QUESTION = 2; + public static final int NO_FLAG = 0; + public static final int FLAG = 1; + public static final int FLAG_QUESTION = 2; - private static final int DEFAULT_BUTTON = -2; - private static final Map BUTTON_THEMES = new HashMap<>(); + private static final int INITIAL_BEST_SCORE = Integer.MAX_VALUE; - static { - BUTTON_THEMES.put(-2, "-fx-background-color: #b3b3b3; -fx-text-fill: black;"); - BUTTON_THEMES.put(-1, "-fx-background-color: #d9d9d9; -fx-text-fill: black;"); - BUTTON_THEMES.put(0, "-fx-background-color: #d9d9d9; -fx-text-fill: black;"); - BUTTON_THEMES.put(1, "-fx-background-color: #c8ffbf; -fx-text-fill: black;"); - BUTTON_THEMES.put(2, "-fx-background-color: #edfc9f; -fx-text-fill: black;"); - BUTTON_THEMES.put(3, "-fx-background-color: #fad08c; -fx-text-fill: black;"); - BUTTON_THEMES.put(4, "-fx-background-color: #f59338; -fx-text-fill: black;"); - BUTTON_THEMES.put(5, "-fx-background-color: #ff644d; -fx-text-fill: black;"); - BUTTON_THEMES.put(6, "-fx-background-color: #ff644d; -fx-text-fill: black;"); - BUTTON_THEMES.put(7, "-fx-background-color: #ff644d; -fx-text-fill: black;"); - BUTTON_THEMES.put(8, "-fx-background-color: #ff644d; -fx-text-fill: black;"); + private static final String SCORE_FILE_NAME = "scores.txt"; + + private static final Random RANDOM_GENERATOR; + + static + { + RANDOM_GENERATOR = new Random(); } + private final int totalMines; + private boolean randomMode; + private int[] field; private boolean[] revealed; private int[] flagged; - private Button[] buttons; - private int width; - private int height; - private int flags; - private Label flagLabel; - private Label timerLabel; - private int totalMines; + private int bestScoreSeconds; - private int seconds; - private Timeline timer; - private boolean timerRunning = false; - private boolean randomMode = false; - - private void startTimer() { - seconds = 0; - timerLabel.setText("Time: 0"); - - timer = new javafx.animation.Timeline( - new javafx.animation.KeyFrame(javafx.util.Duration.seconds(1), e -> { - seconds++; - timerLabel.setText("Time: " + seconds); - }) - ); - timer.setCycleCount(javafx.animation.Animation.INDEFINITE); - timer.play(); - timerRunning = true; + public Mines( + final int width, + final int height, + final int mines, + final boolean randomMode + ) { + super(width, height); + this.totalMines = mines; + this.randomMode = randomMode; + this.bestScoreSeconds = INITIAL_BEST_SCORE; + reset(); + loadBestScore(); } - private void stopTimer() { - if (timer != null) { - timer.stop(); - } - timerRunning = false; + public void startNewGame() + { + reset(); + } + + public void startNewGame(final boolean randomMode) + { + this.randomMode = randomMode; + reset(); + } + + public void setRandomMode(final boolean randomMode) + { + this.randomMode = randomMode; + } + + public boolean isRandomMode() + { + return this.randomMode; } @Override - public void start(final Stage stage) + public void reset() { - final Label title; - final Button smallBtn; - final Button largeBtn; + final int totalCells; - title = new Label("Select Game Size"); - title.setStyle("-fx-font-size: 20px; -fx-font-weight: bold;"); + totalCells = this.width * this.height; - smallBtn = new Button("8 × 8 (Beginner)"); - largeBtn = new Button("36 × 16 (Expert)"); + this.field = new int[totalCells]; + this.revealed = new boolean[totalCells]; + this.flagged = new int[totalCells]; - smallBtn.setPrefWidth(MENU_BUTTON_WIDTH); - largeBtn.setPrefWidth(MENU_BUTTON_WIDTH); - smallBtn.setOnAction(e -> startGame(EASY_WIDTH, EASY_HEIGHT, EASY_MINES)); - largeBtn.setOnAction(e -> startGame(HARD_WIDTH, HARD_HEIGHT, HARD_MINES)); + generateField(); + } - final VBox root; - final Scene scene; + private void generateField() + { + int placedMines; + final int totalCells; - root = new VBox(VERTICAL_MARGIN); - scene = new Scene(root, WINDOW_WIDTH, WINDOW_HEIGHT); + placedMines = NO_MINE; + totalCells = this.width * this.height; - root.setPadding(new Insets(PADDING)); - root.setAlignment(Pos.CENTER); - root.getChildren().addAll(title, smallBtn, largeBtn); + while (placedMines < totalMines) + { + final int index; - stage.setTitle("Random Mines - A Minesweeper Game"); - stage.setResizable(false); - stage.setScene(scene); - stage.show(); + index = RANDOM_GENERATOR.nextInt(totalCells); + + if (this.field[index] != MINE) + { + this.field[index] = MINE; + placedMines++; + } + } + + for (int i = 0; i < this.field.length; i++) + { + if (this.field[i] == MINE) + { + continue; + } + + final int[] count; + + count = new int[] { NO_MINE }; + + forEachNeighbor(i, neighborIndex -> { + if (this.field[neighborIndex] == MINE) + { + count[SELF_OFFSET]++; + } + }); + + this.field[i] = count[SELF_OFFSET]; + } } private void forEachNeighbor( - final int index, + final int index, final Consumer action ) { final int row; final int col; - row = index / width; - col = index % width; + row = index / this.width; + col = index % this.width; for (int dr = MIN_OFFSET; dr <= MAX_OFFSET; dr++) { @@ -168,70 +162,34 @@ public class Mines extends Application nr = row + dr; nc = col + dc; - if (nr < FIRST_ROW || nr >= height || - nc < FIRST_COL || nc >= width) + if (nr < FIRST_ROW || nr >= this.height || + nc < FIRST_COL || nc >= this.width) { continue; } final int neighborIndex; - neighborIndex = nr * width + nc; + + neighborIndex = nr * this.width + nc; action.accept(neighborIndex); } } } - private void generateField(final int mines) - { - this.revealed = new boolean[width * height]; - this.field = new int[width * height]; - this.flagged = new int[width * height]; - - final Random rand; - int placed; - - rand = new Random(); - placed = NO_MINE; - - while (placed < mines) - { - final int index; - index = rand.nextInt(width * height); - - if (this.field[index] != MINE) - { - this.field[index] = MINE; - placed++; - } - } - - for (int i = 0; i < this.field.length; i++) - { - if (this.field[i] == MINE) - { - continue; - } - - final int[] count = { NO_MINE }; - - forEachNeighbor(i, neighborIndex -> { - if (this.field[neighborIndex] == MINE) - { - count[SELF_OFFSET]++; - } - }); - - this.field[i] = count[SELF_OFFSET]; - } - } - private void popFieldVoid(final int index) { forEachNeighbor(index, neighborIndex -> { if (!this.revealed[neighborIndex]) { - reveal(neighborIndex); + try + { + reveal(neighborIndex); + } + catch (final InvalidMoveException e) + { + // revealing neighbors should never be invalid + } if (this.field[neighborIndex] == NO_MINE) { @@ -241,284 +199,14 @@ public class Mines extends Application }); } - private void startGame( - final int width, - final int height, - final int mines - ) { - this.flags = NO_FLAG; - this.buttons = new Button[width * height]; - this.width = width; - this.height = height; - this.totalMines = mines; - - generateField(mines); - - final Stage gameStage; - final VBox box; - final VBox topBar; - final GridPane grid; - final Label modeLabel; - final Button toggleModeBtn; - - gameStage = new Stage(); - box = new VBox(); - grid = createGrid(width, height); - modeLabel = new Label("Random Mode: OFF"); - toggleModeBtn = new Button("Toggle Random Mode"); - - this.flagLabel = new Label("Flags: 0 / " + totalMines); - this.timerLabel = new Label("Time: 0"); - this.flagLabel.setFont(FONT); - this.timerLabel.setFont(FONT); - - toggleModeBtn.setOnAction(e -> { - randomMode = !randomMode; - modeLabel.setText("Random Mode: " + (randomMode ? "ON" : "OFF")); - }); - - - topBar = new VBox(5, flagLabel, timerLabel); - - topBar.setAlignment(Pos.CENTER); - box.getChildren().add(0, topBar); - - box.getChildren().add(grid); - box.setAlignment(Pos.CENTER); - grid.setAlignment(Pos.CENTER); - - final Scene scene; - scene = new Scene(box, WINDOW_WIDTH, WINDOW_HEIGHT); - root.getChildren().addAll(title, smallBtn, largeBtn, modeLabel, toggleModeBtn); - - gameStage.setScene(scene); - gameStage.setTitle("Random Mines " + width + "x" + height); - gameStage.show(); - startTimer(); - } - - private void flag(final int index) + public boolean reveal(final int index) + throws InvalidMoveException { - this.flagged[index] = (this.flagged[index] + FLAG) % (FLAG_QUESTION + FLAG); - - final String buttonText; - - buttonText = this.flagged[index] == FLAG ? "F" : - this.flagged[index] == FLAG_QUESTION ? "?" : ""; - - this.buttons[index].setText(buttonText); - - this.flags = this.flagged[index] == FLAG ? - this.flags + FLAG : - this.flagged[index] == FLAG_QUESTION ? - this.flags - FLAG : - this.flags; - - this.flagLabel.setText("Flags: " + flags + " / " + totalMines); - } - - private void checkWin() - { - int numRevealed; - numRevealed = NO_MINE; - - for (int i = 0; i < this.field.length; i++) + if (this.flagged[index] == FLAG) { - if (this.revealed[i]) - { - numRevealed++; - } - else if (this.field[i] != MINE) - { - // if a non revealed cell is not a mine, we know its not a win - return; - } - else - { - // do nothing - continue; - } + throw new InvalidMoveException("Cannot reveal a flagged cell."); } - if (numRevealed == (this.field.length - totalMines)) - { - // WIN CONDITION - stopTimer(); - - final Alert win; - win = new Alert(Alert.AlertType.INFORMATION); - win.setHeaderText("You Win!"); - win.setContentText("You successfully cleared all safe squares!"); - win.showAndWait(); - - ((Stage) buttons[0].getScene().getWindow()).close(); - } - } - - private GridPane createGrid( - final int width, - final int height - ) { - final GridPane grid; - grid = new GridPane(); - - grid.setPadding(new Insets(GAME_PADDING)); - grid.setHgap(GAME_PADDING); - grid.setVgap(GAME_PADDING); - - for (int i = 0; i < width; i++) - { - for (int j = 0; j < height; j++) - { - final Button button; - final int index; - - index = (j * width) + i; - button = new Button(); - - button.setFont(FONT); - button.setPrefSize(BUTTON_WIDTH, BUTTON_HEIGHT); - button.setStyle(BUTTON_THEMES.get(DEFAULT_BUTTON)); - button.setOnMouseEntered(e -> button.setCursor(javafx.scene.Cursor.HAND)); - button.setOnMouseExited(e -> button.setCursor(javafx.scene.Cursor.DEFAULT)); - button.setOnMouseClicked(e -> { - if (e.getButton() == MouseButton.PRIMARY) - { - final boolean lossed; - lossed = reveal(index); - - if (lossed) - { - final Alert loss; - loss = new Alert(Alert.AlertType.ERROR); - loss.setHeaderText("You lost..."); - loss.setContentText("Unfortunately, you dug up a mine and lost your legs. I hear there is a deal on wheelchairs though."); - loss.showAndWait(); - - final Stage gameStage; - gameStage = (Stage) buttons[index].getScene().getWindow(); - gameStage.close(); - return; - } - - checkWin(); - - randomizeRemaining(); - } - else if (e.getButton() == MouseButton.SECONDARY) - { - flag(index); - } - else - { - // do nothing - return; - } - }); - - grid.add(button, i, j); - this.buttons[index] = button; - } - } - - return grid; - } - - private void randomizeRemaining() - { - int regenMine; - - regenMine = NO_MINE; - - for (int i = 0; i < this.field.length; i++) - { - // Ignore correctly flagged mines - if (this.field[i] == MINE && this.flagged[i] == FLAG) - { - continue; - } - - if (this.field[i] == MINE) - { - regenMine++; - } - - this.field[i] = NO_MINE; - } - - final Random rand; - int placed; - - rand = new Random(); - placed = NO_MINE; - - while (placed < regenMine) - { - final int index; - index = rand.nextInt(width * height); - - if (this.field[index] == NO_MINE && !this.revealed[index]) - { - this.field[index] = MINE; - placed++; - } - } - - for (int i = 0; i < this.field.length; i++) - { - if (this.field[i] == MINE) - { - continue; - } - - final int[] count = { NO_MINE }; - - forEachNeighbor(i, neighborIndex -> { - if (this.field[neighborIndex] == MINE) - { - count[SELF_OFFSET]++; - } - }); - - this.field[i] = count[SELF_OFFSET]; - } - - for (int i = 0; i < this.field.length; i++) - { - if (this.revealed[i]) - { - this.buttons[i].setText(this.field[i] == NO_MINE ? "" : "" + this.field[i]); - this.buttons[i].setStyle(BUTTON_THEMES.get(this.field[i])); - } - - if (this.revealed[i] && this.field[i] == NO_MINE) - { - popFieldVoid(i); - } - } - } - - private boolean reveal(final int index) - { - if (this.revealed[index]) - { - return false; - } - - final String buttonText; - final Button button; - - button = this.buttons[index]; - - buttonText = "" + (this.field[index] == MINE ? "*" : - this.field[index] == NO_MINE ? " " : - this.field[index]); - - button.setText(buttonText); - button.setStyle(BUTTON_THEMES.get(this.field[index])); - button.setMouseTransparent(true); - button.setFocusTraversable(false); - this.revealed[index] = true; if (this.field[index] == NO_MINE) @@ -529,8 +217,199 @@ public class Mines extends Application return this.field[index] == MINE; } - public static void main(final String[] args) + public int toggleFlag(final int index) { - launch(args); + final int nextState; + + nextState = (this.flagged[index] + FLAG) % (FLAG_QUESTION + FLAG); + this.flagged[index] = nextState; + return nextState; + } + + public int getFieldValue(final int index) + { + return this.field[index]; + } + + public boolean isRevealed(final int index) + { + return this.revealed[index]; + } + + public boolean isMine(final int index) + { + return this.field[index] == MINE; + } + + public boolean isFlagged(final int index) + { + return this.flagged[index] == FLAG; + } + + public boolean isQuestionMarked(final int index) + { + return this.flagged[index] == FLAG_QUESTION; + } + + public int getTotalMines() + { + return this.totalMines; + } + + public boolean hasWon() + { + int revealedCount; + + revealedCount = NO_MINE; + + for (int i = 0; i < this.field.length; i++) + { + if (this.revealed[i]) + { + revealedCount++; + } + else if (this.field[i] != MINE) + { + return false; + } + } + + return revealedCount == (this.field.length - this.totalMines); + } + + public void randomizeRemaining() + { + if (!this.randomMode) + { + return; + } + + int minesToReplant; + + minesToReplant = NO_MINE; + + for (int i = 0; i < this.field.length; i++) + { + if (this.field[i] == MINE && this.flagged[i] == FLAG) + { + continue; + } + + if (this.field[i] == MINE) + { + minesToReplant++; + } + + this.field[i] = NO_MINE; + } + + while (minesToReplant > NO_MINE) + { + final int index; + + index = RANDOM_GENERATOR.nextInt(this.width * this.height); + + if (this.field[index] == NO_MINE && !this.revealed[index]) + { + this.field[index] = MINE; + minesToReplant--; + } + } + + for (int i = 0; i < this.field.length; i++) + { + if (this.field[i] == MINE) + { + continue; + } + + final int[] count; + + count = new int[] { NO_MINE }; + + forEachNeighbor(i, neighborIndex -> { + if (this.field[neighborIndex] == MINE) + { + count[SELF_OFFSET]++; + } + }); + + this.field[i] = count[SELF_OFFSET]; + } + + for (int i = 0; i < this.field.length; i++) + { + if (this.revealed[i] && this.field[i] == NO_MINE) + { + popFieldVoid(i); + } + } + + } + + public void saveScore(final int seconds) + { + try + { + final BufferedWriter writer; + + writer = new BufferedWriter(new FileWriter(SCORE_FILE_NAME)); + + writer.write(Integer.toString(seconds)); + writer.newLine(); + } + catch (final IOException e) + { + // ignore failure + } + + if (seconds < this.bestScoreSeconds) + { + this.bestScoreSeconds = seconds; + } + } + + private void loadBestScore() + { + final File scoreFile; + + scoreFile = new File(SCORE_FILE_NAME); + + if (!scoreFile.exists()) + { + return; + } + + int best; + best = INITIAL_BEST_SCORE; + + try + { + final Scanner scanner; + scanner = new Scanner(new BufferedReader(new FileReader(scoreFile))); + + while (scanner.hasNextInt()) + { + final int candidate; + + candidate = scanner.nextInt(); + + if (candidate < best) + { + best = candidate; + } + } + } + catch (final IOException e) + { + // ignore failure + } + + this.bestScoreSeconds = best; + } + + public int getBestScoreSeconds() + { + return this.bestScoreSeconds; } } diff --git a/src/code/ca/bcit/comp2522/project/MinesUI.java b/src/code/ca/bcit/comp2522/project/MinesUI.java new file mode 100644 index 0000000..43b506f --- /dev/null +++ b/src/code/ca/bcit/comp2522/project/MinesUI.java @@ -0,0 +1,471 @@ +package ca.bcit.comp2522.project; + +import javafx.animation.Animation; +import javafx.animation.KeyFrame; +import javafx.animation.Timeline; +import javafx.geometry.Insets; +import javafx.geometry.Pos; +import javafx.scene.Scene; +import javafx.scene.control.Alert; +import javafx.scene.control.Button; +import javafx.scene.control.Label; +import javafx.scene.input.MouseButton; +import javafx.scene.layout.GridPane; +import javafx.scene.layout.VBox; +import javafx.scene.text.Font; +import javafx.scene.text.FontWeight; +import javafx.stage.Stage; +import javafx.util.Duration; + +import java.util.ArrayList; +import java.util.Iterator; +import java.util.List; +import java.util.Map; + +public class MinesUI +{ + private static final int FONT_SIZE = 18; + private static final Font FONT = Font.font("Arial", FontWeight.BOLD, FONT_SIZE); + + private static final int WINDOW_WIDTH = 900; + private static final int WINDOW_HEIGHT = 700; + private static final int BUTTON_WIDTH = 40; + private static final int BUTTON_HEIGHT = 40; + private static final int MENU_BUTTON_WIDTH = 200; + private static final int MENU_BUTTON_HEIGHT = 60; + + private static final int PADDING = 20; + private static final int GAME_PADDING = 5; + private static final int VERTICAL_MARGIN = 15; + private static final int TOPBAR_SPACING = 5; + + private static final int EASY_WIDTH = 8; + private static final int EASY_HEIGHT = 8; + private static final int EASY_MINES = 10; + private static final int HARD_WIDTH = 36; + private static final int HARD_HEIGHT = 16; + private static final int HARD_MINES = 99; + + private static final int STARTING_FLAGS = 0; + private static final int STARTING_SECONDS = 0; + private static final int TIMER_TICK_SECONDS = 1; + + private static final int DEFAULT_BUTTON_KEY = -2; + private static final int MINE_KEY = -1; + private static final int ZERO_KEY = 0; + + private static final String TITLE_TEXT = "Random Mines - A Minesweeper Game"; + + private static final Map BUTTON_THEMES; + + static + { + BUTTON_THEMES = new java.util.HashMap<>(); + BUTTON_THEMES.put(-2, "-fx-background-color: #b3b3b3; -fx-text-fill: black;"); + BUTTON_THEMES.put(-1, "-fx-background-color: #d9d9d9; -fx-text-fill: black;"); + BUTTON_THEMES.put(0, "-fx-background-color: #d9d9d9; -fx-text-fill: black;"); + BUTTON_THEMES.put(1, "-fx-background-color: #c8ffbf; -fx-text-fill: black;"); + BUTTON_THEMES.put(2, "-fx-background-color: #edfc9f; -fx-text-fill: black;"); + BUTTON_THEMES.put(3, "-fx-background-color: #fad08c; -fx-text-fill: black;"); + BUTTON_THEMES.put(4, "-fx-background-color: #f59338; -fx-text-fill: black;"); + BUTTON_THEMES.put(5, "-fx-background-color: #ff644d; -fx-text-fill: black;"); + BUTTON_THEMES.put(6, "-fx-background-color: #ff644d; -fx-text-fill: black;"); + BUTTON_THEMES.put(7, "-fx-background-color: #ff644d; -fx-text-fill: black;"); + BUTTON_THEMES.put(8, "-fx-background-color: #ff644d; -fx-text-fill: black;"); + } + + private final List