diff --git a/.gitignore b/.gitignore
index 21f59736ad015cfd0077ec30b7865b54748a5eb2..e9cbfccb64f35aa20776f2e01d59128e6718d02a 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,6 +1,6 @@
-# This file tells git what files to "ignore"
-# Typically, these are all the generated files (as we only commit source code, not binary output)
-
-.gradle/
-.idea/
-build/
+# This file tells git what files to "ignore"
+# Typically, these are all the generated files (as we only commit source code, not binary output)
+
+.gradle/
+.idea/
+build/
diff --git a/README.md b/README.md
index 3fde8647f795a9612818c45a018fba9aa6f39728..23749630d816bcb918d22a802794670f5064e3a9 100644
--- a/README.md
+++ b/README.md
@@ -1,124 +1,124 @@
-## A Git, GitLab, and JUnit exercise
-
-This assignment is intended to give you a relatively small exercise to give you a little familiarisation working with Git, Gradle,
-JUnit, and JavaFX on a very small codebase - before you and your group do something much more exciting on the much larger
-class-wide project.
-
-The example code you have been given is a simple JavaFX "dots and boxes" game. It has a couple of known bugs in it
-(already commented for you - the task is not really in finding the bugs). Please note: your task **is not simply to fix the bugs**. 
-Your task is a series of steps that show you can work with git, gitlab, gradle, and junit.
-
-You will notice that this is a git repository, but it is provided to you just as a zip that you download.
-If you run `git status`, you should see that you are on branch `main`.
-
-Dots And Boxes is normally a two-player pencil-and-paper game. See https://en.wikipedia.org/wiki/Dots_and_Boxes  
-In our version, a player "draws" a line by clicking on it. If it completes a square, they automatically claim the
-square and get another turn. There are two known bugs in our code-base:
-
-1. The code for checking if a square is complete is wrong. It just returns `true` at the moment, whereas it should
-   test if the lines surrounding the square have been "drawn".
-2. The grid doesn't complain if you "draw" a line that has already been drawn. It should throw an `IllegalStateException`.
-
-Remember, your task *isn't* just to fix the bugs.
-
-Your tasks:
-
-1. Create a repository on gitlab.une.edu.au and push the main branch of this repository to it **entirely unmodified**. 
-   **You will need to set the visibility on your repository so that the marker can read from it**. 
-   Repositories we cannot access cannot be marked (and will receive 0 until you can fix it)
-   
-2. Set your name and email on the repository for your future commits, using `git config`
-
-3. Update the "name" label in the application to show **your name**.
-   Commit this change and push it to your **main** branch.
-
-3. Create an Issue in your GitLab project for fixing the errors in the assignment.
-   
-4. Create and check out a branch for your bugfix. 
-   This should follow the convention of having the issue number, followed by a hyphenated description of the issue.
-   e.g. `1-fix-assignment-errors`.  
-   Push this branch to your remote repository. (From here on, I'll refer to this as your "issue branch")
-
-5. Create **unit tests** that will detect the errors in the code. Particularly:
-   * That the algorithm for testing whether a box is complete is wrong.
-   * That the DotsAndBoxesGrid currently permits you to "draw" a line that has already been drawn, whereas it should throw an exception.
-    
-6. Commit these unit tests with an appropriately descriptive commit message.  
-   **Do not fix the bugs in this commit. The unit tests should *fail*.**    
-   Push this commit to your remote repository (on your issue branch)
-
-7. **Tag** this commit, with the label `testsfail`. Push this tag to your remote repository.
-
-8. Fix the bugs in the code. Run your unit tests again. The tests should now pass.
-
-9. Commit your bugfix. Push it to your issue branch.
-
-10. Check out `main`. Merge your issue branch to main. The tests should still pass. Push this to your gitlab repository.
-
-11. Close your issue with a reference to the commit hash in which you fixed the bugs.
-
-12. Paste the link to your gitlab repository into the assignment and submit.
-
-Marking. 
-
-1. You have submitted a link to your repository on gitlab.une.edu.au and it is visible to the marker (1 point)
-2. The first few commits on the main branch on the repository contains the starter code, showing me as author. 
-   The last of my commits has the *same commit hash* as in the original code I gave you.  
-   (i.e. you successfully pushed the original code I gave you to your GitLab repository). (1 point)
-3. The next commit on the main branch adds your name to the label and shows you as author  
-   (i.e. you have successfully configured your name & email and you have successfully created and pushed a commit) (1 point)
-4. You have at least one issue on your repository for the bugfixes. It is closed referencing the bugfix commit. (1 point)
-5. There is a `testsfail` tag in your repository (1 point)
-6. Checking out the `testsfail` tag, and running the `gradlew test`, produces two failed tests (one for each bug). (2 points)
-7. Checking out the main branch, both tests are present and pass (2 points)
-8. The most recent commit on the `main` branch is a merge commit, merging the commit in which you set your name on the label
-   and the commit in which you fixed the tests. (1 point)
-
-
-## Features of this code base
-
-As well as being an assignment repository, this codebase is also a sample codebase, showing you a few things:
-
-* It uses a *gradle wrapper* (a script that will download the correct version of gradle for you.) This means you can
-  `gradlew build` and it'll go get gradle before it builds. Normally, that would fetch from a URL on the gradle site,
-  but so this works behind UNE's webproxy, we've got it fetching the gradle jar from a url on turing instead.
-  
-* It is a *modular* application. JavaFX is provided as a set of modules. At the moment, that might seem like an esoteric
-  distinction, but if we wanted to *distribute* our application, it would be helpful. If the app is written as a 
-  modular app (it has a `module-info.java` file), then the `gradlew distZip` task can generate a distributable zip 
-  for us, containing not only our code but also the modules our app depends on (including JavaFX).
-  
-* It contains Log4J, which is the logging library (basically, super-powered printlns) that we will use.
-
-* We pass lambdas around, especially as listeners and event handlers. 
-  Lambdas may be familiar to students who've studied Scala, but they are making 
-  their way into Java too. For instance, notice that in `DotsAndBoxesUI` we register a number of listeners onto the dots
-  and boxes grid by registering lambda functions.
-  
-  ```java
-  grid.addConsumer((g) -> {
-      if (g.getHorizontal(x, y)) {
-          line.setStroke(Color.BLACK);
-      } else {
-          line.setStroke(Color.LIGHTGRAY);
-      }
-  });
-  ```
-  
-  In Java, functions aren't "first class citizens" in the way they are in Scala, however. Our code here is really 
-  creating an *anonymous inner class*.
-  
-  Instead, Java has the idea of "SAM types" (Single Abstract Method types). `addConsumer` asks for an *object* of type
-  `Consumer<DotsAndBoxesGrid>`. But `Consumer<>` has only one abstract method. So, Java gives us the shorthand
-  that if we just describe how we want to implement the abstract method (`(g) -> { ...`) then the Java compiler will 
-  fill in the rest of the code about creating an anonymous inner class of type `Consumer<>` for us.
-  
-* JavaFX uses a lot of observable lists. So for instance notice the line for adding a line to the anchorpane:
-
-  ```java
-  anchorPane.getChildren().add(line);
-  ```
-
-  We get the pane's list of children *and we add the line to it*. That *get ... add* code is something that is fairly
-  common in JavaFX code. The list of children is a mutable list that has some triggers on it, so that if you add 
+## A Git, GitLab, and JUnit exercise
+
+This assignment is intended to give you a relatively small exercise to give you a little familiarisation working with Git, Gradle,
+JUnit, and JavaFX on a very small codebase - before you and your group do something much more exciting on the much larger
+class-wide project.
+
+The example code you have been given is a simple JavaFX "dots and boxes" game. It has a couple of known bugs in it
+(already commented for you - the task is not really in finding the bugs). Please note: your task **is not simply to fix the bugs**. 
+Your task is a series of steps that show you can work with git, gitlab, gradle, and junit.
+
+You will notice that this is a git repository, but it is provided to you just as a zip that you download.
+If you run `git status`, you should see that you are on branch `main`.
+
+Dots And Boxes is normally a two-player pencil-and-paper game. See https://en.wikipedia.org/wiki/Dots_and_Boxes  
+In our version, a player "draws" a line by clicking on it. If it completes a square, they automatically claim the
+square and get another turn. There are two known bugs in our code-base:
+
+1. The code for checking if a square is complete is wrong. It just returns `true` at the moment, whereas it should
+   test if the lines surrounding the square have been "drawn".
+2. The grid doesn't complain if you "draw" a line that has already been drawn. It should throw an `IllegalStateException`.
+
+Remember, your task *isn't* just to fix the bugs.
+
+Your tasks:
+
+1. Create a repository on gitlab.une.edu.au and push the main branch of this repository to it **entirely unmodified**. 
+   **You will need to set the visibility on your repository so that the marker can read from it**. 
+   Repositories we cannot access cannot be marked (and will receive 0 until you can fix it)
+   
+2. Set your name and email on the repository for your future commits, using `git config`
+
+3. Update the "name" label in the application to show **your name**.
+   Commit this change and push it to your **main** branch.
+
+3. Create an Issue in your GitLab project for fixing the errors in the assignment.
+   
+4. Create and check out a branch for your bugfix. 
+   This should follow the convention of having the issue number, followed by a hyphenated description of the issue.
+   e.g. `1-fix-assignment-errors`.  
+   Push this branch to your remote repository. (From here on, I'll refer to this as your "issue branch")
+
+5. Create **unit tests** that will detect the errors in the code. Particularly:
+   * That the algorithm for testing whether a box is complete is wrong.
+   * That the DotsAndBoxesGrid currently permits you to "draw" a line that has already been drawn, whereas it should throw an exception.
+    
+6. Commit these unit tests with an appropriately descriptive commit message.  
+   **Do not fix the bugs in this commit. The unit tests should *fail*.**    
+   Push this commit to your remote repository (on your issue branch)
+
+7. **Tag** this commit, with the label `testsfail`. Push this tag to your remote repository.
+
+8. Fix the bugs in the code. Run your unit tests again. The tests should now pass.
+
+9. Commit your bugfix. Push it to your issue branch.
+
+10. Check out `main`. Merge your issue branch to main. The tests should still pass. Push this to your gitlab repository.
+
+11. Close your issue with a reference to the commit hash in which you fixed the bugs.
+
+12. Paste the link to your gitlab repository into the assignment and submit.
+
+Marking. 
+
+1. You have submitted a link to your repository on gitlab.une.edu.au and it is visible to the marker (1 point)
+2. The first few commits on the main branch on the repository contains the starter code, showing me as author. 
+   The last of my commits has the *same commit hash* as in the original code I gave you.  
+   (i.e. you successfully pushed the original code I gave you to your GitLab repository). (1 point)
+3. The next commit on the main branch adds your name to the label and shows you as author  
+   (i.e. you have successfully configured your name & email and you have successfully created and pushed a commit) (1 point)
+4. You have at least one issue on your repository for the bugfixes. It is closed referencing the bugfix commit. (1 point)
+5. There is a `testsfail` tag in your repository (1 point)
+6. Checking out the `testsfail` tag, and running the `gradlew test`, produces two failed tests (one for each bug). (2 points)
+7. Checking out the main branch, both tests are present and pass (2 points)
+8. The most recent commit on the `main` branch is a merge commit, merging the commit in which you set your name on the label
+   and the commit in which you fixed the tests. (1 point)
+
+
+## Features of this code base
+
+As well as being an assignment repository, this codebase is also a sample codebase, showing you a few things:
+
+* It uses a *gradle wrapper* (a script that will download the correct version of gradle for you.) This means you can
+  `gradlew build` and it'll go get gradle before it builds. Normally, that would fetch from a URL on the gradle site,
+  but so this works behind UNE's webproxy, we've got it fetching the gradle jar from a url on turing instead.
+  
+* It is a *modular* application. JavaFX is provided as a set of modules. At the moment, that might seem like an esoteric
+  distinction, but if we wanted to *distribute* our application, it would be helpful. If the app is written as a 
+  modular app (it has a `module-info.java` file), then the `gradlew distZip` task can generate a distributable zip 
+  for us, containing not only our code but also the modules our app depends on (including JavaFX).
+  
+* It contains Log4J, which is the logging library (basically, super-powered printlns) that we will use.
+
+* We pass lambdas around, especially as listeners and event handlers. 
+  Lambdas may be familiar to students who've studied Scala, but they are making 
+  their way into Java too. For instance, notice that in `DotsAndBoxesUI` we register a number of listeners onto the dots
+  and boxes grid by registering lambda functions.
+  
+  ```java
+  grid.addConsumer((g) -> {
+      if (g.getHorizontal(x, y)) {
+          line.setStroke(Color.BLACK);
+      } else {
+          line.setStroke(Color.LIGHTGRAY);
+      }
+  });
+  ```
+  
+  In Java, functions aren't "first class citizens" in the way they are in Scala, however. Our code here is really 
+  creating an *anonymous inner class*.
+  
+  Instead, Java has the idea of "SAM types" (Single Abstract Method types). `addConsumer` asks for an *object* of type
+  `Consumer<DotsAndBoxesGrid>`. But `Consumer<>` has only one abstract method. So, Java gives us the shorthand
+  that if we just describe how we want to implement the abstract method (`(g) -> { ...`) then the Java compiler will 
+  fill in the rest of the code about creating an anonymous inner class of type `Consumer<>` for us.
+  
+* JavaFX uses a lot of observable lists. So for instance notice the line for adding a line to the anchorpane:
+
+  ```java
+  anchorPane.getChildren().add(line);
+  ```
+
+  We get the pane's list of children *and we add the line to it*. That *get ... add* code is something that is fairly
+  common in JavaFX code. The list of children is a mutable list that has some triggers on it, so that if you add 
   an element, JavaFX knows it needs to go and repaint the parent component.
\ No newline at end of file
diff --git a/build.gradle b/build.gradle
index 5705373c7f0724928eb4cbaed9cd028179e1239a..b9418661d19434d18ac9e0ad4ca5495b214149d9 100644
--- a/build.gradle
+++ b/build.gradle
@@ -1,42 +1,42 @@
-buildscript {
-    repositories {
-        maven { url 'https://hopper.une.edu.au/artifactory/libs-release/' }
-        mavenCentral()
-    }
-}
-
-plugins {
-    id 'application'
-    id 'org.openjfx.javafxplugin' version '0.0.10'
-}
-
-javafx {
-    version = "15.0.1"
-    modules = [ 'javafx.controls' ]
-}
-
-group 'org.example'
-version '1.0-SNAPSHOT'
-
-
-repositories {
-    maven { url 'https://hopper.une.edu.au/artifactory/libs-release/' }
-    mavenCentral()
-}
-
-dependencies {
-    // Log4J does logging. We'll meet it properly in a later week...
-    implementation 'org.apache.logging.log4j:log4j-api:2.12.0'
-    implementation 'org.apache.logging.log4j:log4j-core:2.12.0'
-
-    testImplementation 'org.junit.jupiter:junit-jupiter-api:5.7.0'
-    testRuntimeOnly 'org.junit.jupiter:junit-jupiter-engine:5.7.0'
-}
-
-test {
-    useJUnitPlatform()
-}
-
-application {
-    mainClass = 'dotsandboxes.Main'
+buildscript {
+    repositories {
+        maven { url 'https://hopper.une.edu.au/artifactory/libs-release/' }
+        mavenCentral()
+    }
+}
+
+plugins {
+    id 'application'
+    id 'org.openjfx.javafxplugin' version '0.0.10'
+}
+
+javafx {
+    version = "15.0.1"
+    modules = [ 'javafx.controls' ]
+}
+
+group 'org.example'
+version '1.0-SNAPSHOT'
+
+
+repositories {
+    maven { url 'https://hopper.une.edu.au/artifactory/libs-release/' }
+    mavenCentral()
+}
+
+dependencies {
+    // Log4J does logging. We'll meet it properly in a later week...
+    implementation 'org.apache.logging.log4j:log4j-api:2.12.0'
+    implementation 'org.apache.logging.log4j:log4j-core:2.12.0'
+
+    testImplementation 'org.junit.jupiter:junit-jupiter-api:5.7.0'
+    testRuntimeOnly 'org.junit.jupiter:junit-jupiter-engine:5.7.0'
+}
+
+test {
+    useJUnitPlatform()
+}
+
+application {
+    mainClass = 'dotsandboxes.Main'
 }
\ No newline at end of file
diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties
index 068a225d0a542f0224482fdde421b956b3ed2e2d..4975f1c9c7daffc56755d58582667cbe806e4feb 100644
--- a/gradle/wrapper/gradle-wrapper.properties
+++ b/gradle/wrapper/gradle-wrapper.properties
@@ -1,5 +1,5 @@
-distributionBase=GRADLE_USER_HOME
-distributionPath=wrapper/dists
-distributionUrl=https\://turing.une.edu.au/~cosc220/distributions/gradle-7.1.1-bin.zip
-zipStoreBase=GRADLE_USER_HOME
-zipStorePath=wrapper/dists
+distributionBase=GRADLE_USER_HOME
+distributionPath=wrapper/dists
+distributionUrl=https\://turing.une.edu.au/~cosc220/distributions/gradle-7.1.1-bin.zip
+zipStoreBase=GRADLE_USER_HOME
+zipStorePath=wrapper/dists
diff --git a/gradlew b/gradlew
index 4f906e0c811fc9e230eb44819f509cd0627f2600..02640cba68b8881cb234133808bb8fa88db5856c 100755
--- a/gradlew
+++ b/gradlew
@@ -1,185 +1,185 @@
-#!/usr/bin/env sh
-
-#
-# Copyright 2015 the original author or authors.
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-#      https://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-#
-
-##############################################################################
-##
-##  Gradle start up script for UN*X
-##
-##############################################################################
-
-# Attempt to set APP_HOME
-# Resolve links: $0 may be a link
-PRG="$0"
-# Need this for relative symlinks.
-while [ -h "$PRG" ] ; do
-    ls=`ls -ld "$PRG"`
-    link=`expr "$ls" : '.*-> \(.*\)$'`
-    if expr "$link" : '/.*' > /dev/null; then
-        PRG="$link"
-    else
-        PRG=`dirname "$PRG"`"/$link"
-    fi
-done
-SAVED="`pwd`"
-cd "`dirname \"$PRG\"`/" >/dev/null
-APP_HOME="`pwd -P`"
-cd "$SAVED" >/dev/null
-
-APP_NAME="Gradle"
-APP_BASE_NAME=`basename "$0"`
-
-# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
-DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"'
-
-# Use the maximum available, or set MAX_FD != -1 to use that value.
-MAX_FD="maximum"
-
-warn () {
-    echo "$*"
-}
-
-die () {
-    echo
-    echo "$*"
-    echo
-    exit 1
-}
-
-# OS specific support (must be 'true' or 'false').
-cygwin=false
-msys=false
-darwin=false
-nonstop=false
-case "`uname`" in
-  CYGWIN* )
-    cygwin=true
-    ;;
-  Darwin* )
-    darwin=true
-    ;;
-  MINGW* )
-    msys=true
-    ;;
-  NONSTOP* )
-    nonstop=true
-    ;;
-esac
-
-CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
-
-
-# Determine the Java command to use to start the JVM.
-if [ -n "$JAVA_HOME" ] ; then
-    if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
-        # IBM's JDK on AIX uses strange locations for the executables
-        JAVACMD="$JAVA_HOME/jre/sh/java"
-    else
-        JAVACMD="$JAVA_HOME/bin/java"
-    fi
-    if [ ! -x "$JAVACMD" ] ; then
-        die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
-
-Please set the JAVA_HOME variable in your environment to match the
-location of your Java installation."
-    fi
-else
-    JAVACMD="java"
-    which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
-
-Please set the JAVA_HOME variable in your environment to match the
-location of your Java installation."
-fi
-
-# Increase the maximum file descriptors if we can.
-if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then
-    MAX_FD_LIMIT=`ulimit -H -n`
-    if [ $? -eq 0 ] ; then
-        if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then
-            MAX_FD="$MAX_FD_LIMIT"
-        fi
-        ulimit -n $MAX_FD
-        if [ $? -ne 0 ] ; then
-            warn "Could not set maximum file descriptor limit: $MAX_FD"
-        fi
-    else
-        warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT"
-    fi
-fi
-
-# For Darwin, add options to specify how the application appears in the dock
-if $darwin; then
-    GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\""
-fi
-
-# For Cygwin or MSYS, switch paths to Windows format before running java
-if [ "$cygwin" = "true" -o "$msys" = "true" ] ; then
-    APP_HOME=`cygpath --path --mixed "$APP_HOME"`
-    CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
-
-    JAVACMD=`cygpath --unix "$JAVACMD"`
-
-    # We build the pattern for arguments to be converted via cygpath
-    ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`
-    SEP=""
-    for dir in $ROOTDIRSRAW ; do
-        ROOTDIRS="$ROOTDIRS$SEP$dir"
-        SEP="|"
-    done
-    OURCYGPATTERN="(^($ROOTDIRS))"
-    # Add a user-defined pattern to the cygpath arguments
-    if [ "$GRADLE_CYGPATTERN" != "" ] ; then
-        OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)"
-    fi
-    # Now convert the arguments - kludge to limit ourselves to /bin/sh
-    i=0
-    for arg in "$@" ; do
-        CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -`
-        CHECK2=`echo "$arg"|egrep -c "^-"`                                 ### Determine if an option
-
-        if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then                    ### Added a condition
-            eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"`
-        else
-            eval `echo args$i`="\"$arg\""
-        fi
-        i=`expr $i + 1`
-    done
-    case $i in
-        0) set -- ;;
-        1) set -- "$args0" ;;
-        2) set -- "$args0" "$args1" ;;
-        3) set -- "$args0" "$args1" "$args2" ;;
-        4) set -- "$args0" "$args1" "$args2" "$args3" ;;
-        5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
-        6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
-        7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
-        8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
-        9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
-    esac
-fi
-
-# Escape application args
-save () {
-    for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done
-    echo " "
-}
-APP_ARGS=`save "$@"`
-
-# Collect all arguments for the java command, following the shell quoting and substitution rules
-eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS"
-
-exec "$JAVACMD" "$@"
+#!/usr/bin/env sh
+
+#
+# Copyright 2015 the original author or authors.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#      https://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+##############################################################################
+##
+##  Gradle start up script for UN*X
+##
+##############################################################################
+
+# Attempt to set APP_HOME
+# Resolve links: $0 may be a link
+PRG="$0"
+# Need this for relative symlinks.
+while [ -h "$PRG" ] ; do
+    ls=`ls -ld "$PRG"`
+    link=`expr "$ls" : '.*-> \(.*\)$'`
+    if expr "$link" : '/.*' > /dev/null; then
+        PRG="$link"
+    else
+        PRG=`dirname "$PRG"`"/$link"
+    fi
+done
+SAVED="`pwd`"
+cd "`dirname \"$PRG\"`/" >/dev/null
+APP_HOME="`pwd -P`"
+cd "$SAVED" >/dev/null
+
+APP_NAME="Gradle"
+APP_BASE_NAME=`basename "$0"`
+
+# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
+DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"'
+
+# Use the maximum available, or set MAX_FD != -1 to use that value.
+MAX_FD="maximum"
+
+warn () {
+    echo "$*"
+}
+
+die () {
+    echo
+    echo "$*"
+    echo
+    exit 1
+}
+
+# OS specific support (must be 'true' or 'false').
+cygwin=false
+msys=false
+darwin=false
+nonstop=false
+case "`uname`" in
+  CYGWIN* )
+    cygwin=true
+    ;;
+  Darwin* )
+    darwin=true
+    ;;
+  MINGW* )
+    msys=true
+    ;;
+  NONSTOP* )
+    nonstop=true
+    ;;
+esac
+
+CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
+
+
+# Determine the Java command to use to start the JVM.
+if [ -n "$JAVA_HOME" ] ; then
+    if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
+        # IBM's JDK on AIX uses strange locations for the executables
+        JAVACMD="$JAVA_HOME/jre/sh/java"
+    else
+        JAVACMD="$JAVA_HOME/bin/java"
+    fi
+    if [ ! -x "$JAVACMD" ] ; then
+        die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
+
+Please set the JAVA_HOME variable in your environment to match the
+location of your Java installation."
+    fi
+else
+    JAVACMD="java"
+    which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
+
+Please set the JAVA_HOME variable in your environment to match the
+location of your Java installation."
+fi
+
+# Increase the maximum file descriptors if we can.
+if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then
+    MAX_FD_LIMIT=`ulimit -H -n`
+    if [ $? -eq 0 ] ; then
+        if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then
+            MAX_FD="$MAX_FD_LIMIT"
+        fi
+        ulimit -n $MAX_FD
+        if [ $? -ne 0 ] ; then
+            warn "Could not set maximum file descriptor limit: $MAX_FD"
+        fi
+    else
+        warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT"
+    fi
+fi
+
+# For Darwin, add options to specify how the application appears in the dock
+if $darwin; then
+    GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\""
+fi
+
+# For Cygwin or MSYS, switch paths to Windows format before running java
+if [ "$cygwin" = "true" -o "$msys" = "true" ] ; then
+    APP_HOME=`cygpath --path --mixed "$APP_HOME"`
+    CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
+
+    JAVACMD=`cygpath --unix "$JAVACMD"`
+
+    # We build the pattern for arguments to be converted via cygpath
+    ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`
+    SEP=""
+    for dir in $ROOTDIRSRAW ; do
+        ROOTDIRS="$ROOTDIRS$SEP$dir"
+        SEP="|"
+    done
+    OURCYGPATTERN="(^($ROOTDIRS))"
+    # Add a user-defined pattern to the cygpath arguments
+    if [ "$GRADLE_CYGPATTERN" != "" ] ; then
+        OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)"
+    fi
+    # Now convert the arguments - kludge to limit ourselves to /bin/sh
+    i=0
+    for arg in "$@" ; do
+        CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -`
+        CHECK2=`echo "$arg"|egrep -c "^-"`                                 ### Determine if an option
+
+        if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then                    ### Added a condition
+            eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"`
+        else
+            eval `echo args$i`="\"$arg\""
+        fi
+        i=`expr $i + 1`
+    done
+    case $i in
+        0) set -- ;;
+        1) set -- "$args0" ;;
+        2) set -- "$args0" "$args1" ;;
+        3) set -- "$args0" "$args1" "$args2" ;;
+        4) set -- "$args0" "$args1" "$args2" "$args3" ;;
+        5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
+        6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
+        7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
+        8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
+        9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
+    esac
+fi
+
+# Escape application args
+save () {
+    for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done
+    echo " "
+}
+APP_ARGS=`save "$@"`
+
+# Collect all arguments for the java command, following the shell quoting and substitution rules
+eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS"
+
+exec "$JAVACMD" "$@"
diff --git a/gradlew.bat b/gradlew.bat
index 107acd32c4e687021ef32db511e8a206129b88ec..ac1b06f93825db68fb0c0b5150917f340eaa5d02 100755
--- a/gradlew.bat
+++ b/gradlew.bat
@@ -1,89 +1,89 @@
-@rem
-@rem Copyright 2015 the original author or authors.
-@rem
-@rem Licensed under the Apache License, Version 2.0 (the "License");
-@rem you may not use this file except in compliance with the License.
-@rem You may obtain a copy of the License at
-@rem
-@rem      https://www.apache.org/licenses/LICENSE-2.0
-@rem
-@rem Unless required by applicable law or agreed to in writing, software
-@rem distributed under the License is distributed on an "AS IS" BASIS,
-@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-@rem See the License for the specific language governing permissions and
-@rem limitations under the License.
-@rem
-
-@if "%DEBUG%" == "" @echo off
-@rem ##########################################################################
-@rem
-@rem  Gradle startup script for Windows
-@rem
-@rem ##########################################################################
-
-@rem Set local scope for the variables with windows NT shell
-if "%OS%"=="Windows_NT" setlocal
-
-set DIRNAME=%~dp0
-if "%DIRNAME%" == "" set DIRNAME=.
-set APP_BASE_NAME=%~n0
-set APP_HOME=%DIRNAME%
-
-@rem Resolve any "." and ".." in APP_HOME to make it shorter.
-for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi
-
-@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
-set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m"
-
-@rem Find java.exe
-if defined JAVA_HOME goto findJavaFromJavaHome
-
-set JAVA_EXE=java.exe
-%JAVA_EXE% -version >NUL 2>&1
-if "%ERRORLEVEL%" == "0" goto execute
-
-echo.
-echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
-echo.
-echo Please set the JAVA_HOME variable in your environment to match the
-echo location of your Java installation.
-
-goto fail
-
-:findJavaFromJavaHome
-set JAVA_HOME=%JAVA_HOME:"=%
-set JAVA_EXE=%JAVA_HOME%/bin/java.exe
-
-if exist "%JAVA_EXE%" goto execute
-
-echo.
-echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
-echo.
-echo Please set the JAVA_HOME variable in your environment to match the
-echo location of your Java installation.
-
-goto fail
-
-:execute
-@rem Setup the command line
-
-set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
-
-
-@rem Execute Gradle
-"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %*
-
-:end
-@rem End local scope for the variables with windows NT shell
-if "%ERRORLEVEL%"=="0" goto mainEnd
-
-:fail
-rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
-rem the _cmd.exe /c_ return code!
-if  not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
-exit /b 1
-
-:mainEnd
-if "%OS%"=="Windows_NT" endlocal
-
-:omega
+@rem
+@rem Copyright 2015 the original author or authors.
+@rem
+@rem Licensed under the Apache License, Version 2.0 (the "License");
+@rem you may not use this file except in compliance with the License.
+@rem You may obtain a copy of the License at
+@rem
+@rem      https://www.apache.org/licenses/LICENSE-2.0
+@rem
+@rem Unless required by applicable law or agreed to in writing, software
+@rem distributed under the License is distributed on an "AS IS" BASIS,
+@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+@rem See the License for the specific language governing permissions and
+@rem limitations under the License.
+@rem
+
+@if "%DEBUG%" == "" @echo off
+@rem ##########################################################################
+@rem
+@rem  Gradle startup script for Windows
+@rem
+@rem ##########################################################################
+
+@rem Set local scope for the variables with windows NT shell
+if "%OS%"=="Windows_NT" setlocal
+
+set DIRNAME=%~dp0
+if "%DIRNAME%" == "" set DIRNAME=.
+set APP_BASE_NAME=%~n0
+set APP_HOME=%DIRNAME%
+
+@rem Resolve any "." and ".." in APP_HOME to make it shorter.
+for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi
+
+@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
+set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m"
+
+@rem Find java.exe
+if defined JAVA_HOME goto findJavaFromJavaHome
+
+set JAVA_EXE=java.exe
+%JAVA_EXE% -version >NUL 2>&1
+if "%ERRORLEVEL%" == "0" goto execute
+
+echo.
+echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
+echo.
+echo Please set the JAVA_HOME variable in your environment to match the
+echo location of your Java installation.
+
+goto fail
+
+:findJavaFromJavaHome
+set JAVA_HOME=%JAVA_HOME:"=%
+set JAVA_EXE=%JAVA_HOME%/bin/java.exe
+
+if exist "%JAVA_EXE%" goto execute
+
+echo.
+echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
+echo.
+echo Please set the JAVA_HOME variable in your environment to match the
+echo location of your Java installation.
+
+goto fail
+
+:execute
+@rem Setup the command line
+
+set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
+
+
+@rem Execute Gradle
+"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %*
+
+:end
+@rem End local scope for the variables with windows NT shell
+if "%ERRORLEVEL%"=="0" goto mainEnd
+
+:fail
+rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
+rem the _cmd.exe /c_ return code!
+if  not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
+exit /b 1
+
+:mainEnd
+if "%OS%"=="Windows_NT" endlocal
+
+:omega
diff --git a/settings.gradle b/settings.gradle
index a78f99387c1604f132de5528304111a3a35cf626..f6ebe9c198d0f50987d7ec3d8081096fdd5fb9bb 100644
--- a/settings.gradle
+++ b/settings.gradle
@@ -1,9 +1,9 @@
-pluginManagement {
-    repositories {
-        maven { url "https://hopper.une.edu.au/artifactory/gradle-plugins/" }
-        gradlePluginPortal()
-    }
-}
-
-rootProject.name = 'dotsAndBoxes'
-
+pluginManagement {
+    repositories {
+        maven { url "https://hopper.une.edu.au/artifactory/gradle-plugins/" }
+        gradlePluginPortal()
+    }
+}
+
+rootProject.name = 'dotsAndBoxes'
+
diff --git a/src/main/java/dotsandboxes/DotsAndBoxesGrid.java b/src/main/java/dotsandboxes/DotsAndBoxesGrid.java
index 4f774b198f230ca82e5cc94d51967846aa05d5f5..32667af6c63a0287bd4f91c37682acb30c08e9a4 100644
--- a/src/main/java/dotsandboxes/DotsAndBoxesGrid.java
+++ b/src/main/java/dotsandboxes/DotsAndBoxesGrid.java
@@ -1,198 +1,198 @@
-package dotsandboxes;
-
-
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.Observer;
-import java.util.function.Consumer;
-
-/**
- * The state of a dots and boxes grid.
- *
- * A (4, 3) dots and boxes grid looks like this:
- *
- * *-*-*-*
- * | | | |
- * *-*-*-*
- * | | | |
- * *-*-*-*
- *
- * Notice that:
- *
- * - for each row, there is one less horizontal than the number of corner dots
- * - for each row, there are as many verticals as there are corner dots
- * - for each row, there is one less box than the number of corner dots
- * - for each column, there is one less vertical than the number of corner dots.
- * - for each column, there are as many horizontals as there are corner dots.
- * - for each column, there is one less box than the number of corner dots
- *
- * For example, in this (4, 3) grid, there are (3, 3) horizontal lines, and (4, 2) vertical lines, and (3, 2) boxes.
- *
- * We number all lines and boxes by their top-left coordinate.
- *
- * In Java 14+, we might use a Record class for this, but we're using 11+ as an LTS version, so we don't have that yet.
- */
-public class DotsAndBoxesGrid {
-
-    final int width;
-    final int height;
-
-    /** The horizontal lines in the grid. True if drawn. */
-    private boolean[][] horizontals;
-
-    /** The vertical lines in the grid. True if drawn. */
-    private boolean[][] verticals;
-
-    /** Which owner (if any) claimed any given box. */
-    private int[][] boxOwners;
-
-    /** A list of functions to notify when there is an update */
-    private ArrayList<Consumer<DotsAndBoxesGrid>> watchers = new ArrayList<>();
-
-    final int players;
-    private int player = 1;
-    public int getPlayer() {
-        return player;
-    }
-
-    /** Moves to the next player */
-    private void nextPlayer() {
-        player++;
-        if (player > players) {
-            player = 1;
-        }
-    }
-
-    public DotsAndBoxesGrid(int width, int height, int players) {
-        this.width = width;
-        this.height = height;
-        this.players = players;
-
-        this.horizontals = new boolean[width - 1][height];
-        this.verticals = new boolean[width][height - 1];
-        this.boxOwners = new int[width - 1][height - 1];
-    }
-
-    private void notifyObservers() {
-        for (Consumer<DotsAndBoxesGrid> consumer : watchers) {
-            consumer.accept(this);
-        }
-    }
-
-    /** Listens to this grid for changes */
-    public void addConsumer(Consumer<DotsAndBoxesGrid> consumer) {
-        watchers.add(consumer);
-    }
-
-    /** Returns whether a horizontal line has been drawn */
-    public boolean getHorizontal(int x, int y) {
-        return horizontals[x][y];
-    }
-
-    /** Returns whether a vertical line has been drawn */
-    public boolean getVertical(int x, int y) {
-        return verticals[x][y];
-    }
-
-    /** Returns which player owns a box. By convention, 0 is unowned. */
-    public int getBoxOwner(int x, int y) {
-        return boxOwners[x][y];
-    }
-
-
-    /**
-     * Checks whether a box has been fully drawn (all four sides)
-     * @param x coordinate of the left side of the box
-     * @param y coordinate of the top of the box
-     * @return true if all four sides have been drawn.
-     */
-    public boolean boxComplete(int x, int y) {
-        if (x >= width - 1 || x < 0 || y >= height - 1 || y < 0) {
-            return false;
-        }
-
-        // A box is complete if the north and south horizontals and the east and west verticals have all been drawn.
-        // FIXME: You'll need to fix this code (after writing a test first).
-        return true;
-    }
-
-    /** Tries to claim a box for a player. If the box is complete, sets the ownership and returns true. */
-    private boolean claimBox(int x, int y, int p) {
-        if (boxComplete(x, y)) {
-            boxOwners[x][y] = player;
-            return true;
-        } else {
-            return false;
-        }
-    }
-
-    /**
-     * "Draws" a horizontal line, from grid point (x, y) to (x + 1, y). (i.e. sets that line to true)
-     * @param x
-     * @param y
-     * @return true if it completes a box
-     */
-    public boolean drawHorizontal(int x, int y, int player) {
-        if (x >= width - 1 || x < 0) {
-            throw new IndexOutOfBoundsException(String.format("x was %d, which is out of range. Range is 0 to %d", x, width - 1));
-        }
-        if (y >= height || y < 0) {
-            throw new IndexOutOfBoundsException(String.format("y was %d, which is out of range. Range is 0 to %d", y, height));
-        }
-
-        // FIXME: You need to throw an exception if the line was already drawn.
-
-        this.horizontals[x][y] = true;
-
-        // Try to claim the north or south boxes
-        boolean claimN = claimBox(x, y-1, player);
-        boolean claimS = claimBox(x, y, player);
-        if (claimN || claimS) {
-            notifyObservers();
-            return true;
-        } else {
-            nextPlayer();
-            notifyObservers();
-            return false;
-        }
-    }
-
-    /**
-     * "Draws" a vertical line, from grid point (x, y) to (x, y + 1). (i.e. sets that line to true)
-     * @param x
-     * @param y
-     * @return true if it completes a box
-     */
-    public boolean drawVertical(int x, int y, int player) {
-        if (x >= width || x < 0) {
-            throw new IndexOutOfBoundsException(String.format("x was %d, which is out of range. Range is 0 to %d", x, width));
-        }
-        if (y >= height - 1 || y < 0) {
-            throw new IndexOutOfBoundsException(String.format("y was %d, which is out of range. Range is 0 to %d", y, height - 1));
-        }
-
-        // You need to throw an exception if the line was already drawn.
-
-        this.verticals[x][y] = true;
-        // Try to claim the north or south boxes
-        boolean claimE = claimBox(x, y, player);
-        boolean claimW = claimBox(x-1, y, player);
-        if (claimE || claimW) {
-            notifyObservers();
-            return true;
-        } else {
-            nextPlayer();
-            notifyObservers();
-            return false;
-        }
-
-    }
-
-    public boolean gameComplete() {
-        // Students who took COSC250 might recognise this style of code. This is Java's version of higher order functions.
-        // The grid is complete if "for all rows, all the boxes in that row have a non-zero owner"
-        return Arrays.stream(boxOwners).allMatch((row) -> Arrays.stream(row).allMatch((owner) -> owner > 0));
-    }
-
-
-}
+package dotsandboxes;
+
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Observer;
+import java.util.function.Consumer;
+
+/**
+ * The state of a dots and boxes grid.
+ *
+ * A (4, 3) dots and boxes grid looks like this:
+ *
+ * *-*-*-*
+ * | | | |
+ * *-*-*-*
+ * | | | |
+ * *-*-*-*
+ *
+ * Notice that:
+ *
+ * - for each row, there is one less horizontal than the number of corner dots
+ * - for each row, there are as many verticals as there are corner dots
+ * - for each row, there is one less box than the number of corner dots
+ * - for each column, there is one less vertical than the number of corner dots.
+ * - for each column, there are as many horizontals as there are corner dots.
+ * - for each column, there is one less box than the number of corner dots
+ *
+ * For example, in this (4, 3) grid, there are (3, 3) horizontal lines, and (4, 2) vertical lines, and (3, 2) boxes.
+ *
+ * We number all lines and boxes by their top-left coordinate.
+ *
+ * In Java 14+, we might use a Record class for this, but we're using 11+ as an LTS version, so we don't have that yet.
+ */
+public class DotsAndBoxesGrid {
+
+    final int width;
+    final int height;
+
+    /** The horizontal lines in the grid. True if drawn. */
+    private boolean[][] horizontals;
+
+    /** The vertical lines in the grid. True if drawn. */
+    private boolean[][] verticals;
+
+    /** Which owner (if any) claimed any given box. */
+    private int[][] boxOwners;
+
+    /** A list of functions to notify when there is an update */
+    private ArrayList<Consumer<DotsAndBoxesGrid>> watchers = new ArrayList<>();
+
+    final int players;
+    private int player = 1;
+    public int getPlayer() {
+        return player;
+    }
+
+    /** Moves to the next player */
+    private void nextPlayer() {
+        player++;
+        if (player > players) {
+            player = 1;
+        }
+    }
+
+    public DotsAndBoxesGrid(int width, int height, int players) {
+        this.width = width;
+        this.height = height;
+        this.players = players;
+
+        this.horizontals = new boolean[width - 1][height];
+        this.verticals = new boolean[width][height - 1];
+        this.boxOwners = new int[width - 1][height - 1];
+    }
+
+    private void notifyObservers() {
+        for (Consumer<DotsAndBoxesGrid> consumer : watchers) {
+            consumer.accept(this);
+        }
+    }
+
+    /** Listens to this grid for changes */
+    public void addConsumer(Consumer<DotsAndBoxesGrid> consumer) {
+        watchers.add(consumer);
+    }
+
+    /** Returns whether a horizontal line has been drawn */
+    public boolean getHorizontal(int x, int y) {
+        return horizontals[x][y];
+    }
+
+    /** Returns whether a vertical line has been drawn */
+    public boolean getVertical(int x, int y) {
+        return verticals[x][y];
+    }
+
+    /** Returns which player owns a box. By convention, 0 is unowned. */
+    public int getBoxOwner(int x, int y) {
+        return boxOwners[x][y];
+    }
+
+
+    /**
+     * Checks whether a box has been fully drawn (all four sides)
+     * @param x coordinate of the left side of the box
+     * @param y coordinate of the top of the box
+     * @return true if all four sides have been drawn.
+     */
+    public boolean boxComplete(int x, int y) {
+        if (x >= width - 1 || x < 0 || y >= height - 1 || y < 0) {
+            return false;
+        }
+
+        // A box is complete if the north and south horizontals and the east and west verticals have all been drawn.
+        // FIXME: You'll need to fix this code (after writing a test first).
+        return true;
+    }
+
+    /** Tries to claim a box for a player. If the box is complete, sets the ownership and returns true. */
+    private boolean claimBox(int x, int y, int p) {
+        if (boxComplete(x, y)) {
+            boxOwners[x][y] = player;
+            return true;
+        } else {
+            return false;
+        }
+    }
+
+    /**
+     * "Draws" a horizontal line, from grid point (x, y) to (x + 1, y). (i.e. sets that line to true)
+     * @param x
+     * @param y
+     * @return true if it completes a box
+     */
+    public boolean drawHorizontal(int x, int y, int player) {
+        if (x >= width - 1 || x < 0) {
+            throw new IndexOutOfBoundsException(String.format("x was %d, which is out of range. Range is 0 to %d", x, width - 1));
+        }
+        if (y >= height || y < 0) {
+            throw new IndexOutOfBoundsException(String.format("y was %d, which is out of range. Range is 0 to %d", y, height));
+        }
+
+        // FIXME: You need to throw an exception if the line was already drawn.
+
+        this.horizontals[x][y] = true;
+
+        // Try to claim the north or south boxes
+        boolean claimN = claimBox(x, y-1, player);
+        boolean claimS = claimBox(x, y, player);
+        if (claimN || claimS) {
+            notifyObservers();
+            return true;
+        } else {
+            nextPlayer();
+            notifyObservers();
+            return false;
+        }
+    }
+
+    /**
+     * "Draws" a vertical line, from grid point (x, y) to (x, y + 1). (i.e. sets that line to true)
+     * @param x
+     * @param y
+     * @return true if it completes a box
+     */
+    public boolean drawVertical(int x, int y, int player) {
+        if (x >= width || x < 0) {
+            throw new IndexOutOfBoundsException(String.format("x was %d, which is out of range. Range is 0 to %d", x, width));
+        }
+        if (y >= height - 1 || y < 0) {
+            throw new IndexOutOfBoundsException(String.format("y was %d, which is out of range. Range is 0 to %d", y, height - 1));
+        }
+
+        // You need to throw an exception if the line was already drawn.
+
+        this.verticals[x][y] = true;
+        // Try to claim the north or south boxes
+        boolean claimE = claimBox(x, y, player);
+        boolean claimW = claimBox(x-1, y, player);
+        if (claimE || claimW) {
+            notifyObservers();
+            return true;
+        } else {
+            nextPlayer();
+            notifyObservers();
+            return false;
+        }
+
+    }
+
+    public boolean gameComplete() {
+        // Students who took COSC250 might recognise this style of code. This is Java's version of higher order functions.
+        // The grid is complete if "for all rows, all the boxes in that row have a non-zero owner"
+        return Arrays.stream(boxOwners).allMatch((row) -> Arrays.stream(row).allMatch((owner) -> owner > 0));
+    }
+
+
+}
diff --git a/src/main/java/dotsandboxes/DotsAndBoxesUI.java b/src/main/java/dotsandboxes/DotsAndBoxesUI.java
index 66010e3938d422d2418c50f1962ed1c3d6f33050..e646cc4ee68f674e0c2a6610ea5fd174927eaf41 100644
--- a/src/main/java/dotsandboxes/DotsAndBoxesUI.java
+++ b/src/main/java/dotsandboxes/DotsAndBoxesUI.java
@@ -1,139 +1,139 @@
-package dotsandboxes;
-
-import javafx.scene.control.Label;
-import javafx.scene.layout.AnchorPane;
-import javafx.scene.paint.Color;
-import javafx.scene.shape.Circle;
-import javafx.scene.shape.Line;
-import javafx.scene.shape.Rectangle;
-
-public class DotsAndBoxesUI {
-
-    final int lineLength = 32;
-    final int margin = 10;
-    final int gap = 0;
-    final int dotDiameter = 6;
-
-    final DotsAndBoxesGrid grid;
-    final AnchorPane anchorPane;
-    final Label label;
-
-    /** Colours for the different players. Only goes up to 5. */
-    final Color[] playerColours = { Color.WHITE, Color.RED, Color.BLUE, Color.GREEN, Color.PURPLE, Color.ORANGE };
-
-    private void updateLabel() {
-        label.setTextFill(playerColours[grid.getPlayer()]);
-        label.setText(String.format("Player %d's turn", grid.getPlayer()));
-    }
-
-    public DotsAndBoxesUI(final DotsAndBoxesGrid grid) {
-        this.grid = grid;
-        anchorPane = new AnchorPane();
-
-        label = new Label("");
-        updateLabel();
-        grid.addConsumer((g) -> updateLabel());
-
-        // Size the anchorPane to just contain the elements
-        int width = margin + dotDiameter + gap + (grid.width - 1) * (gap + lineLength + gap + dotDiameter) + gap + margin;
-        int height = margin + dotDiameter + gap + (grid.height - 1) * (gap + lineLength + gap + dotDiameter) + gap + margin;
-        anchorPane.setPrefSize(width, height);
-
-
-        // Lay out the boxes
-        for (int row = 0; row < grid.height - 1; row++) {
-            for (int col = 0; col < grid.width - 1; col++) {
-                final int x = col;
-                final int y = row;
-                Rectangle box = new Rectangle(gap, gap, lineLength, lineLength);
-                box.setFill(Color.WHITE);
-
-                grid.addConsumer((g) -> {
-                    box.setFill(playerColours[g.getBoxOwner(x, y)]);
-                });
-
-                AnchorPane.setLeftAnchor(box, gap + dotDiameter + col * (gap + lineLength + gap + dotDiameter) + dotDiameter/2.0);
-                AnchorPane.setTopAnchor(box, gap + dotDiameter + row * (gap + lineLength + gap + dotDiameter) + dotDiameter/2.0);
-                anchorPane.getChildren().add(box);
-            }
-        }
-
-        // Lay out the horizontals
-        for (int row = 0; row < grid.height; row++) {
-            for (int col = 0; col < grid.width - 1; col++) {
-                Line line = new Line(0, dotDiameter/2.0, lineLength, dotDiameter/2.0);
-                line.setStrokeWidth(dotDiameter);
-                line.setStroke(Color.DARKGREY);
-
-                final int x = col;
-                final int y = row;
-                grid.addConsumer((g) -> {
-                    if (g.getHorizontal(x, y)) {
-                        line.setStroke(Color.BLACK);
-                    } else {
-                        line.setStroke(Color.LIGHTGRAY);
-                    }
-                });
-
-                line.setOnMouseClicked((evt) -> {try {
-                    grid.drawHorizontal(x, y, grid.getPlayer());
-                } catch (IllegalStateException ex) {
-                    // do nothing
-                    // This is a little artificial, as normally we'd implement this with a check that the line isn't
-                    // already "drawn" and then not calling the function. But for the exercise, we wanted students
-                    // to write a test that would ensure an exception is thrown, so we're relying on an exception
-                    // being thrown!
-                }});
-
-                AnchorPane.setLeftAnchor(line, 0.0 + gap + dotDiameter + col * (gap + lineLength + gap + dotDiameter));
-                AnchorPane.setTopAnchor(line, -dotDiameter/2.0 + gap + dotDiameter + row * (gap + lineLength + gap + dotDiameter));
-                anchorPane.getChildren().add(line);
-            }
-        }
-
-        // Lay out the verticals
-        for (int row = 0; row < grid.height - 1; row++) {
-            for (int col = 0; col < grid.width; col++) {
-                Line line = new Line(-dotDiameter/2.0, 0, -dotDiameter/2.0, lineLength);
-                line.setStrokeWidth(dotDiameter);
-                line.setStroke(Color.DARKGREY);
-
-                final int x = col;
-                final int y = row;
-                grid.addConsumer((g) -> {
-                    if (g.getVertical(x, y)) {
-                        line.setStroke(Color.BLACK);
-                    } else {
-                        line.setStroke(Color.LIGHTGRAY);
-                    }
-                });
-
-                line.setOnMouseClicked((evt) -> {try {
-                    grid.drawVertical(x, y, grid.getPlayer());
-                } catch (IllegalStateException ex) {
-                    // do nothing
-                }});
-
-                AnchorPane.setTopAnchor(line, 0.0 + gap + dotDiameter + row * (gap + lineLength + gap + dotDiameter));
-                AnchorPane.setLeftAnchor(line, -dotDiameter/2.0 + gap + dotDiameter + col * (gap + lineLength + gap + dotDiameter));
-                anchorPane.getChildren().add(line);
-            }
-        }
-
-        // Lay out the dots
-        for (int row = 0; row < grid.height; row++) {
-            for (int col = 0; col < grid.width; col++) {
-                Circle dot = new Circle(dotDiameter / 2.0);
-                dot.setFill(Color.YELLOW);
-
-                AnchorPane.setLeftAnchor(dot, gap + col * (gap + lineLength + gap + dotDiameter) + dotDiameter/2.0);
-                AnchorPane.setTopAnchor(dot, gap + row * (gap + lineLength + gap + dotDiameter) + dotDiameter/2.0);
-                anchorPane.getChildren().add(dot);
-            }
-        }
-
-    }
-
-
-
-}
+package dotsandboxes;
+
+import javafx.scene.control.Label;
+import javafx.scene.layout.AnchorPane;
+import javafx.scene.paint.Color;
+import javafx.scene.shape.Circle;
+import javafx.scene.shape.Line;
+import javafx.scene.shape.Rectangle;
+
+public class DotsAndBoxesUI {
+
+    final int lineLength = 32;
+    final int margin = 10;
+    final int gap = 0;
+    final int dotDiameter = 6;
+
+    final DotsAndBoxesGrid grid;
+    final AnchorPane anchorPane;
+    final Label label;
+
+    /** Colours for the different players. Only goes up to 5. */
+    final Color[] playerColours = { Color.WHITE, Color.RED, Color.BLUE, Color.GREEN, Color.PURPLE, Color.ORANGE };
+
+    private void updateLabel() {
+        label.setTextFill(playerColours[grid.getPlayer()]);
+        label.setText(String.format("Player %d's turn", grid.getPlayer()));
+    }
+
+    public DotsAndBoxesUI(final DotsAndBoxesGrid grid) {
+        this.grid = grid;
+        anchorPane = new AnchorPane();
+
+        label = new Label("");
+        updateLabel();
+        grid.addConsumer((g) -> updateLabel());
+
+        // Size the anchorPane to just contain the elements
+        int width = margin + dotDiameter + gap + (grid.width - 1) * (gap + lineLength + gap + dotDiameter) + gap + margin;
+        int height = margin + dotDiameter + gap + (grid.height - 1) * (gap + lineLength + gap + dotDiameter) + gap + margin;
+        anchorPane.setPrefSize(width, height);
+
+
+        // Lay out the boxes
+        for (int row = 0; row < grid.height - 1; row++) {
+            for (int col = 0; col < grid.width - 1; col++) {
+                final int x = col;
+                final int y = row;
+                Rectangle box = new Rectangle(gap, gap, lineLength, lineLength);
+                box.setFill(Color.WHITE);
+
+                grid.addConsumer((g) -> {
+                    box.setFill(playerColours[g.getBoxOwner(x, y)]);
+                });
+
+                AnchorPane.setLeftAnchor(box, gap + dotDiameter + col * (gap + lineLength + gap + dotDiameter) + dotDiameter/2.0);
+                AnchorPane.setTopAnchor(box, gap + dotDiameter + row * (gap + lineLength + gap + dotDiameter) + dotDiameter/2.0);
+                anchorPane.getChildren().add(box);
+            }
+        }
+
+        // Lay out the horizontals
+        for (int row = 0; row < grid.height; row++) {
+            for (int col = 0; col < grid.width - 1; col++) {
+                Line line = new Line(0, dotDiameter/2.0, lineLength, dotDiameter/2.0);
+                line.setStrokeWidth(dotDiameter);
+                line.setStroke(Color.DARKGREY);
+
+                final int x = col;
+                final int y = row;
+                grid.addConsumer((g) -> {
+                    if (g.getHorizontal(x, y)) {
+                        line.setStroke(Color.BLACK);
+                    } else {
+                        line.setStroke(Color.LIGHTGRAY);
+                    }
+                });
+
+                line.setOnMouseClicked((evt) -> {try {
+                    grid.drawHorizontal(x, y, grid.getPlayer());
+                } catch (IllegalStateException ex) {
+                    // do nothing
+                    // This is a little artificial, as normally we'd implement this with a check that the line isn't
+                    // already "drawn" and then not calling the function. But for the exercise, we wanted students
+                    // to write a test that would ensure an exception is thrown, so we're relying on an exception
+                    // being thrown!
+                }});
+
+                AnchorPane.setLeftAnchor(line, 0.0 + gap + dotDiameter + col * (gap + lineLength + gap + dotDiameter));
+                AnchorPane.setTopAnchor(line, -dotDiameter/2.0 + gap + dotDiameter + row * (gap + lineLength + gap + dotDiameter));
+                anchorPane.getChildren().add(line);
+            }
+        }
+
+        // Lay out the verticals
+        for (int row = 0; row < grid.height - 1; row++) {
+            for (int col = 0; col < grid.width; col++) {
+                Line line = new Line(-dotDiameter/2.0, 0, -dotDiameter/2.0, lineLength);
+                line.setStrokeWidth(dotDiameter);
+                line.setStroke(Color.DARKGREY);
+
+                final int x = col;
+                final int y = row;
+                grid.addConsumer((g) -> {
+                    if (g.getVertical(x, y)) {
+                        line.setStroke(Color.BLACK);
+                    } else {
+                        line.setStroke(Color.LIGHTGRAY);
+                    }
+                });
+
+                line.setOnMouseClicked((evt) -> {try {
+                    grid.drawVertical(x, y, grid.getPlayer());
+                } catch (IllegalStateException ex) {
+                    // do nothing
+                }});
+
+                AnchorPane.setTopAnchor(line, 0.0 + gap + dotDiameter + row * (gap + lineLength + gap + dotDiameter));
+                AnchorPane.setLeftAnchor(line, -dotDiameter/2.0 + gap + dotDiameter + col * (gap + lineLength + gap + dotDiameter));
+                anchorPane.getChildren().add(line);
+            }
+        }
+
+        // Lay out the dots
+        for (int row = 0; row < grid.height; row++) {
+            for (int col = 0; col < grid.width; col++) {
+                Circle dot = new Circle(dotDiameter / 2.0);
+                dot.setFill(Color.YELLOW);
+
+                AnchorPane.setLeftAnchor(dot, gap + col * (gap + lineLength + gap + dotDiameter) + dotDiameter/2.0);
+                AnchorPane.setTopAnchor(dot, gap + row * (gap + lineLength + gap + dotDiameter) + dotDiameter/2.0);
+                anchorPane.getChildren().add(dot);
+            }
+        }
+
+    }
+
+
+
+}
diff --git a/src/main/java/dotsandboxes/Main.java b/src/main/java/dotsandboxes/Main.java
index cd003d1a27d26053a78244c6f69da68b883fd9be..cd2bce88d0715271aba46b8947f1d903ec301a1b 100644
--- a/src/main/java/dotsandboxes/Main.java
+++ b/src/main/java/dotsandboxes/Main.java
@@ -1,40 +1,40 @@
-package dotsandboxes;
-
-import javafx.application.Application;
-import javafx.scene.Scene;
-import javafx.scene.control.Label;
-import javafx.scene.layout.BorderPane;
-import javafx.stage.Stage;
-
-/** Our main class that launches the app. */
-public class Main extends Application {
-
-    DotsAndBoxesGrid grid = new DotsAndBoxesGrid(15, 8, 2);
-
-    @Override
-    public void start(Stage primaryStage) throws Exception {
-        primaryStage.setTitle("Dots and Boxes");
-
-        // FIXME: Update this label to show your name and student number
-        Label label = new Label("Name: (Your name and student number goes here)");
-
-        BorderPane borderPane = new BorderPane();
-        borderPane.setBottom(label);
-        Scene scene = new Scene(borderPane, 600, 400);
-
-        DotsAndBoxesUI dbUi = new DotsAndBoxesUI(grid);
-        borderPane.setCenter(dbUi.anchorPane);
-        borderPane.setTop(dbUi.label);
-
-        primaryStage.setScene(scene);
-
-        primaryStage.show();
-
-        // This sets what to do when we close the main window.
-        // Notice that we are using a "lambda function" (i.e., an anonymously defined function defined within the
-        // call to setOnCloseRequest). These are very useful in GUI code and we'll probably see a lot of them in the
-        // project.
-        primaryStage.setOnCloseRequest((evt) -> System.exit(0));
-    }
-
-}
+package dotsandboxes;
+
+import javafx.application.Application;
+import javafx.scene.Scene;
+import javafx.scene.control.Label;
+import javafx.scene.layout.BorderPane;
+import javafx.stage.Stage;
+
+/** Our main class that launches the app. */
+public class Main extends Application {
+
+    DotsAndBoxesGrid grid = new DotsAndBoxesGrid(15, 8, 2);
+
+    @Override
+    public void start(Stage primaryStage) throws Exception {
+        primaryStage.setTitle("Dots and Boxes");
+
+        // FIXME: Update this label to show your name and student number
+        Label label = new Label("Name: (Your name and student number goes here)");
+
+        BorderPane borderPane = new BorderPane();
+        borderPane.setBottom(label);
+        Scene scene = new Scene(borderPane, 600, 400);
+
+        DotsAndBoxesUI dbUi = new DotsAndBoxesUI(grid);
+        borderPane.setCenter(dbUi.anchorPane);
+        borderPane.setTop(dbUi.label);
+
+        primaryStage.setScene(scene);
+
+        primaryStage.show();
+
+        // This sets what to do when we close the main window.
+        // Notice that we are using a "lambda function" (i.e., an anonymously defined function defined within the
+        // call to setOnCloseRequest). These are very useful in GUI code and we'll probably see a lot of them in the
+        // project.
+        primaryStage.setOnCloseRequest((evt) -> System.exit(0));
+    }
+
+}
diff --git a/src/main/java/module-info.java b/src/main/java/module-info.java
index eb9361f159b402160086de3fe6b01b1272ab53b0..e51a2313046b8aa9453a946e97237e0e8f298fae 100644
--- a/src/main/java/module-info.java
+++ b/src/main/java/module-info.java
@@ -1,19 +1,19 @@
-/**
- * This is a module file.
- *
- * Modules were introduced in Java 9, allowing modules to express dependencies on other modules and to publish their
- * public packages.
- *
- * Using modules makes things easier when working with JavaFX, because JavaFX is itself published as a module.
- *
- * Please note: "module" in Java is not quite the same as "dependency" in Gradle. They are similar concepts, but
- * "modules" is part of the Java language (but doesn't express how to find them on the internet) whereas
- * "dependencies" is part of the Gradle build system and expresses how to find them on the internet (but does not
- * specify the module imports to the Java compiler). We need both.
- */
-module dotsAndBoxes {
-    requires javafx.graphics;
-    requires javafx.controls;
-    requires org.apache.logging.log4j;
-    exports dotsandboxes;
+/**
+ * This is a module file.
+ *
+ * Modules were introduced in Java 9, allowing modules to express dependencies on other modules and to publish their
+ * public packages.
+ *
+ * Using modules makes things easier when working with JavaFX, because JavaFX is itself published as a module.
+ *
+ * Please note: "module" in Java is not quite the same as "dependency" in Gradle. They are similar concepts, but
+ * "modules" is part of the Java language (but doesn't express how to find them on the internet) whereas
+ * "dependencies" is part of the Gradle build system and expresses how to find them on the internet (but does not
+ * specify the module imports to the Java compiler). We need both.
+ */
+module dotsAndBoxes {
+    requires javafx.graphics;
+    requires javafx.controls;
+    requires org.apache.logging.log4j;
+    exports dotsandboxes;
 }
\ No newline at end of file
diff --git a/src/test/java/dotsandboxes/DotsAndBoxesGridTest.java b/src/test/java/dotsandboxes/DotsAndBoxesGridTest.java
index 1946beda974d180686c65c0259a7b881e9a4eb5a..1aac7ccc87bd5620cdcd1db9b008f20a08d50640 100644
--- a/src/test/java/dotsandboxes/DotsAndBoxesGridTest.java
+++ b/src/test/java/dotsandboxes/DotsAndBoxesGridTest.java
@@ -1,31 +1,31 @@
-package dotsandboxes;
-
-import org.junit.jupiter.api.*;
-import static org.junit.jupiter.api.Assertions.*;
-import static org.junit.jupiter.api.Assumptions.*;
-
-import org.apache.logging.log4j.LogManager;
-import org.apache.logging.log4j.Logger;
-
-public class DotsAndBoxesGridTest {
-    /*
-     * Because Test classes are classes, they can have fields, and can have static fields.
-     * This field is a logger. Loggers are like a more advanced println, for writing messages out to the console or a log file.
-     */
-    private static final Logger logger = LogManager.getLogger(DotsAndBoxesGridTest.class);
-
-    /*
-     * Tests are functions that have an @Test annotation before them.
-     * The typical format of a test is that it contains some code that does something, and then one
-     * or more assertions to check that a condition holds.
-     *
-     * This is a dummy test just to show that the test suite itself runs
-     */
-    @Test
-    public void testTestSuiteRuns() {
-        logger.info("Dummy test to show the test suite runs");
-        assertTrue(true);
-    }
-
-    // FIXME: You need to write tests for the two known bugs in the code.
-}
+package dotsandboxes;
+
+import org.junit.jupiter.api.*;
+import static org.junit.jupiter.api.Assertions.*;
+import static org.junit.jupiter.api.Assumptions.*;
+
+import org.apache.logging.log4j.LogManager;
+import org.apache.logging.log4j.Logger;
+
+public class DotsAndBoxesGridTest {
+    /*
+     * Because Test classes are classes, they can have fields, and can have static fields.
+     * This field is a logger. Loggers are like a more advanced println, for writing messages out to the console or a log file.
+     */
+    private static final Logger logger = LogManager.getLogger(DotsAndBoxesGridTest.class);
+
+    /*
+     * Tests are functions that have an @Test annotation before them.
+     * The typical format of a test is that it contains some code that does something, and then one
+     * or more assertions to check that a condition holds.
+     *
+     * This is a dummy test just to show that the test suite itself runs
+     */
+    @Test
+    public void testTestSuiteRuns() {
+        logger.info("Dummy test to show the test suite runs");
+        assertTrue(true);
+    }
+
+    // FIXME: You need to write tests for the two known bugs in the code.
+}
diff --git a/src/test/resources/log4j2.xml b/src/test/resources/log4j2.xml
index 32c8f6bc729bb2d82f81583fb3215b7c669b4f32..fc48a88519bd2c9dc4af3e86af8e2ce0c18b2486 100644
--- a/src/test/resources/log4j2.xml
+++ b/src/test/resources/log4j2.xml
@@ -1,13 +1,13 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<Configuration status="WARN">
-    <Appenders>
-        <Console name="Console" target="SYSTEM_OUT">
-            <PatternLayout pattern="%d{HH:mm:ss.SSS} [%t] %-5level %logger{36} - %msg%n"/>
-        </Console>
-    </Appenders>
-    <Loggers>
-        <Root level="debug">
-            <AppenderRef ref="Console"/>
-        </Root>
-    </Loggers>
+<?xml version="1.0" encoding="UTF-8"?>
+<Configuration status="WARN">
+    <Appenders>
+        <Console name="Console" target="SYSTEM_OUT">
+            <PatternLayout pattern="%d{HH:mm:ss.SSS} [%t] %-5level %logger{36} - %msg%n"/>
+        </Console>
+    </Appenders>
+    <Loggers>
+        <Root level="debug">
+            <AppenderRef ref="Console"/>
+        </Root>
+    </Loggers>
 </Configuration>
\ No newline at end of file