diff --git a/bin/coursework/Constraints.class b/bin/coursework/Constraints.class
new file mode 100644
index 0000000000000000000000000000000000000000..3c70c8fb30b14d6a2391e0f208b022abb821ebc1
Binary files /dev/null and b/bin/coursework/Constraints.class differ
diff --git a/bin/coursework/Main.class b/bin/coursework/Main.class
index 3d978104687481173a895a9c50c1b4e9b64dec3b..4ff668e892537ec5df1044acc4cfbe5cf09b0d2b 100644
Binary files a/bin/coursework/Main.class and b/bin/coursework/Main.class differ
diff --git a/src/coursework/Constraints.java b/src/coursework/Constraints.java
new file mode 100644
index 0000000000000000000000000000000000000000..eafc64554cdba995ad051d130dcab3b76d8fef32
--- /dev/null
+++ b/src/coursework/Constraints.java
@@ -0,0 +1,138 @@
+package coursework;
+
+import java.util.ArrayList;
+import java.util.HashSet;
+import java.util.List;
+import javafx.scene.control.TextField;
+import javafx.scene.layout.VBox;
+
+public class Constraints {
+
+	private TextField[] gridNumbers = new TextField[Main.N*Main.N];
+	private VBox[] gridBoxes = new VBox[Main.N*Main.N];
+	private List<Cage> gridCages = new ArrayList<Cage>();
+	private boolean[][] gridErrors = new boolean[Main.N*Main.N][3];
+	
+	
+	public Constraints() {}
+	
+	private void updateData() {
+		gridNumbers = Main.getGridNumbers();
+		gridBoxes = Main.getGridBoxes();
+		gridCages = Main.getGridCages();
+		gridErrors = Main.getGridErrors();
+	}
+	
+	public void checkConstraints(int col, int row, boolean showMistakes) {
+		updateData();
+		columnConstraint(row, col);
+		rowConstraint(row, col);
+		cageConstraint(row, col);
+		highlightCells(showMistakes);
+	}
+
+	private void rowConstraint(int row, int col) {
+		if (!doesRowRepeat(row)) {
+			clearRow(row);
+		}
+		else {
+			highlightRow(row);
+		}
+	}
+	
+	private boolean doesRowRepeat(int row) {
+		boolean repeat = false;
+		HashSet<String> rowValues = new HashSet<String>();
+		String number;
+		for (int i = 0; i < Main.N; i++) {
+			number = gridNumbers[row*Main.N + i].getText();
+			if (rowValues.contains(number) && !number.equals("")) {
+				repeat = true;
+			}
+			else {
+				rowValues.add(number);
+			}
+		}
+		return repeat;
+	}
+	
+	private void columnConstraint(int row, int col) {	
+		if (!doesColumnRepeat(col)) {
+			clearColumn(col);
+		}
+		else {
+			highlightColumn(col);
+		}
+	}
+	
+	private boolean doesColumnRepeat(int col) {
+		boolean repeat = false;
+		HashSet<String> colValues = new HashSet<String>();
+		String number;
+		for (int i = 0; i < Main.N; i++) {
+			number = gridNumbers[i*Main.N + col].getText();
+			if (colValues.contains(number) && !number.equals("")) {
+				repeat = true;
+			}
+			else {
+				colValues.add(number);
+			}
+		}
+		return repeat;
+	}
+		
+	private void cageConstraint(int row, int col) {
+		if (gridCages.size() > 0) {
+			Cage searchCage = null;
+			for (Cage cage : gridCages) {
+				for (int id : cage.getCageIds()) {
+					if (id == (row*Main.N + col)) {
+						searchCage = cage;
+						break;
+					}
+				}
+			}
+			
+			boolean validCageValues = searchCage.checkCageValues();
+			for (int id : searchCage.getCageIds()) {
+				gridErrors[id][2] = validCageValues;
+			}
+		}
+	}
+	
+	private void clearRow(int row) {
+		for (int i = 0; i < Main.N; i++) {
+			gridErrors[row*Main.N + i][0] = false;		
+		}
+	}
+	
+	private void clearColumn(int col) {
+		for (int i = 0; i < Main.N; i++) {
+			gridErrors[i*Main.N + col][1] = false;
+		}
+	}
+	
+	private void highlightRow(int row) {
+		for (int i = 0; i < Main.N; i++) {
+			gridErrors[row*Main.N + i][0] = true;
+		}
+	}
+	
+	private void highlightColumn(int col) {
+		for (int i = 0; i < Main.N; i++) {
+			gridErrors[i*Main.N + col][1] = true;
+		}
+	}
+	
+	public void highlightCells(boolean showMistakes) {
+		for (int i = 0; i < Main.N*Main.N; i++) {
+			if ((gridErrors[i][0] || gridErrors[i][1] || gridErrors[i][2]) && showMistakes) {
+				gridBoxes[i].setStyle("-fx-background-color: rgba(255,0,0,0.5);");
+			}
+			else {
+				gridBoxes[i].setStyle("-fx-background-color: rgba(255,0,0,0);");
+			}
+		}
+	}
+	
+}
diff --git a/src/coursework/Main.java b/src/coursework/Main.java
index 35d0332f9ce560bf5fd770704cfa63c64e12b973..86f2cb407ccb964ceb35dccce626bb0d8df096b5 100644
--- a/src/coursework/Main.java
+++ b/src/coursework/Main.java
@@ -6,17 +6,12 @@ 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;
-
 import javafx.application.*;
-import javafx.event.EventHandler;
 import javafx.geometry.Insets;
 import javafx.geometry.Pos;
 import javafx.scene.Group;
-import javafx.scene.Node;
 import javafx.scene.Scene;
 import javafx.scene.control.Alert;
 import javafx.scene.control.Alert.AlertType;
@@ -28,19 +23,12 @@ import javafx.scene.control.TextField;
 import javafx.scene.image.Image;
 import javafx.scene.image.ImageView;
 import javafx.scene.input.MouseEvent;
-import javafx.scene.layout.BorderPane;
 import javafx.scene.layout.GridPane;
 import javafx.scene.layout.HBox;
 import javafx.scene.layout.Pane;
 import javafx.scene.layout.VBox;
 import javafx.scene.paint.Color;
-import javafx.scene.shape.HLineTo;
-import javafx.scene.shape.Line;
-import javafx.scene.shape.LineTo;
-import javafx.scene.shape.MoveTo;
-import javafx.scene.shape.Path;
 import javafx.scene.shape.Rectangle;
-import javafx.scene.shape.VLineTo;
 import javafx.stage.FileChooser;
 import javafx.stage.Stage;
 
@@ -52,21 +40,21 @@ public class Main extends Application {
 	private Scene scene;
 	private Stage stage;
 	
-	
 	private static Square[] gridSquares = new Square[N*N];
 	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 VBox[] gridBoxes = new VBox[N*N];
-	private List<Cage> gridCages = new ArrayList<Cage>();
+	private static VBox[] gridBoxes = new VBox[N*N];
+	private static List<Cage> gridCages = new ArrayList<Cage>();
+	private static boolean[][] gridErrors = new boolean[N*N][3];
 	
+	private static boolean showMistakes = false;
 	private boolean isWider;
 	private Pane previousPane = null;
 	private Square previousSquare = null;
 	private boolean clearing = false;
 	private boolean undoing = false;
-	private boolean showMistakes = false;
 	private int fontSize;
+	private Constraints constraints = new Constraints();
 	
 	private Stack<GameState> undoStack = new Stack<GameState>();
 	private Stack<GameState> redoStack = new Stack<GameState>();
@@ -74,6 +62,31 @@ public class Main extends Application {
 	private Button undoButton;
 	private Button redoButton;
 	
+	
+	public static Square[] getGridSquares() {
+		return gridSquares;
+	}
+	
+	public static TextField[] getGridNumbers() {
+		return gridNumbers;
+	}
+	
+	public static Label[] getCageLabels() {
+		return cageLabels;
+	}
+	
+	public static VBox[] getGridBoxes() {
+		return gridBoxes;
+	}
+	
+	public static List<Cage> getGridCages() {
+		return gridCages;
+	}
+	
+	public static boolean[][] getGridErrors() {
+		return gridErrors;
+	}
+	
 	private GridPane setupGrid() {
 		GridPane gridPane = new GridPane();
 		gridPane.setAlignment(Pos.CENTER);
@@ -104,20 +117,24 @@ public class Main extends Application {
 		gridPane.add(vbox, j, i);
 		
 		textField.textProperty().addListener((observable, oldValue, newValue) -> {
-			if (!clearing && !undoing) {
-				undoStack.push(new GameState(GameState.getCurrentGameState(gridNumbers)));
-				if (undoButton.isDisabled()) {
-					undoButton.setDisable(false);
-				}
-			}
-			checkConstraints(j, i);
-			checkWinCondition();
+			textFieldClickEvent(i, j);
 		});
 		
 		square.getRectangle().toFront();
 		return gridPane;
 	}
 	
+	private void textFieldClickEvent(int i, int j) {
+		if (!clearing && !undoing) {
+			undoStack.push(new GameState(GameState.getCurrentGameState(gridNumbers)));
+			if (undoButton.isDisabled()) {
+				undoButton.setDisable(false);
+			}
+		}
+		constraints.checkConstraints(j, i, showMistakes);;
+		checkWinCondition();
+	}
+	
 	private void checkWinCondition() {
 		if (checkCellsFull() && checkConstraintErrors()) {
 			// win condition fulfilled
@@ -136,7 +153,7 @@ public class Main extends Application {
 	}
 	
 	private boolean checkConstraintErrors() {
-		for (boolean[] cellErrors : highlightedError) {
+		for (boolean[] cellErrors : gridErrors) {
 			for (boolean errorVal : cellErrors) {
 				if (errorVal) {
 					return false;
@@ -146,111 +163,6 @@ public class Main extends Application {
 		return true;
 	}
 	
-	private void checkConstraints(int col, int row) {
-		columnConstraint(row, col);
-		rowConstraint(row, col);
-		cageConstraint(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++) {
-			number = gridNumbers[row*N + i].getText();
-			if (rowValues.contains(number) && !number.equals("")) {
-				repeat = true;
-			}
-			else {
-				rowValues.add(number);
-			}
-		}
-		
-		if (!repeat) {
-			clearRow(row);
-		}
-		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++) {
-			number = gridNumbers[i*N + col].getText();
-			if (colValues.contains(number) && !number.equals("")) {
-				repeat = true;
-			}
-			else {
-				colValues.add(number);
-			}
-		}
-		
-		if (!repeat) {
-			clearColumn(col);
-		}
-		else {
-			highlightColumn(col);
-		}
-	}
-		
-	private void cageConstraint(int row, int col) {
-		if (gridCages.size() > 0) {
-			Cage searchCage = null;
-			for (Cage cage : gridCages) {
-				for (int id : cage.getCageIds()) {
-					if (id == (row*N + col)) {
-						searchCage = cage;
-						break;
-					}
-				}
-			}
-			
-			boolean validCageValues = searchCage.checkCageValues();
-			for (int id : searchCage.getCageIds()) {
-				highlightedError[id][2] = validCageValues;
-			}
-		}
-	}
-	
-	private void clearRow(int row) {
-		for (int i = 0; i < N; i++) {
-			highlightedError[row*N + i][0] = false;		
-		}
-	}
-	
-	private void clearColumn(int col) {
-		for (int i = 0; i < N; i++) {
-			highlightedError[i*N + col][1] = false;
-		}
-	}
-	
-	private void highlightRow(int row) {
-		for (int i = 0; i < N; i++) {
-			highlightedError[row*N + i][0] = true;
-		}
-	}
-	
-	private void highlightColumn(int col) {
-		for (int i = 0; i < N; i++) {
-			highlightedError[i*N + col][1] = true;
-		}
-	}
-	
-	private void highlightCells() {
-		for (int i = 0; i < N*N; i++) {
-			if ((highlightedError[i][0] || highlightedError[i][1] || highlightedError[i][2]) && showMistakes) {
-				gridBoxes[i].setStyle("-fx-background-color: rgba(255,0,0,0.5);");
-			}
-			else {
-				gridBoxes[i].setStyle("-fx-background-color: rgba(255,0,0,0);");
-			}
-		}
-	}
-	
 	private VBox setupGridVBox(Square square, int i, int j) {
 		VBox vbox = new VBox();
 		Label cageInfoLabel = new Label("");
@@ -302,7 +214,7 @@ public class Main extends Application {
 		
 		showMistakesCheck.selectedProperty().addListener((obs, oldVal, newVal) -> {
 			showMistakes = showMistakesCheck.isSelected();
-			highlightCells();
+			constraints.highlightCells(showMistakes);
 		});
 		
 		loadGameFileButton.setOnAction(e -> {
@@ -402,14 +314,14 @@ public class Main extends Application {
 		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) {
+				if ((gridErrors[previousIndex][0] || gridErrors[previousIndex][1] || gridErrors[previousIndex][2]) && showMistakes) {
 					previousPane.setStyle("-fx-background-color: rgba(255,0,20,0.5); -fx-border-width: 0px;");
 				}
 				else {
 					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]) && showMistakes) {
+			if ((gridErrors[i*N + j][0] || gridErrors[i*N + j][1] || gridErrors[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 {
@@ -584,18 +496,6 @@ public class Main extends Application {
 		}
 	}
 	
-	public static Square[] getGridSquares() {
-		return gridSquares;
-	}
-	
-	public static Label[] getCageLabels() {
-		return cageLabels;
-	}
-	
-	public static TextField[] getGridNumbers() {
-		return gridNumbers;
-	}
-	
 	@Override
 	public void start(Stage stage) throws Exception {
 		VBox vBox = new VBox();