diff --git a/bin/coursework/Animation.class b/bin/coursework/Animation.class new file mode 100644 index 0000000000000000000000000000000000000000..ea9fd11221e9b362801b9cf1f759bb0931b3b95c Binary files /dev/null and b/bin/coursework/Animation.class differ diff --git a/bin/coursework/Cage.class b/bin/coursework/Cage.class index 70a114efa9b35343e040b2214c124d1c0de03eb7..f93cf6cd92afb4721aa5581143ec6bcac4afbf0f 100644 Binary files a/bin/coursework/Cage.class and b/bin/coursework/Cage.class differ diff --git a/bin/coursework/ConstraintsHandler.class b/bin/coursework/ConstraintsHandler.class index d80f886ace8cb45794c9249a022cb37de2a66d45..0a68b66c3ee4a187021e0e0b1082d8babf7d6818 100644 Binary files a/bin/coursework/ConstraintsHandler.class and b/bin/coursework/ConstraintsHandler.class differ diff --git a/bin/coursework/GameState.class b/bin/coursework/GameState.class index 7da95ce3340cd26d28aaa90c45379d71f8c06b7d..05a8e904dce51e954e51bf717fb058b235294275 100644 Binary files a/bin/coursework/GameState.class and b/bin/coursework/GameState.class differ diff --git a/bin/coursework/Main.class b/bin/coursework/Main.class index eebd54f556d3480d151a72b3fd5448dad7431061..0bac322ce29c478d59d85bef452194620b73f727 100644 Binary files a/bin/coursework/Main.class and b/bin/coursework/Main.class differ diff --git a/src/coursework/Animation.java b/src/coursework/Animation.java new file mode 100644 index 0000000000000000000000000000000000000000..cdf17e1f032b4ae690e853df85ef2799cb7b7ff2 --- /dev/null +++ b/src/coursework/Animation.java @@ -0,0 +1,184 @@ +package coursework; + +import javafx.animation.Timeline; +import java.util.ArrayList; +import java.util.List; +import javafx.animation.KeyFrame; +import javafx.scene.layout.VBox; +import javafx.util.Duration; + +public class Animation { + + private VBox[] gridBoxes; + private String[] colors = {"#FF0000", "#FF7F00", "#FFFF00", "#00FF00", "#00FFFF", "#0000FF", "#3F00FF", "#7F00FF", "rgba(255,0,0,0)"}; + private Integer[] indexArray; + private List<Integer> indexList = new ArrayList<Integer>(); + private int index = 0; + private int count = 1; + private int colorIndex = 0; + + public Animation() { + gridBoxes = Main.getGridBoxes(); + } + + public void go() { + initialiseIndex(); + Timeline timeline = new Timeline(); + KeyFrame keyframe = new KeyFrame(Duration.seconds(0.1), e -> { + if (index != indexArray.length) { + for (int j = 0; j < colors.length; j++) { + if (index - j >= 0) { + if (indexArray[index - j] >= 0 && indexArray[index] - j <= Main.N*Main.N) { + gridBoxes[indexArray[index - j]].setStyle("-fx-background-color:"+colors[j]+";"); + } + } + } + index++; + } + if (index == indexArray.length && count < 9) { + for (int i = 0; i < colors.length - count; i++) { + gridBoxes[indexArray[indexArray.length - i - 1]].setStyle("-fx-background-color:"+colors[i+count]+";"); + } + count++; + } + if (count == 9) { + if (Main.N % 2 == 0) { + //even + int maxCentre = Main.N / 2; + int minCentre = maxCentre - 1; + + int topLeft = (minCentre * Main.N) + minCentre; + int topRight = (minCentre * Main.N) + maxCentre; + int botLeft = (maxCentre * Main.N) + minCentre; + int botRight = (maxCentre * Main.N + maxCentre); + int[] gridIndicies = { topLeft, topRight, botLeft, botRight }; + + if (colorIndex < colors.length) { + for (int gridIndex : gridIndicies) { + gridBoxes[gridIndex].setStyle("-fx-background-color:"+colors[colorIndex]+";"); + } + } + if (colorIndex - 1 > 0 && colorIndex < colors.length + 1) { + gridBoxes[topLeft - 1].setStyle("-fx-background-color:"+colors[colorIndex - 1]+";"); + gridBoxes[topLeft - Main.N].setStyle("-fx-background-color:"+colors[colorIndex - 1]+";"); + gridBoxes[topLeft - Main.N - 1].setStyle("-fx-background-color:"+colors[colorIndex - 1]+";"); + + gridBoxes[topRight + 1].setStyle("-fx-background-color:"+colors[colorIndex - 1]+";"); + gridBoxes[topRight - Main.N].setStyle("-fx-background-color:"+colors[colorIndex - 1]+";"); + gridBoxes[topRight - Main.N + 1].setStyle("-fx-background-color:"+colors[colorIndex - 1]+";"); + + gridBoxes[botLeft - 1].setStyle("-fx-background-color:"+colors[colorIndex - 1]+";"); + gridBoxes[botLeft + Main.N].setStyle("-fx-background-color:"+colors[colorIndex - 1]+";"); + gridBoxes[botLeft + Main.N - 1].setStyle("-fx-background-color:"+colors[colorIndex - 1]+";"); + + gridBoxes[botRight + 1].setStyle("-fx-background-color:"+colors[colorIndex - 1]+";"); + gridBoxes[botRight + Main.N].setStyle("-fx-background-color:"+colors[colorIndex - 1]+";"); + gridBoxes[botRight + Main.N + 1].setStyle("-fx-background-color:"+colors[colorIndex - 1]+";"); + } + + + + } + else { + //odd + int centre = Main.N - 1 / 2; + + gridBoxes[centre * Main.N + centre].setStyle("-fx-background-color:"+colors[colorIndex]+";"); + } + colorIndex++; + } + + }); + timeline.getKeyFrames().add(keyframe); + timeline.setCycleCount(indexArray.length + 20); + timeline.play(); + + } + + private void initialiseIndex() { + for (int i = 0; i < Main.N; i++) { + for (int j = 0; j < Main.N; j++) { + if (i % 2 == 0) { + indexList.add(i*Main.N + j); + } + else { + indexList.add((i+1) * Main.N - 1 - j); + } + } + } + + if (getPrevious(indexList) % Main.N == 0) { + // even n + for (int j = 0; j < Main.N / 2; j++) { + moveUpDown(1, Main.N - 1); + moveLeftRight(1, 1); + moveUpDown(-1, Main.N - 1); + if (j != Main.N/2 - 1) { + moveLeftRight(1, 1); + } + } + + int count = Main.N - 1; + moveLeftRight(-1, count); + moveUpDown(1, count); + moveLeftRight(1, count); + count--; + + while (count > 0) { + moveUpDown(-1, count); + moveLeftRight(-1, count); + count--; + moveUpDown(1, count ); + moveLeftRight(1, count); + count--; + } + } + else { + // odd n + for (int j = 0; j < Main.N / 2; j++) { + moveUpDown(1, Main.N - 1); + moveLeftRight(-1, 1); + moveUpDown(-1, Main.N - 1); + moveLeftRight(-1, 1); + } + moveUpDown(1, Main.N - 1); + + int count = Main.N - 1; + moveLeftRight(1, count); + moveUpDown(-1, count); + moveLeftRight(-1, count); + + while (count > 3) { + count--; + moveUpDown(1, count); + moveLeftRight(1, count); + count--; + moveUpDown(-1, count); + moveLeftRight(-1, count); + } + count--; + moveUpDown(1, count); + moveLeftRight(1, count); + } + + indexArray = indexList.toArray(new Integer[indexList.size()]); + } + + private Integer getPrevious(List<Integer> indexList) { + return indexList.get(indexList.size() - 1); + } + + private void moveUpDown(int value, int n) { + // value == 1 to move up, value == -1 to move down + for (int i = 0; i < n; i++) { + indexList.add(getPrevious(indexList) - Main.N*value); + } + } + + private void moveLeftRight(int value, int n) { + // value == 1, move right, value == -1 move left + for (int i = 0; i < n; i++) { + indexList.add(getPrevious(indexList) + value); + } + } +} diff --git a/src/coursework/ConstraintsHandler.java b/src/coursework/ConstraintsHandler.java index be5667258d9cecb55d0ab14649c137a4f7ca9725..989872b304379d9738fa2627dfe301081df63355 100644 --- a/src/coursework/ConstraintsHandler.java +++ b/src/coursework/ConstraintsHandler.java @@ -12,7 +12,7 @@ public class ConstraintsHandler { private VBox[] gridBoxes = new VBox[Main.N*Main.N]; private List<Cage> gridCages = new ArrayList<Cage>(); private boolean[][] gridErrors = new boolean[Main.N*Main.N][3]; - + private boolean constraintChecked = false; public ConstraintsHandler() {} @@ -23,7 +23,12 @@ public class ConstraintsHandler { gridErrors = Main.getGridErrors(); } + public boolean checked() { + return constraintChecked; + } + public void checkConstraints(int col, int row, boolean showMistakes) { + constraintChecked = true; updateData(); columnConstraint(row, col); rowConstraint(row, col); @@ -136,16 +141,17 @@ public class ConstraintsHandler { } public void checkWinCondition() { + updateData(); if (checkCellsFull() && checkConstraintErrors()) { - // win condition fulfilled - // animation and pop up - System.out.println("You won"); + Animation animation = new Animation(); + animation.go(); } } private boolean checkCellsFull() { + System.out.println(""); for (TextField textField : gridNumbers) { - if (!textField.getText().equals("")) { + if (textField.getText().equals("")) { return false; } } diff --git a/src/coursework/Main.java b/src/coursework/Main.java index 3416de1a951f792bb230dafa7a20866ea2c94eeb..9c8ff2fc07cda09e28392ba7e34623683e2570c9 100644 --- a/src/coursework/Main.java +++ b/src/coursework/Main.java @@ -19,6 +19,7 @@ import javafx.scene.control.Button; import javafx.scene.control.ButtonType; import javafx.scene.control.CheckBox; import javafx.scene.control.Label; +import javafx.scene.control.TextArea; import javafx.scene.control.TextField; import javafx.scene.image.Image; import javafx.scene.image.ImageView; @@ -30,12 +31,12 @@ import javafx.scene.layout.VBox; import javafx.scene.paint.Color; import javafx.scene.shape.Rectangle; import javafx.stage.FileChooser; +import javafx.stage.Modality; import javafx.stage.Stage; public class Main extends Application { - final static public int N = 5; - final private double GRID_PERCENTAGE = 0.75; + final static public int N = 6; private Scene scene; private Stage stage; @@ -48,7 +49,6 @@ public class Main extends Application { private static boolean[][] gridErrors = new boolean[N*N][3]; private static boolean showMistakes = false; - private boolean isWider; private Pane previousPane = null; private Square previousSquare = null; private boolean clearing = false; @@ -86,18 +86,19 @@ public class Main extends Application { public static boolean[][] getGridErrors() { return gridErrors; } - ////////////////////////////////////////////////////////////////////////////////// - - private GridPane setupGrid() { + // + //////////////////////////////////////////////////////////////////////////////// + private GridPane setupGrid(int width, int height) { GridPane gridPane = new GridPane(); gridPane.setAlignment(Pos.CENTER); - double size = (scene.getWidth() * GRID_PERCENTAGE) / N; - + double value = width < height ? width : height; + double size = value / N; for (int i = 0; i < N; i++) { for (int j = 0; j < N; j++) { gridPane = addToGridPane(gridPane, size, i, j); } } + return gridPane; } @@ -182,29 +183,13 @@ public class Main extends Application { loadFileButtonClickEvent(); }); - return topHBox; - } - - private void createNewCage(String line) { - String[] splitLine = line.split(" "); - String[] shiftedIds = splitLine[1].split(","); - int[] ids = new int[shiftedIds.length]; - for (int i = 0; i < shiftedIds.length; i++) { - ids[i] = Integer.parseInt(shiftedIds[i]) - 1; - } - - if (splitLine[0].contains("÷")) { - splitLine[0] = splitLine[0].replace("÷", "�"); - } - - int value = Integer.parseInt(splitLine[0].substring(0, splitLine[0].length()- 1)); - String operator = splitLine[0].substring(splitLine[0].length() - 1); + loadGameTextInputButton.setOnAction(e -> { + loadTextButtonClickEvent(); + }); - Cage cage = new Cage(ids, value, operator); - gridCages.add(cage); + return topHBox; } - private void updateGameState(GameState gameState) { String[] gameValues = gameState.getGameState(); for (int i = 0; i < gridNumbers.length; i++) { @@ -239,34 +224,43 @@ public class Main extends Application { private VBox setupNumbersVBox() { VBox vbox = new VBox(); + Button balanceButtonTop = new Button(""); + balanceButtonTop.setPrefWidth(111); + balanceButtonTop.setVisible(false); + Button balanceButtonBottom = new Button(""); + balanceButtonBottom.setPrefWidth(111); + balanceButtonBottom.setVisible(false); + vbox.getChildren().add(balanceButtonTop); for (int i = 1; i <= N; i++) { Button button = new Button(i + ""); - double cellWidth = gridSquares[0].getRectangle().getWidth() / 2; - double fontSize = cellWidth * 0.4; + final double WIDTH = 50; - button.setPrefSize(cellWidth, cellWidth); - button.setMaxSize(150, 150); - button.setStyle("-fx-font-size:"+fontSize+"pt"); + button.setPrefSize(WIDTH, WIDTH); + button.setMaxSize(WIDTH, WIDTH); + button.setStyle("-fx-font-size:"+18+"pt"); button.setOnAction(e -> { numbersButtonClickEvent(button); }); vbox.getChildren().add(button); } + vbox.getChildren().add(balanceButtonBottom); vbox.setSpacing(10); - vbox.setAlignment(Pos.CENTER); + vbox.setAlignment(Pos.CENTER_LEFT); return vbox; } private VBox setupFontSizeHBox() { VBox vbox = new VBox(); - vbox.getChildren().addAll(setupButton("Tiny", 10), setupButton("Small", 14), setupButton("Medium", 18), setupButton("Large", 22), setupButton("Huge", 26)); - vbox.setSpacing(10); + vbox.getChildren().addAll(setupButton("Tiny", 10, 71), setupButton("Small", 14, 81), setupButton("Medium", 18, 91), setupButton("Large", 22, 101), setupButton("Huge", 26, 111)); + vbox.setSpacing(15); vbox.setAlignment(Pos.CENTER); return vbox; } - private Button setupButton(String name, int size) { + private Button setupButton(String name, int size, int width) { Button button = new Button(name); + button.setMinWidth(width); + button.setPrefWidth(width); button.setStyle("-fx-font-size:" + size + "px;"); button.setOnAction(e -> { changeFontSizeEvent(size); @@ -274,6 +268,59 @@ public class Main extends Application { return button; } + private void createNewCage(String line) { + String[] splitLine = line.split(" "); + String[] shiftedIds = splitLine[1].split(","); + int[] ids = new int[shiftedIds.length]; + + for (int i = 0; i < shiftedIds.length; i++) { + ids[i] = Integer.parseInt(shiftedIds[i]) - 1; + } + + if (splitLine[0].contains("÷") || splitLine[0].contains("/")) { + splitLine[0] = splitLine[0].replace("÷", "�"); + } + + int value = Integer.parseInt(splitLine[0].substring(0, splitLine[0].length()- 1)); + String operator = splitLine[0].substring(splitLine[0].length() - 1); + + Cage cage = new Cage(ids, value, operator); + gridCages.add(cage); + } + + + private void clearGridAlert() { + clearing = true; + Alert alert = new Alert(AlertType.CONFIRMATION); + alert.setContentText("Are you sure you wish to clear the board?"); + alert.setTitle("Clearing Board."); + alert.showAndWait().ifPresent(type -> { + if (type == ButtonType.OK) { + clearGridData(); + undoStack.push(new GameState(GameState.getCurrentGameState(gridNumbers))); + } + });; + clearing = false; + } + + private void clearEmptyGridAlert() { + Alert alert = new Alert(AlertType.WARNING); + alert.setContentText("Nothing to clear on the board."); + alert.setTitle("Empty Board"); + alert.showAndWait(); + } + + private void clearGridData() { + for (TextField textField : gridNumbers) { + textField.setText(""); + } + for (int i = 0; i < N*N; i++) { + for (int j = 0; j < 3; j++) { + gridErrors[i][j] = false; + } + } + } + /////////////////////////////////////////////////////////// private void loadFileButtonClickEvent() { try { @@ -294,9 +341,51 @@ public class Main extends Application { } } + private void loadTextButtonClickEvent() { + Stage popupStage = new Stage(); + popupStage.initModality(Modality.APPLICATION_MODAL); + popupStage.initOwner(stage); + + VBox vbox = new VBox(); + vbox.setPadding(new Insets(10)); + vbox.setSpacing(10); + + HBox hbox = new HBox(); + hbox.setSpacing(162); + + TextArea textArea = new TextArea(); + Button cancelButton = new Button("Cancel"); + cancelButton.setAlignment(Pos.TOP_LEFT); + cancelButton.setOnAction(e -> { + popupStage.hide(); + }); + Button loadButton = new Button("Load"); + loadButton.setAlignment(Pos.TOP_RIGHT); + loadButton.setOnAction(e -> { + String[] lines = textArea.getText().split("\n"); + for (String line : lines) { + if (!line.equals(null) && !line.equals("")) { + createNewCage(line); + } + } + popupStage.hide(); + }); + + hbox.getChildren().addAll(cancelButton, loadButton); + vbox.getChildren().addAll(textArea, hbox); + + popupStage.setScene(new Scene(vbox, 300, 300)); + popupStage.show(); + } + private void showMistakesCheckEvent(CheckBox showMistakesCheck) { + if (!constraints.checked()) { + constraints.checkConstraints(0, 0, false); + } showMistakes = showMistakesCheck.isSelected(); constraints.highlightCells(showMistakes); + Animation animation = new Animation(); + animation.go(); } private void undoButtonClickEvent() { @@ -351,8 +440,7 @@ public class Main extends Application { private void stageWidthResizeEvent(Stage stage, GridPane gridPane) { stage.widthProperty().addListener((obs, oldVal, newVal) -> { if (newVal.doubleValue() < stage.getHeight()) { - isWider = false; - resizeGrid(gridPane.getLayoutX(), gridPane.getLayoutY(), gridPane.getWidth()); + resizeGrid(); } }); } @@ -360,20 +448,21 @@ public class Main extends Application { private void stageHeightResizeEvent(Stage stage, GridPane gridPane) { stage.heightProperty().addListener((obs, oldVal, newVal) -> { if (newVal.doubleValue() < stage.getWidth()) { - isWider = true; - resizeGrid(gridPane.getLayoutX(), gridPane.getLayoutY(), gridPane.getWidth()); + resizeGrid(); } }); } - public void resizeGrid(double gridX, double gridY, double gridWidth) { - double newValue = isWider ? scene.getHeight() : scene.getWidth(); + public void resizeGrid() { + double width = scene.getWidth() - 200; + double height = scene.getHeight() - 150; + double newValue = height < width ? height : width; for (int i = 0; i < N; i++) { for (int j = 0; j < N; j++) { Rectangle rectangle = gridSquares[i*N + j].getRectangle(); - rectangle.setWidth(newValue * GRID_PERCENTAGE / N); - rectangle.setHeight(newValue * GRID_PERCENTAGE / N); - gridSquares[i*N + j].resizeLines(newValue * GRID_PERCENTAGE / N); + rectangle.setWidth(newValue / N); + rectangle.setHeight(newValue / N); + gridSquares[i*N + j].resizeLines(newValue / N); } } } @@ -417,25 +506,10 @@ public class Main extends Application { private void clearButtonClickEvent(Button clearButton) { clearButton.setOnAction(e -> { if (!lastOperationClear()) { - clearing = true; - Alert alert = new Alert(AlertType.CONFIRMATION); - alert.setContentText("Are you sure you wish to clear the board?"); - alert.setTitle("Clearing Board."); - alert.showAndWait().ifPresent(type -> { - if (type == ButtonType.OK) { - for (TextField textField : gridNumbers) { - textField.setText(""); - } - undoStack.push(new GameState(GameState.getCurrentGameState(gridNumbers))); - } - });; - clearing = false; + clearGridAlert(); } else { - Alert alert = new Alert(AlertType.WARNING); - alert.setContentText("Nothing to clear on the board."); - alert.setTitle("Empty Board"); - alert.showAndWait(); + clearEmptyGridAlert(); } }); } @@ -467,12 +541,17 @@ public class Main extends Application { @Override public void start(Stage stage) throws Exception { VBox vBox = new VBox(); - scene = new Scene(vBox,500+50*N,500+50*N); + int width = 400 + 80 * N; + int height = 275 + 80 * N; + + scene = new Scene(vBox, width, height); + stage.setWidth(width); + stage.setHeight(height); vBox.setSpacing(10); vBox.setPadding(new Insets(20)); vBox.setAlignment(Pos.CENTER); - GridPane gridPane = setupGrid(); + GridPane gridPane = setupGrid(width - 200, height - 150); undoStack.push(new GameState(GameState.getCurrentGameState(gridNumbers))); fontSize = 18; @@ -484,6 +563,7 @@ public class Main extends Application { HBox gridHBox = new HBox(); gridHBox.getChildren().addAll(fontSizeVBox, gridPane, numbersVBox); gridHBox.setSpacing(20); + gridHBox.setAlignment(Pos.CENTER); HBox bottomHBox = setupBottomHBox(); @@ -492,8 +572,8 @@ public class Main extends Application { stageWidthResizeEvent(stage, gridPane); stageHeightResizeEvent(stage, gridPane); - stage.setMinWidth(500 + 50*N); - stage.setMinHeight(500 + 50*N); + stage.setMinWidth(width + 50); + stage.setMinHeight(height + 50); stage.setScene(scene); stage.setTitle("Mathdoku"); stage.show();