diff --git a/bin/coursework/Main.class b/bin/coursework/Main.class index d732c086f0f50b0b91218527463bd8a5593b2706..ae468b9521fc5d9f39ff9b1a989129e7ce984656 100644 Binary files a/bin/coursework/Main.class and b/bin/coursework/Main.class differ diff --git a/src/coursework/Main.java b/src/coursework/Main.java index 417ce75c94aaefee20e8f1ccc113827571e366e3..09e4417febc640fbc39d1e558bd925292c41d6c0 100644 --- a/src/coursework/Main.java +++ b/src/coursework/Main.java @@ -5,6 +5,7 @@ import java.io.File; import java.io.FileNotFoundException; import java.io.FileReader; import java.io.IOException; +import java.util.ArrayList; import java.util.List; import java.util.Stack; import java.util.Vector; @@ -20,6 +21,7 @@ import javafx.scene.control.Alert; import javafx.scene.control.Alert.AlertType; import javafx.scene.control.Button; import javafx.scene.control.ButtonType; +import javafx.scene.control.CheckBox; import javafx.scene.control.Label; import javafx.scene.control.TextField; import javafx.scene.image.Image; @@ -44,18 +46,25 @@ import javafx.stage.Stage; public class Main extends Application { final static public int N = 6; + final private double GRID_PERCENTAGE = 0.75; private Scene scene; private Stage stage; - final private double GRID_PERCENTAGE = 0.75; + private static Square[] gridSquares = new Square[N*N]; private TextField[] gridNumbers = new TextField[N*N]; private static Label[][] cageLabels = new Label[N*N][2]; + private boolean[][] highlightedError = new boolean[N*N][3]; + private HBox[] gridHBoxes = new HBox[N*N]; + private List<Cage> gridCages = new ArrayList<Cage>(); + private boolean isWider; private HBox previousHBox = null; private Square previousSquare = null; private boolean clearing = false; + private boolean undoing = false; + private boolean showMistakes = false; private Stack<GameState> undoStack = new Stack<GameState>(); private Stack<GameState> redoStack = new Stack<GameState>(); @@ -89,18 +98,86 @@ public class Main extends Application { gridPane.add(hbox, j, i); textField.textProperty().addListener((observable, oldValue, newValue) -> { - if (!clearing) { + if (!clearing && !undoing) { undoStack.push(new GameState(GameState.getCurrentGameState(gridNumbers))); if (undoButton.isDisabled()) { undoButton.setDisable(false); } } + checkConstraints(textField, j, i); }); square.getRectangle().toFront(); return gridPane; } + private void checkConstraints(TextField textField, int col, int row) { + String value = textField.getText(); + boolean found = false; + for (int i = 0; i < N; i++) { + if (!gridNumbers[row*N + i].getText().equals("")) { + if (gridNumbers[row*N + i].getText().equals(value) && i != col) { + highlightRow(row); + found = true; + break; + } + } + } + if (!found) { + clearRow(row); + } + + found = false; + for (int i = 0; i < N; i++) { + if (!gridNumbers[i*N + col].getText().equals("")) { + if (gridNumbers[i*N + col].getText().equals(value) && i != row) { + highlightColumn(col); + found = true; + break; + } + } + } + if (!found) { + clearColumn(col); + } + highlightCells(); + } + + private void clearRow(int row) { + for (int i = 0; i < N; i++) { + highlightedError[row*N + i][0] = false; + } + } + + private void clearColumn(int col) { + for (int i = 0; i < N; i++) { + highlightedError[i*N + col][1] = false; + } + } + + private void highlightRow(int row) { + for (int i = 0; i < N; i++) { + highlightedError[row*N + i][0] = true; + } + } + + private void highlightColumn(int col) { + for (int i = 0; i < N; i++) { + highlightedError[i*N + col][1] = true; + } + } + + private void highlightCells() { + for (int i = 0; i < N*N; i++) { + if ((highlightedError[i][0] || highlightedError[i][1] || highlightedError[i][2]) && showMistakes) { + gridHBoxes[i].setStyle("-fx-background-color: rgba(255,0,20,0.4);"); + } + else { + gridHBoxes[i].setStyle("-fx-background-color: rgba(255,0,20,0);"); + } + } + } + private HBox setupGridHBox(Square square, TextField textField, int i, int j) { HBox hbox = new HBox(); VBox vbox = new VBox(); @@ -114,7 +191,8 @@ public class Main extends Application { vbox.setAlignment(Pos.CENTER); hbox.getChildren().add(vbox); hbox.setAlignment(Pos.CENTER); - hboxClickSquareEvent(hbox, square); + gridHBoxes[i*N + j] = hbox; + hboxClickSquareEvent(i, j, square); return hbox; } @@ -130,9 +208,10 @@ public class Main extends Application { } private TextField setupGridTextField(double size) { + final double PERCENT = 0.7; TextField textField = new TextField(); textField.setMinWidth(size/4); - textField.setPrefSize(size*0.5, size*0.5); + textField.setPrefSize(size*PERCENT, size*PERCENT); textField.setAlignment(Pos.CENTER); textField.setStyle("-fx-focus-color: transparent;"); textField.setStyle("-fx-text-box-border: transparent;"); @@ -145,12 +224,18 @@ public class Main extends Application { topHBox.setSpacing(10); Button loadGameFileButton = new Button("Load game - file"); - Button showMistakesButton = new Button("Show mistakes"); + CheckBox showMistakesCheck = new CheckBox("Show mistakes"); Button loadGameTextInputButton = new Button("Load game - text input"); loadGameFileButton.setPrefWidth(200); loadGameTextInputButton.setPrefWidth(loadGameFileButton.getPrefWidth()); - topHBox.getChildren().addAll(loadGameFileButton, showMistakesButton, loadGameTextInputButton); + topHBox.getChildren().addAll(loadGameFileButton, showMistakesCheck, loadGameTextInputButton); + + showMistakesCheck.selectedProperty().addListener((obs, oldVal, newVal) -> { + showMistakes = showMistakesCheck.isSelected(); + System.out.println(showMistakes + ", " + showMistakesCheck.isSelected()); + highlightCells(); + }); loadGameFileButton.setOnAction(e -> { try { @@ -196,8 +281,6 @@ public class Main extends Application { private void updateGameState(GameState gameState) { String[] gameValues = gameState.getGameState(); for (int i = 0; i < gridNumbers.length; i++) { -// if (!gridNumbers[i].getText().equals("") && gameValues.equals("")) -// System.out.println("Current: " + gridNumbers[i].getText() + ", Previous: " + textFields[i].getText()); gridNumbers[i].setText(gameValues[i]); } } @@ -211,24 +294,22 @@ public class Main extends Application { redoButton = new Button("", new ImageView(new Image("file:Images/redo_icon.png"))); Button clearButton = new Button("Clear"); undoButton.setOnAction(e -> { - // undoStack.pop() is the current GameState - + undoing = true; + redoStack.push(undoStack.pop()); updateGameState(undoStack.peek()); - // if (!redoStack.empty()) { redoButton.setDisable(false); } if (undoStack.size() == 1) { undoButton.setDisable(true); } + undoing = false; }); redoButton.setOnAction(e -> { GameState gameState = redoStack.pop(); updateGameState(gameState); - - undoStack.push(gameState); if (!undoStack.empty()) { undoButton.setDisable(false); @@ -248,13 +329,27 @@ public class Main extends Application { return bottomHBox; } - private void hboxClickSquareEvent(HBox hbox, Square square) { - hbox.addEventHandler(MouseEvent.MOUSE_CLICKED, e -> { + private void hboxClickSquareEvent(int i, int j, Square square) { + gridHBoxes[i*N + j].addEventHandler(MouseEvent.MOUSE_CLICKED, e -> { if (previousHBox != null) { - previousHBox.setStyle("-fx-border-width:0px;"); + int previousIndex = getIndexOf(previousHBox); + if (highlightedError[previousIndex][0] || highlightedError[previousIndex][1] || highlightedError[previousIndex][2]) { + previousHBox.setStyle("-fx-background-color: rgba(255,0,20,0.4); -fx-border-width:0px;"); + } + else { + previousHBox.setStyle("-fx-border-width:0px;"); + } + } + + if (highlightedError[i*N + j][0] || highlightedError[i*N + j][1] || highlightedError[i*N + j][2]) { + gridHBoxes[i*N + j].setStyle("-fx-background-color: rgba(255,0,20,0.4); -fx-border-color: #0016CD; -fx-border-width:3px;"); + } + else { + gridHBoxes[i*N + j].setStyle("-fx-border-color: #0016CD; -fx-border-width:3px;"); } - hbox.setStyle("-fx-border-color:red; -fx-border-width:2px;"); - previousHBox = hbox; + + + previousHBox = gridHBoxes[i*N + j]; previousSquare = square; for (TextField textField : gridNumbers) { textField.deselect(); @@ -262,23 +357,52 @@ public class Main extends Application { }); } + private int getIndexOf(HBox hbox) { + for (int i = 0; i < N*N; i++) { + if (hbox.equals(gridHBoxes[i])) { + return i; + } + } + return -1; + } + private void clearButtonClickEvent(Button clearButton) { clearButton.setOnAction(e -> { - clearing = true; - undoStack.push(new GameState(GameState.getCurrentGameState(gridNumbers))); - Alert alert = new Alert(AlertType.CONFIRMATION); - alert.setContentText("Are you sure you wish to clear the board?"); - alert.showAndWait().ifPresent(type -> { - if (type == ButtonType.OK) { - for (TextField textField : gridNumbers) { - textField.setText(""); + 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; + });; + clearing = false; + } + else { + Alert alert = new Alert(AlertType.WARNING); + alert.setContentText("Nothing to clear on the board."); + alert.setTitle("Empty Board"); + alert.showAndWait(); + } }); } + private boolean lastOperationClear() { + GameState gameState = undoStack.peek(); + boolean emptyGrid = true; + for (String textFieldValue : gameState.getGameState()) { + if (textFieldValue.length() > 0) { + emptyGrid = false; + } + } + return emptyGrid; + } + private void stageWidthResizeEvent(Stage stage, GridPane gridPane) { stage.widthProperty().addListener((obs, oldVal, newVal) -> { if (newVal.doubleValue() < stage.getHeight()) {