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