diff --git a/bin/coursework/GameState.class b/bin/coursework/GameState.class
new file mode 100644
index 0000000000000000000000000000000000000000..05a8e904dce51e954e51bf717fb058b235294275
Binary files /dev/null and b/bin/coursework/GameState.class differ
diff --git a/bin/coursework/Main.class b/bin/coursework/Main.class
index ed2ce99b3a07ae04a7b79c6a058d9939fb40ebf8..d732c086f0f50b0b91218527463bd8a5593b2706 100644
Binary files a/bin/coursework/Main.class and b/bin/coursework/Main.class differ
diff --git a/src/coursework/GameState.java b/src/coursework/GameState.java
new file mode 100644
index 0000000000000000000000000000000000000000..092aa5eaf00f4146a8594d214cb45320248222ff
--- /dev/null
+++ b/src/coursework/GameState.java
@@ -0,0 +1,25 @@
+package coursework;
+
+import javafx.scene.control.TextField;
+
+public class GameState {
+
+	private String[] gridValues;
+	
+	public GameState(String[] gridValues) {
+		this.gridValues = gridValues;
+	}
+	
+	public String[] getGameState() {
+		return gridValues;
+	}
+	
+	public static String[] getCurrentGameState(TextField[] gridNumbers) {
+		String[] gridValues = new String[Main.N*Main.N];
+		for (int k = 0; k < gridValues.length; k++) {
+			gridValues[k] = gridNumbers[k].getText();
+		}
+		return gridValues;
+	}
+	
+}
diff --git a/src/coursework/Main.java b/src/coursework/Main.java
index 7a28ea1bbee7c520bac574a44e2c8c8375d43b8d..417ce75c94aaefee20e8f1ccc113827571e366e3 100644
--- a/src/coursework/Main.java
+++ b/src/coursework/Main.java
@@ -5,6 +5,9 @@ import java.io.File;
 import java.io.FileNotFoundException;
 import java.io.FileReader;
 import java.io.IOException;
+import java.util.List;
+import java.util.Stack;
+import java.util.Vector;
 
 import javafx.application.*;
 import javafx.event.EventHandler;
@@ -13,7 +16,10 @@ 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;
 import javafx.scene.control.Button;
+import javafx.scene.control.ButtonType;
 import javafx.scene.control.Label;
 import javafx.scene.control.TextField;
 import javafx.scene.image.Image;
@@ -49,6 +55,13 @@ public class Main extends Application {
 	private boolean isWider;
 	private HBox previousHBox = null;
 	private Square previousSquare = null;
+	private boolean clearing = false;
+	
+	private Stack<GameState> undoStack = new Stack<GameState>();
+	private Stack<GameState> redoStack = new Stack<GameState>();
+	
+	private Button undoButton;
+	private Button redoButton;
 	
 	private GridPane setupGrid() {
 		GridPane gridPane = new GridPane();
@@ -75,6 +88,15 @@ public class Main extends Application {
 		gridPane.add(group, j, i);
 		gridPane.add(hbox, j, i);
 		
+		textField.textProperty().addListener((observable, oldValue, newValue) -> {
+			if (!clearing) {
+				undoStack.push(new GameState(GameState.getCurrentGameState(gridNumbers)));
+				if (undoButton.isDisabled()) {
+					undoButton.setDisable(false);
+				}
+			}
+		});
+		
 		square.getRectangle().toFront();
 		return gridPane;
 	}
@@ -170,14 +192,54 @@ public class Main extends Application {
 		new Cage(ids, value, operator);
 	}
 	
+	
+	private void updateGameState(GameState gameState) {
+		String[] gameValues = gameState.getGameState();
+		for (int i = 0; i < gridNumbers.length; i++) {
+//			if (!gridNumbers[i].getText().equals("") && gameValues.equals(""))
+//				System.out.println("Current: " + gridNumbers[i].getText() + ", Previous: " + textFields[i].getText());
+			gridNumbers[i].setText(gameValues[i]);
+		}
+	}
+	
 	private HBox setupBottomHBox() {
 		HBox bottomHBox = new HBox();
 		bottomHBox.setSpacing(10);
 		bottomHBox.setAlignment(Pos.TOP_CENTER);
 		
-		Button undoButton = new Button("", new ImageView(new Image("file:Images/undo_icon.png")));
-		Button redoButton = new Button("", new ImageView(new Image("file:Images/redo_icon.png")));
+		undoButton = new Button("", new ImageView(new Image("file:Images/undo_icon.png")));
+		redoButton = new Button("", new ImageView(new Image("file:Images/redo_icon.png")));
 		Button clearButton = new Button("Clear");
+		undoButton.setOnAction(e -> {
+			// undoStack.pop() is the current GameState
+						
+			redoStack.push(undoStack.pop());
+			updateGameState(undoStack.peek());
+			
+			// 
+			if (!redoStack.empty()) {
+				redoButton.setDisable(false);
+			}
+			if (undoStack.size() == 1) {
+				undoButton.setDisable(true);
+			}
+		});
+		redoButton.setOnAction(e -> {
+			GameState gameState = redoStack.pop();
+			updateGameState(gameState);
+		
+			undoStack.push(gameState);
+			
+			if (!undoStack.empty()) {
+				undoButton.setDisable(false);
+			}
+			if (redoStack.empty()) {
+				redoButton.setDisable(true);
+			}
+		});
+		
+		undoButton.setDisable(true);
+		redoButton.setDisable(true);
 		clearButton.setPrefHeight(36);
 		clearButton.setPrefWidth(120);
 		clearButtonClickEvent(clearButton);
@@ -194,14 +256,26 @@ public class Main extends Application {
 			hbox.setStyle("-fx-border-color:red; -fx-border-width:2px;");
 			previousHBox = hbox;
 			previousSquare = square;
+			for (TextField textField : gridNumbers) {
+				textField.deselect();
+			}
 		});
 	}
 	
-	private void clearButtonClickEvent(Button clearButton) {
+	private void clearButtonClickEvent(Button clearButton) {		
 		clearButton.setOnAction(e -> {
-			for (TextField textField : gridNumbers) {
-				textField.setText("");
-			}
+			clearing = true;
+			undoStack.push(new GameState(GameState.getCurrentGameState(gridNumbers)));
+			Alert alert = new Alert(AlertType.CONFIRMATION);
+			alert.setContentText("Are you sure you wish to clear the board?");
+			alert.showAndWait().ifPresent(type -> {
+				if (type == ButtonType.OK) {
+					for (TextField textField : gridNumbers) {
+						textField.setText("");
+					}
+				}
+			});;
+			clearing = false;
 		});
 	}
 	
@@ -284,6 +358,7 @@ public class Main extends Application {
 		vBox.setAlignment(Pos.CENTER);
 		
 		GridPane gridPane = setupGrid();
+		undoStack.push(new GameState(GameState.getCurrentGameState(gridNumbers)));
 		
 		HBox topHBox = setupTopHBox();
 		HBox centerHBox = setupCenterHBox();