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