Commits

Alex Hixon committed 2d23949 Draft

Done!

  • Participants
  • Parent commits db88716

Comments (0)

Files changed (34)

File .idea/artifacts/Quoridor_JAR.xml

+<component name="ArtifactManager">
+  <artifact type="jar" build-on-make="true" name="Quoridor JAR">
+    <output-path>$PROJECT_DIR$/out/artifacts/Quoridor_JAR</output-path>
+    <root id="archive" name="quoridor.jar">
+      <element id="module-output" name="Quoridor" />
+      <element id="directory" name="META-INF">
+        <element id="file-copy" path="$PROJECT_DIR$/META-INF/MANIFEST.MF" />
+      </element>
+    </root>
+  </artifact>
+</component>

File .idea/codeStyleSettings.xml

+<?xml version="1.0" encoding="UTF-8"?>
+<project version="4">
+  <component name="ProjectCodeStyleSettingsManager">
+    <option name="PER_PROJECT_SETTINGS">
+      <value>
+        <XML>
+          <option name="XML_LEGACY_SETTINGS_IMPORTED" value="true" />
+        </XML>
+      </value>
+    </option>
+  </component>
+</project>
+

File META-INF/MANIFEST.MF

+Manifest-Version: 1.0
+Main-Class: view.ConsoleUI
+

File src/model/Baseline.java

 package model;
 
-public class Baseline {
+import java.io.Serializable;
+
+/**
+ * A baseline is the line that a player either starts from, or seeks to reach in order to win the game.
+ */
+public class Baseline implements Serializable {
     private enum LineParameter {
         X,
         Y
     private final int x;
     private final int y;
 
-    private final LineParameter location;   // TODO: bad naming?
+    private final LineParameter importantAxis;
 
+    /**
+     * Creates a new baseline for brains who are starting in a given direction.
+     *
+     * @param startDirection The direction brains are working towards/facing when they start the game.
+     */
     public Baseline (Direction startDirection) {
         if (startDirection == Direction.DOWN) {
             x = (Board.WIDTH - 1) / 2;
             y = Board.HEIGHT - 1;
-            location = LineParameter.Y;
+            importantAxis = LineParameter.Y;
         } else if (startDirection == Direction.UP) {
             // starting from bottom (so middle of bottom row)
             x = (Board.WIDTH - 1) / 2;
             y = 0;
-            location = LineParameter.Y;
+            importantAxis = LineParameter.Y;
         } else if (startDirection == Direction.RIGHT) {
             // starting from left (so middle of left row)
             x = 0;
             y = (Board.HEIGHT - 1) / 2;
-            location = LineParameter.X;
+            importantAxis = LineParameter.X;
         } else {
             // starting from right (middle of right row)
             x = Board.WIDTH - 1;
             y = (Board.HEIGHT - 1) / 2;
-            location = LineParameter.X;
+            importantAxis = LineParameter.X;
         }
     }
 
-    public BoardCoordinate getCenterCoordinate() {
-        return new BoardCoordinate(x, y);
+    /**
+     * Gets the center/middle coordinate of a baseline
+     *
+     * @return Coordinate representing the middle of a baseline
+     */
+    public BoardCoordinate getCenterCoordinate () {
+        return new BoardCoordinate (x, y);
     }
 
+    /**
+     * Checks to see if a coordinate lies on a baseline.
+     *
+     * @param coordinate the coordinate to check
+     * @return true if the coordinate lies on the baseline, false otherwise.
+     */
     public boolean hasCoordinateOnBaseline (BoardCoordinate coordinate) {
-        if (this.location == LineParameter.X) {
-            return coordinate.getX() == this.x;
+        if (this.importantAxis == LineParameter.X) {
+            return coordinate.getX () == this.x;
         } else {
-            return coordinate.getY() == this.y;
+            return coordinate.getY () == this.y;
         }
     }
 
-    public int getDistance(BoardCoordinate coordinate) {
-        if (this.location == LineParameter.X) {
-            return coordinate.getX() - this.x;
+    /**
+     * Calculates the distance between a coordinate and this baseline.
+     *
+     * @param coordinate The coordinate to measure from (often the player's location)
+     * @param d          The direction the player is aiming towards (ie where their goal baseline is)
+     * @return Number of tiles between the given coordinate and this baseline
+     */
+    public int getDistance (BoardCoordinate coordinate, Direction d) {
+        int ans;
+        if (this.importantAxis == LineParameter.X) {
+            ans = coordinate.getX () - this.x;
         } else {
-            return coordinate.getY() - this.y;
+            ans = coordinate.getY () - this.y;
         }
+
+        if (d == Direction.RIGHT || d == Direction.UP) {
+            ans = ans * -1;
+        }
+
+        return ans;
     }
 
     @Override
-    public String toString() {
-        if (this.location == LineParameter.X) {
+    public String toString () {
+        if (this.importantAxis == LineParameter.X) {
             return "x = " + this.x;
         } else {
             return "y = " + this.y;

File src/model/Board.java

 package model;
 
-public class Board {
+import java.io.Serializable;
+
+/**
+ * Represents the actual Quoridor game board.
+ */
+public class Board implements Serializable {
     public static final int WIDTH = 9;
     public static final int HEIGHT = 9;
 
         // set bottom and left links on the tiles when we create them
         for (int x = 0; x < WIDTH; x++) {
             for (int y = 0; y < HEIGHT; y++) {
-                Tile t = new Tile (new BoardCoordinate(x, y));
+                Tile t = new Tile (new BoardCoordinate (x, y));
 
                 // set left if it's not 0,0
                 if (x != 0) {
-                    t.setTile(Direction.LEFT, tiles[x - 1][y]);
+                    t.setTile (Direction.LEFT, tiles[x - 1][y]);
                 }
 
                 if (y != 0) {
-                    t.setTile(Direction.DOWN, tiles[x][y - 1]);
+                    t.setTile (Direction.DOWN, tiles[x][y - 1]);
                 }
 
                 tiles[x][y] = t;
                 Tile t = tiles[x][y];
 
                 if (x != (WIDTH - 1)) {
-                    t.setTile(Direction.RIGHT, tiles[x + 1][y]);
+                    t.setTile (Direction.RIGHT, tiles[x + 1][y]);
                 }
 
                 if (y != (HEIGHT - 1)) {
-                    t.setTile(Direction.UP, tiles[x][y + 1]);
+                    t.setTile (Direction.UP, tiles[x][y + 1]);
                 }
             }
         }
 
     /**
      * Creates a deep copy of a Board.
+     *
      * @param other The Board you want this to be a copy of.
      */
     public Board (Board other) {
         for (int x = 0; x < WIDTH; x++) {
             for (int y = 0; y < HEIGHT; y++) {
                 // first copy where the broken links lie
-                for (Direction d : Direction.values()) {
-                    if (other.tiles[x][y].getAdjacentLink(d) == null) {
-                        this.tiles[x][y].breakAdjacent(d);
+                for (Direction d : Direction.values ()) {
+                    if (other.tiles[x][y].getAdjacentLink (d) == null) {
+                        this.tiles[x][y].breakAdjacent (d);
                     }
                 }
 
                 // and copy the tile contents
-                this.tiles[x][y].setPlayer(other.tiles[x][y].getPlayer());
+                this.tiles[x][y].setPlayer (other.tiles[x][y].getPlayer ());
             }
         }
     }
 
+    /**
+     * Places a wall on the board.
+     *
+     * @param coordinate    the coordinate at the bottom left of a square of four tiles where the wall will be built.
+     * @param wallDirection the orientation of the wall within those four tiles.
+     * @return True if the build was successful, false otherwise.
+     */
     public boolean placeWall (BoardCoordinate coordinate, WallDirection wallDirection) {
-        boolean canBuild = true;
-        Tile start = tiles[coordinate.getX()][coordinate.getY()];
+        boolean canBuild;
+        Tile start = tiles[coordinate.getX ()][coordinate.getY ()];
 
         // can't start build on the outer top rows/columns of the board (requires 4 tiles)
-        if (coordinate.getX() == (WIDTH - 1) || coordinate.getY() == (HEIGHT - 1)) {
+        if (coordinate.getX () == (WIDTH - 1) || coordinate.getY () == (HEIGHT - 1)) {
             return false;
         }
 
-        Tile right = this.getTile(start.getCoordinate().add(Direction.RIGHT));
-        Tile above = this.getTile(start.getCoordinate().add(Direction.UP));
+        Tile right = this.getTile (start.getCoordinate ().add (Direction.RIGHT));
+        Tile above = this.getTile (start.getCoordinate ().add (Direction.UP));
 
         Direction dirA, dirB;
         Tile tileA, tileB;
         }
 
         // make sure there's no wall already directly on top
-        canBuild &= (start.getAdjacentLink(dirA) != null);
-        canBuild &= (tileA.getAdjacentLink(dirA) != null);
+        canBuild = (start.getAdjacentLink (dirA) != null);
+        canBuild &= (tileA.getAdjacentLink (dirA) != null);
 
         // check perpendicular to see if we can build on a T
         // if BOTH are blocked then we get an X which we is invalid
-        canBuild &= (start.getAdjacentLink(dirB) != null || tileB.getAdjacentLink(dirB) != null);
+        canBuild &= (start.getAdjacentLink (dirB) != null || tileB.getAdjacentLink (dirB) != null);
 
         if (canBuild) {
-            start.breakAdjacent(dirA);
-            tileA.breakAdjacent(dirA);
+            start.breakAdjacent (dirA);
+            tileA.breakAdjacent (dirA);
         }
 
         return canBuild;
     }
 
+    /**
+     * Retuns the tile at a given coordinate.
+     * <p/>
+     * Note that even if Tile links are broken, you can use this method to fetch the respective Tile.
+     *
+     * @param c the coordinate you wish to fetch the respective tile at.
+     * @return the Tile at that location.
+     */
     public Tile getTile (BoardCoordinate c) {
-        return this.tiles[c.getX()][c.getY()];
+        return this.tiles[c.getX ()][c.getY ()];
     }
 }

File src/model/BoardCoordinate.java

 package model;
 
-public class BoardCoordinate extends Coordinate {
+import java.io.Serializable;
+
+/**
+ * A type of coordinate used specifically on the Board, and where it represents a coordinate that would
+ * be seen on the game board. This contrasts to the general nature of the Coordinate class.
+ */
+public class BoardCoordinate extends Coordinate implements Serializable {
+    /**
+     * Creates a new BoardCoordinate, given an X and Y position.
+     *
+     * @param x the X coordinate
+     * @param y the Y coordinate
+     * @throws IllegalArgumentException if the X and Y values are not in the Board bounds
+     * @see Board
+     */
     public BoardCoordinate (int x, int y) {
         super (x, y);
 
-        if (!isInBounds()) {
+        if (!isInBounds ()) {
             throw new IllegalArgumentException ();
         }
     }
     public BoardCoordinate (Coordinate c) {
         super (c);
 
-        if (!isInBounds()) {
+        if (!isInBounds ()) {
             throw new IllegalArgumentException ();
         }
     }
 
+    /**
+     * Creates a new BoardCoordinate given a two character String notation in the form of
+     * [a-i][1-9].
+     *
+     * @param notation The notation to parse and create a BoardCoordinate from.
+     * @throws IllegalArgumentException if the notation was incorrect
+     */
     public BoardCoordinate (String notation) {
-        if (notation.length() != 2) {
-            throw new IllegalArgumentException("Notation is 2 character column-row only");
+        if (notation.length () != 2) {
+            throw new IllegalArgumentException ("Notation is 2 character column-row only");
         }
 
-        notation = notation.toLowerCase();
-        this.x = notation.charAt(0) - 'a';                          // column
-        this.y = Integer.parseInt(notation.substring(1)) - 1;       // row
+        notation = notation.toLowerCase ();
+        this.x = notation.charAt (0) - 'a';                          // column
+        this.y = Integer.parseInt (notation.substring (1)) - 1;       // row
 
-        if (!isInBounds()) {
-            throw new IllegalArgumentException ("Column between a-i, row between 1-9"); // FIXME: variable sized boards?
+        if (!isInBounds ()) {
+            throw new IllegalArgumentException ("Column between a-i, row between 1-9");
         }
     }
 
+    /**
+     * Converts the BoardCoordinate back into a notation string, that is, a two character string of the form [a-i][1-9]
+     *
+     * @return the notation string representing this coordinate
+     */
     public String toNotationString () {
-        return (char)(this.x + 'a') + ((this.y + 1) + "");
+        return (char) (this.x + 'a') + ((this.y + 1) + "");
     }
 
+    /**
+     * Increases or decreases a coordinate by one (1) in a given direction.
+     *
+     * @param d Direction to add to BoardCoordinate.
+     * @return The new, modified BoardCoordinate.
+     * @throws IllegalArgumentException if the new coordinate is outside the Board (thrown by the constructor).
+     */
     public BoardCoordinate add (Direction d) {
-        return new BoardCoordinate (super.add(d));
+        return new BoardCoordinate (super.add (d));
     }
 
     private boolean isInBounds () {
         return (this.x >= 0 && this.y >= 0 && this.x < Board.WIDTH && this.y < Board.HEIGHT);
     }
 
-    public boolean isEdge() {
+    /**
+     * Checks to see if this BoardCoordinate is on the edge of the Board.
+     *
+     * @return true if it is, false otherwise
+     */
+    public boolean isEdge () {
         return (this.x == 0 || this.x == (Board.WIDTH - 1) || this.y == 0 || this.y == (Board.HEIGHT - 1));
     }
 }

File src/model/Coordinate.java

 package model;
 
+/**
+ * Basic coodinate. Represents an x-y coordinate system.
+ * <p/>
+ * For coordinates that are going to be used on the Board or similar, please use BoardCoordinate.
+ */
 public class Coordinate {
     protected int x;
     protected int y;
 
-    protected Coordinate () { }
+    protected Coordinate () {
+    }
 
     public Coordinate (int x, int y) {
         this.x = x;
         this.y = c.y;
     }
 
+    /**
+     * Returns the X part of the coordinate in the XY plane.
+     *
+     * @return the X coordinate
+     */
     public int getX () {
         return x;
     }
 
+    /**
+     * Returns the Y part of the coordinate in the XY plane.
+     *
+     * @return the Y coordinate
+     */
     public int getY () {
         return y;
     }
 
+    /**
+     * Increases or decreases a coordinate by one (1) in a given direction.
+     *
+     * @param d Direction to add to Coordinate.
+     * @return The new, modified Coordinate.
+     */
     public Coordinate add (Direction d) {
-        Coordinate delta = new Coordinate(0, 0);
+        Coordinate delta = new Coordinate (0, 0);
 
         switch (d) {
             case UP:
                 break;
         }
 
-        return this.add(delta);
+        return this.add (delta);
     }
 
+    /**
+     * Adds two coordinates together.
+     *
+     * @param other The other coordinate to add
+     * @return The resulting Coordinate (this + other)
+     */
     public Coordinate add (Coordinate other) {
         return new Coordinate (this.x + other.x, this.y + other.y);
     }
     @Override
     public boolean equals (Object other) {
         if (other == this) return true;
-        if (! (other instanceof BoardCoordinate)) return false;
+        if (!(other instanceof BoardCoordinate)) return false;
 
-        BoardCoordinate that = (BoardCoordinate)other;
+        BoardCoordinate that = (BoardCoordinate) other;
         return (this.x == that.x && this.y == that.y);
     }
 
     @Override
-    public String toString() {
+    public String toString () {
         return "(" + this.x + ", " + this.y + ")";
     }
-
-    public Coordinate subtract (Coordinate other) {
-        return new Coordinate(this.x - other.x, this.y - other.y);
-    }
 }
 

File src/model/Direction.java

 package model;
 
+/**
+ * Represents a cardinal direction. That is; up, down, left or right.
+ */
 public enum Direction {
     LEFT,
     RIGHT,
     UP,
     DOWN;
 
-    public static Direction getInverse(Direction direction) {
+    /**
+     * Gets the opposite direction to one given.
+     *
+     * @param direction The direction you currently have
+     * @return The opposite direction to the one that is given.
+     */
+    public static Direction getInverse (Direction direction) {
         switch (direction) {
             case UP:
                 return DOWN;
         return null;
     }
 
+    /**
+     * Gets a pair of directions that represent the two perpendicular directions from the given direction.
+     * For example, given UP or DOWN, you would get back both LEFT and RIGHT.
+     *
+     * @param d The direction you're after
+     * @return A pair of directions perpendicular to the one given.
+     */
     public static Direction[] getPerpendicular (Direction d) {
         if (d == UP || d == DOWN) {
-            return new Direction[]{ LEFT, RIGHT };
+            return new Direction[] { LEFT, RIGHT };
         } else {
-            return new Direction[]{ UP, DOWN };
+            return new Direction[] { UP, DOWN };
         }
     }
 }

File src/model/Game.java

 package model;
 
-import model.players.AbstractPersonality;
+import model.brains.AbstractBrain;
 
+import java.io.Serializable;
 import java.util.*;
 
-public class Game {
+/**
+ * The main Game class, that plays the game of Quoridor.
+ * Supports up to 4 brains.
+ */
+public class Game implements Serializable {
     public final static int MAX_PLAYER_WALL_COUNT = 10;
 
-    private LinkedList<GamePlayer> players = new LinkedList<GamePlayer>();
+    private LinkedList<GamePlayer> players = new LinkedList<GamePlayer> ();
     private GamePlayer currentPlayer = null;
     private Board board;
     private boolean hasStarted = false;
-    private AbstractPersonality winner = null;
+    private AbstractBrain winner = null;
 
+    /**
+     * Creates a new Game that can play Quoridor.
+     */
     public Game () {
         this.board = new Board ();
     }
 
+    /**
+     * Creates a copy of a Game object, from another Game object.
+     *
+     * @param other The Game object you would like to clone.
+     */
     public Game (Game other) {
-        this.board = new Board(other.board);
+        this.board = new Board (other.board);
         for (GamePlayer player : other.players) {
             GamePlayer copy = new GamePlayer (player);
             if (other.currentPlayer.equals (player)) {
                 this.currentPlayer = copy;
             }
 
-            this.players.add(copy);
+            this.players.add (copy);
         }
 
         this.hasStarted = other.hasStarted;
         this.winner = other.winner;
     }
 
-    public void addPlayer (AbstractPersonality user) {
+    /**
+     * Adds a new player to the board.
+     * The player should not already be added in the same preferred starting location.
+     *
+     * @param user The AbstractBrain that you wish to add. The Game class will create an internal
+     *             GamePlayer to represent this player.
+     */
+    public void addPlayer (AbstractBrain user) {
         // and put them on the board
         GamePlayer player = new GamePlayer (user);
 
-        Tile requestedTile = this.board.getTile (player.getCurrentCoordinate());
-        if (requestedTile.getPlayer() == null) {
-            requestedTile.setPlayer(player);
+        Tile requestedTile = this.board.getTile (player.getCurrentCoordinate ());
+        if (requestedTile.getPlayer () == null) {
+            requestedTile.setPlayer (player);
         }
 
         players.add (player);
     }
 
+    /**
+     * Starts a game of Quordior. Should be called after all the brains have been added to the game.
+     *
+     * @see #addPlayer(model.brains.AbstractBrain)
+     */
     public void startGame () {
         this.currentPlayer = players.peek ();
         this.hasStarted = true;
     }
 
-    public AbstractPersonality getCurrentPersonality () {
-        return this.currentPlayer.getPersonality();
+    /**
+     * Gets the current player personality whose turn it is.
+     *
+     * @return The player who has the current turn.
+     */
+    public AbstractBrain getCurrentBrain () {
+        return this.currentPlayer.getBrain ();
     }
 
-    public PlayerInfo getCurrentPlayerInfo () {
-        return new PlayerInfo (this.currentPlayer);
-    }
-
-    public PlayerInfo getPlayerInfo (AbstractPersonality personality) {
+    /**
+     * Returns a new PlayerInfo for a given player at this current point in time.
+     *
+     * @param brain The player you would like to generate a PlayerInfo for.
+     * @return The PlayerInfo of the given player, representing their current state.
+     */
+    public PlayerInfo getPlayerInfo (AbstractBrain brain) {
         for (GamePlayer player : players) {
-            if (player.getPersonality().equals(personality)) {
-                return new PlayerInfo(player);
+            if (player.getBrain ().equals (brain)) {
+                return new PlayerInfo (player);
             }
         }
 
         return null;
     }
 
+    /**
+     * Ends the current player's turn.
+     */
     public void endTurn () {
         players.add (players.remove ());
         this.currentPlayer = players.peek ();
     }
 
+    /**
+     * Checks if a given move is valid - that is, if it conforms with both the games rules, and if the inputs are
+     * sane.
+     *
+     * @param move The move you wish to check is valid or not.
+     * @return True if the move is valid and can be played, false otherwise.
+     */
     public boolean moveIsValid (Move move) {
         boolean valid = false;
 
             return false;
         }
 
-        if (move.getType() == MoveType.PLACE_WALL) {
+        if (move.getType () == MoveType.PLACE_WALL) {
             // haven't exceeded wall limit
-            if (this.currentPlayer.getWallCount() < MAX_PLAYER_WALL_COUNT) {
+            if (this.currentPlayer.getWallCount () < MAX_PLAYER_WALL_COUNT) {
                 Board testBoard = new Board (this.board);
 
-                if (testBoard.placeWall (move.getCoordinate(), move.getWallDirection())) {
+                if (testBoard.placeWall (move.getCoordinate (), move.getWallDirection ())) {
                     boolean hadOpenGoal = true;
-                    // make sure that a path is still left open to goal line for ALL players
+                    // make sure that a path is still left open to goal line for ALL brains
                     for (GamePlayer p : players) {
                         if (!this.hasPathToBaseline (testBoard, p.getCurrentCoordinate (), p.getFinishBaseline ())) {
                             hadOpenGoal = false;
                 }
             }
         } else {
-            LinkedList<BoardCoordinate> possible = this.getPossibleCoordinates();
-            valid = possible.contains (move.getCoordinate());
+            LinkedList<BoardCoordinate> possible = this.getPossibleCoordinates ();
+            valid = possible.contains (move.getCoordinate ());
         }
 
         return valid;
     }
 
+    /**
+     * Makes a move. Assumes that the move is valid.
+     * You **MUST** check this yourself - Game does not do it for you.
+     *
+     * @param move The valid move you wish to make.
+     */
     public void makeMove (Move move) {
-        if (move.getType() == MoveType.PLACE_WALL) {
-            this.board.placeWall(move.getCoordinate(), move.getWallDirection());
-            this.currentPlayer.incrementWallCount();
+        if (move.getType () == MoveType.PLACE_WALL) {
+            this.board.placeWall (move.getCoordinate (), move.getWallDirection ());
+            this.currentPlayer.incrementWallCount ();
         } else {
-            Tile destinationTile = this.board.getTile (move.getCoordinate());
-            Tile currentTile = this.getPlayerTile();
+            Tile destinationTile = this.board.getTile (move.getCoordinate ());
+            Tile currentTile = this.getPlayerTile ();
 
-            currentTile.setPlayer(null);
-            destinationTile.setPlayer(this.currentPlayer);
-            this.currentPlayer.setCurrentCoordinate (destinationTile.getCoordinate());
+            currentTile.setPlayer (null);
+            destinationTile.setPlayer (this.currentPlayer);
+            this.currentPlayer.setCurrentCoordinate (destinationTile.getCoordinate ());
         }
     }
 
+    /**
+     * Checks if there's a path to the current player's baseline. Used to determine if a player hasn't been blocked in.
+     *
+     * @param board             Board to check against
+     * @param currentCoordinate Location of the current player
+     * @param finishBaseline    Location the current player's goal.
+     * @return True if there is still a path, false otherwise
+     */
     private boolean hasPathToBaseline (Board board, BoardCoordinate currentCoordinate, Baseline finishBaseline) {
-        ArrayList<Tile> seen = new ArrayList<Tile>(); // using hashset makes no difference?
-        Deque<Tile> queue = new LinkedList<Tile>();
+        ArrayList<Tile> seen = new ArrayList<Tile> (); // using hashset makes no difference?
+        Deque<Tile> queue = new LinkedList<Tile> ();
 
-        queue.add(board.getTile(currentCoordinate));
+        queue.add (board.getTile (currentCoordinate));
 
-        while (!queue.isEmpty()) {
-            Tile current = queue.removeLast();
-            seen.add(current);
+        while (!queue.isEmpty ()) {
+            Tile current = queue.removeLast ();
+            seen.add (current);
 
-            if (finishBaseline.hasCoordinateOnBaseline(current.getCoordinate())) {
+            if (finishBaseline.hasCoordinateOnBaseline (current.getCoordinate ())) {
                 return true;
             }
 
-            for (Direction d : Direction.values()) {
-                Tile other = current.getAdjacentLink(d);
+            for (Direction d : Direction.values ()) {
+                Tile other = current.getAdjacentLink (d);
 
-                if (other != null && !seen.contains(other)) {
-                    queue.addLast(other);
+                if (other != null && !seen.contains (other)) {
+                    queue.addLast (other);
                 }
             }
         }
         return false;
     }
 
+    /**
+     * Gets the tile that the current player is standing on.
+     *
+     * @return The tile that the current player is on.
+     */
     private Tile getPlayerTile () {
-        return this.board.getTile (this.currentPlayer.getCurrentCoordinate());
+        return this.board.getTile (this.currentPlayer.getCurrentCoordinate ());
     }
 
+    /**
+     * Returns all the possible locations the current player can move.
+     *
+     * @return A LinkedList of BoardCoordinates the current player can move to.
+     */
     public LinkedList<BoardCoordinate> getPossibleCoordinates () {
-        LinkedList<BoardCoordinate> possible = new LinkedList<BoardCoordinate>();
-        return getPossibleCoordinates(currentPlayer.getCurrentCoordinate());
+        return getPossibleCoordinates (currentPlayer.getCurrentCoordinate ());
     }
 
-    public LinkedList<BoardCoordinate> getPossibleCoordinates (GamePlayer player) {
-        return getPossibleCoordinates(player.getCurrentCoordinate());
-    }
-
+    /**
+     * Returns a list of all valid movements off a given coordinate.
+     * <p/>
+     * All BoardCoordinates returned by this function should be valid move locations.
+     *
+     * @param boardCoordinate the coordinate on the board you want to move from
+     * @return a list of valid coordinates that can be moved to from the given coordinate.
+     */
     public LinkedList<BoardCoordinate> getPossibleCoordinates (BoardCoordinate boardCoordinate) {
-        LinkedList<BoardCoordinate> possible = new LinkedList<BoardCoordinate>();
+        LinkedList<BoardCoordinate> possible = new LinkedList<BoardCoordinate> ();
         Tile currentTile = this.board.getTile (boardCoordinate);
-        for (Direction d : Direction.values()) {
-            Tile destinationTile = currentTile.getAdjacentLink(d);
+        for (Direction d : Direction.values ()) {
+            Tile destinationTile = currentTile.getAdjacentLink (d);
 
             // if we couldn't find an unbroken link to the tile (ie no wall) then we obviously can't move there
             if (destinationTile == null) {
             }
 
             // check if there's another player where they want to move
-            if (destinationTile.getPlayer() != null) {
+            if (destinationTile.getPlayer () != null) {
                 // see if there's a fence behind that player
-                Tile behind = destinationTile.getAdjacentLink(d);
+                Tile behind = destinationTile.getAdjacentLink (d);
 
                 // make sure we're not trying to move off the board
-                // TODO: write a test for this guy
-                if (behind == null && destinationTile.getCoordinate().isEdge()) {
+                if (behind == null && destinationTile.getCoordinate ().isEdge ()) {
                     continue;
                 }
 
                 if (behind == null) {
                     // can place pawn either to left or right of other player
-                    Direction[] perpendicular = Direction.getPerpendicular(d);
+                    Direction[] perpendicular = Direction.getPerpendicular (d);
                     for (Direction other : perpendicular) {
                         // if there's a tile to the left/right of the one we're going for
-                        Tile otherTile = destinationTile.getAdjacentLink(other);
+                        Tile otherTile = destinationTile.getAdjacentLink (other);
                         if (otherTile != null) {
-                            possible.add(otherTile.getCoordinate());
+                            possible.add (otherTile.getCoordinate ());
                         }
                     }
                 } else {
                     // no fence, can move behind
-                    possible.add(behind.getCoordinate());
+                    possible.add (behind.getCoordinate ());
                 }
             } else {
                 // no player on this tile, go nuts!
-                possible.add (destinationTile.getCoordinate());
+                possible.add (destinationTile.getCoordinate ());
             }
         }
 
         return possible;
     }
 
-    public Board getBoard() {
+    /**
+     * The current Board that is being used in this game.
+     *
+     * @return the current board being used in this game.
+     */
+    public Board getBoard () {
         return board;
     }
 
-    public boolean hasWinner() {
-        return getWinner() != null;
+    /**
+     * Checks if we have a winner.
+     *
+     * @return True if there is a winner, false otherwise.
+     */
+    public boolean hasWinner () {
+        return getWinner () != null;
     }
 
-    public AbstractPersonality getWinner() {
+    /**
+     * Returns the Player who has one the game.
+     *
+     * @return A valid player if there is a winner, null otherwise.
+     */
+    public AbstractBrain getWinner () {
         if (this.winner == null) {
             // look for one if it's still undecided
             for (GamePlayer p : this.players) {
-                if (p.getFinishBaseline().hasCoordinateOnBaseline(p.getCurrentCoordinate())) {
-                    this.winner = p.getPersonality();
+                if (p.getFinishBaseline ().hasCoordinateOnBaseline (p.getCurrentCoordinate ())) {
+                    this.winner = p.getBrain ();
                     break;
                 }
             }
 
         return this.winner;
     }
+
+    /**
+     * Returns a LinkedList of PlayerInfos representing the current players in this game.
+     *
+     * @return List of PlayerInfos representing the players in the game.
+     */
+    public LinkedList<PlayerInfo> getPlayers () {
+        // TODO: memoize this if it gets called lots?
+        LinkedList<PlayerInfo> result = new LinkedList<PlayerInfo> ();
+        for (GamePlayer player : players) {
+            result.add (new PlayerInfo (player));
+        }
+
+        return result;
+    }
+
+    /**
+     * Returns a PlayerInfo about the current player.
+     *
+     * @return PlayerInfo about the current player
+     */
+    public PlayerInfo getCurrentPlayerInfo () {
+        return new PlayerInfo (currentPlayer);
+    }
 }

File src/model/GameException.java

-package model;
-
-public class GameException extends Exception {
-    public GameException(String s) {
-        super(s);
-    }
-}

File src/model/GameManager.java

 package model;
 
-import model.players.AbstractPersonality;
+import model.brains.AbstractBrain;
 
+import java.io.*;
 import java.util.LinkedList;
 import java.util.List;
 
+/**
+ * Manages Game states, and provides the ability to undo and redo moves.
+ * <p/>
+ * GameManager is a singleton class.
+ */
 public class GameManager {
     private List<Game> games;
     private int currentGameIdx = 0;
     private Game currentGame;
 
     public GameManager () {
-        games = new LinkedList<Game>();
-        currentGame = new Game();
+        games = new LinkedList<Game> ();
+        currentGame = new Game ();
     }
 
+    /**
+     * Undoes the last move.
+     *
+     * @return True is the undo was successful, false otherwise (that is, no moves to undo).
+     */
     public boolean undo () {
-        if (currentGameIdx > 0 && currentGameIdx <= games.size()) {
+        if (currentGameIdx > 0 && currentGameIdx <= games.size ()) {
             currentGameIdx--;
             currentGame = games.get (currentGameIdx);
             return true;
         }
     }
 
+    /**
+     * Redoes the last move.
+     *
+     * @return True if the redo was successful, false otherwise (that is, no moves to redo).
+     */
     public boolean redo () {
-        if (currentGameIdx >= 0 && currentGameIdx <= games.size() - 1) {
+        if (currentGameIdx >= 0 && currentGameIdx <= games.size () - 1) {
             currentGameIdx++;
             currentGame = games.get (currentGameIdx - 1);
             return true;
         }
     }
 
-    public void save () {
-        // TODO
+    /*public void save () {
     }
 
     public void load () {
-        // TODO
-    }
+    }*/
 
+    /**
+     * Makes a move. Stores the current state so that undos and redos can be done, then passes it on to the current
+     * internal Game instance.
+     *
+     * @param move The move to make.
+     */
     public void makeMove (Move move) {
         // only make Human moves un-doable
-        if (currentGame.getCurrentPersonality().getType() != "ai") {
+        if (!currentGame.getCurrentBrain ().getType ().equals ("ai")) {
             // if we're not on the end, DESTROY THE FUTURE
-            if (currentGameIdx <= games.size() - 1) {
-                games = games.subList(0, currentGameIdx);
+            if (currentGameIdx <= games.size () - 1) {
+                games = games.subList (0, currentGameIdx);
             }
 
             // clone the game
-            games.add(currentGame);
+            games.add (currentGame);
 
-            Game copy = new Game(currentGame);
-            copy.makeMove(move);
-            this.currentGame = copy;
+            Game copy = new Game (currentGame);
+            copy.makeMove (move);
+            currentGame = copy;
 
-            currentGameIdx ++;
+            currentGameIdx++;
+        } else {
+            currentGame.makeMove (move);
         }
     }
 
+    /**
+     * Returns the current instance of the GameManager. GameManager is a singleton.
+     * <p/>
+     * This function should be used instead of making your own Games directly.
+     *
+     * @return the current GameManager instance.
+     */
     public static GameManager getInstance () {
         if (instance == null) {
-            instance = new GameManager();
+            instance = new GameManager ();
         }
 
         return instance;
     }
 
+    /**
+     * Gets the current underlying Game instance.
+     *
+     * @return The current Game. Moves should NOT be done against this Game.
+     */
     public Game getCurrentGame () {
         return this.currentGame;
     }
 
-    public void startGame() {
-        this.currentGame.startGame();
+    /**
+     * Starts a new game.
+     */
+    public void startGame () {
+        this.currentGame.startGame ();
     }
 
     /**
      * Asks all the brains in the game for their moves, until somebody wins the game.
+     * <p/>
+     * If one "player" returns null or an invalid move, then gameplay is stopped, and no winner is returned.
      *
-     * If one brain returns null or an invalid move, then gameplay is stopped, and no winner is returned.
-     * @return The winner if game was played to completion, null if a brain stopped/returned a bad move.
+     * @return The winner if game was played to completion, null if a "player" stopped/returned a bad move.
      */
-    public AbstractPersonality playGame() {
+    public AbstractBrain playGame () {
         while (!currentGame.hasWinner ()) {
-            Move m = currentGame.getCurrentPersonality().getMove();
+            Move m = currentGame.getCurrentBrain ().getMove ();
 
             if (m == null || !currentGame.moveIsValid (m)) {
                 return null;
             this.currentGame.endTurn ();
         }
 
-        return currentGame.getWinner();
+        return currentGame.getWinner ();
     }
 
-    public AbstractPersonality getCurrentPersonality () {
-        return currentGame.getCurrentPersonality();
+    /**
+     * Returns the current player personality who enjoys the current turn.
+     *
+     * @return Current personality associated with the current turn.
+     */
+    public AbstractBrain getCurrentBrain () {
+        return currentGame.getCurrentBrain ();
+    }
+
+    public void save (String filename) throws IOException {
+        FileOutputStream fileOut = new FileOutputStream (filename);
+        ObjectOutputStream out = new ObjectOutputStream (fileOut);
+
+        out.writeObject (currentGame);
+
+        out.close ();
+        fileOut.close ();
+    }
+
+    public void load (String filename) throws IOException {
+        Game restored;
+
+        FileInputStream fileIn = new FileInputStream (filename);
+        ObjectInputStream in = new ObjectInputStream (fileIn);
+
+        try {
+            restored = (Game) in.readObject ();
+
+            this.games.clear ();
+            this.currentGame = restored;
+        } catch (ClassNotFoundException ex) {
+
+        } finally {
+            in.close ();
+            fileIn.close ();
+        }
     }
 }

File src/model/GamePlayer.java

 package model;
 
-import model.players.AbstractPersonality;
+import model.brains.AbstractBrain;
 
-public class GamePlayer {
+import java.io.Serializable;
+
+/**
+ * This class encapsulates the information required by the Game to keep track of brains. It is not coupled to a
+ * specific instance of the Game class.
+ * <p/>
+ * Generally, most classes will only (and should only) deal with a PlayerInfo based off this class.
+ */
+public class GamePlayer implements Serializable {
     private int wallCount;
 
     private BoardCoordinate currentCoordinate;
     private final Baseline startBaseline;
     private final Baseline finishBaseline;
 
-    private AbstractPersonality personality;
+    private AbstractBrain brain;
 
-    public GamePlayer (AbstractPersonality p) {
-        this.startBaseline = new Baseline (p.getDirection());
-        this.finishBaseline = new Baseline (Direction.getInverse(p.getDirection()));
+    public GamePlayer (AbstractBrain p) {
+        this.startBaseline = new Baseline (p.getDirection ());
+        this.finishBaseline = new Baseline (Direction.getInverse (p.getDirection ()));
 
         this.currentCoordinate = this.startBaseline.getCenterCoordinate ();
-        this.personality = p;
+        this.brain = p;
     }
 
     public GamePlayer (GamePlayer p) {
-        // FIXME: fingers crossed this works? otherwise need to clone
         this.startBaseline = p.startBaseline;
         this.finishBaseline = p.finishBaseline;
         this.currentCoordinate = p.currentCoordinate;
-        this.personality = p.personality;
+        this.brain = p.brain;
     }
 
-    public int getWallCount() {
+    /**
+     * Returns the number of walls a player has built so far.
+     *
+     * @return the number of walls a player has built
+     */
+    public int getWallCount () {
         return wallCount;
     }
 
-    public BoardCoordinate getCurrentCoordinate() {
+    /**
+     * Returns the current coordinate the player is on.
+     *
+     * @return the current coordinate the player is on.
+     */
+    public BoardCoordinate getCurrentCoordinate () {
         return currentCoordinate;
     }
 
-    public Baseline getFinishBaseline() {
+    /**
+     * Returns the baseline the player is trying to reach to win the game.
+     *
+     * @return the baseline the player wins on
+     */
+    public Baseline getFinishBaseline () {
         return finishBaseline;
     }
 
+    /**
+     * Increments the player's wall count.
+     * Does not check to see if the player has exceeded their wall allocation - that is the job of Game.
+     */
     public void incrementWallCount () {
         this.wallCount++;
     }
 
-    public void setCurrentCoordinate(BoardCoordinate currentCoordinate) {
+    /**
+     * Sets the player to be at a new current coordinate.
+     * <p/>
+     * Note that existing tiles are not notified if the player's position has changed, they must do this manually.
+     * This is done by the Game class.
+     *
+     * @param currentCoordinate new coordinate the player should be on
+     */
+    public void setCurrentCoordinate (BoardCoordinate currentCoordinate) {
         this.currentCoordinate = currentCoordinate;
     }
 
-    public AbstractPersonality getPersonality() {
-        return personality;
+    /**
+     * Gets the brain associated with this player.
+     *
+     * @return the brain associated with this player.
+     */
+    public AbstractBrain getBrain () {
+        return brain;
     }
 
     public boolean equals (Object other) {
         if (other == this) return true;
-        if (! (other instanceof GamePlayer)) return false;
+        if (!(other instanceof GamePlayer)) return false;
 
-        GamePlayer that = (GamePlayer)other;
-        return (this.currentCoordinate.equals(that.currentCoordinate));
+        GamePlayer that = (GamePlayer) other;
+        return (this.currentCoordinate.equals (that.currentCoordinate));
     }
 }

File src/model/Move.java

 package model;
 
+/**
+ * A move that can be made in a game of Quoridor.
+ */
 public class Move {
     private final MoveType type;
     private final BoardCoordinate coordinate;
         this.coordinate = coordinate;
     }
 
+    /**
+     * Create a Move. This form of the constructor is usually only used for wall builds.
+     * <p/>
+     * Note that that when building a wall, the coordinate refers to the bottom left corner of a block of four tiles.
+     *
+     * @param type          what kind of move should be made
+     * @param coordinate    coordinate to move to/start building at.
+     * @param wallDirection orientation to build the wall
+     */
     public Move (MoveType type, BoardCoordinate coordinate, WallDirection wallDirection) {
         this (type, coordinate);
         this.wallDirection = wallDirection;
     }
 
-    public BoardCoordinate getCoordinate() {
+    /**
+     * Gets the coordinate that this move refers to.
+     * <p/>
+     * Note that that when building a wall, the coordinate refers to the bottom left corner of a block of four tiles.
+     *
+     * @return this move's coordinate
+     */
+    public BoardCoordinate getCoordinate () {
         return coordinate;
     }
 
-    public MoveType getType() {
+    /**
+     * Gets the type of move.
+     *
+     * @return the MoveType representing the type of move
+     */
+    public MoveType getType () {
         return type;
     }
 
-    public WallDirection getWallDirection() {
+    /**
+     * Gets the direction a wall is intended to be built in.
+     *
+     * @return Direction the wall should be built in if it is of BUILD_WALL type, null otherwise.
+     */
+    public WallDirection getWallDirection () {
         return wallDirection;
     }
 
+    /**
+     * Translates a string move (in 2 or 3 character format) to a new Move object.
+     *
+     * @param move the string-based move you wish to convert
+     * @return a new Move representing the same string
+     * @throws IllegalArgumentException if the coordinate (first 2 characters) are out of the board bounds
+     */
     public static Move translate (String move) {
-        if (move.length() == 3) {
+        if (move.length () == 3) {
             // want to place a fence
             WallDirection placement;
-            if (move.substring(2).equals("h")) {
+            if (move.substring (2).equals ("h")) {
                 placement = WallDirection.HORIZONTAL;
             } else {
                 placement = WallDirection.VERTICAL;
             }
 
-            BoardCoordinate location = new BoardCoordinate(move.substring(0, 2));
+            BoardCoordinate location = new BoardCoordinate (move.substring (0, 2));
             return new Move (MoveType.PLACE_WALL, location, placement);
         } else {
-            return new Move (MoveType.MOVE_PLAYER, new BoardCoordinate(move));
+            return new Move (MoveType.MOVE_PLAYER, new BoardCoordinate (move));
+        }
+    }
+
+    public String toString () {
+        if (type == MoveType.MOVE_PLAYER) {
+            return "Move player to " + coordinate;
+        } else {
+            return "Place wall at " + coordinate + " " + (wallDirection == WallDirection.HORIZONTAL ?
+                    "horizontally" : "vertically");
         }
     }
 }

File src/model/MoveType.java

 package model;
 
+/**
+ * Represents the different kinds of moves a player can make in the game.
+ */
 public enum MoveType {
     PLACE_WALL,
     MOVE_PLAYER

File src/model/PlayerInfo.java

 package model;
 
+import model.brains.AbstractBrain;
+
+/**
+ * PlayerInfo contains information about a Player and their game state at a given point in time.
+ * <p/>
+ * It is an immutable class. You should not rely on PlayerInfo to be up to date after a move has been made, in fact,
+ * it has most likely changed inside the Game and you should fetch another one.
+ */
 public final class PlayerInfo {
     private final BoardCoordinate currentCoordinate;
     private final Baseline finishBaseline;
     private final int wallCount;
+    private AbstractBrain brain;
 
+    /**
+     * Create a new PlayerInfo given a (somewhat-internal) GamePlayer.
+     *
+     * @param player the player to create the PlayerInfo from.
+     */
     public PlayerInfo (GamePlayer player) {
-        this.currentCoordinate = player.getCurrentCoordinate();
-        this.finishBaseline = player.getFinishBaseline();
-        this.wallCount = player.getWallCount();
+        this.currentCoordinate = player.getCurrentCoordinate ();
+        this.finishBaseline = player.getFinishBaseline ();
+        this.wallCount = player.getWallCount ();
+        this.brain = player.getBrain ();
     }
 
-    public BoardCoordinate getCurrentCoordinate() {
+    /**
+     * Returns the baseline that the player will try to finish on to win.
+     *
+     * @return Player's finish baseline.
+     */
+    public Baseline getFinishBaseline () {
+        return finishBaseline;
+    }
+
+    /**
+     * The number of walls already built by this player
+     *
+     * @return The number of walls build by this player so far
+     */
+    public int getWallCount () {
+        return wallCount;
+    }
+
+    /**
+     * Returns the current coordinate that this player is sitting on.
+     *
+     * @return BoardCoordinate of this player.
+     */
+    public BoardCoordinate getCurrentCoordinate () {
         return currentCoordinate;
     }
 
-    public Baseline getFinishBaseline() {
-        return finishBaseline;
+    public AbstractBrain getBrain () {
+        return brain;
     }
 
-    public int getWallCount() {
-        return wallCount;
+    public int getDistanceFromBaseline () {
+        // FIXME: change HEIGHT to DIMENSION
+        return (Board.HEIGHT - distanceToBaseline ());
+    }
+
+    public int distanceToBaseline () {
+        return finishBaseline.getDistance (currentCoordinate, brain.getDirection ());
     }
 }

File src/model/Tile.java

 package model;
 
-public class Tile {
+import java.io.Serializable;
+
+/**
+ * Represents a Tile on the Board.
+ */
+public class Tile implements Serializable {
     private Tile links[] = new Tile[4];
     private GamePlayer player;
     private final BoardCoordinate coordinate;
 
+    /**
+     * Create a new Tile at a given coordinate.
+     *
+     * @param coordinate Coordinate that this tile is located at.
+     */
     public Tile (BoardCoordinate coordinate) {
         this.coordinate = coordinate;
     }
 
-    public GamePlayer getPlayer() {
+    /**
+     * Returns the player that is currently on this tile
+     *
+     * @return a valid #GamePlayer if there s a player on this tile, null otherwise.
+     */
+    public GamePlayer getPlayer () {
         return player;
     }
 
-    public void setPlayer(GamePlayer player) {
+    /**
+     * Sets the current player on this tile.
+     *
+     * @param player The tile that will now be occupying this tile.
+     */
+    public void setPlayer (GamePlayer player) {
         this.player = player;
     }
 
-    public Tile getAdjacentLink(Direction d) {
-        return links[d.ordinal()];
+    /**
+     * Gets an adjacent tile in a given direction next to this tile, if and only if there is no wall between them,
+     * and as long as there is a tile in that position (eg you don't ask for the adjacent tile off the edge of the
+     * board).
+     *
+     * @param d The direction you wish to seek the adjacent tile.
+     * @return The tile adjacent, assuming there's no wall in between and it's not off the edge of the board.
+     */
+    public Tile getAdjacentLink (Direction d) {
+        return links[d.ordinal ()];
     }
 
+    /**
+     * Breaks a link between two tiles. This is most commonly used when a wall is built between two tiles.
+     * <p/>
+     * Note that this breakage is done MUTUALLY. Both this Tile and Tile in the given direction (if it can
+     * be reached from this tile) will have their links broken.
+     *
+     * @param d The direction you wish to break the tiles on.
+     */
     public void breakAdjacent (Direction d) {
-        Tile adjacent = links[d.ordinal()];
+        Tile adjacent = links[d.ordinal ()];
         if (adjacent != null) {
             // make sure we're broken the other way too
-            links[d.ordinal()] = null;
-            adjacent.breakAdjacent(Direction.getInverse(d));
+            links[d.ordinal ()] = null;
+            adjacent.breakAdjacent (Direction.getInverse (d));
         }
     }
 
+    /**
+     * Sets the Tile's link to another Tile in a given direction. This link is one-way/
+     *
+     * @param d    The direction you wish to crete the one-way link.
+     * @param tile The tile you wish to set this link to.
+     */
     public void setTile (Direction d, Tile tile) {
-        links[d.ordinal()] = tile;
+        links[d.ordinal ()] = tile;
     }
 
 
-    public BoardCoordinate getCoordinate() {
+    /**
+     * The coordinate representing this Tile on the Board.
+     *
+     * @return where this tile is located on the board.
+     */
+    public BoardCoordinate getCoordinate () {
         return coordinate;
     }
 }

File src/model/WallDirection.java

 package model;
 
+/**
+ * Describes the possible directions a fence/wall can be build in Quoridor.
+ */
 public enum WallDirection {
     HORIZONTAL,
     VERTICAL

File src/model/brains/AbstractBrain.java

+package model.brains;
+
+import model.*;
+
+import java.io.Serializable;
+
+/**
+ * The AbstractBrain. Represents the Brains of a player - it knows who it's called and what it looks like (player name
+ * and icon), and can find out where it is/how it's going.
+ * <p/>
+ * All it needs now is the brainpower to decide what to do! Implement getMove and give it all the smarts you need! (or
+ * lack thereof).
+ * <p/>
+ * Brains should avoid returning null from getMove! (unless you want gameplay to pause/stop).
+ */
+public abstract class AbstractBrain implements Serializable {
+    protected String name;
+    protected Direction direction;
+    protected String icon;
+
+    /**
+     * Creates a new AbstractBrain.
+     *
+     * @param name      the player name
+     * @param icon      the player's icon
+     * @param direction the direction the player is starting in
+     */
+    public AbstractBrain (String name, String icon, Direction direction) {
+        this.name = name;
+        this.direction = direction;
+        this.icon = icon;
+    }
+
+    /**
+     * Returns the player's name
+     *
+     * @return the player's name
+     */
+    public String getName () {
+        return name;
+    }
+
+    /**
+     * Returns the player's starting direction
+     *
+     * @return player's starting direction
+     */
+    public Direction getDirection () {
+        return direction;
+    }
+
+    /**
+     * Returns the player's icon.
+     * <p/>
+     * This is usually a single character string uniquely identifying the player on the board.
+     *
+     * @return the player's icon.
+     */
+    public String getIcon () {
+        return this.icon;
+    }
+
+    /**
+     * Calculates the next VALID move for the player. Shouldn't return null unless expecting gameplay to pause.
+     *
+     * @return the next, valid move the player would like to make
+     */
+    public abstract Move getMove ();
+
+    /**
+     * Gets the Brain type - AI should usually represent themselves as 'ai', other classes may do as they wish.
+     *
+     * @return A string representing the class/brain type.
+     */
+    public abstract String getType ();
+
+    /**
+     * Shortcut function for fetching the current Game that is being played.
+     *
+     * @return current Game
+     */
+    public Game getCurrentGame () {
+        return GameManager.getInstance ().getCurrentGame ();
+    }
+
+    /**
+     * Shortcut function for fetching this player's PlayerInfo. Use this to retrive information about where
+     * the player currently is in the current game.
+     *
+     * @return the player's current PlayerInfo.
+     */
+    public PlayerInfo getPlayerInfo () {
+        return getCurrentGame ().getPlayerInfo (this);
+    }
+}

File src/model/brains/MinMaxBrain.java

+package model.brains;
+
+import model.*;
+
+/**
+ * An AI brain that uses the negamax algorithm (based on an alpha-beta pruned minimax search) to play against
+ * competitors.
+ */
+public class MinMaxBrain extends AbstractBrain {
+    private final int LOOK_AHEAD = 4;
+
+    public MinMaxBrain (String name, String icon, Direction direction) {
+        super (name, icon, direction);
+    }
+
+    @Override
+    public Move getMove () {
+        Move bestMove = null;
+        double bestScore = Double.NEGATIVE_INFINITY;
+
+        Game g = getCurrentGame ();
+        for (BoardCoordinate coordinate : g.getPossibleCoordinates ()) {
+            Game child = new Game (g);
+
+            Move mockMove = new Move (MoveType.MOVE_PLAYER, coordinate);
+            child.makeMove (mockMove);
+
+            double score = negamax (child, LOOK_AHEAD, Double.NEGATIVE_INFINITY, Double.POSITIVE_INFINITY, 1);
+
+            if (score > bestScore) {
+                bestMove = mockMove;
+                bestScore = score;
+            }
+        }
+
+        return bestMove;
+    }
+
+    private double negamax (Game g, int depth, double alpha, double beta, int color) {
+        if (g.hasWinner () || depth == 0) {
+            return color * evaluateGameState (g);
+        } else {
+            for (BoardCoordinate coordinate : g.getPossibleCoordinates ()) {
+                Game child = new Game (g);
+                child.makeMove (new Move (MoveType.MOVE_PLAYER, coordinate));
+                child.endTurn ();
+
+                double val = -1 * negamax (child, depth - 1, -1 * beta, -1 * alpha, -1 * color);
+                if (val >= beta) {
+                    return val;
+                }
+
+                if (val >= alpha) {
+                    alpha = val;
+                }
+            }
+
+            return alpha;
+        }
+    }
+
+    private double evaluateGameState (Game g) {
+        PlayerInfo info = g.getCurrentPlayerInfo ();
+
+        // our distance away (bigger is better, +ve function)
+        double answer = info.getDistanceFromBaseline ();
+
+        // now average the other player's distances away
+        // and make then -ve function (smaller is better)
+        double otherAvg = 0.0;
+        int players = 0;
+        for (PlayerInfo player : g.getPlayers ()) {
+            // find enemy players
+            if (!player.getBrain ().equals (g.getCurrentBrain ())) {
+                //otherAvg += player.
+                otherAvg += player.distanceToBaseline ();
+            }
+
+            players++;
+        }
+
+        otherAvg = (otherAvg / players) * -1;
+        answer = answer + otherAvg;
+
+        return answer;
+    }
+
+    @Override
+    public String getType () {
+        return "ai";
+    }
+}

File src/model/brains/NullBrain.java

+package model.brains;
+
+import model.Direction;
+import model.Move;
+
+/**
+ * Null Brain does nothing.
+ */
+public class NullBrain extends AbstractBrain {
+    public NullBrain (String name, String icon, Direction direction) {
+        super (name, icon, direction);
+    }
+
+    @Override
+    public Move getMove () {
+        return null;
+    }
+
+    public String getType () {
+        return "null";
+    }
+}

File src/model/players/AIPersonality.java

-package model.players;
-
-import model.*;
-
-public class AIPersonality extends AbstractPersonality {
-
-    private int difficulty = 2;
-
-    public AIPersonality(String name, String icon, Direction direction) {
-        super(name, icon, direction);
-    }
-
-    @Override
-    public Move getMove() {
-        return new Move (MoveType.MOVE_PLAYER, initializeBuildTree (getCurrentGame()));
-    }
-
-    private BoardCoordinate initializeBuildTree (Game game) {
-        TreeNode root = new TreeNode(game.getCurrentPlayerInfo().getCurrentCoordinate());
-        treeBuilder(difficulty, root, game);   //TODO set difficulty level
-        minMax(root, difficulty);
-        return root.getMaxChild().boardCoordinate;
-    }
-
-    //assumes root is MAX player
-    private void treeBuilder (int level, TreeNode parent, Game game){
-        if(level == -1){
-            return;
-        } else {
-            for (BoardCoordinate b : game.getPossibleCoordinates(parent.boardCoordinate)){
-                TreeNode t = new TreeNode(b, parent);
-                if(level==0){
-                    t.heuristic = heuristic(b);
-                    parent.children.add(t);
-                } else {
-
-                    parent.children.add(t);
-                }
-                treeBuilder(level - 1, t, game);
-            }
-        }
-    }
-
-    private int heuristic (BoardCoordinate possibility) {
-        int score = getPlayerInfo().getFinishBaseline().getDistance (possibility);
-        return score;
-    }
-
-    private void minMax (TreeNode root, int level){
-        if(level == 0){
-            return;
-        } else {
-            for (TreeNode t : root.children){
-                minMax(t, level - 1);
-                if(level%2==0){
-                    if(t.getMaxChild()==null){
-                        //System.out.println("ITS NULL!");
-                    }
-                    t.heuristic = t.getMaxChild().heuristic;
-                } else {
-                    t.heuristic = t.getMinChild().heuristic;
-                }
-            }
-        }
-    }
-
-    public String getType (){
-        return "ai";
-    }
-}

File src/model/players/AbstractPersonality.java

-package model.players;
-
-import model.*;
-
-public abstract class AbstractPersonality {
-    protected String name;
-    protected Direction direction;
-    protected String icon;
-
-    public AbstractPersonality(String name, String icon, Direction direction) {
-        this.name = name;
-        this.direction = direction;
-        this.icon = icon;
-    }
-
-    public String getName() {
-        return name;
-    }
-
-    public Direction getDirection() {
-        return direction;
-    }
-
-    public String getIcon() {
-        return this.icon;
-    }
-
-    public abstract Move getMove ();
-
-    public abstract String getType();
-
-    public Game getCurrentGame (){
-        return GameManager.getInstance().getCurrentGame();
-    }
-
-    public PlayerInfo getPlayerInfo () {
-        return getCurrentGame().getPlayerInfo (this);
-    }
-}

File src/model/players/NullPersonality.java

-package model.players;
-
-import model.Direction;
-import model.Move;
-
-public class NullPersonality extends AbstractPersonality {
-    public NullPersonality(String name, String icon, Direction direction) {
-        super (name, icon, direction);
-    }
-
-    @Override
-    public Move getMove() {
-        return null;
-    }
-
-    public String getType () {
-        return "null";
-    }
-}

File src/model/players/TreeNode.java

-package model.players;
-
-import model.BoardCoordinate;
-
-import javax.sound.midi.SysexMessage;
-import java.util.LinkedList;
-
-public class TreeNode {
-
-    public TreeNode parent;
-    public LinkedList<TreeNode> children;
-    public int heuristic;
-    public BoardCoordinate boardCoordinate;
-
-    public TreeNode (BoardCoordinate b) {
-        this(b, null);
-    }
-
-    public TreeNode (BoardCoordinate b, TreeNode parent){
-        this.parent = parent;
-        this.boardCoordinate = b;
-        children = new LinkedList<TreeNode>();
-    }
-
-    public TreeNode getMinChild () {
-    TreeNode r = null;
-        if(!children.isEmpty()){
-            r = children.peek();
-            for (TreeNode temp : this.children){
-                if(r.heuristic > temp.heuristic){
-                    r = temp;
-                }
-            }
-        }
-        return r;
-    }
-
-    public TreeNode getMaxChild () {
-        TreeNode r = null;
-        if(!children.isEmpty()){
-            r = children.peek();
-            for (TreeNode temp : this.children){
-                if(r.heuristic < temp.heuristic){
-                    r = temp;
-                }
-            }
-        }
-        return r;
-    }
-
-}

File src/tests/BaselineTest.java

 import model.BoardCoordinate;
 import model.Direction;
 import org.junit.Test;
+
 import static org.junit.Assert.assertTrue;
 import static org.junit.Assert.assertFalse;
 
 
     @Test
     public void testOnBaselineHorizontal () {
-        Baseline baseline = new Baseline(Direction.UP);
-        BoardCoordinate b1 = new BoardCoordinate(3, 0);
-        BoardCoordinate b2 = new BoardCoordinate(0, 0);
-        BoardCoordinate b3 = new BoardCoordinate(8, 0);
+        Baseline baseline = new Baseline (Direction.UP);
+        BoardCoordinate b1 = new BoardCoordinate (3, 0);
+        BoardCoordinate b2 = new BoardCoordinate (0, 0);
+        BoardCoordinate b3 = new BoardCoordinate (8, 0);
 
-        assertTrue (baseline.hasCoordinateOnBaseline(b1));
-        assertTrue (baseline.hasCoordinateOnBaseline(b2));
-        assertTrue (baseline.hasCoordinateOnBaseline(b3));
+        assertTrue (baseline.hasCoordinateOnBaseline (b1));
+        assertTrue (baseline.hasCoordinateOnBaseline (b2));
+        assertTrue (baseline.hasCoordinateOnBaseline (b3));
 
-        BoardCoordinate not1 = new BoardCoordinate(3, 4);
-        BoardCoordinate not2 = new BoardCoordinate(0, 5);
-        assertFalse (baseline.hasCoordinateOnBaseline(not1));
-        assertFalse (baseline.hasCoordinateOnBaseline(not2));
+        BoardCoordinate not1 = new BoardCoordinate (3, 4);
+        BoardCoordinate not2 = new BoardCoordinate (0, 5);
+        assertFalse (baseline.hasCoordinateOnBaseline (not1));
+        assertFalse (baseline.hasCoordinateOnBaseline (not2));
     }
 }

File src/tests/BoardCoordinateTest.java

 public class BoardCoordinateTest {
     @Test
     public void testNotation () {
-        BoardCoordinate result = new BoardCoordinate(4, 7);
-        assertTrue (new BoardCoordinate("e8").equals (result));
+        BoardCoordinate result = new BoardCoordinate (4, 7);
+        assertTrue (new BoardCoordinate ("e8").equals (result));
     }
 }

File src/tests/GameTest.java

-package tests;
-
-import model.*;
-import org.junit.Before;
-import org.junit.Test;
-import view.ConsoleUI;
-
-import java.util.LinkedList;
-
-
-import static org.junit.Assert.assertTrue;
-import static org.junit.Assert.assertFalse;
-
-public class GameTest {
-    private Game game;
-
-    /*@Before
-    public void setUp () throws Exception {