import javafx.beans.value.ChangeListener; import javafx.beans.value.ObservableValue; import javafx.event.ActionEvent; import javafx.event.EventHandler; import javafx.geometry.Insets; import javafx.scene.Node; import javafx.scene.control.Button; import javafx.scene.control.ButtonType; import javafx.scene.input.MouseButton; import javafx.scene.input.MouseEvent; import javafx.scene.layout.Background; import javafx.scene.layout.BackgroundFill; 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; 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) { help.setOnAction(new EventHandler<ActionEvent>() { @Override public void handle(ActionEvent actionEvent) { if(help.getText().equals("Enable Help")) { help.setText("Disable Help"); highlight(grid); for(Node cell : grid.getChildren()) { enableHighlight((Cell) cell, grid); } } else { help.setText("Enable Help"); setTransparent(grid); for(Node cell : grid.getChildren()) { disableHighlight((Cell) cell, grid); } } } }); } public void submitButton(Button submit) { submit.setOnAction(new EventHandler<ActionEvent>() { @Override public void handle(ActionEvent actionEvent) { for(int i = 0; i < n; i ++) { for(int j = 0; j < n; j ++) { System.out.print(getCellValues()[i][j]); } System.out.println(); } 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"); } } }); } 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 -> { 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); } } } }); } public void memoriseValues(Cell cell) { cell.getTextField().textProperty().addListener(new ChangeListener<String>() { @Override public void changed(ObservableValue<? extends String> observableValue, String oldValue, String newValue) { if (cell.isNumeric(newValue)) { 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; } } }); } public void enableHighlight(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); highlight(grid); } }); } 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 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;"); } } doubleClick(cell); memoriseValues(cell); grid.add(cell, cell.getColumn(), cell.getRow(), 1, 1); } } } public void clear(GridPane grid) { for(int i =0; i < n; i ++) { for(int j = 0; j < n; j ++) { cellValues[i][j] = 0; getCell(grid, i, j).getTextField().clear(); getCell(grid, i, j).setBackground(new Background(new BackgroundFill(Color.TRANSPARENT, CornerRadii.EMPTY, Insets.EMPTY))); } } undoStack.root = null; redoStack.root = null; } public void setTransparent(GridPane grid) { for(Node cell : grid.getChildren()) { ((Cell) cell).setBackground(new Background(new BackgroundFill(Color.TRANSPARENT, CornerRadii.EMPTY, Insets.EMPTY))); } } public void highlight(GridPane grid) { for(int i = 0; i < n; i ++) { for(int j = 0; j < n; j ++) { if(cellValues[i][j] != 0) { if(!verifyRow(cellValues[i][j], i)) { highlightRow(i, grid, true); } if(!verifyColumn(cellValues[i][j], j)) { highlightColumn(j, grid, true); } } } } for(Cage cage : cages) { highlightCage(cage); } } public boolean verify() { for(int i = 0; i < n; i ++) { for(int j = 0; j < n; j ++) { if(cellValues[i][j] !=0 ) { if(verifyRow(cellValues[i][j], i) == false || verifyColumn(cellValues[i][j], j) == false) { System.out.println(cellValues[i][j] + " " + i + " " + j); return false; } } } } return true; } public boolean verifyRow(int x, int row) { int count = 0; for(int i = 0; i < n; i ++) { if(cellValues[row][i] == x) { count++; } } if(count == 1) { return true; } return false; } public boolean verifyColumn(int x, int column) { int count = 0; for(int i = 0; i < n; i ++) { if(cellValues[i][column] == x) { count++; } } if(count == 1) { return true; } 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) { for(int i = 0; i < n; i ++) { getCell(grid, row, i).setBackground(new Background(new BackgroundFill(Color.YELLOW, CornerRadii.EMPTY, Insets.EMPTY))); } } else { for(int i = 0; i < n; i ++) { getCell(grid, row, i).setBackground(new Background(new BackgroundFill(Color.TRANSPARENT, CornerRadii.EMPTY, Insets.EMPTY))); } } } public void highlightColumn(int column, GridPane grid, boolean highlight) { if(highlight) { for(int i = 0; i < n; i ++) { getCell(grid, i, column).setBackground(new Background(new BackgroundFill(Color.YELLOW, CornerRadii.EMPTY, Insets.EMPTY))); } } else { for(int i = 0; i < n; i ++) { getCell(grid, i, column).setBackground(new Background(new BackgroundFill(Color.TRANSPARENT, CornerRadii.EMPTY, Insets.EMPTY))); } } } 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) { return (Cell) cell; } } return null; } public int[][] getCellValues() { return cellValues; } public void setN(int n) { this.n = n; } }