diff --git a/bin/coursework/Cage.class b/bin/coursework/Cage.class index 35378411b02a029b9347a545d98c2226b59dd351..cf42078f2a031fef67fad643a5262c83393bbbda 100644 Binary files a/bin/coursework/Cage.class and b/bin/coursework/Cage.class differ diff --git a/bin/coursework/Main.class b/bin/coursework/Main.class index ae468b9521fc5d9f39ff9b1a989129e7ce984656..50b401ba1f7cfe454d8d9798e6a8f2ef4f8247e8 100644 Binary files a/bin/coursework/Main.class and b/bin/coursework/Main.class differ diff --git a/bin/coursework/Square.class b/bin/coursework/Square.class index ef7b1b6f1ab6cf0ef440306e32c5b7b42af133f4..d244d5b2579894b681036730669ad911a3c75bf4 100644 Binary files a/bin/coursework/Square.class and b/bin/coursework/Square.class differ diff --git a/src/coursework/Cage.java b/src/coursework/Cage.java index c8db9610eaca3a1f16092739da60b20ab877fd15..ac9a83f5abb1a1431a981817852c3889ccf6fe9c 100644 --- a/src/coursework/Cage.java +++ b/src/coursework/Cage.java @@ -1,8 +1,12 @@ package coursework; +import java.util.ArrayList; import java.util.Arrays; +import java.util.Collections; +import java.util.List; import javafx.scene.control.Label; +import javafx.scene.control.TextField; import javafx.scene.paint.Color; public class Cage { @@ -11,16 +15,116 @@ public class Cage { private int value; private String operator; private Square[] gridSquares; - private Label[][] cageLabels; + private TextField[] gridNumbers; + private Label[] cageLabels; public Cage(int[] squareIds, int value, String operator) { this.squareIds = squareIds; this.value = value; this.operator = operator; this.gridSquares = Main.getGridSquares(); + this.gridNumbers = Main.getGridNumbers(); this.cageLabels = Main.getCageLabels(); buildCage(); setCageInfo(); + setSquareCages(); + } + + private boolean plusOperator() { + String gridValue; + int cageVal = 0; + for (int id : squareIds) { + gridValue = gridNumbers[id].getText(); + if (!gridValue.equals("")) { + cageVal += Integer.parseInt(gridValue); + } + else { + return false; + } + } + if (cageVal == value) { + return false; + } + return true; + } + + private boolean multiplyOperator() { + String gridValue; + int cageVal = 1; + for (int id : squareIds) { + gridValue = gridNumbers[id].getText(); + if (!gridValue.equals("")) { + cageVal *= Integer.parseInt(gridValue); + } + else { + return false; + } + } + if (cageVal == value) { + return false; + } + return true; + } + + private boolean subtractOperator() { + String gridValue; + List<Integer> sortedCageValues = new ArrayList<Integer>(); + for (int id : squareIds) { + gridValue = gridNumbers[id].getText(); + if (gridValue.equals("")) { + return true; + } + else { + sortedCageValues.add(Integer.parseInt(gridValue)); + } + } + Collections.sort(sortedCageValues); + int cageVal = sortedCageValues.get(0); + for (int i = 1; i < sortedCageValues.size() - 1; i++) { + cageVal -= sortedCageValues.get(i); + } + if (cageVal == value) { + return false; + } + return true; + } + + private boolean divideOperator() { + String gridValue; + List<Integer> sortedCageValues = new ArrayList<Integer>(); + for (int id : squareIds) { + gridValue = gridNumbers[id].getText(); + if (gridValue.equals("")) { + return true; + } + else { + sortedCageValues.add(Integer.parseInt(gridValue)); + } + } + Collections.sort(sortedCageValues); + int cageVal = sortedCageValues.get(0); + for (int i = 1; i < sortedCageValues.size() - 1; i++) { + cageVal /= sortedCageValues.get(i); + } + if (cageVal == value) { + return false; + } + return true; + } + + public boolean checkCageValues() { + switch (operator) { + case "+": + return plusOperator(); + case "x": + return multiplyOperator(); + case "-": + return subtractOperator(); + case "�": + return divideOperator(); + default: + return false; + } } public void buildCage() { @@ -39,16 +143,16 @@ public class Cage { final double WIDTH = 2; if (rowDiff == -1 && colDiff == 0) { - gridSquares[aCoord[0]*Main.N + aCoord[1]].setRightStroke(WIDTH, Color.LIGHTGREY); + gridSquares[aCoord[0]*Main.N + aCoord[1]].setRightStroke(WIDTH, Color.GREY); } else if (rowDiff == 1 && colDiff == 0) { - gridSquares[aCoord[0]*Main.N + aCoord[1]].setLeftStroke(WIDTH, Color.LIGHTGREY); + gridSquares[aCoord[0]*Main.N + aCoord[1]].setLeftStroke(WIDTH, Color.GREY); } else if (rowDiff == 0 && colDiff == -1) { - gridSquares[aCoord[0]*Main.N + aCoord[1]].setBottomStroke(WIDTH, Color.LIGHTGREY); + gridSquares[aCoord[0]*Main.N + aCoord[1]].setBottomStroke(WIDTH, Color.GREY); } else if (rowDiff == 0 && colDiff == 1) { - gridSquares[aCoord[0]*Main.N + aCoord[1]].setTopStroke(WIDTH, Color.LIGHTGREY); + gridSquares[aCoord[0]*Main.N + aCoord[1]].setTopStroke(WIDTH, Color.GREY); } } } @@ -59,9 +163,7 @@ public class Cage { if (squareIds.length > 1) Arrays.sort(squareIds); int minVal = squareIds[0]; - cageLabels[minVal][0].setText(value + " " + operator); - cageLabels[minVal][1].setText(value + " " + operator); - cageLabels[minVal][1].setVisible(false); + cageLabels[minVal].setText(value + operator); } public static int[] idToCoord(int id) { @@ -69,5 +171,15 @@ public class Cage { int col = id % Main.N; return new int[] {row, col}; } + + public void setSquareCages() { + for (Square square : gridSquares) { + square.setCage(this); + } + } + + public int[] getCageIds() { + return squareIds; + } } \ No newline at end of file diff --git a/src/coursework/Main.java b/src/coursework/Main.java index 09e4417febc640fbc39d1e558bd925292c41d6c0..e068d7c2648b683a2aa59e42609542dd9d034520 100644 --- a/src/coursework/Main.java +++ b/src/coursework/Main.java @@ -6,6 +6,7 @@ import java.io.FileNotFoundException; import java.io.FileReader; import java.io.IOException; import java.util.ArrayList; +import java.util.HashSet; import java.util.List; import java.util.Stack; import java.util.Vector; @@ -53,18 +54,19 @@ public class Main extends Application { 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 static TextField[] gridNumbers = new TextField[N*N]; + private static Label[] cageLabels = new Label[N*N]; private boolean[][] highlightedError = new boolean[N*N][3]; - private HBox[] gridHBoxes = new HBox[N*N]; + private VBox[] gridBoxes = new VBox[N*N]; private List<Cage> gridCages = new ArrayList<Cage>(); private boolean isWider; - private HBox previousHBox = null; + private Pane previousPane = null; private Square previousSquare = null; private boolean clearing = false; private boolean undoing = false; private boolean showMistakes = false; + private int fontSize; private Stack<GameState> undoStack = new Stack<GameState>(); private Stack<GameState> redoStack = new Stack<GameState>(); @@ -88,14 +90,18 @@ public class Main extends Application { private GridPane addToGridPane(GridPane gridPane, double size, int i, int j) { Square square = setupGridSquare(size); TextField textField = setupGridTextField(size); - HBox hbox = setupGridHBox(square, textField, i, j); + HBox hbox = new HBox(textField); + hbox.setAlignment(Pos.CENTER); + VBox vbox = setupGridVBox(square, i, j); + GridPane.setMargin(vbox, new Insets(2)); Group group = square.getGroup(); gridSquares[i*N + j] = square; gridNumbers[i*N + j] = textField; - + gridPane.add(group, j, i); gridPane.add(hbox, j, i); + gridPane.add(vbox, j, i); textField.textProperty().addListener((observable, oldValue, newValue) -> { if (!clearing && !undoing) { @@ -104,43 +110,71 @@ public class Main extends Application { undoButton.setDisable(false); } } - checkConstraints(textField, j, i); + checkConstraints(j, i); }); square.getRectangle().toFront(); return gridPane; } - private void checkConstraints(TextField textField, int col, int row) { - String value = textField.getText(); - boolean found = false; + private void checkConstraints(int col, int row) { + columnConstraint(row, col); + rowConstraint(row, col); + highlightCells(); + } + + private void rowConstraint(int row, int col) { + boolean repeat = false; + HashSet<String> rowValues = new HashSet<String>(); + String number; 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; - } + number = gridNumbers[row*N + i].getText(); + if (rowValues.contains(number) && !number.equals("")) { + repeat = true; + } + else { + rowValues.add(number); } } - if (!found) { + + if (!repeat) { clearRow(row); } - - found = false; + else { + highlightRow(row); + } + } + + private void columnConstraint(int row, int col) { + boolean repeat = false; + HashSet<String> colValues = new HashSet<String>(); + String number; 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; - } + number = gridNumbers[i*N + col].getText(); + if (colValues.contains(number) && !number.equals("")) { + repeat = true; + } + else { + colValues.add(number); } } - if (!found) { + + if (!repeat) { clearColumn(col); } - highlightCells(); + else { + highlightColumn(col); + } + } + + private void cageConstraint(int row, int col) { + if (gridCages.size() > 0) { + Cage cage = gridSquares[row*N + col].getCage(); + boolean cageConstraintsValue = cage.checkCageValues(); + for (int id : cage.getCageIds()) { + highlightedError[id][2] = cageConstraintsValue; + } + } } private void clearRow(int row) { @@ -170,51 +204,47 @@ public class Main extends Application { 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);"); + gridBoxes[i].setStyle("-fx-background-color: rgba(255,0,0,0.5);"); } else { - gridHBoxes[i].setStyle("-fx-background-color: rgba(255,0,20,0);"); + gridBoxes[i].setStyle("-fx-background-color: rgba(255,0,0,0);"); } } } - private HBox setupGridHBox(Square square, TextField textField, int i, int j) { - HBox hbox = new HBox(); + private VBox setupGridVBox(Square square, int i, int j) { VBox vbox = new VBox(); Label cageInfoLabel = new Label(""); - Label balanceLabel = new Label(""); - cageLabels[i*N + j][0] = cageInfoLabel; - cageLabels[i*N + j][1] = balanceLabel; + cageLabels[i*N + j] = cageInfoLabel; - vbox.getChildren().addAll(cageInfoLabel, textField, balanceLabel); - vbox.setAlignment(Pos.CENTER); - hbox.getChildren().add(vbox); - hbox.setAlignment(Pos.CENTER); - gridHBoxes[i*N + j] = hbox; - hboxClickSquareEvent(i, j, square); + vbox.getChildren().addAll(cageInfoLabel); + vbox.setStyle("-fx-border-width: 0px;"); + vbox.setPadding(new Insets(5)); + gridBoxes[i*N + j] = vbox; + paneClickSquareEvent(i, j, square); - return hbox; + return vbox; } private Square setupGridSquare(double size) { + final double WIDTH = 3; Square square = new Square(size); - square.setTopStroke(3, Color.BLACK); - square.setBottomStroke(3, Color.BLACK); - square.setLeftStroke(3, Color.BLACK); - square.setRightStroke(3, Color.BLACK); + square.setTopStroke(WIDTH, Color.BLACK); + square.setBottomStroke(WIDTH, Color.BLACK); + square.setLeftStroke(WIDTH, Color.BLACK); + square.setRightStroke(WIDTH, Color.BLACK); square.resizeLines(size); return square; } private TextField setupGridTextField(double size) { - final double PERCENT = 0.7; TextField textField = new TextField(); textField.setMinWidth(size/4); - textField.setPrefSize(size*PERCENT, size*PERCENT); + textField.setPrefSize(size*0.9, size*0.9); textField.setAlignment(Pos.CENTER); - textField.setStyle("-fx-focus-color: transparent;"); - textField.setStyle("-fx-text-box-border: transparent;"); + textField.setPadding(new Insets(5)); + textField.setStyle("-fx-focus-color: transparent; -fx-text-box-border: transparent; -fx-background-color: -fx-text-box-border, -fx-control-inner-background;"); return textField; } @@ -233,7 +263,6 @@ public class Main extends Application { showMistakesCheck.selectedProperty().addListener((obs, oldVal, newVal) -> { showMistakes = showMistakesCheck.isSelected(); - System.out.println(showMistakes + ", " + showMistakesCheck.isSelected()); highlightCells(); }); @@ -274,7 +303,8 @@ public class Main extends Application { int value = Integer.parseInt(splitLine[0].substring(0, splitLine[0].length()- 1)); String operator = splitLine[0].substring(splitLine[0].length() - 1); - new Cage(ids, value, operator); + Cage cage = new Cage(ids, value, operator); + gridCages.add(cage); } @@ -329,37 +359,36 @@ public class Main extends Application { return bottomHBox; } - private void hboxClickSquareEvent(int i, int j, Square square) { - gridHBoxes[i*N + j].addEventHandler(MouseEvent.MOUSE_CLICKED, e -> { - if (previousHBox != null) { - 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;"); + private void paneClickSquareEvent(int i, int j, Square square) { + gridBoxes[i*N + j].addEventHandler(MouseEvent.MOUSE_CLICKED, e -> { + if (previousPane != null) { + int previousIndex = getIndexOf(previousPane); + if ((highlightedError[previousIndex][0] || highlightedError[previousIndex][1] || highlightedError[previousIndex][2]) && showMistakes) { + previousPane.setStyle("-fx-background-color: rgba(255,0,20,0.5); -fx-border-width: 0px;"); } else { - previousHBox.setStyle("-fx-border-width:0px;"); + previousPane.setStyle("-fx-background-color: rgba(255,0,20,0); -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;"); + if ((highlightedError[i*N + j][0] || highlightedError[i*N + j][1] || highlightedError[i*N + j][2]) && showMistakes) { + gridBoxes[i*N + j].setStyle("-fx-border-color: #2309FB; -fx-border-width: 2px; -fx-background-color: rgba(255,0,0,0.3);"); } else { - gridHBoxes[i*N + j].setStyle("-fx-border-color: #0016CD; -fx-border-width:3px;"); + gridBoxes[i*N + j].setStyle("-fx-border-color: #2309FB; -fx-border-width: 2px; -fx-background-color: rgba(255,0,0,0);"); } - - previousHBox = gridHBoxes[i*N + j]; + previousPane = gridBoxes[i*N + j]; previousSquare = square; for (TextField textField : gridNumbers) { textField.deselect(); } + gridNumbers[i*N + j].requestFocus(); }); } - private int getIndexOf(HBox hbox) { + private int getIndexOf(Pane pane) { for (int i = 0; i < N*N; i++) { - if (hbox.equals(gridHBoxes[i])) { + if (pane.equals(gridBoxes[i])) { return i; } } @@ -441,6 +470,7 @@ public class Main extends Application { double fontSize = cellWidth * 0.4; button.setPrefSize(cellWidth, cellWidth); + button.setMaxSize(150, 150); button.setStyle("-fx-font-size:"+fontSize+"pt"); button.setOnAction(e -> { numbersButtonClickEvent(button); @@ -460,8 +490,79 @@ public class Main extends Application { } } } - else { - // Some message about selecting a cell first + } + + private HBox setupFontSizeHBox() { + HBox hbox = new HBox(); + Button minus = new Button("-"); + Button font12 = new Button("Tiny"); + Button font16 = new Button("Small"); + Button font20 = new Button("Medium"); + Button font24 = new Button("Large"); + Button font28 = new Button("Huge"); + Button plus = new Button("+"); + + plus.setStyle("-fx-font-size:28px;"); + plus.setOnAction(e -> { + changeFontSize(fontSize + 1, minus, plus); + }); + minus.setStyle("-fx-font-size:12px;"); + minus.setOnAction(e -> { + changeFontSize(fontSize - 1, minus, plus); + }); + + font12.setStyle("-fx-font-size:12px;"); + font12.setOnAction(e -> { + changeFontSize(12, minus, plus); + }); + + font16.setStyle("-fx-font-size:16px;"); + font16.setOnAction(e -> { + changeFontSize(16, minus, plus); + }); + + font20.setStyle("-fx-font-size:20px;"); + font20.setOnAction(e -> { + changeFontSize(20, minus, plus); + }); + + font24.setStyle("-fx-font-size:24px;"); + font24.setOnAction(e -> { + changeFontSize(24, minus, plus); + }); + + font28.setStyle("-fx-font-size:28px;"); + font28.setOnAction(e -> { + changeFontSize(28, minus, plus); + }); + + hbox.getChildren().addAll(minus, font12, font16, font20, font24, font28, plus); + hbox.setSpacing(10); + hbox.setAlignment(Pos.CENTER); + return hbox; + } + + private void changeFontSize(int size, Button minus, Button plus) { + fontSize = size; + for (TextField textField : gridNumbers) { + textField.setStyle("-fx-focus-color: transparent; -fx-text-box-border: transparent;" + + "-fx-background-color: -fx-text-box-border, -fx-control-inner-background;" + + "-fx-font-size:" + size + ";"); + } + for (Label label : cageLabels) { + label.setStyle("-fx-font-size:" + size + ";"); + } + if (fontSize == 10) { + minus.setDisable(true); + } + else if (fontSize > 10) { + minus.setDisable(false); + } + if (fontSize == 30) { + plus.setDisable(true); + } + else if (fontSize < 30) { + plus.setDisable(false); } } @@ -469,32 +570,38 @@ public class Main extends Application { return gridSquares; } - public static Label[][] getCageLabels() { + public static Label[] getCageLabels() { return cageLabels; } + public static TextField[] getGridNumbers() { + return gridNumbers; + } + @Override public void start(Stage stage) throws Exception { VBox vBox = new VBox(); - scene = new Scene(vBox,500 + 50*N,500 + 50*N); + scene = new Scene(vBox,400+50*N,450+50*N); vBox.setSpacing(10); - vBox.setPadding(new Insets(20, 20, 20, 20)); + vBox.setPadding(new Insets(20)); vBox.setAlignment(Pos.CENTER); GridPane gridPane = setupGrid(); undoStack.push(new GameState(GameState.getCurrentGameState(gridNumbers))); + fontSize = (int) gridNumbers[0].getFont().getSize(); + HBox fontSizeHBox = setupFontSizeHBox(); HBox topHBox = setupTopHBox(); HBox centerHBox = setupCenterHBox(); HBox bottomHBox = setupBottomHBox(); - vBox.getChildren().addAll(topHBox, gridPane, centerHBox, bottomHBox); + vBox.getChildren().addAll(topHBox, gridPane, centerHBox, bottomHBox, fontSizeHBox); stageWidthResizeEvent(stage, gridPane); stageHeightResizeEvent(stage, gridPane); - stage.setMinWidth(400 + 50*N); - stage.setMinHeight(400 + 50*N); + stage.setMinWidth(500 + 50*N); + stage.setMinHeight(500 + 50*(N+1)); stage.setScene(scene); stage.setTitle("Mathdoku"); stage.show(); diff --git a/src/coursework/Square.java b/src/coursework/Square.java index c44142484257f3bdd77e279b62de530ba3b096b8..8aa589af591cec3ae69a91b9651dcf7442707176 100644 --- a/src/coursework/Square.java +++ b/src/coursework/Square.java @@ -14,12 +14,21 @@ public class Square { private Line bottom; private Line left; private Group group = new Group(); + private Cage cage = null; public Square(double size) { this.size = size; draw(); } + public void setCage(Cage cage) { + this.cage = cage; + } + + public Cage getCage() { + return cage; + } + public void draw() { rectangle = new Rectangle(0, 0, size, size); rectangle.setFill(Color.WHITE);