diff --git a/src/com/patryk/mathdoku/CageData.java b/src/com/patryk/mathdoku/CageData.java deleted file mode 100644 index c433a0b529e4aa6564c11db809181d9337debd64..0000000000000000000000000000000000000000 --- a/src/com/patryk/mathdoku/CageData.java +++ /dev/null @@ -1,112 +0,0 @@ -package com.patryk.mathdoku; - -import com.patryk.mathdoku.global.BoardPosVec; - -import java.io.File; -import java.io.IOException; -import java.util.ArrayList; -import java.util.List; -import java.util.Scanner; - - -public class CageData { - int width; - - Cell[] data; - List<Cage> cageList = new ArrayList<Cage>(); - int cageCount; - - static CageData instance; - - //todo maybe make rest of the code like this? - public static CageData me() { - return instance; - } - - //always called - private CageData(int width) { - instance = this; - this.width = width; - data = new Cell[width * width]; - } - - public CageData(String fileName, int width) throws IOException{ - this(width); - readFromFile(fileName); - } - - public List<Cage> getCages() {return cageList; } - - public boolean cellConnectsTo(BoardPosVec pos, Util.Direction direction) { - - Cell nextCell = getCellAt(pos.add(direction.vector)); - if (nextCell == null) { - return false; - } - - return getCellAt(pos).getCageId() == nextCell.getCageId(); - -} - - //util methods - - private void readFromFile(String fileName) throws IOException{ - - - CageParser parser = new CageParser(data); - Scanner scanner = new Scanner(new File(fileName)); - - String line; - int cageId = 0; - while (scanner.hasNextLine()) { - /*take a line that represents each cage, create cage with target, sign, display cell - and create the cells with that cage in the right positions - */ - line = scanner.nextLine(); - - cageList.add(parser.parse(line, cageId)); - cageId++; - } - - cageCount = cageId; - - } - - - public int getWidth() { - return width; - } - - private Cell getCellAt(BoardPosVec posVec) { - if (!posVec.isValid()) { - return null; - } - return data[posVec.toIndex()]; - } - - //TODO move to parent class BoardData - public int getValueAtCell(BoardPosVec cell) { - return data[cell.toIndex()].getCageId(); - } - - //TODO IMPLE - public int getCageCount() { - return cageCount; - } - - //todo - /*public Cage getCage(int i) { - todo impl; - }*/ -} - -class Cell { - private int cageID; - - public Cell (int cageID) { - this.cageID = cageID; - } - - public int getCageId() {return cageID; } -} - diff --git a/src/com/patryk/mathdoku/CageParser.java b/src/com/patryk/mathdoku/CageParser.java deleted file mode 100644 index df8cd977ca208ca335aa329e3d16476d8ad2c941..0000000000000000000000000000000000000000 --- a/src/com/patryk/mathdoku/CageParser.java +++ /dev/null @@ -1,54 +0,0 @@ -package com.patryk.mathdoku; - -import java.util.ArrayList; - -public class CageParser { - Cell[] data; - - MatcherHelper targetAndSign = new MatcherHelper( "(\\d+)(.) "); - MatcherHelper cageMember = new MatcherHelper("(\\d+)"); - - public CageParser(Cell[] data) { - this.data = data; - } - - public Cage parse(String cageLine, int cageID) { - - //make the matchers be of this particular cage - targetAndSign.initMatcher(cageLine); - cageMember.initMatcher(cageLine); - - //extract target and sign - targetAndSign.matcher.find(); - int target = Integer.parseInt(targetAndSign.matcher.group(1)); - char sign = targetAndSign.matcher.group(2).charAt(0); - - //System.out.printf("Target is %d and sign is %c.\n", target, sign); - - //extract first occurence of cage member cell - cageMember.matcher.find(targetAndSign.matcher.end()); - - boolean isFirstCell = true; - int markedCellId = 0; - - //for every cage member cell, instantiate that cell with this cage id - ArrayList<Integer> cageMembers = new ArrayList<>(); - do { - // - int cageCellId = Integer.parseInt(cageMember.matcher.group(0)) - 1; - data[cageCellId] = new Cell(cageID); - cageMembers.add(cageCellId); - //additionally, if it is the first cell, make that cage have this cell - if (isFirstCell) { - markedCellId = cageCellId; - isFirstCell = false; - } - - } while (cageMember.matcher.find()); - - //finally, instantiate the cage and return it - return new Cage(target, Cage.Operator.fromChar(sign), markedCellId, cageMembers); - - } - -} diff --git a/src/com/patryk/mathdoku/GameContext.java b/src/com/patryk/mathdoku/GameContext.java index d15f2755c1fa09cf0dc8ac15a9e75b3b62907b8c..dc858ca46e35f6f0ef08448e3e6089df607dc20b 100644 --- a/src/com/patryk/mathdoku/GameContext.java +++ b/src/com/patryk/mathdoku/GameContext.java @@ -1,27 +1,21 @@ package com.patryk.mathdoku; -import com.patryk.mathdoku.actions.Action; -import com.patryk.mathdoku.actions.CellValueChangeAction; -import com.patryk.mathdoku.actions.ClearAction; -//todo -//import com.patryk.mathdoku.errorChecking.GridErrorChecker; -import com.patryk.mathdoku.errorChecking.GridErrorChecker; -import com.patryk.mathdoku.global.BoardPosVec; - -import java.io.BufferedWriter; -import java.io.FileWriter; -import java.io.IOException; +import com.patryk.mathdoku.actions.*; +import com.patryk.mathdoku.cageData.CageData; +import com.patryk.mathdoku.cageData.DataFormatException; +import com.patryk.mathdoku.errorChecking.UserErrorChecker; +import com.patryk.mathdoku.util.BoardPosVec; /** * Represents one status of the playing of the game e.g. the cage data, what the user has entered */ public class GameContext { - private static GameContext activeContext; + private int boardWidth; - CageData cageData; - UserData userData; - GridErrorChecker gridErrorChecker; + private CageData cageData; + private UserData userData; + private UserErrorChecker userErrorChecker; StackActionRecorder<Action> actionRecorder; @@ -29,40 +23,30 @@ public class GameContext { return actionRecorder; } - private int boardWidth; - - public static GameContext me() { - return activeContext; - } - - //todo UserData.ChangeListener updateErrorState = (UserData.ChangeListener.ChangeData changeData) -> { - gridErrorChecker.onGridChange(changeData); - if (userData.isFull() && gridErrorChecker.noErrors()) { - System.out.println("Game won"); - userData.saveToFile("winning.txt"); - } + userErrorChecker.onGridChange(changeData); }; - - //TODO improve this exception choice - public GameContext(String cageDataFilePath, int boardWidth) throws IOException { - this.boardWidth = boardWidth; + public GameContext(String data) throws DataFormatException { + cageData = new CageData(data); + this.boardWidth = cageData.getWidth(); BoardPosVec.setBoardWidth(boardWidth); - cageData = new CageData(cageDataFilePath, boardWidth); + Action.setGameContext(this); userData = new UserData(boardWidth); - actionRecorder = new StackActionRecorder(5); + actionRecorder = new StackActionRecorder<>(5); //userData.fill(); - gridErrorChecker = new GridErrorChecker(boardWidth, userData, cageData); + userErrorChecker = new UserErrorChecker(boardWidth, userData, cageData); userData.addChangeListener(updateErrorState); } + + public CageData getCageData() { return cageData; } @@ -89,12 +73,8 @@ public class GameContext { } - public void setActive() { - GameContext.activeContext = this; - } - - public static int getBoardWidth() { - return GameContext.me().boardWidth; + public int getBoardWidth() { + return boardWidth; } public void undo() { @@ -106,7 +86,19 @@ public class GameContext { UndoRedoButtonManager.me().onRedoButtonPressed(); } - public GridErrorChecker getErrorChecker() { - return gridErrorChecker; + + public UserErrorChecker getErrorChecker() { + return userErrorChecker; + } + + + public boolean isWon() { + if (userData.isFull()) { + if (userErrorChecker.noErrors()) { + return true; + } + } + + return false; } } \ No newline at end of file diff --git a/src/com/patryk/mathdoku/GameDimensions.java b/src/com/patryk/mathdoku/GameDimensions.java deleted file mode 100644 index c7ebbab5bf46f1b21d0109b63519ff9e49bb8ef1..0000000000000000000000000000000000000000 --- a/src/com/patryk/mathdoku/GameDimensions.java +++ /dev/null @@ -1,15 +0,0 @@ -package com.patryk.mathdoku; - -public class GameDimensions { - public int pixelWidth; - public int boardWidth; - - public int getPixelWidth() { - return pixelWidth; - } - - public int getSquarePixelWidth() { - return pixelWidth / boardWidth; - } - -} diff --git a/src/com/patryk/mathdoku/GameGridView.java b/src/com/patryk/mathdoku/GameGridView.java deleted file mode 100644 index 53fa89718fbec4b6bde3a05cdc947eb9740c17fb..0000000000000000000000000000000000000000 --- a/src/com/patryk/mathdoku/GameGridView.java +++ /dev/null @@ -1,237 +0,0 @@ -package com.patryk.mathdoku; - -import com.patryk.mathdoku.drawers.CageDrawer; -import com.patryk.mathdoku.drawers.Drawer; -import com.patryk.mathdoku.drawers.SelectedCellDrawer; -import com.patryk.mathdoku.drawers.UserDataDrawer; -import com.patryk.mathdoku.errorChecking.ErrorShower; -import com.patryk.mathdoku.global.BoardPosVec; -import javafx.event.EventHandler; -import javafx.scene.Group; -import javafx.scene.Node; -import javafx.scene.canvas.Canvas; -import javafx.scene.input.KeyEvent; -import javafx.scene.input.MouseEvent; - - -public class GameGridView { - private static int pixelWidth= 600; - - private CageDrawer cageDrawer; - private SelectedCellDrawer selectedCellDrawer; - private UserDataDrawer userDataDrawer; - private ErrorsHighlighter errorHighlighter; - - Canvas cageCanvas; - Canvas selectedCellCanvas; - Canvas userNumbersCanvas; - Canvas errorCanvas; - - Group group; - - InputHandler inputHandler = new InputHandler(this); - - private GameContext gameContext; - BoardPosVec selectedCell = new BoardPosVec(0, 0); - - ErrorShower errorCallback; - public GameGridView(GameContext gameContext) { - - //create canvases - cageCanvas = new Canvas(pixelWidth, pixelWidth); - selectedCellCanvas = new Canvas(pixelWidth, pixelWidth); - userNumbersCanvas = new Canvas(pixelWidth, pixelWidth); - errorCanvas = new Canvas(pixelWidth, pixelWidth); - - //add them to group - group = new Group(); - group.getChildren().addAll(cageCanvas, selectedCellCanvas, userNumbersCanvas, errorCanvas); - errorCanvas.toBack(); - - //note game context - this.gameContext = gameContext; - - gameContext.getUserData().addChangeListener(new UserData.ChangeListener() { - @Override - public void onDataChanged(UserData.ChangeListener.ChangeData data) { - userDataDrawer.draw(); - errorHighlighter.clearCanvas(); - } - }); - - //link cage drawer to canvas and draw the cages - cageDrawer = new CageDrawer(gameContext.getCageData(), cageCanvas.getGraphicsContext2D()); - cageDrawer.draw(); - - //link the user data drawer but don't draw the user data - userDataDrawer = new UserDataDrawer(userNumbersCanvas.getGraphicsContext2D(), gameContext.getUserData()); - userDataDrawer.draw(); - //link selected cell drawer to canvas - selectedCellDrawer = new SelectedCellDrawer(selectedCellCanvas.getGraphicsContext2D()); - selectedCellDrawer.draw(selectedCell); - - //draw the selected cell - selectedCellDrawer.draw(selectedCell); - - //error checking - errorHighlighter = new ErrorsHighlighter(errorCanvas.getGraphicsContext2D()); - - errorCallback = new ErrorShower() { - @Override - public void onCageInvalid(Cage cage) { - errorHighlighter.drawErroneousCage(cage); - } - - @Override - public void onRowColInvalid(boolean isRow, int index) { - errorHighlighter.drawErroneousRow(isRow, index); - } - }; - - - } - - public void configureKeyEvents() { - //initialize input handler - group.addEventHandler(MouseEvent.MOUSE_CLICKED, inputHandler.getMouseHandler()); - group.getScene().setOnKeyPressed(inputHandler.getKeyEventHandler()); - - } - - public void setSelectedCell(BoardPosVec selectedCell) { - if (!selectedCell.clampToArea()) { - this.selectedCell = selectedCell; - selectedCellDrawer.draw(selectedCell); - } - } - - public BoardPosVec getSelectedCell() { - return selectedCell; - } - - public static int getPixelWidth() { - return pixelWidth; - } - - public static int getSquarePixelWidth() { - return pixelWidth / GameContext.getBoardWidth(); - } - - public GameContext getGameContext() { - return gameContext; - } - - public ErrorShower getErrorCallback() { - return errorCallback; - } - - public Node getNode() { - return group; - } -} - -class InputHandler { - //the class must store view in order to be able to call its methods - GameGridView view; - - //constructor - public InputHandler(GameGridView view){ - this.view = view; - - } - - //mouse callback - EventHandler<MouseEvent> mouseHandler = new EventHandler<MouseEvent>() { - @Override - public void handle(MouseEvent mouseEvent) { - view.getNode().requestFocus(); - BoardPosVec selectedCellPos = new BoardPosVec((int)mouseEvent.getY(), (int)mouseEvent.getX()); - selectedCellPos = selectedCellPos.fromPixelToBoardSpace(); - view.setSelectedCell(selectedCellPos); - - } - }; - - //key callback - EventHandler<KeyEvent> keyEventHandler = new EventHandler<KeyEvent>() { - @Override - //can either be user entering a value, or navigating - public void handle(KeyEvent keyEvent) { - if (!handleDirectionKeyPress(keyEvent)) handleValueEntered(keyEvent); - } - }; - - public boolean handleDirectionKeyPress(KeyEvent event) { - - Util.Direction direction;// = Util.Direction.NORTH; - switch (event.getCode()) { - - case W: - case UP: - direction = Util.Direction.NORTH; - break; - case D: - case RIGHT: - direction = Util.Direction.EAST; - break; - - case S: - case DOWN: - direction = Util.Direction.SOUTH; - break; - - case A: - case LEFT: - direction = Util.Direction.WEST; - break; - - - default: - return false; - - - } - - //consume if arrow key to prevent loss of focus - switch (event.getCode()) { - case UP: - case RIGHT: - case DOWN: - case LEFT: - event.consume(); - } - view.setSelectedCell(view.getSelectedCell().add(direction.vector)); - return true; - } - - public boolean handleValueEntered (KeyEvent keyEvent) { - switch (keyEvent.getCode()) { - case BACK_SPACE: - view.getGameContext().setValueAtCell(view.getSelectedCell(), 0, true); - break; - default: - char keyCharacter = keyEvent.getText().charAt(0); - char maxChar = Character.forDigit(view.getGameContext().getBoardWidth(), 10); - //if digit entered: - if ( keyCharacter >='1'&& keyCharacter <= maxChar) { - view.getGameContext().setValueAtCell(view.getSelectedCell(), Util.charToInt(keyCharacter), true); - return true; - } - - return false; - - - } - - return true; - } - - //returns handlers so that the view can register them - public EventHandler<MouseEvent> getMouseHandler() { - return mouseHandler; - } - - public EventHandler<KeyEvent> getKeyEventHandler() { - return keyEventHandler; - } -} diff --git a/src/com/patryk/mathdoku/MainWindow.java b/src/com/patryk/mathdoku/MainWindow.java deleted file mode 100644 index 2849ac20e8fea0fcc0b875aeba5d31cfd62e116a..0000000000000000000000000000000000000000 --- a/src/com/patryk/mathdoku/MainWindow.java +++ /dev/null @@ -1,96 +0,0 @@ -package com.patryk.mathdoku; - -import com.patryk.mathdoku.errorChecking.ErrorShower; -import javafx.event.ActionEvent; -import javafx.event.EventHandler; -import javafx.scene.Group; -import javafx.scene.Scene; -import javafx.scene.canvas.Canvas; -import javafx.scene.control.Button; -import javafx.scene.input.KeyEvent; -import javafx.scene.layout.HBox; -import javafx.scene.layout.VBox; - -public class MainWindow { - - Scene scene; - - VBox controlPane; - - Button undoButton = new Button("Undo"); - Button redoButton = new Button("Redo"); - Button clearButton = new Button("Clear"); - Button checkButton = new Button("Check"); - Button fileLoadButton = new Button("Load game from file"); - Button textLoadButton = new Button("Load game from text input"); - - - VBox numberPad = new VBox(); - GameGridView gameGridView; - UndoRedoButtonManager undoRedoButtonManager; - - EventHandler<ActionEvent> onClearButtonPressed = (ActionEvent actionEvent) -> gameGridView.getGameContext().clear(true); - EventHandler<ActionEvent> onUndoButtonPressed = (ActionEvent event) -> { - gameGridView.getGameContext().undo(); - }; - EventHandler<ActionEvent> onRedoButtonPressed = (ActionEvent event) -> gameGridView.getGameContext().redo(); - - EventHandler<ActionEvent> onCheckButtonPressed = new EventHandler<ActionEvent>() { - - @Override - public void handle(ActionEvent actionEvent) { - GameContext.me().getErrorChecker().showErrors(gameGridView.getErrorCallback()); - } - }; - - - - - - public MainWindow(GameContext gameContext) { - - undoRedoButtonManager = new UndoRedoButtonManager(undoButton, redoButton, gameContext.me().getActionRecorder()); - //initialize control pane - controlPane = new VBox(); - controlPane.getChildren().addAll(undoButton, redoButton, clearButton, checkButton, fileLoadButton, textLoadButton); - - //clear button - clearButton.addEventHandler(ActionEvent.ANY, onClearButtonPressed); - - //undo button - undoButton.addEventHandler(ActionEvent.ANY, onUndoButtonPressed); - - redoButton.addEventHandler(ActionEvent.ANY, onRedoButtonPressed); - redoButton.setDisable(true); - - //initialize button pane - //todo give them actions! - for (int i = 1; i <= gameContext.getBoardWidth(); i++) { - controlPane.getChildren().add(new Button(Integer.toString(i))); - } - - checkButton.addEventHandler(ActionEvent.ANY, onCheckButtonPressed); - - //init game grid view - gameGridView = new GameGridView(gameContext); - - - //initialize master layout - HBox masterLayout = new HBox(); - masterLayout.getChildren().addAll(gameGridView.getNode(), controlPane, numberPad); - - //init scene - scene = new Scene(masterLayout, gameGridView.getPixelWidth() + 250, gameGridView.getPixelWidth()); - gameGridView.configureKeyEvents(); - gameGridView.getNode().requestFocus(); - - - - } - - public Scene getScene() { - return scene; - } - -} - diff --git a/src/com/patryk/mathdoku/MathDoku.java b/src/com/patryk/mathdoku/MathDoku.java index 95b0255e6e7f199814ac9c9dde21078ad46537e2..d6c0d7a8c49d497c259ccf2aa86f132c9fc9aa92 100644 --- a/src/com/patryk/mathdoku/MathDoku.java +++ b/src/com/patryk/mathdoku/MathDoku.java @@ -1,83 +1,157 @@ package com.patryk.mathdoku; +import com.patryk.mathdoku.cageData.DataFormatException; +import com.patryk.mathdoku.gui.GameUI; +import com.patryk.mathdoku.gui.ManualGameInputDialog; import javafx.application.Application; import javafx.application.Platform; +import javafx.event.ActionEvent; import javafx.event.EventHandler; import javafx.scene.input.KeyCode; import javafx.scene.input.KeyEvent; +import javafx.stage.FileChooser; import javafx.stage.Stage; +import java.io.File; import java.io.IOException; +import java.nio.file.Files; +import java.nio.file.Paths; +import java.util.Optional; public class MathDoku extends Application { - MainWindow mainWindow; + GameUI gameUI; GameContext gameContext; + Stage stage; - private static final String dataFilePath = "example.txt"; private static final String title = "MathDoku!"; - int boardWidth = 6; + + EventHandler<ActionEvent> onFileLoadButtonPressed = (event) -> { + + FileChooser fileChooser = new FileChooser(); + File file = fileChooser.showOpenDialog(stage); + if (file == null) + return; + + try { + + setGameContext(new GameContext(Files.readString(Paths.get(file.getAbsolutePath())))); + } catch (IOException e) { + //this should never happen + } catch (DataFormatException e) { + gameUI.showDataFormatErrorAlert(e); + } + + }; + + EventHandler<ActionEvent> onManualInputButtonPressed = (event) -> { + ManualGameInputDialog dialog = new ManualGameInputDialog(); + while (true) { + + Optional<String> result = dialog.showAndWait(); + if (result.isPresent()) { + try { + setGameContext(new GameContext(result.get())); + break; + } catch (DataFormatException e) { + gameUI.showDataFormatErrorAlert(e); + } + } else { + break; + } + + } + + + }; + + //key event handler - private EventHandler<KeyEvent> keyEventHandler = new EventHandler<KeyEvent>() { - @Override - public void handle(KeyEvent keyEvent) { - if (keyEvent.getCode() == KeyCode.ESCAPE) { + private EventHandler<KeyEvent> keyEventHandler = keyEvent -> { + if (keyEvent.getCode() == KeyCode.ESCAPE) { + if (wantsToExit()) { Platform.exit(); } } }; - + public void start(Stage primaryStage) { + this.stage = primaryStage; + primaryStage.addEventHandler(KeyEvent.KEY_PRESSED, keyEventHandler); - try { - //set up the game context and the UI - NewGameWindow newGameWindow = new NewGameWindow(); - newGameWindow.showAndWait(); - gameContext = new GameContext(dataFilePath, boardWidth); - gameContext.setActive(); - mainWindow = new MainWindow(gameContext); - - //set up the key press - //creates a blank board with nothing - /*ui.controlMenu.addEvent(new EventHandler<ActionEvent>(){ - handle() { - //if it's load from file - loadFromFile(); + gameUI = new GameUI(); + + primaryStage.setOnCloseRequest((windowEvent) -> { + if (wantsToExit()) { + Platform.exit(); + } else { + windowEvent.consume(); } - })*/ + }); + initUiFunctionality(); - primaryStage.setScene(mainWindow.getScene()); - primaryStage.setTitle(title); - primaryStage.show(); - } catch (IOException e) { - System.err.println("Something's wrong with loading the file."); - Platform.exit(); + primaryStage.setScene(gameUI.getScene()); + primaryStage.setTitle(title); + primaryStage.show(); + + + } + + /*In order to abstract the functionality of the GUI from the layout, i have decided to + declare the layout in the gameUI class and the functionality in this class. + This is the way Qt does it in C++, which inspired me to do it that way in case you are + wondering.*/ + private void initUiFunctionality() { + gameUI.undoButton.addEventHandler(ActionEvent.ANY, (ActionEvent event) -> { + if (gameUI.showConfirmDialog()) + gameContext.undo(); + }); + + + gameUI.redoButton.addEventHandler(ActionEvent.ANY,(ActionEvent event) -> { + if (gameUI.showConfirmDialog()) + gameContext.redo(); + }); + gameUI.clearButton.addEventHandler(ActionEvent.ANY, (ActionEvent actionEvent) -> { + if (gameUI.showConfirmDialog()) + gameContext.clear(true); + }); + + gameUI.checkButton.addEventHandler(ActionEvent.ANY,(event) -> gameUI.gameGridView.showErrors()); + gameUI.fileLoadButton.addEventHandler(ActionEvent.ANY, onFileLoadButtonPressed); + gameUI.textLoadButton.addEventHandler(ActionEvent.ANY, onManualInputButtonPressed); + + gameUI.setNumberButtonCallback((digit) -> gameUI.gameGridView.getInputHandler().injectNumberKey(digit)); + + } + + public void setGameContext(GameContext gameContext) { + this.gameContext = gameContext; + gameUI.setGameContext(gameContext); + + } + + public boolean wantsToExit() { + if (shouldDisplayExitDialog()) { + //show confirmation dialog + + + return gameUI.showConfirmExitDialog(); } + return true; } - //T - /*private void loadFromFile() { + public boolean shouldDisplayExitDialog() { if (gameContext != null) { - //(if there is a loaded game) and it has had some changes made to it - //ask the user if they really want to over-write the game - } - //open file dialog, read data from file and - try { - setGameContext(new GameContext(data)); - } catch (InvalidDataException e) { - //show a dialog saying the error and quit + return !(gameContext.getUserData().isEmpty() || gameUI.hasWonBefore()); } + return false; } - private void setGameContext(GameContext context) { - gameContext = context; - ui.setGameContext(context); - }*/ - public static void main(String[] args) { launch(args); } diff --git a/src/com/patryk/mathdoku/NewGameWindow.java b/src/com/patryk/mathdoku/NewGameWindow.java deleted file mode 100644 index 9bc60fe2b65b7a2bddf1565c15ea18e3d6d76c89..0000000000000000000000000000000000000000 --- a/src/com/patryk/mathdoku/NewGameWindow.java +++ /dev/null @@ -1,61 +0,0 @@ -package com.patryk.mathdoku; - -import javafx.event.ActionEvent; -import javafx.event.Event; -import javafx.event.EventHandler; -import javafx.scene.Scene; -import javafx.scene.control.Button; -import javafx.scene.control.Dialog; -import javafx.scene.control.Label; -import javafx.scene.layout.HBox; -import javafx.scene.layout.VBox; -import javafx.stage.FileChooser; -import javafx.stage.Stage; - -import java.io.File; - -public class NewGameWindow extends Stage { - private static int WIDTH = 400; - private static int HEIGHT = 300; - Scene scene; - Button manualInputButton; - Button fileButton; - Button cancelButton; - - public NewGameWindow() { - setTitle("New Game ..."); - VBox masterLayout = new VBox( - new Label("How do you want to load the game?"), - new HBox(new Label("By file:"), fileButton = new Button("Load file")), - new HBox(new Label("Or"), manualInputButton = new Button(" type it up manually")), - cancelButton = new Button("Cancel") - - ); - - masterLayout.setSpacing(0.4); - - manualInputButton.addEventHandler(ActionEvent.ANY, (Event e) -> { - Dialog<String> dialog = new ManualGameInputDialog(); - System.out.println("Return value: " + dialog.showAndWait().get()); - }); - - fileButton.addEventHandler(ActionEvent.ANY, (Event e) -> { - FileChooser fileChooser = new FileChooser(); - File file = fileChooser.showOpenDialog(this); - System.out.println("file chosen: " + file.getAbsolutePath()); - }); - - cancelButton.addEventHandler(ActionEvent.ANY, new EventHandler<Event>() { - @Override - public void handle(Event event) { - close(); - } - }); - - scene = new Scene(masterLayout, WIDTH, HEIGHT); - setScene(scene); - - - - } -} diff --git a/src/com/patryk/mathdoku/UserData.java b/src/com/patryk/mathdoku/UserData.java index c56780a2db20f31cb86d067c28a6e002d871d571..608db4927af86b573d9cb0e4d6f8b0989610f91c 100644 --- a/src/com/patryk/mathdoku/UserData.java +++ b/src/com/patryk/mathdoku/UserData.java @@ -1,6 +1,6 @@ package com.patryk.mathdoku; -import com.patryk.mathdoku.global.BoardPosVec; +import com.patryk.mathdoku.util.BoardPosVec; import java.io.BufferedWriter; import java.io.FileWriter; @@ -61,9 +61,6 @@ public class UserData { int fullSize; int populationCount = 0; List<ChangeListener> changeListenerList = new LinkedList<>(); - static UserData instance; // instance of current, active userdata - - public static UserData me() {return instance; } private UserData() {}; @@ -71,7 +68,6 @@ public class UserData { boardWidth = width; fullSize = width * width; data = new int[fullSize]; - instance = this; clear(); } @@ -82,7 +78,6 @@ public class UserData { */ public static UserData move(UserData other) { UserData newData = new UserData(); - instance = newData; newData.boardWidth = other.boardWidth; //boardwidths are the same @@ -99,15 +94,23 @@ public class UserData { public void copy(UserData other) { //this.boardWidth = other.boardWidth; this.data = Arrays.copyOf(other.data, boardWidth * boardWidth); + this.populationCount = other.populationCount; notifyListener(new ChangeListener.MultipleCellChange(false)); } + public int getPopulationCount() { + return populationCount; + } + + public boolean isEmpty() { + return populationCount == 0; + } + public void addChangeListener(ChangeListener listener) { changeListenerList.add(listener); } public void notifyListener(ChangeListener.ChangeData changeData) { - //TODO fix for (ChangeListener changeListener: changeListenerList){ changeListener.onDataChanged(changeData); } @@ -123,12 +126,14 @@ public class UserData { if (oldValue != value) { data[cell.toIndex()] = value; - notifyListener(new ChangeListener.SingleCellChange(cell, oldValue, value)); if (oldValue == 0) populationCount++; - else if (value == 0) { + + if (value == 0) { populationCount--; } + notifyListener(new ChangeListener.SingleCellChange(cell, oldValue, value)); + } } @@ -144,6 +149,8 @@ public class UserData { public void clear() { Arrays.fill(data, 0); + populationCount = 0; + notifyListener(new ChangeListener.MultipleCellChange(true)); } @Override @@ -185,7 +192,7 @@ public class UserData { bw.close(); } catch (IOException e) { - System.out.println("some serious shit has happened!"); + //this is very rare } } diff --git a/src/com/patryk/mathdoku/actions/Action.java b/src/com/patryk/mathdoku/actions/Action.java index b1708ad68523b4764955b6928eca9c0ace88c0d5..b2650143ef2020b558f1d4013daf793fad632023 100644 --- a/src/com/patryk/mathdoku/actions/Action.java +++ b/src/com/patryk/mathdoku/actions/Action.java @@ -1,7 +1,14 @@ package com.patryk.mathdoku.actions; -public interface Action { - void undo(); - void redo(); - void flip(); +import com.patryk.mathdoku.GameContext; + +public abstract class Action { + public static GameContext gameContext; + + public static void setGameContext(GameContext gameContext) { + Action.gameContext = gameContext; + } + + public abstract void undo(); + public abstract void redo(); } diff --git a/src/com/patryk/mathdoku/ActionRecorder.java b/src/com/patryk/mathdoku/actions/ActionRecorder.java similarity index 79% rename from src/com/patryk/mathdoku/ActionRecorder.java rename to src/com/patryk/mathdoku/actions/ActionRecorder.java index 0393fed9eff32c85087a6a48d1104d218188e13a..9b668f6361cbf52a1b7fb2da57afa12f2f0c995c 100644 --- a/src/com/patryk/mathdoku/ActionRecorder.java +++ b/src/com/patryk/mathdoku/actions/ActionRecorder.java @@ -1,4 +1,4 @@ -package com.patryk.mathdoku; +package com.patryk.mathdoku.actions; public interface ActionRecorder<T> { void record(T action); diff --git a/src/com/patryk/mathdoku/actions/CellValueChangeAction.java b/src/com/patryk/mathdoku/actions/CellValueChangeAction.java index c33b3bcb1ba0ccdf5d55c2ba081ed3370fe7d475..e2a6eea6a8a17ab25b6e0024e4114d6da3760451 100644 --- a/src/com/patryk/mathdoku/actions/CellValueChangeAction.java +++ b/src/com/patryk/mathdoku/actions/CellValueChangeAction.java @@ -1,10 +1,8 @@ package com.patryk.mathdoku.actions; -import com.patryk.mathdoku.GameContext; -import com.patryk.mathdoku.actions.Action; -import com.patryk.mathdoku.global.BoardPosVec; +import com.patryk.mathdoku.util.BoardPosVec; -public class CellValueChangeAction implements Action { +public class CellValueChangeAction extends Action { BoardPosVec cell; int oldValue; int newValue; @@ -17,29 +15,13 @@ public class CellValueChangeAction implements Action { @Override public void undo() { - GameContext.me().setValueAtCell(cell, oldValue, false); + gameContext.setValueAtCell(cell, oldValue, false); } @Override public void redo() { - GameContext.me().setValueAtCell(cell, newValue, false); + gameContext.setValueAtCell(cell, newValue, false); } - @Override - public void flip() { - - } - - -/* public int getOldValue() { - return oldValue; - }*/ - -/* public Util.BoardPosVec getCell() { - return cell; - } - public int getNewValue() { - return newValue; - }*/ } diff --git a/src/com/patryk/mathdoku/actions/ClearAction.java b/src/com/patryk/mathdoku/actions/ClearAction.java index 7e769956495ea343139096492242d8ec68a62f56..690d94ea0be11ac96079f9a6e105412322419356 100644 --- a/src/com/patryk/mathdoku/actions/ClearAction.java +++ b/src/com/patryk/mathdoku/actions/ClearAction.java @@ -4,7 +4,7 @@ import com.patryk.mathdoku.GameContext; import com.patryk.mathdoku.UserData; import com.patryk.mathdoku.actions.Action; -public class ClearAction implements Action { +public class ClearAction extends Action { private UserData oldUserData; public ClearAction(UserData oldUserData) { this.oldUserData = oldUserData; @@ -12,16 +12,11 @@ public class ClearAction implements Action { @Override public void undo() { - GameContext.me().getUserData().copy(oldUserData); + gameContext.getUserData().copy(oldUserData); } @Override public void redo() { - GameContext.me().getUserData().clear(); - } - - @Override - public void flip() { - + gameContext.getUserData().clear(); } } diff --git a/src/com/patryk/mathdoku/LimitedStack.java b/src/com/patryk/mathdoku/actions/LimitedStack.java similarity index 94% rename from src/com/patryk/mathdoku/LimitedStack.java rename to src/com/patryk/mathdoku/actions/LimitedStack.java index 7e63bd2e3c01275e0953844be1ff0f37620da5ec..45304f935f1632a60304cceb269a9d1edc7e7493 100644 --- a/src/com/patryk/mathdoku/LimitedStack.java +++ b/src/com/patryk/mathdoku/actions/LimitedStack.java @@ -1,4 +1,4 @@ -package com.patryk.mathdoku; +package com.patryk.mathdoku.actions; public class LimitedStack<T> implements LimitedStackBase<T> { final int maxSize; @@ -39,10 +39,6 @@ public class LimitedStack<T> implements LimitedStackBase<T> { return a; } - /*@Override - public void push(Action item, int pos) { - - }*/ @Override public T pop() { @@ -89,8 +85,6 @@ public class LimitedStack<T> implements LimitedStackBase<T> { } sb.append(']'); return sb.toString(); - - } } diff --git a/src/com/patryk/mathdoku/LimitedStackBase.java b/src/com/patryk/mathdoku/actions/LimitedStackBase.java similarity index 70% rename from src/com/patryk/mathdoku/LimitedStackBase.java rename to src/com/patryk/mathdoku/actions/LimitedStackBase.java index 7b300ab1b66b16e4e67d3aaa05a83424551ef395..c77d663d2332aac0bfb82d16f4f73871206aabdf 100644 --- a/src/com/patryk/mathdoku/LimitedStackBase.java +++ b/src/com/patryk/mathdoku/actions/LimitedStackBase.java @@ -1,16 +1,14 @@ -package com.patryk.mathdoku; +package com.patryk.mathdoku.actions; public interface LimitedStackBase<E> { /** * Pushes item at the end */ void push(E item); - //void push(E item, int pos); E pop(); boolean isEmpty(); boolean isFull(); - E popHead(); void clear(); } diff --git a/src/com/patryk/mathdoku/StackActionRecorder.java b/src/com/patryk/mathdoku/actions/StackActionRecorder.java similarity index 98% rename from src/com/patryk/mathdoku/StackActionRecorder.java rename to src/com/patryk/mathdoku/actions/StackActionRecorder.java index 43ba2aa9fc90e18256e1207e5b551ff591742d86..6e98d5296ab10d71ec442fa78756a91134232e55 100644 --- a/src/com/patryk/mathdoku/StackActionRecorder.java +++ b/src/com/patryk/mathdoku/actions/StackActionRecorder.java @@ -1,4 +1,4 @@ -package com.patryk.mathdoku; +package com.patryk.mathdoku.actions; public class StackActionRecorder<T> implements ActionRecorder<T>{ diff --git a/src/com/patryk/mathdoku/UndoRedoButtonManager.java b/src/com/patryk/mathdoku/actions/UndoRedoButtonManager.java similarity index 78% rename from src/com/patryk/mathdoku/UndoRedoButtonManager.java rename to src/com/patryk/mathdoku/actions/UndoRedoButtonManager.java index 1b51d4a02bedda3ee123fe00c7e74787d84c5677..eef24354ecaf90cc14b4ce205e42c387de5d39af 100644 --- a/src/com/patryk/mathdoku/UndoRedoButtonManager.java +++ b/src/com/patryk/mathdoku/actions/UndoRedoButtonManager.java @@ -1,6 +1,6 @@ -package com.patryk.mathdoku; +package com.patryk.mathdoku.actions; -import com.patryk.mathdoku.actions.Action; +import com.patryk.mathdoku.GameContext; import javafx.scene.control.Button; public class UndoRedoButtonManager { @@ -13,13 +13,19 @@ public class UndoRedoButtonManager { Button redoButton; StackActionRecorder<Action> actionRecorder; - public UndoRedoButtonManager(Button undoButton, Button redoButton, StackActionRecorder<Action> actionRecorder) { + + public UndoRedoButtonManager(Button undoButton, Button redoButton) { this.undoButton = undoButton; this.redoButton = redoButton; - this.actionRecorder = actionRecorder; undoButton.setDisable(true); + redoButton.setDisable(true); instance = this; + } + public void setGameContext(GameContext gameContext) { + this.actionRecorder = gameContext.getActionRecorder(); + undoButton.setDisable(true); + redoButton.setDisable(true); } public void onUndoButtonPressed() { diff --git a/src/com/patryk/mathdoku/Cage.java b/src/com/patryk/mathdoku/cageData/Cage.java similarity index 91% rename from src/com/patryk/mathdoku/Cage.java rename to src/com/patryk/mathdoku/cageData/Cage.java index b62876ccd60190ee2cc91021cbd62276925b4d97..147398d2ec01c4393faf9189c396d6cd52889c7e 100644 --- a/src/com/patryk/mathdoku/Cage.java +++ b/src/com/patryk/mathdoku/cageData/Cage.java @@ -1,4 +1,4 @@ -package com.patryk.mathdoku; +package com.patryk.mathdoku.cageData; import java.util.List; @@ -17,8 +17,6 @@ public class Cage { public int getTarget() {return target; } - public char getSign() {return operator.sign; } - public Cage.Operator getOperator() { return operator; } @@ -35,7 +33,10 @@ public class Cage { @Override public String toString() { - return Integer.toString(target) + operator.sign; + String s = Integer.toString(target); + if (getCellCount() > 1) + s+=this.operator.sign; + return s; } public enum Operator { diff --git a/src/com/patryk/mathdoku/cageData/CageData.java b/src/com/patryk/mathdoku/cageData/CageData.java new file mode 100644 index 0000000000000000000000000000000000000000..58c8115f6bffa96e7d6322dbf1b49835561d9e63 --- /dev/null +++ b/src/com/patryk/mathdoku/cageData/CageData.java @@ -0,0 +1,87 @@ +package com.patryk.mathdoku.cageData; + +import com.patryk.mathdoku.util.Direction; +import com.patryk.mathdoku.util.BoardPosVec; + +import java.util.*; + + +public class CageData { + int width; + + Cell[] data; + List<Cage> cageList = new ArrayList<Cage>(); + int cageCount; + + public CageData(String data) throws DataFormatException{ + parseData(data); + } + + + public List<Cage> getCages() {return cageList; } + + public boolean cellConnectsTo(BoardPosVec pos, Direction direction) { + + Cell nextCell = getCellAt(pos.add(direction.vector)); + if (nextCell == null) { + return false; + } + + return getCellAt(pos).getCageId() == nextCell.getCageId(); + + } + + private void parseData(String rawData) throws DataFormatException { + + //new + CageParser parser = new CageParser(); + int size = parser.getCellCount(new Scanner(rawData)); + this.data = new Cell[size]; + this.width = (int)Math.sqrt(size); + if (width * width != size) { + throw new DataFormatException(-1, "Number of cells not square number."); + } + + if (size > 81) + throw new DataFormatException(-1, "Too many cells! Max is 81."); + initData(); + cageCount = parser.parseData(new Scanner(rawData), data, cageList); + + } + + private void initData() { + for (int i = 0; i < data.length; i++) { + data[i] = new Cell(-1); + } + } + + public int getWidth() { + return width; + } + + private Cell getCellAt(BoardPosVec posVec) { + if (!posVec.isValid()) { + return null; + } + return data[posVec.toIndex()]; + } + + public int getValueAtCell(BoardPosVec cell) { + return data[cell.toIndex()].getCageId(); + } + + public int getCageCount() { + return cageCount; + } + +} + +class Cell { + private int cageID; + + public Cell (int cageID) { + this.cageID = cageID; + } + + public int getCageId() {return cageID; } +} \ No newline at end of file diff --git a/src/com/patryk/mathdoku/cageData/CageParser.java b/src/com/patryk/mathdoku/cageData/CageParser.java new file mode 100644 index 0000000000000000000000000000000000000000..095dc1d643decbf0d7f64c1d0d5c652163374a98 --- /dev/null +++ b/src/com/patryk/mathdoku/cageData/CageParser.java @@ -0,0 +1,112 @@ +package com.patryk.mathdoku.cageData; + +import com.patryk.mathdoku.util.MatcherHelper; + +import java.util.ArrayList; +import java.util.List; +import java.util.Scanner; + +public class CageParser { + + MatcherHelper targetAndSign = new MatcherHelper( "(\\d+)([+-x÷])?\\s"); + MatcherHelper cageMember = new MatcherHelper("(\\d+)(,|$)"); + //MatcherHelper cageMembers = new MatcherHelper("((\\d+),)*(\\d+)"); + MatcherHelper comma = new MatcherHelper(","); + + + Cell[] data; + List<Cage> cageList; + + + public int getCellCount(Scanner scanner) { + int cellCount = 0; + while (scanner.hasNextLine()) { + String line = scanner.nextLine(); + comma.initMatcher(line); + int commaCount = 0; + while (comma.matcher.find()) { + commaCount++; + } + commaCount++; //because number of cells at line = "number of commas" + 1 + cellCount+= commaCount; + } + return cellCount; + } + + /** + * + * @param scanner + * @param data + * @param cageList + * @return number of cages + */ + public int parseData(Scanner scanner, Cell[] data, List<Cage> cageList) throws DataFormatException { + this.data = data; + //this.cageList = cageList; + int cageId = 0; + while (scanner.hasNextLine()) { + cageList.add(parseLine(scanner.nextLine(), cageId)); + cageId++; + } + return cageId; // cage count + } + + private Cage parseLine(String cageLine, int cageID) { + int line = cageID + 1; + //make the matchers be of this particular cage + targetAndSign.initMatcher(cageLine); + cageMember.initMatcher(cageLine); + //cageMembers.initMatcher(cageLine); + + //extract target and sign + + if (!targetAndSign.matcher.find() ) { + throw new DataFormatException(line, "Expected digit followed by an optional arithmetic sign."); + } + + int target = Integer.parseInt(targetAndSign.matcher.group(1)); + char sign = '+'; + if (targetAndSign.matcher.group(2) != null) { + sign = targetAndSign.matcher.group(2).charAt(0); + } + + //System.out.printf("Target is %d and sign is %c.\n", target, sign); + + //extract first occurence of cage member cell + if (!cageMember.matcher.find(targetAndSign.matcher.end())) { + throw new DataFormatException(line, "Expected multiple comma-separated digits."); + } + //cageMembers.matcher.find(targetAndSign.matcher.end()); + //System.out.println("Group count: " + cageMembers.matcher.groupCount()); + + boolean isFirstCell = true; + int markedCellId = 0; + + //for every cage member cell, instantiate that cell with this cage id + ArrayList<Integer> cageMembers = new ArrayList<>(); + do { + // + int userCageId = Integer.parseInt(cageMember.matcher.group(1)); + int cageCellId = userCageId - 1; + try { + if (data[cageCellId].getCageId() != -1) + throw new DataFormatException(line, "The cage " + userCageId + " has already been listed!"); + data[cageCellId] = new Cell(cageID); + } catch (ArrayIndexOutOfBoundsException e) { + throw new DataFormatException(line, "A cage identifier is too big for the grid of this size."); + } + cageMembers.add(cageCellId); + //additionally, if it is the first cell, make that cage have this cell + if (isFirstCell) { + markedCellId = cageCellId; + isFirstCell = false; + } + + } while (cageMember.matcher.find()); + + //finally, instantiate the cage and return it + return new Cage(target, Cage.Operator.fromChar(sign), markedCellId, cageMembers); + + } + +} diff --git a/src/com/patryk/mathdoku/drawers/CageDrawer.java b/src/com/patryk/mathdoku/drawers/CageDrawer.java deleted file mode 100644 index bab9178bfb3ace975ad2321dee40ed93e5e4400d..0000000000000000000000000000000000000000 --- a/src/com/patryk/mathdoku/drawers/CageDrawer.java +++ /dev/null @@ -1,94 +0,0 @@ -package com.patryk.mathdoku.drawers; - -import com.patryk.mathdoku.*; -import com.patryk.mathdoku.global.BoardPosVec; -import javafx.scene.canvas.GraphicsContext; -import javafx.scene.paint.Color; -import javafx.scene.text.Font; - -public class CageDrawer extends Drawer{ - - - - private CageData data; - private Font font = new Font("Zapfino", 12); - - - public CageDrawer(CageData data, GraphicsContext gc) { - super(gc); - this.data = data; - } - - public void draw() { - - drawMainLines(); - drawCageBoundaries(); - drawCageSigns(); - //drawLineFromPoint(new Util.BoardPosVec(2,1), Util.Direction.EAST); - } - - private void drawCageBoundaries() { - - gc.setLineWidth(2.0); - gc.setStroke(Color.BLACK); - - - for (int r = 0; r < GameContext.getBoardWidth(); r++) { - for (int c = 0; c < GameContext.getBoardWidth(); c++) { - for (Util.Direction d: Util.Direction.values()) { - BoardPosVec squareVec = new BoardPosVec(r, c); - - if (! data.cellConnectsTo(squareVec, d)) { - drawLineFromSquare(new BoardPosVec(r, c), d); - } - } - } - } - } - - - private void drawMainLines() { - gc.setLineWidth(1.0); - gc.setStroke(Color.GRAY); - - //draw back grid - - for (int i = 1; i < GameContext.getBoardWidth(); i++) { - //vertical - gc.strokeLine(i * GameGridView.getSquarePixelWidth(), 0.0, i * GameGridView.getSquarePixelWidth(), GameGridView.getPixelWidth()); - //horizontal - gc.strokeLine(0.0, i * GameGridView.getSquarePixelWidth(), GameGridView.getPixelWidth(), i * GameGridView.getSquarePixelWidth()); - } - } - - private void drawBoundaries() { - int SQUARE_WIDTH = GameGridView.getSquarePixelWidth(); - gc.setLineWidth(2.0); - - gc.setStroke(Color.BLACK); - gc.strokeLine(SQUARE_WIDTH, SQUARE_WIDTH, 2 * SQUARE_WIDTH, SQUARE_WIDTH); - - } - - private void drawCageSigns() { - - //draw mathematical signs - gc.setFill(Color.BLACK); - gc.setFont(font); - - /*for (int i = 0; i < nSquares; i++) { - for (int j = 0; j < nSquares; j++) { - gc.fillText(String.valueOf(data.getCellAt(j, i).getSign()), i * SQUARE_WIDTH, j * SQUARE_WIDTH + 12); - } - }*/ - - for (Cage c: data.getCages()) { - drawCageText(new BoardPosVec(c.getMarkedCell()), c.toString()); - } - } - - private void drawCageText(BoardPosVec pos, String text) { - int SQUARE_WIDTH = GameGridView.getSquarePixelWidth(); - gc.fillText(text, pos.c * SQUARE_WIDTH, pos.r * SQUARE_WIDTH + 12); - } -} diff --git a/src/com/patryk/mathdoku/drawers/UserDataDrawer.java b/src/com/patryk/mathdoku/drawers/UserDataDrawer.java deleted file mode 100644 index 81ea89e7784ac7925119c914ae90ac4ded04cf44..0000000000000000000000000000000000000000 --- a/src/com/patryk/mathdoku/drawers/UserDataDrawer.java +++ /dev/null @@ -1,48 +0,0 @@ -package com.patryk.mathdoku.drawers; - -import com.patryk.mathdoku.GameContext; -import com.patryk.mathdoku.GameGridView; -import com.patryk.mathdoku.UserData; -import com.patryk.mathdoku.global.BoardPosVec; -import javafx.scene.canvas.GraphicsContext; -import javafx.scene.text.Font; -import javafx.scene.text.TextAlignment; - - -public class UserDataDrawer extends Drawer { - private UserData userData; - private final int fontSize = (int) ((double) GameGridView.getSquarePixelWidth() * 0.7 ); - private Font font = new Font("Zapfino", fontSize); - - public UserDataDrawer(GraphicsContext gc, UserData userData) { - super(gc); - this.userData = userData; - } - - public void draw() { - clearCanvas(); - gc.setFont(font); - gc.setTextAlign(TextAlignment.CENTER); - - for (int r = 0; r < GameContext.getBoardWidth(); r++) { - for (int c = 0; c < GameContext.getBoardWidth(); c++) { - BoardPosVec pos = new BoardPosVec(r, c); - int digit = userData.getValueAtCell(pos); - if (digit != 0) - drawUserDigit(pos, digit); - //drawUserDigit(pos, pos.toIndex()); - } - } - } - - public void drawUserDigit(BoardPosVec pos, int digit) { - pos.r++; - BoardPosVec pixelPos = pos.toPixelSpace(); - int squareWidth = GameGridView.getSquarePixelWidth();/* - int offset = (GameContext.getInstance().getSquarePixelWidth() - fontSize) / 2;*/ - pixelPos.c += squareWidth / 2; - pixelPos.r -= (squareWidth - fontSize) / 2; - - gc.fillText(Integer.toString(digit), pixelPos.c, pixelPos.r); - } -} diff --git a/src/com/patryk/mathdoku/errorChecking/CageChecker.java b/src/com/patryk/mathdoku/errorChecking/CageChecker.java index 3ed9c68e7979436db29bc57085073a5e1dd4e6a7..4e3c430af9bcaa69a253cd63858b0f7ebf79b76e 100644 --- a/src/com/patryk/mathdoku/errorChecking/CageChecker.java +++ b/src/com/patryk/mathdoku/errorChecking/CageChecker.java @@ -1,36 +1,32 @@ package com.patryk.mathdoku.errorChecking; -import com.patryk.mathdoku.CageData; +import com.patryk.mathdoku.cageData.CageData; import com.patryk.mathdoku.UserData; public class CageChecker { CageData cageData; CageInfo[] cageInfos; - UserData userData; - public CageChecker(CageData cageData) { + public CageChecker(UserData userData, CageData cageData) { this.cageData = cageData; // fill cage info array cageInfos = new CageInfo[cageData.getCageCount()]; + CageInfo.setUserData(userData); for (int i = 0; i < cageData.getCageCount(); i++) { cageInfos[i] = new CageInfo(cageData.getCages().get(i)); } } - // public void onDigitEntered(UserData.ChangeListener.SingleCellChange changeData) { int cageId = cageData.getValueAtCell(changeData.getCellChanged()); - System.out.println("Digit added. Cage is: " + cageId); CageInfo cageInfo = cageInfos[cageId]; cageInfo.onDigitEntered(); - //todo cageInfos[cageId].setRecordValidity(false); } public void onDigitRemoved(UserData.ChangeListener.SingleCellChange changeData) { int cageId = cageData.getValueAtCell(changeData.getCellChanged()); - System.out.println("Digit removed. Cage is: " + cageId); CageInfo cageInfo = cageInfos[cageId]; cageInfo.onDigitRemoved(); } @@ -39,29 +35,6 @@ public class CageChecker { return cageInfos; } - -// public void reCalculate() { -// //reminder: cage is only invalid when it full and has a mistake, not otherwise -// /*when board is not fully filled in: -// for every cage, if cage info is out of date, if the cage is filled in: -// if its valid -// -// */ -// for (int cageId = 0; cageId < cageData.getCageCount(); cageId++) { -// CageInfo cageInfo = cageInfos[cageId]; -// if (cageInfo.isRecordOutOfDate()) { -// if (cageInfo.cageIsfull()) { -// Cage cage = cageData.getCage(cageId); -// int[] cageMemberData = getMembersOfCage(cage); -// cageInfo.setCorrectness(RecursiveSolver.testSign(cageMemberData, cage.getTarget(), cage.getOperator())); -// cageInfo.setRecordValidity(true); -// } -// } -// } -// } - - - public boolean noErrors() { for (CageInfo cageInfo: cageInfos) { if (cageInfo.isCageInvalid()) @@ -78,32 +51,3 @@ public class CageChecker { } } - -/*class CageInfo_old { - private final GridErrorChecker gridErrorChecker; - private final Cage cage; - private final int[] memberData; - private boolean cageValid; - private boolean validityOutOfDate; - - public CageInfo(GridErrorChecker gridErrorChecker, Cage cage) { - this.gridErrorChecker = gridErrorChecker; - this.cage = cage; - memberData = new int[cage.getMemberCells().size()]; - cageValid = false; - validityOutOfDate = false; - } - - //public int onCell - - - public void reCalculate() { - for (int i = 0; i < memberData.length; i++) { - memberData[i] = gridErrorChecker.userData.getValueAtCell(cage.getMemberCells().get(i)); - } - - cageValid = RecursiveSolver.testSign(memberData, cage.getTarget(), cage.getOperator()); - - validityOutOfDate = false; - } -}*/ diff --git a/src/com/patryk/mathdoku/errorChecking/CageInfo.java b/src/com/patryk/mathdoku/errorChecking/CageInfo.java index e8f98b0dcc7bc7549be07ee6703e3200850849a5..6e9dab6a1a58f32a8c867fe223cd38434b4198ed 100644 --- a/src/com/patryk/mathdoku/errorChecking/CageInfo.java +++ b/src/com/patryk/mathdoku/errorChecking/CageInfo.java @@ -1,7 +1,6 @@ package com.patryk.mathdoku.errorChecking; -import com.patryk.mathdoku.Cage; -import com.patryk.mathdoku.RecursiveSolver; +import com.patryk.mathdoku.cageData.Cage; import com.patryk.mathdoku.UserData; import java.util.List; @@ -11,11 +10,14 @@ public class CageInfo { private boolean isInvalid = false; private boolean recordValid = false; private int populationCount = 0; + private static UserData userData; + public static void setUserData(UserData userData) { + CageInfo.userData = userData; + } public CageInfo (Cage cage) { this.cage = cage; - isInvalid = false; } @@ -27,7 +29,7 @@ public class CageInfo { return cage; } - public boolean isRecordOutOfDate() { + /*public boolean isRecordOutOfDate() { return !recordValid; } @@ -37,14 +39,13 @@ public class CageInfo { public void setCorrectness(boolean value) { isInvalid = value; - } + }*/ public void onDigitEntered() { populationCount++; if (isFull()) { int[] cageMemberData = getMembersOfCage(); isInvalid = !RecursiveSolver.testSign(cageMemberData, cage.getTarget(), cage.getOperator()); - System.out.println("Cage has been made full. Is there a problem?: " + isInvalid); } } @@ -58,7 +59,7 @@ public class CageInfo { List<Integer> memberCells = cage.getMemberCells(); int[] memberData = new int[memberCells.size()]; for (int i = 0; i < memberCells.size(); i++) { - memberData[i] = UserData.me().getValueAtCell(memberCells.get(i)); + memberData[i] = userData.getValueAtCell(memberCells.get(i)); } return memberData; diff --git a/src/com/patryk/mathdoku/errorChecking/ErrorShower.java b/src/com/patryk/mathdoku/errorChecking/ErrorShower.java index b8535f6fb892bb6364327310baa68a97a70a93cc..6ffec21c8ec359ae83cc6db98bb5cf18a6e0b68b 100644 --- a/src/com/patryk/mathdoku/errorChecking/ErrorShower.java +++ b/src/com/patryk/mathdoku/errorChecking/ErrorShower.java @@ -1,6 +1,6 @@ package com.patryk.mathdoku.errorChecking; -import com.patryk.mathdoku.Cage; +import com.patryk.mathdoku.cageData.Cage; public interface ErrorShower { void onCageInvalid(Cage cage); diff --git a/src/com/patryk/mathdoku/errorChecking/RCChecker.java b/src/com/patryk/mathdoku/errorChecking/RCChecker.java index 8239dc4139f4518d2c3e4231f05663c061d32e9b..a25a93b44a2b90a32f33fb63ed9fb89542f79e30 100644 --- a/src/com/patryk/mathdoku/errorChecking/RCChecker.java +++ b/src/com/patryk/mathdoku/errorChecking/RCChecker.java @@ -1,7 +1,7 @@ package com.patryk.mathdoku.errorChecking; import java.util.Arrays; -import com.patryk.mathdoku.global.BoardPosVec; +import com.patryk.mathdoku.util.BoardPosVec; import com.patryk.mathdoku.UserData; public class RCChecker { @@ -19,17 +19,16 @@ public class RCChecker { public void onDigitEntered(BoardPosVec cellChanged, int digit) { rowInfos.getList()[cellChanged.r].onDigitEntered(digit); colInfos.getList()[cellChanged.c].onDigitEntered(digit); - System.out.printf("Digit %d entered at %s.\nData for row is: %s\nData for column is: %s\n\n", digit, cellChanged, rowInfos.getList()[cellChanged.r], colInfos.getList()[cellChanged.c]); + //System.out.printf("Digit %d entered at %s.\nData for row is: %s\nData for column is: %s\n\n", digit, cellChanged, rowInfos.getList()[cellChanged.r], colInfos.getList()[cellChanged.c]); } public void onDigitRemoved(BoardPosVec cellChanged, int digit) { rowInfos.getList()[cellChanged.r].onDigitRemoved(digit); colInfos.getList()[cellChanged.c].onDigitRemoved(digit); - System.out.printf("Digit %d removed at %s.\nData for row is: %s\nData for column is: %s\n\n", digit, cellChanged, rowInfos.getList()[cellChanged.r], colInfos.getList()[cellChanged.c]); + //System.out.printf("Digit %d removed at %s.\nData for row is: %s\nData for column is: %s\n\n", digit, cellChanged, rowInfos.getList()[cellChanged.r], colInfos.getList()[cellChanged.c]); } public void recalculate(UserData userData) { - //TODO for every cell in the data, call the corresponding on value changed/removed reset(); for (int r = 0; r < boardWidth; r++) { for (int c = 0; c < boardWidth; c++) { @@ -119,7 +118,6 @@ class RCInfo { digitCount++; } - //TODO call it somewhere! public void onDigitRemoved(int digit) { int finalCount = --digitCounts[digit - 1]; if (finalCount == 0 ) { diff --git a/src/com/patryk/mathdoku/RecursiveSolver.java b/src/com/patryk/mathdoku/errorChecking/RecursiveSolver.java similarity index 94% rename from src/com/patryk/mathdoku/RecursiveSolver.java rename to src/com/patryk/mathdoku/errorChecking/RecursiveSolver.java index 192793f238bf2a4067a82c5f2a6d0a589fc90358..478fa938cb8f8eb44af57a346743e8dc559153b4 100644 --- a/src/com/patryk/mathdoku/RecursiveSolver.java +++ b/src/com/patryk/mathdoku/errorChecking/RecursiveSolver.java @@ -1,4 +1,6 @@ -package com.patryk.mathdoku; +package com.patryk.mathdoku.errorChecking; + +import com.patryk.mathdoku.cageData.Cage; public class RecursiveSolver { @@ -39,8 +41,6 @@ public class RecursiveSolver { this.permute = (operator == Cage.Operator.SUBTRACT || operator == Cage.Operator.DIVIDE); } - //!!!not thread safe!!! - //TODO make cagelist a member! public static boolean testSign(int[] cageList, int target, Cage.Operator operator) { return new RecursiveSolver(target, operator).f(0, cageList, 0, 0); } diff --git a/src/com/patryk/mathdoku/errorChecking/GridErrorChecker.java b/src/com/patryk/mathdoku/errorChecking/UserErrorChecker.java similarity index 80% rename from src/com/patryk/mathdoku/errorChecking/GridErrorChecker.java rename to src/com/patryk/mathdoku/errorChecking/UserErrorChecker.java index 783d9d25b1be85f8492be20ad8c1190cc7bcfa0a..452a9a232dbab4fe31774b4e7c1e96c307b0c3ed 100644 --- a/src/com/patryk/mathdoku/errorChecking/GridErrorChecker.java +++ b/src/com/patryk/mathdoku/errorChecking/UserErrorChecker.java @@ -1,10 +1,10 @@ package com.patryk.mathdoku.errorChecking; -import com.patryk.mathdoku.CageData; +import com.patryk.mathdoku.cageData.CageData; import com.patryk.mathdoku.UserData; -import com.patryk.mathdoku.global.BoardPosVec; +import com.patryk.mathdoku.util.BoardPosVec; -public class GridErrorChecker { +public class UserErrorChecker { /* every time a change to a cell is made, a check is made whether the row, column and cage are valid. @@ -44,14 +44,13 @@ public class GridErrorChecker { CageData cageData; - public GridErrorChecker (int boardWidth, UserData userData, CageData cageData) { + public UserErrorChecker(int boardWidth, UserData userData, CageData cageData) { this.boardWidth = boardWidth; this.userData = userData; this.cageData = cageData; rcChecker = new RCChecker(boardWidth); - cageChecker = new CageChecker(cageData); - //todo call is not needed when grid is initially blank + cageChecker = new CageChecker(userData, cageData); recalculate(); } @@ -65,11 +64,6 @@ public class GridErrorChecker { private void onSingleCellChange(UserData.ChangeListener.SingleCellChange changeData) { - BoardPosVec cellChanged = changeData.getCellChanged(); - //cage checker doesn't care whether it's added or not - // todo cageChecker.onDigitChanged(cellChanged); - //if value entered - //todo what if a digit is neither added or removed?? /* bef after call entered call removed @@ -106,7 +100,6 @@ public class GridErrorChecker { } else { rcChecker.reset(); cageChecker.reset(); - //todo cageChecker.reset(); } } @@ -116,7 +109,6 @@ public class GridErrorChecker { * @param changeData */ public void onGridChange(UserData.ChangeListener.ChangeData changeData) { - System.out.println("Start of change."); //rcchecker updates itself at every change, while cageChecker only recalculates when the grid is full. //however, everything can be recalculated when the check button is pressed if (changeData instanceof UserData.ChangeListener.SingleCellChange) { @@ -124,7 +116,6 @@ public class GridErrorChecker { } else if (changeData instanceof UserData.ChangeListener.MultipleCellChange) { onMultipleCellChange((UserData.ChangeListener.MultipleCellChange) changeData); } - System.out.println("End of change."); } @@ -139,25 +130,6 @@ public class GridErrorChecker { } - - /* TODO private boolean cagesValid() { - for (CageInfo cage: cageInfos) { - if (cage.isRecordOutOfDate()) { - cage.reCalculate(); - } - - if (!cage.isCageCorrect()) { - return false; - } - } - - return true; - }*/ - - /* TODO public boolean isWon() { - return rowsCompleteAndCorrect() && cagesValid(); - }*/ - public void showErrors(ErrorShower errorShower) { //rows and columns for (int i = 0; i < boardWidth; i++) { diff --git a/src/com/patryk/mathdoku/gui/GameGridView.java b/src/com/patryk/mathdoku/gui/GameGridView.java new file mode 100644 index 0000000000000000000000000000000000000000..4caa5ab8a78f00ad9289480396284041aa3cddc7 --- /dev/null +++ b/src/com/patryk/mathdoku/gui/GameGridView.java @@ -0,0 +1,153 @@ +package com.patryk.mathdoku.gui; + +import com.patryk.mathdoku.cageData.Cage; +import com.patryk.mathdoku.GameContext; +import com.patryk.mathdoku.UserData; +import com.patryk.mathdoku.gui.drawers.*; +import com.patryk.mathdoku.errorChecking.ErrorShower; +import com.patryk.mathdoku.util.BoardPosVec; +import javafx.scene.Group; +import javafx.scene.Node; +import javafx.scene.input.MouseEvent; + + +public class GameGridView { + + public enum FontSize {SMALL, MEDIUM, LARGE}; + FontSize fontSize; + + private int pixelWidth; + + private CageDrawer cageDrawer; + private SelectedCellDrawer selectedCellDrawer; + private UserDataDrawer userDataDrawer; + private ErrorsHighlighter errorHighlighter; + + private final Drawer[] drawers; + + Group group; + + InputHandler inputHandler = new InputHandler(this); + + private GameContext gameContext; + BoardPosVec selectedCell = new BoardPosVec(0, 0); + + ErrorShower gameErrorCallback = new ErrorShower() { + @Override + public void onCageInvalid(Cage cage) { + errorHighlighter.drawErroneousCage(cage); + } + + @Override + public void onRowColInvalid(boolean isRow, int index) { + errorHighlighter.drawErroneousRow(isRow, index); + } + }; + + UserData.ChangeListener redrawGame = (data) -> { + userDataDrawer.draw(); + errorHighlighter.clearCanvas(); + }; + + + public GameGridView(int pixelWidth) { + this.pixelWidth = pixelWidth; + Drawer.setPixelWidth(pixelWidth); + BoardPosVec.setPixelWidth(pixelWidth); + //create canvases + + cageDrawer = new CageDrawer(); + userDataDrawer = new UserDataDrawer(); + selectedCellDrawer = new SelectedCellDrawer(); + errorHighlighter = new ErrorsHighlighter(); + + drawers = new Drawer[]{cageDrawer, selectedCellDrawer, userDataDrawer, errorHighlighter}; + + //add them to group + group = new Group(); + group.getChildren().addAll(cageDrawer.getCanvas(), selectedCellDrawer.getCanvas(), userDataDrawer.getCanvas(), errorHighlighter.getCanvas()); + userDataDrawer.getCanvas().toFront(); + errorHighlighter.getCanvas().toBack(); + + } + + private void clear() { + for (Drawer drawer: drawers) + drawer.clearCanvas(); + } + + public void showErrors() { + gameContext.getErrorChecker().showErrors(gameErrorCallback); + } + + public void setGameContext(GameContext gameContext, FontSize fontSize) { + clear(); + Drawer.setBoardWidth(gameContext.getBoardWidth()); + Drawer.setFontSize(fontSize); + //note game context + this.gameContext = gameContext; + //Drawer.init(gameContext.getBoardWidth(), pixelWidth); + + gameContext.getUserData().addChangeListener(redrawGame); + + //link cage drawer to canvas and draw the cages + + userDataDrawer.setData(gameContext.getUserData()); + cageDrawer.setData(gameContext.getCageData()); + userDataDrawer.updateFontSize(); + cageDrawer.updateFontSize(); + + selectedCellDrawer.draw(selectedCell); + + //link the user data drawer but don't draw the user data + //userDataDrawer.draw(); + //link selected cell drawer to canvas + + //error checking + + } + + public void setFontSize(FontSize fontSize) { + + Drawer.setFontSize(fontSize); + cageDrawer.updateFontSize(); + userDataDrawer.updateFontSize(); + + } + + public void configureKeyEvents() { + //initialize input handler + group.addEventHandler(MouseEvent.MOUSE_CLICKED, inputHandler.getMouseHandler()); + group.getScene().setOnKeyPressed(inputHandler.getKeyEventHandler()); + + } + + public InputHandler getInputHandler() { + return inputHandler; + } + + public void setSelectedCell(BoardPosVec selectedCell) { + if (!selectedCell.clampToArea()) { + this.selectedCell = selectedCell; + selectedCellDrawer.draw(selectedCell); + } + } + + public BoardPosVec getSelectedCell() { + return selectedCell; + } + + public int getPixelWidth() { + return pixelWidth; + } + + + public GameContext getGameContext() { + return gameContext; + } + + public Node getNode() { + return group; + } +} + diff --git a/src/com/patryk/mathdoku/gui/GameUI.java b/src/com/patryk/mathdoku/gui/GameUI.java new file mode 100644 index 0000000000000000000000000000000000000000..4ca2379125d96e617af62644d6f4416a3e21b104 --- /dev/null +++ b/src/com/patryk/mathdoku/gui/GameUI.java @@ -0,0 +1,207 @@ +package com.patryk.mathdoku.gui; + +import com.patryk.mathdoku.GameContext; +import com.patryk.mathdoku.actions.UndoRedoButtonManager; +import com.patryk.mathdoku.UserData; +import com.patryk.mathdoku.cageData.DataFormatException; +import javafx.beans.value.ChangeListener; +import javafx.beans.value.ObservableValue; +import javafx.event.ActionEvent; +import javafx.event.EventHandler; +import javafx.scene.Scene; +import javafx.scene.control.Alert; +import javafx.scene.control.Button; +import javafx.scene.control.ButtonType; +import javafx.scene.control.ComboBox; +import javafx.scene.image.Image; +import javafx.scene.image.ImageView; +import javafx.scene.layout.HBox; +import javafx.scene.layout.VBox; + +import java.io.FileInputStream; +import java.io.FileNotFoundException; + +public class GameUI { + + private static final int MAX_WIDTH = 8; + private Scene scene; + GameContext gameContext; + private boolean wonBefore = false; + + public boolean hasWonBefore() { + return wonBefore; + } + + VBox controlPane; + + public Button undoButton = new Button("Undo"); + public Button redoButton = new Button("Redo"); + public Button clearButton = new Button("Clear"); + public Button checkButton = new Button("Check"); + public Button fileLoadButton = new Button("Load game from file"); + public Button textLoadButton = new Button("Load game from text input"); + + public ComboBox<GameGridView.FontSize> fontSizeComboBox; + GameGridView.FontSize defaultFontSize = GameGridView.FontSize.MEDIUM; + + + VBox numberPad = new VBox(); + public GameGridView gameGridView; + UndoRedoButtonManager undoRedoButtonManager; + + UserData.ChangeListener onUserDataChanged = (changeData) -> { + if (gameContext.isWon() && !wonBefore) { + wonBefore = true; + showWinningAnimation(); + } + + if (gameContext.getUserData().isEmpty()) { + clearButton.setDisable(true); + } else { + clearButton.setDisable(false); + } + + }; + + + public interface NumberButtonCallback { + void onNumberButtonPressed(int buttonNumber); + } + + NumberButtonCallback numberButtonCallback; + + + EventHandler<ActionEvent> onNumberButtonPressed = (event) -> { + Button button = (Button)event.getSource(); + numberButtonCallback.onNumberButtonPressed((Integer)button.getUserData()); + }; + + + public GameUI() { + undoRedoButtonManager = new UndoRedoButtonManager(undoButton, redoButton); + //initialize control pane + controlPane = new VBox(); + controlPane.getChildren().addAll(undoButton, redoButton, clearButton, checkButton, fileLoadButton, textLoadButton); + + //disable clear and check buttons + clearButton.setDisable(true); + checkButton.setDisable(true); + + //font combobox# + fontSizeComboBox = new ComboBox<>(); + fontSizeComboBox.setValue(defaultFontSize); + fontSizeComboBox.getItems().addAll(GameGridView.FontSize.SMALL, + GameGridView.FontSize.MEDIUM, + GameGridView.FontSize.LARGE); + + fontSizeComboBox.setDisable(true); + //fontSizeComboBox.se + fontSizeComboBox.valueProperty().addListener(new ChangeListener<GameGridView.FontSize>() { + @Override + public void changed(ObservableValue<? extends GameGridView.FontSize> observableValue, GameGridView.FontSize oldSize, GameGridView.FontSize newSize) { + gameGridView.setFontSize(newSize); + } + }); + + //initialize button pane, disable all + for (int i = 1; i <= MAX_WIDTH; i++) { + Button button = new Button(Integer.toString(i)); + button.setUserData(i); + button.addEventHandler(ActionEvent.ANY, onNumberButtonPressed); + numberPad.getChildren().add(button); + button.setDisable(true); + } + + + + //init game grid view + gameGridView = new GameGridView(600); + + //initialize master layout + HBox masterLayout = new HBox(); + masterLayout.getChildren().addAll(controlPane, gameGridView.getNode(), numberPad, fontSizeComboBox); + + //init scene + scene = new Scene(masterLayout); + + } + + public void setGameContext(GameContext gameContext) { + this.gameContext = gameContext; + undoRedoButtonManager.setGameContext(gameContext); + wonBefore = false; + + //enable some buttons + checkButton.setDisable(false); + + fontSizeComboBox.setDisable(false); + + //enable buttons which are valid ... + for (int i = 0; i < MAX_WIDTH; i++) { + boolean disable = i >= gameContext.getBoardWidth(); + numberPad.getChildren().get(i).setDisable(disable); + } + + + //init game grid view + gameGridView.setGameContext(gameContext, defaultFontSize); + + gameGridView.getNode().requestFocus(); + gameContext.getUserData().addChangeListener(onUserDataChanged); + //init scene + gameGridView.configureKeyEvents(); + + } + + private void showWinningAnimation() { + Alert alert = new Alert(Alert.AlertType.INFORMATION); + alert.setTitle("Congratulations!"); + alert.setHeaderText("You won the game!"); + try { + alert.setGraphic(new ImageView(new Image(new FileInputStream("fireworks.jpg")))); + } catch (FileNotFoundException e) { + + } + alert.showAndWait(); + } + + public void setNumberButtonCallback(NumberButtonCallback numberButtonCallback) { + this.numberButtonCallback = numberButtonCallback; + } + + public void showDataFormatErrorAlert(DataFormatException e) { + Alert alert = new Alert(Alert.AlertType.ERROR); + alert.setTitle("Data format error."); + alert.setContentText(e.getMessage()); + alert.setResizable(true); + alert.showAndWait(); + } + + public boolean showConfirmExitDialog() { + Alert confirmDialog = new Alert(Alert.AlertType.CONFIRMATION); + confirmDialog.setTitle("Confirm Exit"); + confirmDialog.setHeaderText("A game is currently running."); + confirmDialog.setContentText("Are you sure you want to exit? You will lose your progress!"); + confirmDialog.setResizable(true); + + ButtonType userChoice = confirmDialog.showAndWait().get(); + + return userChoice.equals(ButtonType.OK); + } + + public boolean showConfirmDialog( ) { + Alert confirmDialog = new Alert(Alert.AlertType.CONFIRMATION); + confirmDialog.setTitle("Confirm action,"); + confirmDialog.setContentText("Are you sure?"); + + ButtonType userChoice = confirmDialog.showAndWait().get(); + + return userChoice.equals(ButtonType.OK); + + } + public Scene getScene() { + return scene; + } + +} + diff --git a/src/com/patryk/mathdoku/ManualGameInputDialog.java b/src/com/patryk/mathdoku/gui/ManualGameInputDialog.java similarity index 54% rename from src/com/patryk/mathdoku/ManualGameInputDialog.java rename to src/com/patryk/mathdoku/gui/ManualGameInputDialog.java index 6ee1596bd0d4dba93c852f64596f7b8e696b7712..4f6b4a349eef3d4e97babfc044e18b622f0ef3e7 100644 --- a/src/com/patryk/mathdoku/ManualGameInputDialog.java +++ b/src/com/patryk/mathdoku/gui/ManualGameInputDialog.java @@ -1,17 +1,26 @@ -package com.patryk.mathdoku; +package com.patryk.mathdoku.gui; +import javafx.event.EventTarget; import javafx.scene.control.ButtonType; import javafx.scene.control.Dialog; import javafx.scene.control.TextArea; import javafx.util.Callback; public class ManualGameInputDialog extends Dialog<String> { - TextArea textArea; + private TextArea textArea; public ManualGameInputDialog() { getDialogPane().setContent( textArea = new TextArea()); getDialogPane().getButtonTypes().addAll(ButtonType.CANCEL, ButtonType.OK); + setResizable(true); + + setResultConverter(buttonType -> { + if (buttonType.equals(ButtonType.OK)) + return textArea.getText(); + else { + return null; + } + }); - setResultConverter(buttonType -> textArea.getText()); } } diff --git a/src/com/patryk/mathdoku/gui/drawers/CageDrawer.java b/src/com/patryk/mathdoku/gui/drawers/CageDrawer.java new file mode 100644 index 0000000000000000000000000000000000000000..2d99d6d158abf6d8eb1d0b0eadf49cc568be5705 --- /dev/null +++ b/src/com/patryk/mathdoku/gui/drawers/CageDrawer.java @@ -0,0 +1,101 @@ +package com.patryk.mathdoku.gui.drawers; + +import com.patryk.mathdoku.cageData.Cage; +import com.patryk.mathdoku.cageData.CageData; +import com.patryk.mathdoku.util.BoardPosVec; +import com.patryk.mathdoku.util.Direction; +import com.patryk.mathdoku.util.Util; +import javafx.scene.paint.Color; +import javafx.scene.text.Font; + +public class CageDrawer extends Drawer{ + + private static final String fontFamily = "Zapfino"; + private CageData data; + private Font font; + + + public void setData(CageData data) { + this.data = data; + + } + + public void updateFontSize() { + int size = 1; + switch (fontSize) { + case SMALL: + size = 12; + break; + case MEDIUM: + size = 17; + break; + case LARGE: + size = 21; + break; + } + font = new Font(fontFamily, size); + draw(); + } + + public void draw() { + clearCanvas(); + drawMainLines(); + drawCageBoundaries(); + drawCageSigns(); + //drawLineFromPoint(new Util.BoardPosVec(2,1), Util.Direction.EAST); + } + + private void drawCageBoundaries() { + + gc.setLineWidth(2.0); + gc.setStroke(Color.BLACK); + + + for (int r = 0; r < boardWidth; r++) { + for (int c = 0; c < boardWidth; c++) { + for (Direction d: Direction.values()) { + BoardPosVec squareVec = new BoardPosVec(r, c); + + if (! data.cellConnectsTo(squareVec, d)) { + drawLineFromSquare(new BoardPosVec(r, c), d); + } + } + } + } + } + + + private void drawMainLines() { + gc.setLineWidth(1.0); + gc.setStroke(Color.GRAY); + + //draw back grid + + for (int i = 1; i < boardWidth; i++) { + int pixelOffset = Util.boardToPixel(i, boardWidth, pixelWidth); + //vertical + gc.strokeLine(pixelOffset, 0.0, pixelOffset, pixelWidth); + //horizontal + gc.strokeLine(0.0, pixelOffset, pixelWidth, pixelOffset); + } + } + + + + private void drawCageSigns() { + + //draw mathematical signs + gc.setFill(Color.BLACK); + gc.setFont(font); + + + for (Cage c: data.getCages()) { + drawCageText(new BoardPosVec(c.getMarkedCell()), c.toString()); + } + } + + private void drawCageText(BoardPosVec pos, String text) { + pos = pos.toPixelSpace(); + gc.fillText(text, pos.c, pos.r + font.getSize()); + } +} diff --git a/src/com/patryk/mathdoku/drawers/Drawer.java b/src/com/patryk/mathdoku/gui/drawers/Drawer.java similarity index 52% rename from src/com/patryk/mathdoku/drawers/Drawer.java rename to src/com/patryk/mathdoku/gui/drawers/Drawer.java index 071a1affa9f6be940b1b1909fb37e0410ca8d210..530bbd44cf0b16097668c38d65d1e7fb6719e0c7 100644 --- a/src/com/patryk/mathdoku/drawers/Drawer.java +++ b/src/com/patryk/mathdoku/gui/drawers/Drawer.java @@ -1,21 +1,49 @@ -package com.patryk.mathdoku.drawers; +package com.patryk.mathdoku.gui.drawers; -import com.patryk.mathdoku.GameGridView; -import com.patryk.mathdoku.Util; -import com.patryk.mathdoku.global.BoardPosVec; +import com.patryk.mathdoku.gui.GameGridView; +import com.patryk.mathdoku.util.Direction; +import com.patryk.mathdoku.util.BoardPosVec; import javafx.scene.canvas.Canvas; import javafx.scene.canvas.GraphicsContext; public class Drawer { + protected static GameGridView.FontSize fontSize; + + protected static int pixelWidth; + protected static int boardWidth; + protected static int squarePixelWidth; + + public static void setPixelWidth(int pixelWidth) { + Drawer.pixelWidth = pixelWidth; + + } + + public static void setBoardWidth(int boardWidth) { + Drawer.boardWidth = boardWidth; + Drawer.squarePixelWidth = pixelWidth / boardWidth; + } + + protected GraphicsContext gc; + private Canvas canvas; //protected static GameContext gameContext = GameContext.getInstance(); - protected Drawer(GraphicsContext gc) { - this.gc = gc; + protected Drawer() { + assert (pixelWidth != 0); + this.canvas = new Canvas(pixelWidth, pixelWidth); + this.gc = canvas.getGraphicsContext2D(); + } + + public static void setFontSize(GameGridView.FontSize fontSize) { + Drawer.fontSize = fontSize; + } + + public Canvas getCanvas() { + return canvas; } public void clearCanvas() { @@ -24,26 +52,26 @@ public class Drawer { gc.clearRect(0, 0, pixelWidth, pixelWidth); } - protected void drawLineFromSquare (BoardPosVec pos, Util.Direction dir) { - Util.Direction lineDir = Util.Direction.NORTH; + protected void drawLineFromSquare (BoardPosVec pos, Direction dir) { + Direction lineDir = Direction.NORTH; - if (dir == Util.Direction.EAST || dir == Util.Direction.SOUTH) { + if (dir == Direction.EAST || dir == Direction.SOUTH) { pos.r++; pos.c++; } switch (dir) { case NORTH: - lineDir = Util.Direction.EAST; + lineDir = Direction.EAST; break; case WEST: - lineDir = Util.Direction.SOUTH; + lineDir = Direction.SOUTH; break; case EAST: - lineDir = Util.Direction.NORTH; + lineDir = Direction.NORTH; break; case SOUTH: - lineDir = Util.Direction.WEST; + lineDir = Direction.WEST; break; } @@ -54,7 +82,7 @@ public class Drawer { } - protected void drawLineFromPoint (BoardPosVec pos, Util.Direction dir) { + protected void drawLineFromPoint (BoardPosVec pos, Direction dir) { BoardPosVec pos2 = pos.add(dir.vector); @@ -65,9 +93,9 @@ public class Drawer { private void drawSquarePixelwise(boolean stroke, BoardPosVec pos1) { if (stroke) - gc.strokeRect(pos1.c, pos1.r, GameGridView.getSquarePixelWidth(), GameGridView.getSquarePixelWidth()); + gc.strokeRect(pos1.c, pos1.r, squarePixelWidth, squarePixelWidth); else - gc.fillRect(pos1.c, pos1.r, GameGridView.getSquarePixelWidth(), GameGridView.getSquarePixelWidth()); + gc.fillRect(pos1.c, pos1.r, squarePixelWidth, squarePixelWidth); } diff --git a/src/com/patryk/mathdoku/ErrorsHighlighter.java b/src/com/patryk/mathdoku/gui/drawers/ErrorsHighlighter.java similarity index 63% rename from src/com/patryk/mathdoku/ErrorsHighlighter.java rename to src/com/patryk/mathdoku/gui/drawers/ErrorsHighlighter.java index b204ca390cb69fd217c5b414003cff8e83dab5e1..6388a4756a3baec4eff9be6b01dde4623eab9168 100644 --- a/src/com/patryk/mathdoku/ErrorsHighlighter.java +++ b/src/com/patryk/mathdoku/gui/drawers/ErrorsHighlighter.java @@ -1,14 +1,11 @@ -package com.patryk.mathdoku; +package com.patryk.mathdoku.gui.drawers; -import com.patryk.mathdoku.drawers.Drawer; -import com.patryk.mathdoku.global.BoardPosVec; -import javafx.scene.canvas.GraphicsContext; +import com.patryk.mathdoku.cageData.Cage; +import com.patryk.mathdoku.util.BoardPosVec; import javafx.scene.paint.Color; public class ErrorsHighlighter extends Drawer { - public ErrorsHighlighter(GraphicsContext gc) { - super(gc); - } + public void drawErroneousCage(Cage cage) { gc.setFill(Color.RED); @@ -23,10 +20,10 @@ public class ErrorsHighlighter extends Drawer { BoardPosVec size ; if (isRow) { start = new BoardPosVec(index, 0); - size = new BoardPosVec(1, GameContext.getBoardWidth()); + size = new BoardPosVec(1, boardWidth); } else { //col start = new BoardPosVec(0, index); - size = new BoardPosVec(GameContext.getBoardWidth(), 1); + size = new BoardPosVec(boardWidth, 1); } gc.setFill(Color.ORANGE); diff --git a/src/com/patryk/mathdoku/drawers/SelectedCellDrawer.java b/src/com/patryk/mathdoku/gui/drawers/SelectedCellDrawer.java similarity index 57% rename from src/com/patryk/mathdoku/drawers/SelectedCellDrawer.java rename to src/com/patryk/mathdoku/gui/drawers/SelectedCellDrawer.java index 93b590d13380b577ee5c7595cad661f6a48026ab..ce13a1907d7bf19214e836ec9fbcb28a333e4c8f 100644 --- a/src/com/patryk/mathdoku/drawers/SelectedCellDrawer.java +++ b/src/com/patryk/mathdoku/gui/drawers/SelectedCellDrawer.java @@ -1,13 +1,12 @@ -package com.patryk.mathdoku.drawers; +package com.patryk.mathdoku.gui.drawers; -import com.patryk.mathdoku.global.BoardPosVec; -import javafx.scene.canvas.GraphicsContext; +import com.patryk.mathdoku.util.BoardPosVec; import javafx.scene.paint.Color; public class SelectedCellDrawer extends Drawer{ - public SelectedCellDrawer(GraphicsContext gc) { - super(gc); + public SelectedCellDrawer() { + super(); } public void draw(BoardPosVec markedCell) { diff --git a/src/com/patryk/mathdoku/gui/drawers/UserDataDrawer.java b/src/com/patryk/mathdoku/gui/drawers/UserDataDrawer.java new file mode 100644 index 0000000000000000000000000000000000000000..2b15a2d32bb7d5a290639bb6fdf7492664f8a08b --- /dev/null +++ b/src/com/patryk/mathdoku/gui/drawers/UserDataDrawer.java @@ -0,0 +1,63 @@ +package com.patryk.mathdoku.gui.drawers; + +import com.patryk.mathdoku.UserData; +import com.patryk.mathdoku.util.BoardPosVec; +import javafx.scene.text.Font; +import javafx.scene.text.TextAlignment; + + +public class UserDataDrawer extends Drawer { + private UserData data; + private Font font; + + public void setData(UserData data) { + this.data = data; + } + + public void updateFontSize() { + double sizeRatio = 0.0; + switch (fontSize) { + case SMALL: + sizeRatio = 0.6; + break; + case MEDIUM: + sizeRatio = 0.7; + break; + case LARGE: + sizeRatio = 0.8; + break; + } + + int newSize = (int) ((double) squarePixelWidth * sizeRatio ); + font = new Font("Zapfino", newSize); + draw(); + } + + public void draw() { + assert(data != null); + clearCanvas(); + gc.setFont(font); + gc.setTextAlign(TextAlignment.CENTER); + + for (int r = 0; r < boardWidth; r++) { + for (int c = 0; c < boardWidth; c++) { + BoardPosVec pos = new BoardPosVec(r, c); + int digit = data.getValueAtCell(pos); + if (digit != 0) + drawUserDigit(pos, digit); + //drawUserDigit(pos, pos.toIndex()); + } + } + } + + public void drawUserDigit(BoardPosVec pos, int digit) { + pos.r++; + BoardPosVec pixelPos = pos.toPixelSpace(); +/* + int offset = (GameContext.getInstance().getSquarePixelWidth() - fontSize) / 2;*/ + pixelPos.c += squarePixelWidth / 2; + pixelPos.r -= (squarePixelWidth - font.getSize()) / 2; + + gc.fillText(Integer.toString(digit), pixelPos.c, pixelPos.r); + } +} diff --git a/src/com/patryk/mathdoku/global/BoardPosVec.java b/src/com/patryk/mathdoku/util/BoardPosVec.java similarity index 79% rename from src/com/patryk/mathdoku/global/BoardPosVec.java rename to src/com/patryk/mathdoku/util/BoardPosVec.java index dd30c6746a72ee7c31c8e2f1cf46c23a4bae504a..c0375835154c11c756d64eaa3b07f826ada25fba 100644 --- a/src/com/patryk/mathdoku/global/BoardPosVec.java +++ b/src/com/patryk/mathdoku/util/BoardPosVec.java @@ -1,17 +1,19 @@ -package com.patryk.mathdoku.global; - -import com.patryk.mathdoku.GameGridView; -import com.patryk.mathdoku.Util; +package com.patryk.mathdoku.util; public class BoardPosVec { //private static GameContext gameContext = GameContext.getInstance(); //public static int width = GameContext.getBoardWidth(); public static int boardWidth; + public static int pixelWidth; + public static void setBoardWidth(int boardWidth) { BoardPosVec.boardWidth = boardWidth; } + public static void setPixelWidth(int pixelWidth) { + BoardPosVec.pixelWidth = pixelWidth; + } /*public static int pixelWidth; public static void setPixelWidth(int pixelWidth) { @@ -46,7 +48,6 @@ public class BoardPosVec { return (r == boardWidth - 1 && c == boardWidth - 1); } - //TODO test public boolean clampToArea() { //--- int oldRow = r, oldCol = c; @@ -68,13 +69,12 @@ public class BoardPosVec { } public BoardPosVec toPixelSpace() { - return new BoardPosVec(this.r * GameGridView.getSquarePixelWidth(), this.c * GameGridView.getSquarePixelWidth()); + return new BoardPosVec(Util.boardToPixel(this.r, boardWidth, pixelWidth), Util.boardToPixel(this.c, boardWidth, pixelWidth)); } public BoardPosVec fromPixelToBoardSpace() { - int pixelWidth = GameGridView.getSquarePixelWidth(); - return new BoardPosVec(Math.floorDiv(r, pixelWidth), Math.floorDiv(c, pixelWidth)); + return new BoardPosVec(Util.pixelToBoard(this.r, boardWidth, pixelWidth), Util.pixelToBoard(this.c, boardWidth, pixelWidth)); } diff --git a/src/com/patryk/mathdoku/MatcherHelper.java b/src/com/patryk/mathdoku/util/MatcherHelper.java similarity index 91% rename from src/com/patryk/mathdoku/MatcherHelper.java rename to src/com/patryk/mathdoku/util/MatcherHelper.java index b5c5030baff66314c5560539e88d74a8b770b55e..7ca08df17ac40bf2cb81956332f47ab85d04574d 100644 --- a/src/com/patryk/mathdoku/MatcherHelper.java +++ b/src/com/patryk/mathdoku/util/MatcherHelper.java @@ -1,4 +1,4 @@ -package com.patryk.mathdoku; +package com.patryk.mathdoku.util; import java.util.regex.Matcher; import java.util.regex.Pattern; diff --git a/src/com/patryk/mathdoku/Util.java b/src/com/patryk/mathdoku/util/Util.java similarity index 51% rename from src/com/patryk/mathdoku/Util.java rename to src/com/patryk/mathdoku/util/Util.java index 484d295ce792814a6cc5ed177e967cdca134e769..7e6df45b5e63f52bf2662be144eca5fd29cc0975 100644 --- a/src/com/patryk/mathdoku/Util.java +++ b/src/com/patryk/mathdoku/util/Util.java @@ -1,25 +1,7 @@ -package com.patryk.mathdoku; - -import com.patryk.mathdoku.global.BoardPosVec; +package com.patryk.mathdoku.util; public class Util { - /*public static int getNumberOfLinesInFile(String fileName) throws IOException { - FileReader f = new FileReader(fileName); - int lines = 1; - - while (true) { - int charCode = f.read(); - if (charCode == (int)'\n') - lines++; - else if (charCode == -1) { - break; - } - - } - - return lines; - }*/ public static int clampToRange(int x, int maxWidth) { @@ -34,35 +16,43 @@ public class Util { return x; } - /*public static int appendDigitToInt(int mainInt, char digit) { - if (mainInt == -1) { - return charToInt(digit); - } - return Integer.parseInt(Integer.toString(mainInt) + digit); - }*/ + public static int charToInt(char c) { return c & 15; } - // TODO move this to drawer!!! - /* - public static void clearCanvas(GraphicsContext gc) { - int pixelWidth = GameGridView.getPixelWidth(); - gc.clearRect(0, 0, pixelWidth, pixelWidth); - }*/ + public static int boardToPixel(int n, int boardWidth, int pixelWidth) { + return Math.floorDiv(n * pixelWidth, boardWidth); + } + + public static int pixelToBoard(int pixCoord, int boardWidth, int pixelWidth) { + return Math.floorDiv(pixCoord * boardWidth, pixelWidth); + } - public enum Direction { - NORTH (new BoardPosVec(-1, 0)), - EAST (new BoardPosVec( 0, 1)), - SOUTH (new BoardPosVec( 1, 0)), - WEST (new BoardPosVec( 0, -1)); + /*public static int getNumberOfLinesInFile(String fileName) throws IOException { + FileReader f = new FileReader(fileName); + int lines = 1; - public final BoardPosVec vector; + while (true) { + int charCode = f.read(); + + if (charCode == (int)'\n') + lines++; + else if (charCode == -1) { + break; + } - private Direction(BoardPosVec vec) { - vector = vec; } - } + + return lines; + }*/ + + /*public static int appendDigitToInt(int mainInt, char digit) { + if (mainInt == -1) { + return charToInt(digit); + } + return Integer.parseInt(Integer.toString(mainInt) + digit); + }*/ } diff --git a/src/out.txt b/src/out.txt deleted file mode 100644 index 8d951b44ce31f520c899a1f7ff4dba2feb104f4b..0000000000000000000000000000000000000000 Binary files a/src/out.txt and /dev/null differ