From ca6190de93b5fd5505311862a0ce820e4f9e946c Mon Sep 17 00:00:00 2001
From: tmp1u19 <tmp1u19@soton.ac.uk>
Date: Sun, 5 Apr 2020 22:16:16 +0300
Subject: [PATCH] The game can now be accessed and played by the rules showed
 in the menu.

---
 Cage.java      | 112 +++++++++++++++++++++
 Cell.java      |  43 +++++---
 Element.java   |  12 +++
 GameScene.java | 267 +++++++++++++++++++++++++++++++++++++++++++------
 Handler.java   | 242 ++++++++++++++++++++++++++++++++++++--------
 UndoRedo.java  |  46 +++++++++
 Window.java    |  76 +++++++++++++-
 7 files changed, 711 insertions(+), 87 deletions(-)
 create mode 100644 Cage.java
 create mode 100644 Element.java
 create mode 100644 UndoRedo.java

diff --git a/Cage.java b/Cage.java
new file mode 100644
index 0000000..7158531
--- /dev/null
+++ b/Cage.java
@@ -0,0 +1,112 @@
+import java.util.ArrayList;
+
+public class Cage {
+
+    private ArrayList<Cell> cells = new ArrayList<Cell>();
+    private int n;
+    private String result;
+    private Character symbol = null;
+    private String label;
+
+    public Cage(int n) {
+        this.n = n;
+    }
+
+    public void addCell(int cellNumber) {
+
+        int i = cellNumber / n;
+        int j = (cellNumber % n) - 1;
+        Cell cell;
+
+        if(j == - 1) {
+            cell = new Cell(n, i - 1, n - 1);
+        } else {
+            cell = new Cell(n, i, j);
+        }
+
+        cells.add(cell);
+
+    }
+
+    public ArrayList<Cell> getCells() {
+        return cells;
+    }
+
+    public void setResult(String result) {
+        this.result = result;
+    }
+
+    public void setSymbol(char symbol) {
+        this.symbol = symbol;
+    }
+
+    public void setLabel(String label) {
+        this.label = label;
+    }
+
+    public String getLabel() {
+        return label;
+    }
+
+    public char getSymbol() {
+        return symbol;
+    }
+
+    public String getResult() {
+        return result;
+    }
+
+    public boolean hasSymbol() {
+        if(symbol == null) {
+            return false;
+        } else {
+            return true;
+        }
+    }
+    public int[] getValues() {
+        int[] values = new int[cells.size()];
+        int size = 0;
+
+        for(Cell cell : cells) {
+
+            if(isCompleted()) {
+                int x = Integer.parseInt(cell.getTextField().getText());
+
+                if(size != 0) {
+
+                    boolean found = false;
+                    int index = size;
+
+                    while(!found) {
+                        if(index == 0) {
+                            values[index] = x;
+                            found = true;
+                        } else if(values[index - 1] >= x) {
+                            values[index] = x;
+                            found = true;
+                        } else {
+                            values[index] = values[index - 1];
+                            index--;
+                        }
+                    }
+                } else {
+                    values[size] = x;
+                }
+                size++;
+            } else {
+                return null;
+            }
+        }
+
+        return values;
+    }
+
+    public boolean isCompleted() {
+        for(Cell cell : getCells()) {
+            if(!cell.isNumeric(cell.getTextField().getText())) {
+                return false;
+            }
+        }
+        return true;
+    }
+}
diff --git a/Cell.java b/Cell.java
index 0757b12..8ee6022 100644
--- a/Cell.java
+++ b/Cell.java
@@ -1,12 +1,12 @@
+import javafx.geometry.Insets;
 import javafx.geometry.Pos;
 import javafx.scene.control.TextField;
 import javafx.scene.layout.*;
-import javafx.scene.control.Label;
 import javafx.scene.text.Font;
+import javafx.scene.control.*;
 
 public class Cell extends Pane {
 
-    private Label label = new Label();
     private TextField input;
     private int i;
     private int j;
@@ -21,24 +21,21 @@ public class Cell extends Pane {
 
         setStyle("- fx-background-color: transparent;");
 
-        input.setStyle("-fx-text-box-border: transparent; -fx-background-color: transparent;");
+        input.setStyle("-fx-text-box-border: transparent; -fx-background-color: transparent;" +
+                "-fx-font-weight: bold;");
         input.setAlignment(Pos.CENTER);
-        input.setFont(Font.font(35));
+        input.setFont(Font.font(20));
         input.setPrefWidth(400/n);
         input.setPrefHeight(400/n);
 
-        getChildren().add(input);
+        getChildren().addAll(input);
     }
 
     public void setLabel(String label) {
-
-        this.label.setText(label);
-        this.label.setAlignment(Pos.TOP_LEFT);
-        getChildren().add(this.label);
-    }
-
-    public String getLabel() {
-        return label.getText();
+        Label l = new Label(label);
+        l.setPadding(new Insets(5));
+        l.setAlignment(Pos.TOP_LEFT);
+        getChildren().add(l);
     }
 
     public TextField getTextField() {
@@ -60,4 +57,24 @@ public class Cell extends Pane {
     public int getColumn() {
         return j;
     }
+
+    public boolean hasLeftNeighbour(Cage cage) {
+        for(Cell cell : cage.getCells()) {
+            if(cell.getColumn() + 1 == getColumn() &&
+                    cell.getRow() == getRow()) {
+                return true;
+            }
+        }
+        return false;
+    }
+
+    public boolean hasUpNeighbour(Cage cage) {
+        for(Cell cell : cage.getCells()) {
+            if(cell.getRow() + 1 == getRow() &&
+                    cell.getColumn() == getColumn()) {
+                return true;
+            }
+        }
+        return false;
+    }
 }
diff --git a/Element.java b/Element.java
new file mode 100644
index 0000000..91de30d
--- /dev/null
+++ b/Element.java
@@ -0,0 +1,12 @@
+public class Element {
+
+    public int i;
+    public int j;
+    public int value;
+
+    public Element(int i, int j, int value) {
+        this.i = i;
+        this.j = j;
+        this.value = value;
+    }
+}
diff --git a/GameScene.java b/GameScene.java
index d7c3749..1bfce62 100644
--- a/GameScene.java
+++ b/GameScene.java
@@ -1,65 +1,270 @@
 import javafx.application.Application;
+import javafx.beans.value.ChangeListener;
+import javafx.beans.value.ObservableValue;
+import javafx.collections.FXCollections;
+import javafx.event.ActionEvent;
+import javafx.event.EventHandler;
 import javafx.geometry.Insets;
 import javafx.geometry.Pos;
 import javafx.scene.Scene;
 import javafx.scene.control.*;
 import javafx.scene.layout.*;
+import javafx.stage.FileChooser;
+import javafx.stage.Modality;
 import javafx.stage.Stage;
-import javafx.stage.StageStyle;
 
+import java.io.*;
+import java.util.ArrayList;
 
 public class GameScene extends Application {
 
-    private Handler handler = new Handler();
+    boolean sizeSelected = false;
+    private ArrayList<Cage> cages = new ArrayList<Cage>();
+
+    public static void main(String[] args) {
+        launch(args);
+    }
 
     @Override
     public void start(Stage stage) {
 
-        VBox root = new VBox(5);
-        root.setAlignment(Pos.CENTER);
-        root.setPadding(new Insets(20));
+        FileChooser fileChooser = new FileChooser();
+        Window window = new Window();
+        VBox root = new VBox(20);
+        root.setPrefSize(800, 700);
+        root.setAlignment(Pos.TOP_CENTER);
+        root.setPadding(new Insets(30));
+
+        Label greeting = new Label("Mathdoku");
+        greeting.setStyle("-fx-font-size: 70px; -fx-font-weight:bold;");
+
+        String instructions = "A player needs to fill the cells in an NxN square grid with the numbers 1 to N " +
+                "(one number per cell), while adhering to the following constraints:" + '\n' +
+                "- Each number must appear exactly once in each row." + '\n' +
+                "- Each number must appear exactly once in each column." + '\n' +
+                "Furthermore, there are groups of adjacent cells called cages, which are highlighted on the " +
+                "grid by thicker boundaries. Within each cage is a label showing a target number " +
+                "followed by an arithmetic operator (+, -, x, ÷). There is an additional constraint " +
+                "associated with these cages:" + '\n' +
+                "- It must be possible to obtain the target by applying the arithmetic" +
+                " operator to the numbers in that cage. For - and ÷, this can be done in any order." + '\n' +
+                "Note: If a cage consists of a single cell, then no arithmetic operator is shown. " +
+                "The label simply shows the number that must be in that cell.";
+
+        Label instruct = new Label("Instructions:" + '\n' + instructions);
+
+        instruct.setWrapText(true);
+        instruct.setStyle("-fx-font-size: 15px;");
+        instruct.setPadding(new Insets(40));
+
+        GridPane buttons = new GridPane();
+        buttons.setPadding(new Insets(20));
+        buttons.setHgap(10);
+        buttons.setAlignment(Pos.TOP_CENTER);
+
+        Button play = new Button("Play");
+        play.setStyle("-fx-font-size: 20px; -fx-font-weight:bold;");
+        play.setDisable(true);
+
+        Label size = new Label("Choose size: ");
+        size.setStyle("-fx-font-size: 20px; -fx-font-weight:bold;");
+
+        ChoiceBox cbSize = new ChoiceBox();
+        cbSize.setItems(FXCollections.observableArrayList(
+                "2x2", "3x3", "4x4", "5x5",
+                "6x6", "7x7", "8x8")
+        );
+
+        cbSize.setStyle("-fx-font-size: 15px;");
+        cbSize.setPrefWidth(110);
+
+        Label input = new Label("Input from: ");
+        input.setStyle("-fx-font-size: 20px; -fx-font-weight:bold;");
+
+        ChoiceBox cbInput = new ChoiceBox();
+        cbInput.setItems(FXCollections.observableArrayList(
+                "file", "text area")
+        );
+
+        cbInput.setStyle("-fx-font-size: 15px;");
+        cbInput.setPrefWidth(110);
+
+        buttons.add(size, 0, 0, 1, 1);
+        buttons.add(cbSize, 1, 0, 1, 1);
+        buttons.add(input, 2, 0, 1, 1);
+        buttons.add(cbInput, 3, 0, 1, 1);
+
+        input.setDisable(true);
+        cbInput.setDisable(true);
+
+        cbSize.getSelectionModel().selectedItemProperty().addListener(new ChangeListener<String>() {
+            @Override
+            public void changed(ObservableValue<? extends String> observableValue, String oldValue,
+                                String newValue) {
+                sizeSelected = true;
+                size.setDisable(true);
+                input.setDisable(false);
+                cbInput.setDisable(false);
+            }
+        });
+
+        cbInput.getSelectionModel().selectedItemProperty().addListener(new ChangeListener<String>() {
+            @Override
+            public void changed(ObservableValue<? extends String> observableValue, String oldValue, String newValue) {
+
+                int n = Character.getNumericValue(cbSize.getSelectionModel().getSelectedItem().toString().charAt(0));
+
+                if(newValue.equals("file")) {
+
+                    if(cbSize.getSelectionModel().getSelectedItem() != null) {
+
+                        File file = fileChooser.showOpenDialog(stage);
+
+                        if(file != null) {
+                            try {
+                                openFile(file, n);
+                            } catch (IOException e) {
+                                e.printStackTrace();
+                            }
+                        }
+                    }
+                } else if(newValue.equals("text area")) {
+                    directInput(n);
+                }
+
+                input.setDisable(true);
+                play.setDisable(false);
+            }
+        });
 
-        HBox buttons = new HBox();
-        buttons.setAlignment(Pos.CENTER);
+        play.setOnAction(new EventHandler<ActionEvent>() {
+            @Override
+            public void handle(ActionEvent actionEvent) {
+                stage.close();
 
-        GridPane grid = new GridPane();
-        grid.setAlignment(Pos.CENTER);
-        grid.setPadding(new Insets(20));
+                String size = cbSize.getSelectionModel().getSelectedItem().toString();
 
-        Button undo = new Button("Undo");
-        Button redo = new Button("Redo");
-        Button help = new Button("Enable Help");
-        Button clear = new Button("Clear");
-        Button fileLoad = new Button("File");
-        Button textLoad = new Button("Text");
+                Stage newStage = window.mathdokuStage(Character.getNumericValue(size.charAt(0)), cages);
+                newStage.show();
+            }
+        });
 
-        handler.helpButton(help, grid);
-        handler.clearBoard(clear, grid);
+        root.getChildren().addAll(greeting, instruct, buttons, play);
 
-        buttons.getChildren().addAll(undo, redo, help, clear, fileLoad, textLoad);
+        Scene scene = new Scene(root);
+
+        stage.setScene(scene);
+
+        stage.setTitle("Welcome to Mathdoku!");
+        stage.setX(650);
+        stage.setY(250);
+
+        stage.setMinWidth(800);
+        stage.setMinHeight(700);
+
+        stage.show();
+        stage.setResizable(false);
+    }
+
+    public void openFile(File file, int n) throws IOException {
+
+        BufferedReader buffer = new BufferedReader(new FileReader(file.getPath()));
+
+        String line = buffer.readLine();
+
+        while(line != null) {
+
+            String str[] = line.split(" ");
+            Cage cage = new Cage(n);
 
-        handler.draw(grid);
+            if(isNumeric(str[0])) {
 
-        Label note = new Label("Double click the space provided for text in cell");
-        Button submit = new Button("Submit");
+                cage.setResult(str[0]);
+                cage.addCell(Integer.parseInt(str[1]));
+            } else {
 
-        handler.submitButton(submit);
+                String[] cells = str[1].split(",");
 
-        root.getChildren().addAll(buttons, grid, note, submit);
+                for(String cell : cells) {
+                    cage.addCell(Integer.parseInt(cell));
+                }
+
+                cage.setSymbol(str[0].charAt(str[0].length() - 1));
+                cage.setResult(str[0].substring(0, str[0].length() - 1));
+
+            }
+
+            cage.getCells().get(0).setLabel(str[0]);
+            cage.setLabel(str[0]);
+            cages.add(cage);
+            line = buffer.readLine();
+        }
+    }
+
+    public void directInput(int n) {
+
+        VBox root = new VBox(10);
+        root.setPadding(new Insets(20));
+        root.setAlignment(Pos.TOP_CENTER);
+        root.setPrefSize(400, 600);
+        TextArea textArea = new TextArea();
+        textArea.setStyle("-fx-font-size: 15px;");
+        textArea.setPrefWidth(300);
+        textArea.setPrefHeight(400);
+
+        Label label = new Label("Provide data for your board below." +
+                '\n' + "Remember, the size of the board is " + n + "x" + n + " :)");
+        label.setStyle("-fx-font-size: 15px; -fx-font-weight:bold;");
+
+        Button ok = new Button("OK");
+
+        root.getChildren().addAll(label, textArea, ok);
 
         Scene scene = new Scene(root);
+        Stage stage = new Stage();
         stage.setScene(scene);
 
-        stage.setTitle("Mathdoku");
-        stage.initStyle(StageStyle.DECORATED);
+        ok.setOnAction(new EventHandler<ActionEvent>() {
+            @Override
+            public void handle(ActionEvent actionEvent) {
+                File file = new File("temp");
+                try {
+                    FileWriter outputFile = new FileWriter(file);
+                    outputFile.write(textArea.getText());
+                    outputFile.flush();
+                    outputFile.close();
+                } catch (IOException e) {
+                    e.printStackTrace();
+                }
+
+                try {
+                    openFile(file, n);
+                } catch (IOException e) {
+                    e.printStackTrace();
+                }
 
-        stage.setX(750);
-        stage.setY(300);
+                file.delete();
+                stage.close();
+            }
+        });
 
-        stage.setMinHeight(600);
-        stage.setMinWidth(500);
+        stage.setTitle("Direct Input");
+        stage.setMinHeight(530);
+        stage.setMinWidth(400);
+        stage.setX(850);
+        stage.setY(350);
+        stage.initModality(Modality.APPLICATION_MODAL);
 
         stage.show();
+        stage.setResizable(false);
     }
 
-}
\ No newline at end of file
+    public boolean isNumeric(String x) {
+        try {
+            Integer.parseInt(x);
+        } catch (NumberFormatException e) {
+            return false;
+        }
+        return true;
+    }
+}
diff --git a/Handler.java b/Handler.java
index 4d72466..c9d0fd8 100644
--- a/Handler.java
+++ b/Handler.java
@@ -14,11 +14,24 @@ import javafx.scene.layout.CornerRadii;
 import javafx.scene.layout.GridPane;
 import javafx.scene.paint.Color;
 
+import java.util.ArrayList;
+import java.util.Collections;
+
 public class Handler {
 
     private Window window = new Window();
-    private int n = 4;
-    private int[][] cellValues = new int[n][n];
+    private int n;
+    private int[][] cellValues;
+    private UndoRedo undoStack = new UndoRedo();
+    private UndoRedo redoStack = new UndoRedo();
+    private ArrayList<Cage> cages;
+
+    public Handler(int n, ArrayList<Cage> cages) {
+        this.n = n;
+        this.cages = new ArrayList<Cage>();
+        this.cages = cages;
+        cellValues = new int[n][n];
+    }
 
     public void helpButton(Button help, GridPane grid) {
 
@@ -38,6 +51,9 @@ public class Handler {
                 } else {
                     help.setText("Enable Help");
                     setTransparent(grid);
+                    for(Node cell : grid.getChildren()) {
+                        disableHighlight((Cell) cell, grid);
+                    }
                 }
             }
         });
@@ -48,14 +64,20 @@ public class Handler {
             @Override
             public void handle(ActionEvent actionEvent) {
 
-                for(int i = 0; i < getN(); i ++) {
-                    for(int j = 0; j < getN(); j ++) {
+                for(int i = 0; i < n; i ++) {
+                    for(int j = 0; j < n; j ++) {
                         System.out.print(getCellValues()[i][j]);
                     }
                     System.out.println();
                 }
 
-                if(verify()) {
+                System.out.println();
+
+                for(Cage cage : cages) {
+                    System.out.print(cage.getResult() + " ");
+                }
+
+                if(verify() && verifyCages()) {
                     window.win("Congratulations!", "You won the game!");
                 } else {
                     window.win("Too bad...", "You lost the game");
@@ -64,28 +86,81 @@ public class Handler {
         });
     }
 
-    public void clearBoard(Button clear, GridPane grid) {
+    public void clearBoard(Button clear, GridPane grid, Button undo, Button redo) {
 
         clear.setOnAction(new EventHandler<ActionEvent>() {
             @Override
             public void handle(ActionEvent actionEvent) {
 
-                window.getAlertDialog("Are you sure you want to clear the board?").showAndWait().ifPresent(response -> {
+                window.getAlertDialog("Are you sure you want to clear " +
+                        "the board?").showAndWait().ifPresent(response -> {
                     if(response == ButtonType.YES) {
                         clear(grid);
+                        undo.setDisable(true);
+                        redo.setDisable(true);
                     }
                 });
             }
         });
     }
 
+
+    public void undoAction(Button undo, Button redo, GridPane grid) {
+        undo.setOnAction(new EventHandler<ActionEvent>() {
+            @Override
+            public void handle(ActionEvent actionEvent) {
+                if(undoStack.isEmpty()) {
+                    undo.setDisable(true);
+                } else {
+                    redo.setDisable(false);
+                    Element e = undoStack.pop();
+                    redoStack.push(e);
+                    getCell(grid, e.i, e.j).getTextField().clear();
+                    cellValues[e.i][e.j] = 0;
+                }
+            }
+        });
+    }
+
+    public void redoAction(Button redo, GridPane grid) {
+        redo.setOnAction(new EventHandler<ActionEvent>() {
+            @Override
+            public void handle(ActionEvent actionEvent) {
+                if(redoStack.isEmpty()) {
+                    redo.setDisable(true);
+                } else {
+                    Element e = redoStack.pop();
+                    getCell(grid, e.i, e.j).getTextField().setText(String.valueOf(e.value));
+                    undoStack.push(e);
+                }
+            }
+        });
+    }
+
+    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())) {
+                        Element e = new Element(((Cell) cell).getRow(), ((Cell) cell).getColumn(),
+                                Integer.parseInt(((Cell) cell).getTextField().getText()));
+                        undoStack.push(e);
+                        undo.setDisable(false);
+                    }
+                }
+            });
+        }
+    }
+
     public void doubleClick(Cell cell) {
         cell.getTextField().setOnMouseClicked(new EventHandler<MouseEvent>() {
             @Override
             public void handle(MouseEvent mouseEvent) {
                 if(mouseEvent.getButton().equals(MouseButton.PRIMARY)) {
                     if(mouseEvent.getClickCount() == 2) {
-                        window.showButtons(cell, getN());
+                        window.showButtons(cell);
                     }
                 }
             }
@@ -97,16 +172,17 @@ public class Handler {
             @Override
             public void changed(ObservableValue<? extends String> observableValue, String oldValue,
                                 String newValue) {
+
                 if (cell.isNumeric(newValue)) {
-                    if (Integer.parseInt(newValue) > getN() || Integer.parseInt(newValue) == 0) {
-                        cell.getTextField().clear();
+                    if (Integer.parseInt(newValue) > n || Integer.parseInt(newValue) == 0) {
+                        cell.getTextField().setText(oldValue);
                     } else {
                         getCellValues()[cell.getRow()][cell.getColumn()] = Integer.parseInt(newValue);
                     }
                 } else if (!newValue.matches("\\d*")) {
                     cell.getTextField().setText(newValue.replaceAll("[^\\d]", ""));
+                    cellValues[cell.getRow()][cell.getColumn()] = 0;
                 }
-
             }
         });
     }
@@ -116,40 +192,44 @@ public class Handler {
         cell.getTextField().textProperty().addListener(new ChangeListener<String>() {
             @Override
             public void changed(ObservableValue<? extends String> observableValue, String s, String t1) {
-
                 setTransparent(grid);
                 highlight(grid);
             }
         });
     }
 
-    public void draw(GridPane grid) {
-
-        for(int i = 0; i < getN(); i ++) {
-            for (int j = 0; j < getN(); j++) {
-                Cell cell = new Cell(getN(), i, j);
-
-                drawLines(i, j, cell);
-                doubleClick(cell);
-                memoriseValues(cell);
-
-                grid.add(cell, j, i, 1, 1);
+    public void disableHighlight(Cell cell, GridPane grid) {
+        cell.getTextField().textProperty().addListener(new ChangeListener<String>() {
+            @Override
+            public void changed(ObservableValue<? extends String> observableValue, String s, String t1) {
+                setTransparent(grid);
             }
-        }
+        });
     }
 
-    public void drawLines(int i, int j, Cell cell) {
+    public void drawGrid(GridPane grid) {
 
-        cell.setStyle("-fx-border-color: black; -fx-border-width: 1 1 0 0;");
+        for(Cage cage : cages) {
+            cage.getCells().get(0).setStyle("-fx-border-color: black; -fx-border-width: 2 2 2 2;");
 
-        if(j == 0) {
-            cell.setStyle("-fx-border-color: black; -fx-border-width: 1 1 0 1;");
-        }
-        if(i == getN() - 1 && j == 0) {
-            cell.setStyle("-fx-border-color: black; -fx-border-width: 1 1 1 1;");
-        }
-        if( i == getN() - 1 && j != 0) {
-            cell.setStyle("-fx-border-color: black; -fx-border-width: 1 1 1 0;");
+            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;");
+                    }
+                }
+
+                doubleClick(cell);
+                memoriseValues(cell);
+                grid.add(cell, cell.getColumn(), cell.getRow(), 1, 1);
+            }
         }
     }
 
@@ -162,6 +242,8 @@ public class Handler {
                         CornerRadii.EMPTY, Insets.EMPTY)));
             }
         }
+        undoStack.root = null;
+        redoStack.root = null;
     }
 
     public void setTransparent(GridPane grid) {
@@ -186,7 +268,10 @@ public class Handler {
                     }
                 }
             }
+        }
 
+        for(Cage cage : cages) {
+            highlightCage(cage);
         }
     }
 
@@ -239,6 +324,78 @@ public class Handler {
         return false;
     }
 
+    public boolean verifyCages() {
+
+        for(Cage cage : cages) {
+            if(!verifyCage(cage)) {
+                return false;
+            }
+        }
+        return true;
+    }
+
+    public boolean verifyCage(Cage cage) {
+        boolean isCorrect = true;
+
+        if(cage.isCompleted()) {
+            if(!cage.hasSymbol()) {
+                if(Integer.parseInt(cage.getCells().get(0).getTextField().getText()) != Integer.parseInt(cage.getResult()) &&
+                        Integer.parseInt(cage.getCells().get(0).getTextField().getText()) != 0) {
+                    isCorrect = false;
+                }
+            } else if(cage.getSymbol() == '+' && !verifySum(cage)) {
+                isCorrect = false;
+            } else if((cage.getSymbol() == 'x' || cage.getSymbol() == '*') && !verifyProduct(cage)) {
+                isCorrect = false;
+            } else if(cage.getSymbol() == '-' && !verifySubtraction(cage)) {
+                isCorrect = false;
+            } else if((cage.getSymbol() == '/' || cage.getSymbol() == '÷') && !verifyDivision(cage)) {
+                isCorrect = false;
+            }
+        }
+
+        return isCorrect;
+    }
+
+    public boolean verifySum(Cage cage) {
+        int sum = 0;
+        for(Cell cell : cage.getCells()) {
+            sum = sum + Integer.parseInt(cell.getTextField().getText());
+        }
+        return (sum == Integer.parseInt(cage.getResult()));
+    }
+
+    public boolean verifyProduct(Cage cage) {
+        int product = 1;
+        for(Cell cell : cage.getCells()) {
+            product = product * Integer.parseInt(cell.getTextField().getText());
+        }
+        return ((product == Integer.parseInt(cage.getResult())));
+    }
+
+    public boolean verifySubtraction(Cage cage) {
+        int x = cage.getValues()[0];
+        System.out.println();
+        System.out.println(x);
+        for(int i = 1; i < cage.getValues().length; i ++) {
+            x = x - cage.getValues()[i];
+            System.out.println(x);
+        }
+        return (x == Integer.parseInt(cage.getResult()));
+    }
+
+    public boolean verifyDivision(Cage cage) {
+        int x = cage.getValues()[0];
+        for(int i = 1; i < cage.getValues().length; i ++) {
+            if(x % cage.getValues()[i] == 0) {
+                x = x / cage.getValues()[i];
+            } else {
+                return false;
+            }
+        }
+        return (x == Integer.parseInt(cage.getResult()));
+    }
+
     public void highlightRow(int row, GridPane grid, boolean highlight) {
 
         if(highlight) {
@@ -252,7 +409,6 @@ public class Handler {
                         CornerRadii.EMPTY, Insets.EMPTY)));
             }
         }
-
     }
 
     public void highlightColumn(int column, GridPane grid, boolean highlight) {
@@ -270,6 +426,16 @@ public class Handler {
         }
     }
 
+    public void highlightCage(Cage cage) {
+
+        if(!verifyCage(cage)) {
+            for(Cell cell : cage.getCells()) {
+                cell.setBackground(new Background(new BackgroundFill(Color.RED,
+                        CornerRadii.EMPTY, Insets.EMPTY)));
+            }
+        }
+    }
+
     public Cell getCell(GridPane grid, int i, int j) {
         for(Node cell : grid.getChildren()) {
             if(((Cell) cell).getRow() == i && ((Cell) cell).getColumn() == j) {
@@ -283,12 +449,8 @@ public class Handler {
         return cellValues;
     }
 
-    public int getN() {
-        return n;
-    }
-
     public void setN(int n) {
         this.n = n;
     }
-
 }
+
diff --git a/UndoRedo.java b/UndoRedo.java
new file mode 100644
index 0000000..0e86438
--- /dev/null
+++ b/UndoRedo.java
@@ -0,0 +1,46 @@
+
+public class UndoRedo {
+
+    StackNode root;
+
+    private class StackNode {
+        Element e;
+        StackNode next;
+
+        StackNode(Element e) {
+            this.e = e;
+        }
+    }
+
+    public boolean isEmpty() {
+        if(root == null) {
+            return true;
+        } else {
+            return false;
+        }
+    }
+
+    public void push(Element e) {
+        StackNode newNode = new StackNode(e);
+
+        if(root == null) {
+            root = newNode;
+        } else {
+            StackNode temp = root;
+            root = newNode;
+            newNode.next = temp;
+        }
+    }
+
+    public Element pop() {
+
+        if(isEmpty()) {
+            return null;
+        } else {
+            Element e = root.e;
+            root = root.next;
+            return e;
+        }
+    }
+
+}
diff --git a/Window.java b/Window.java
index 4482a53..c6033b1 100644
--- a/Window.java
+++ b/Window.java
@@ -4,15 +4,24 @@ import javafx.geometry.Insets;
 import javafx.geometry.Pos;
 import javafx.scene.Scene;
 import javafx.scene.control.*;
+import javafx.scene.layout.GridPane;
+import javafx.scene.layout.HBox;
 import javafx.scene.layout.VBox;
 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;
+
 public class Window {
 
-    public void showButtons(Cell cell, int n) {
+    static int n;
+
+    public void showButtons(Cell cell) {
 
         VBox menu = new VBox(10);
         menu.setPadding(new Insets(10));
@@ -118,9 +127,70 @@ public class Window {
         alert.setX(800);
         alert.setY(400);
         alert.setTitle("Confirmation of Action");
-        //alert.setHeaderText("Are you sure you want to clear the board?");
-        //alert.setContentText("Be aware that all your data will be cleared.");
 
         return alert;
     }
+
+    public Stage mathdokuStage(int n, ArrayList<Cage> cages) {
+
+        this.n = n;
+
+        Handler handler = new Handler(n, cages);
+        handler.setN(n);
+        Stage stage = new Stage();
+
+        VBox root = new VBox(5);
+        root.setAlignment(Pos.CENTER);
+        root.setPadding(new Insets(20));
+
+        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));
+
+        Button undo = new Button("Undo");
+        Button redo = new Button("Redo");
+        Button help = new Button("Enable Help");
+        Button clear = new Button("Clear");
+
+        undo.setDisable(true);
+        redo.setDisable(true);
+
+        handler.helpButton(help, grid);
+        handler.clearBoard(clear, grid, undo, redo);
+        handler.undoAction(undo, redo, grid);
+        handler.redoAction(redo, grid);
+
+        buttons.getChildren().addAll(undo, redo, help, clear);
+
+        handler.drawGrid(grid);
+
+        handler.addActions(grid, undo);
+
+        Label note = new Label("Double click the space provided for text in cell");
+        Button submit = new Button("Submit");
+
+        handler.submitButton(submit);
+
+        root.getChildren().addAll(buttons, grid, sizes, note, submit);
+
+        Scene scene = new Scene(root);
+        stage.setScene(scene);
+
+        stage.setTitle("Mathdoku");
+        stage.initStyle(StageStyle.DECORATED);
+
+        stage.setX(800);
+        stage.setY(300);
+
+        stage.setMinHeight(600);
+        stage.setMinWidth(500);
+
+        return stage;
+    }
 }
-- 
GitLab