From 276b3df94c8eb0e479f9a4d5f75fa2db35de5c3f Mon Sep 17 00:00:00 2001
From: tmp1u19 <tmp1u19@soton.ac.uk>
Date: Sun, 12 Apr 2020 15:11:52 +0300
Subject: [PATCH] Animation implemented: cells change colors randomly

---
 Cage.java      | 19 ++++++++---
 Cell.java      | 48 +++++++++++++++++---------
 GameScene.java | 73 +++++++++++++++++++++++++++++++++------
 Handler.java   | 74 +++++++++++++++++++++++++++++++---------
 Window.java    | 92 ++++++++++++++++++++++++++++++++++++++++++--------
 5 files changed, 245 insertions(+), 61 deletions(-)

diff --git a/Cage.java b/Cage.java
index 7158531..0a98e9b 100644
--- a/Cage.java
+++ b/Cage.java
@@ -1,3 +1,4 @@
+
 import java.util.ArrayList;
 
 public class Cage {
@@ -24,6 +25,8 @@ public class Cage {
             cell = new Cell(n, i, j);
         }
 
+        cell.setCellNumber(cellNumber);
+
         cells.add(cell);
 
     }
@@ -44,10 +47,6 @@ public class Cage {
         this.label = label;
     }
 
-    public String getLabel() {
-        return label;
-    }
-
     public char getSymbol() {
         return symbol;
     }
@@ -103,10 +102,20 @@ public class Cage {
 
     public boolean isCompleted() {
         for(Cell cell : getCells()) {
-            if(!cell.isNumeric(cell.getTextField().getText())) {
+            if(!isNumeric(cell.getTextField().getText())) {
                 return false;
             }
         }
         return true;
     }
+
+    public boolean isNumeric(String x) {
+        try {
+            Integer.parseInt(x);
+        } catch (NumberFormatException e) {
+            return false;
+        }
+        return true;
+    }
 }
+
diff --git a/Cell.java b/Cell.java
index 8ee6022..9d98c1a 100644
--- a/Cell.java
+++ b/Cell.java
@@ -4,12 +4,15 @@ import javafx.scene.control.TextField;
 import javafx.scene.layout.*;
 import javafx.scene.text.Font;
 import javafx.scene.control.*;
+import javafx.scene.text.FontWeight;
 
 public class Cell extends Pane {
 
     private TextField input;
     private int i;
     private int j;
+    private int cellNumber;
+    private Label l;
 
     public Cell(int n, int i, int j) {
 
@@ -17,39 +20,30 @@ public class Cell extends Pane {
         this.j = j;
 
         input = new TextField();
-        setPrefSize(400/n, 400/n);
-
         setStyle("- fx-background-color: transparent;");
 
-        input.setStyle("-fx-text-box-border: transparent; -fx-background-color: transparent;" +
-                "-fx-font-weight: bold;");
+        input.setStyle("-fx-text-box-border: transparent; -fx-background-color: transparent;");
+        input.setFont(Font.font("Verdana", FontWeight.BOLD, 20));
         input.setAlignment(Pos.CENTER);
-        input.setFont(Font.font(20));
-        input.setPrefWidth(400/n);
-        input.setPrefHeight(400/n);
 
         getChildren().addAll(input);
     }
 
     public void setLabel(String label) {
-        Label l = new Label(label);
+        l = new Label(label);
         l.setPadding(new Insets(5));
         l.setAlignment(Pos.TOP_LEFT);
         getChildren().add(l);
     }
 
+    public Label getLabel() {
+        return l;
+    }
+
     public TextField getTextField() {
         return input;
     }
 
-    public boolean isNumeric(String text) {
-        try {
-            Integer.parseInt(text);
-            return true;
-        } catch(Exception e) {
-            return false;
-        }
-    }
     public int getRow() {
         return i;
     }
@@ -77,4 +71,26 @@ public class Cell extends Pane {
         }
         return false;
     }
+
+    public boolean isAdjacent(Cage cage) {
+        for(Cell cell : cage.getCells()) {
+            if((cell.getCellNumber() == getCellNumber() - 1 ||
+                    cell.getCellNumber() == getCellNumber() + 1 ||
+                    cell.getCellNumber() == getCellNumber() - 8 ||
+                    cell.getCellNumber() == getCellNumber() + 8) &&
+                    cell.getCellNumber() != getCellNumber()) {
+                return true;
+            }
+        }
+        return false;
+    }
+
+    public void setCellNumber(int cellNumber) {
+        this.cellNumber = cellNumber;
+    }
+
+    public int getCellNumber() {
+        return cellNumber;
+    }
 }
+
diff --git a/GameScene.java b/GameScene.java
index 1bfce62..ffd89a1 100644
--- a/GameScene.java
+++ b/GameScene.java
@@ -18,8 +18,8 @@ import java.util.ArrayList;
 
 public class GameScene extends Application {
 
-    boolean sizeSelected = false;
     private ArrayList<Cage> cages = new ArrayList<Cage>();
+    private Window window = new Window();
 
     public static void main(String[] args) {
         launch(args);
@@ -29,7 +29,6 @@ public class GameScene extends Application {
     public void start(Stage stage) {
 
         FileChooser fileChooser = new FileChooser();
-        Window window = new Window();
         VBox root = new VBox(20);
         root.setPrefSize(800, 700);
         root.setAlignment(Pos.TOP_CENTER);
@@ -63,7 +62,8 @@ public class GameScene extends Application {
         buttons.setAlignment(Pos.TOP_CENTER);
 
         Button play = new Button("Play");
-        play.setStyle("-fx-font-size: 20px; -fx-font-weight:bold;");
+        play.setStyle("-fx-font-size: 20px; -fx-font-weight:bold; -fx-background-color: MediumSeaGreen;" +
+                "-fx-border-color: black; -fx-border-width: 4 4 4 4;");
         play.setDisable(true);
 
         Label size = new Label("Choose size: ");
@@ -101,7 +101,7 @@ public class GameScene extends Application {
             @Override
             public void changed(ObservableValue<? extends String> observableValue, String oldValue,
                                 String newValue) {
-                sizeSelected = true;
+
                 size.setDisable(true);
                 input.setDisable(false);
                 cbInput.setDisable(false);
@@ -114,6 +114,8 @@ public class GameScene extends Application {
 
                 int n = Character.getNumericValue(cbSize.getSelectionModel().getSelectedItem().toString().charAt(0));
 
+                //play.setDisable(false);
+
                 if(newValue.equals("file")) {
 
                     if(cbSize.getSelectionModel().getSelectedItem() != null) {
@@ -122,18 +124,19 @@ public class GameScene extends Application {
 
                         if(file != null) {
                             try {
-                                openFile(file, n);
+                                openFile(file, n, play);
                             } catch (IOException e) {
                                 e.printStackTrace();
                             }
+                        } else {
+                            play.setDisable(true);
                         }
                     }
                 } else if(newValue.equals("text area")) {
-                    directInput(n);
+                    directInput(n, play);
                 }
 
                 input.setDisable(true);
-                play.setDisable(false);
             }
         });
 
@@ -166,7 +169,7 @@ public class GameScene extends Application {
         stage.setResizable(false);
     }
 
-    public void openFile(File file, int n) throws IOException {
+    public boolean openFile(File file, int n, Button play) throws IOException {
 
         BufferedReader buffer = new BufferedReader(new FileReader(file.getPath()));
 
@@ -199,9 +202,58 @@ public class GameScene extends Application {
             cages.add(cage);
             line = buffer.readLine();
         }
+
+        try {
+            if(!checkUniqueCells(n)) {
+                cages = new ArrayList<Cage>();
+                play.setDisable(true);
+                window.inputError("The cells are not part of exactly " +
+                        "one cage.").showAndWait();
+                return false;
+            }
+        } catch (ArrayIndexOutOfBoundsException e) {
+            cages = new ArrayList<Cage>();
+            play.setDisable(true);
+            window.inputError("Some cells don't belong to the bord").showAndWait();
+            return false;
+        }
+
+        play.setDisable(false);
+        return true;
     }
 
-    public void directInput(int n) {
+    public boolean checkUniqueCells(int n) throws IOException {
+
+        int[] verify = new int[n*n + 1];
+
+        for(Cage cage : cages) {
+             for(Cell cell : cage.getCells()) {
+                 verify[cell.getCellNumber()] += 1;
+             }
+        }
+
+        for(int i = 1; i <= n*n; i ++) {
+            if(verify[i] != 1) {
+                return false;
+            }
+        }
+
+        return true;
+    }
+
+    public boolean checkAdjacent() {
+
+        for(Cage cage : cages) {
+            for(Cell cell : cage.getCells()) {
+                if(!cell.isAdjacent(cage)) {
+                    return false;
+                }
+            }
+        }
+        return true;
+    }
+
+    public void directInput(int n, Button play) {
 
         VBox root = new VBox(10);
         root.setPadding(new Insets(20));
@@ -223,6 +275,7 @@ public class GameScene extends Application {
         Scene scene = new Scene(root);
         Stage stage = new Stage();
         stage.setScene(scene);
+        play.setDisable(true);
 
         ok.setOnAction(new EventHandler<ActionEvent>() {
             @Override
@@ -238,7 +291,7 @@ public class GameScene extends Application {
                 }
 
                 try {
-                    openFile(file, n);
+                    openFile(file, n, play);
                 } catch (IOException e) {
                     e.printStackTrace();
                 }
diff --git a/Handler.java b/Handler.java
index c9d0fd8..975b2c7 100644
--- a/Handler.java
+++ b/Handler.java
@@ -1,3 +1,4 @@
+import javafx.animation.*;
 import javafx.beans.value.ChangeListener;
 import javafx.beans.value.ObservableValue;
 import javafx.event.ActionEvent;
@@ -13,9 +14,11 @@ import javafx.scene.layout.BackgroundFill;
 import javafx.scene.layout.CornerRadii;
 import javafx.scene.layout.GridPane;
 import javafx.scene.paint.Color;
+import javafx.scene.text.Font;
+import javafx.scene.text.FontWeight;
+import javafx.util.Duration;
 
 import java.util.ArrayList;
-import java.util.Collections;
 
 public class Handler {
 
@@ -78,7 +81,7 @@ public class Handler {
                 }
 
                 if(verify() && verifyCages()) {
-                    window.win("Congratulations!", "You won the game!");
+                    win();
                 } else {
                     window.win("Too bad...", "You lost the game");
                 }
@@ -137,13 +140,30 @@ public class Handler {
         });
     }
 
+    public void changeFont(Button button, int number) {
+        button.setOnAction(new EventHandler<ActionEvent>() {
+            @Override
+            public void handle(ActionEvent actionEvent) {
+                for(Cage cage : cages) {
+                    for(Cell cell : cage.getCells()) {
+
+                        cell.getTextField().setStyle("-fx-text-box-border: transparent; " +
+                                "-fx-background-color: transparent;");
+                        cell.getTextField().setFont(Font.font("Verdana", FontWeight.BOLD, number));
+                    }
+                    cage.getCells().get(0).getLabel().setFont(Font.font(number - 10));
+                }
+            }
+        });
+    }
+
     public void addActions(GridPane grid, Button undo) {
 
         for(Node cell : grid.getChildren()) {
             ((Cell) cell).getTextField().textProperty().addListener(new ChangeListener<String>() {
                 @Override
                 public void changed(ObservableValue<? extends String> observableValue, String s, String t1) {
-                    if(((Cell) cell).isNumeric(((Cell) cell).getTextField().getText())) {
+                    if(isNumeric(((Cell) cell).getTextField().getText())) {
                         Element e = new Element(((Cell) cell).getRow(), ((Cell) cell).getColumn(),
                                 Integer.parseInt(((Cell) cell).getTextField().getText()));
                         undoStack.push(e);
@@ -173,7 +193,7 @@ public class Handler {
             public void changed(ObservableValue<? extends String> observableValue, String oldValue,
                                 String newValue) {
 
-                if (cell.isNumeric(newValue)) {
+                if (isNumeric(newValue)) {
                     if (Integer.parseInt(newValue) > n || Integer.parseInt(newValue) == 0) {
                         cell.getTextField().setText(oldValue);
                     } else {
@@ -210,20 +230,16 @@ public class Handler {
     public void drawGrid(GridPane grid) {
 
         for(Cage cage : cages) {
-            cage.getCells().get(0).setStyle("-fx-border-color: black; -fx-border-width: 2 2 2 2;");
-
             for(Cell cell : cage.getCells()) {
 
-                if(cell != cage.getCells().get(0)) {
-                    if(cell.hasLeftNeighbour(cage) && cell.hasUpNeighbour(cage)) {
-                        cell.setStyle("-fx-border-color: black; -fx-border-width: 0 2 2 0;");
-                    } else if(cell.hasLeftNeighbour(cage)) {
-                        cell.setStyle("-fx-border-color: black; -fx-border-width: 2 2 2 0;");
-                    } else if(cell.hasUpNeighbour(cage)) {
-                        cell.setStyle("-fx-border-color: black; -fx-border-width: 0 2 2 2;");
-                    } else {
-                        cell.setStyle("-fx-border-color: black; -fx-border-width: 2 2 2 2;");
-                    }
+                if(cell.hasLeftNeighbour(cage) && cell.hasUpNeighbour(cage)) {
+                    cell.setStyle("-fx-border-color: black; -fx-border-width: 0 4 4 0;");
+                } else if(cell.hasLeftNeighbour(cage)) {
+                    cell.setStyle("-fx-border-color: black; -fx-border-width: 4 4 4 0;");
+                } else if(cell.hasUpNeighbour(cage)) {
+                    cell.setStyle("-fx-border-color: black; -fx-border-width: 0 4 4 4;");
+                } else {
+                    cell.setStyle("-fx-border-color: black; -fx-border-width: 4 4 4 4;");
                 }
 
                 doubleClick(cell);
@@ -436,6 +452,23 @@ public class Handler {
         }
     }
 
+    public void win() {
+        Timeline timeline = new Timeline(new KeyFrame(Duration.millis(100), new EventHandler<ActionEvent>() {
+            @Override
+            public void handle(ActionEvent actionEvent) {
+                for(Cage cage : cages) {
+                    for(Cell cell : cage.getCells()) {
+                        cell.setBackground(new Background(new BackgroundFill(Color.color(Math.random(), Math.random(),
+                                Math.random()), CornerRadii.EMPTY, Insets.EMPTY)));
+                    }
+                }
+            }
+        }));
+
+        timeline.setCycleCount(Transition.INDEFINITE);
+        timeline.play();
+    }
+
     public Cell getCell(GridPane grid, int i, int j) {
         for(Node cell : grid.getChildren()) {
             if(((Cell) cell).getRow() == i && ((Cell) cell).getColumn() == j) {
@@ -452,5 +485,14 @@ public class Handler {
     public void setN(int n) {
         this.n = n;
     }
+
+    public boolean isNumeric(String x) {
+        try {
+            Integer.parseInt(x);
+        } catch (NumberFormatException e) {
+            return false;
+        }
+        return true;
+    }
 }
 
diff --git a/Window.java b/Window.java
index c6033b1..a7a5656 100644
--- a/Window.java
+++ b/Window.java
@@ -11,11 +11,8 @@ import javafx.scene.text.Font;
 import javafx.stage.Modality;
 import javafx.stage.Stage;
 import javafx.stage.StageStyle;
-
-import java.io.File;
-import java.io.FileWriter;
-import java.io.IOException;
 import java.util.ArrayList;
+import java.util.TimerTask;
 
 public class Window {
 
@@ -131,6 +128,15 @@ public class Window {
         return alert;
     }
 
+    public Alert inputError(String comment) {
+        Alert alert = new Alert(Alert.AlertType.ERROR);
+        alert.setTitle("Error");
+        alert.setHeaderText("Input error");
+        alert.setContentText(comment);
+
+        return alert;
+    }
+
     public Stage mathdokuStage(int n, ArrayList<Cage> cages) {
 
         this.n = n;
@@ -138,6 +144,12 @@ public class Window {
         Handler handler = new Handler(n, cages);
         handler.setN(n);
         Stage stage = new Stage();
+        TimerTask task= new TimerTask() {
+            @Override
+            public void run() {
+
+            }
+        };
 
         VBox root = new VBox(5);
         root.setAlignment(Pos.CENTER);
@@ -146,17 +158,26 @@ public class Window {
         HBox buttons = new HBox();
         buttons.setAlignment(Pos.CENTER);
 
-        HBox sizes = new HBox(5);
-        sizes.setAlignment(Pos.CENTER);
-
         GridPane grid = new GridPane();
         grid.setAlignment(Pos.CENTER);
-        grid.setPadding(new Insets(20));
+        grid.setStyle("-fx-border-color: black; -fx-border-width: 4 4 4 4;");
 
         Button undo = new Button("Undo");
         Button redo = new Button("Redo");
         Button help = new Button("Enable Help");
         Button clear = new Button("Clear");
+        Button hint = new Button("Hint");
+
+        undo.setStyle("-fx-font-size: 20px; -fx-font-weight:bold; -fx-background-color: MediumSeaGreen;" +
+                "-fx-border-color: black; -fx-border-width: 4 4 4 4;");
+        redo.setStyle("-fx-font-size: 20px; -fx-font-weight:bold; -fx-background-color: MediumSeaGreen;" +
+                "-fx-border-color: black; -fx-border-width: 4 4 4 4;");
+        help.setStyle("-fx-font-size: 20px; -fx-font-weight:bold; -fx-background-color: MediumSeaGreen;" +
+                "-fx-border-color: black; -fx-border-width: 4 4 4 4;");
+        clear.setStyle("-fx-font-size: 20px; -fx-font-weight:bold; -fx-background-color: MediumSeaGreen;" +
+                "-fx-border-color: black; -fx-border-width: 4 4 4 4;");
+        hint.setStyle("-fx-font-size: 20px; -fx-font-weight:bold; -fx-background-color: MediumSeaGreen;" +
+                "-fx-border-color: black; -fx-border-width: 4 4 4 4;");
 
         undo.setDisable(true);
         redo.setDisable(true);
@@ -166,31 +187,74 @@ public class Window {
         handler.undoAction(undo, redo, grid);
         handler.redoAction(redo, grid);
 
-        buttons.getChildren().addAll(undo, redo, help, clear);
+        buttons.getChildren().addAll(undo, redo, help, clear, hint);
 
         handler.drawGrid(grid);
-
         handler.addActions(grid, undo);
 
+        Button small = new Button("Small");
+        Button medium = new Button("Medium");
+        Button large = new Button("Large");
+
+        small.setStyle("-fx-font-size: 20px; -fx-font-weight:bold; -fx-background-color: MediumSeaGreen;" +
+                " -fx-border-color: black; -fx-border-width: 4 4 4 4;");
+        medium.setStyle("-fx-font-size: 20px; -fx-font-weight:bold; -fx-background-color: MediumSeaGreen; " +
+                "-fx-border-color: black; -fx-border-width: 4 4 4 4;");
+        large.setStyle("-fx-font-size: 20px; -fx-font-weight:bold; -fx-background-color: MediumSeaGreen; " +
+                "-fx-border-color: black; -fx-border-width: 4 4 4 4;");
+
+        HBox sizes = new HBox(5);
+        sizes.setAlignment(Pos.CENTER);
+
+        sizes.getChildren().addAll(small, medium, large);
+
         Label note = new Label("Double click the space provided for text in cell");
         Button submit = new Button("Submit");
 
+        note.setStyle("-fx-font-size: 15px; -fx-font-weight:bold;");
+        submit.setStyle("-fx-font-size: 20px; -fx-font-weight:bold; -fx-background-color: MediumSeaGreen; " +
+                "-fx-border-color: black; -fx-border-width: 4 4 4 4;");
+
+        handler.changeFont(small, 20);
+        handler.changeFont(medium, 30);
+        handler.changeFont(large, 40);
         handler.submitButton(submit);
 
         root.getChildren().addAll(buttons, grid, sizes, note, submit);
 
+        root.widthProperty().addListener((obs, oldVal, newVal) -> {
+            grid.setMaxWidth((Double) newVal - 100);
+            for(Cage cage : cages) {
+                for(Cell cell : cage.getCells()) {
+                    cell.setPrefWidth((Double) newVal - 100);
+                    cell.getTextField().setPrefSize(cell.getWidth(), cell.getHeight());
+                }
+            }
+        });
+
+        root.heightProperty().addListener((obs, oldVal, newVal) -> {
+            grid.setMaxHeight((Double) newVal - 100);
+            for(Cage cage : cages) {
+                for(Cell cell : cage.getCells()) {
+                    cell.setPrefHeight((Double) newVal- 100);
+                    cell.getTextField().setPrefSize(cell.getWidth(), cell.getHeight());
+                }
+            }
+        });
+
         Scene scene = new Scene(root);
         stage.setScene(scene);
 
         stage.setTitle("Mathdoku");
         stage.initStyle(StageStyle.DECORATED);
 
-        stage.setX(800);
-        stage.setY(300);
+        stage.setX(700);
+        stage.setY(200);
 
-        stage.setMinHeight(600);
-        stage.setMinWidth(500);
+        stage.setMinHeight(700);
+        stage.setMinWidth(700);
 
         return stage;
     }
 }
+
-- 
GitLab