Skip to content
Snippets Groups Projects
Commit 2b0becd3 authored by Padinharayil Anoop's avatar Padinharayil Anoop
Browse files

Fix bugs in DotsAndBoxesGrid

parent e2a2aa46
No related branches found
No related tags found
No related merge requests found
package dotsandboxes; package dotsandboxes;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Arrays; import java.util.Arrays;
import java.util.function.Consumer; 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 { public class DotsAndBoxesGrid {
final int width; final int width;
final int height; final int height;
/** The horizontal lines in the grid. True if drawn. */
private boolean[][] horizontals; private boolean[][] horizontals;
/** The vertical lines in the grid. True if drawn. */
private boolean[][] verticals; private boolean[][] verticals;
/** Which owner (if any) claimed any given box. */
private int[][] boxOwners; private int[][] boxOwners;
/** A list of functions to notify when there is an update */
private ArrayList<Consumer<DotsAndBoxesGrid>> watchers = new ArrayList<>(); private ArrayList<Consumer<DotsAndBoxesGrid>> watchers = new ArrayList<>();
final int players; final int players;
private int player = 1; private int player = 1;
public int getPlayer() { public int getPlayer() {
return player; return player;
} }
/** Moves to the next player */
private void nextPlayer() { private void nextPlayer() {
player++; player++;
if (player > players) { if (player > players) {
...@@ -78,44 +44,30 @@ public class DotsAndBoxesGrid { ...@@ -78,44 +44,30 @@ public class DotsAndBoxesGrid {
} }
} }
/** Listens to this grid for changes */
public void addConsumer(Consumer<DotsAndBoxesGrid> consumer) { public void addConsumer(Consumer<DotsAndBoxesGrid> consumer) {
watchers.add(consumer); watchers.add(consumer);
} }
/** Returns whether a horizontal line has been drawn */
public boolean getHorizontal(int x, int y) { public boolean getHorizontal(int x, int y) {
return horizontals[x][y]; return horizontals[x][y];
} }
/** Returns whether a vertical line has been drawn */
public boolean getVertical(int x, int y) { public boolean getVertical(int x, int y) {
return verticals[x][y]; return verticals[x][y];
} }
/** Returns which player owns a box. By convention, 0 is unowned. */
public int getBoxOwner(int x, int y) { public int getBoxOwner(int x, int y) {
return boxOwners[x][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) { public boolean boxComplete(int x, int y) {
if (x >= width - 1 || x < 0 || y >= height - 1 || y < 0) { if (x >= width - 1 || x < 0 || y >= height - 1 || y < 0) {
return false; return false;
} }
// A box is complete if the north and south horizontals and the east and west verticals have all been drawn. return horizontals[x][y] && horizontals[x][y+1] && verticals[x][y] && verticals[x+1][y];
// 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) { private boolean claimBox(int x, int y, int p) {
if (boxComplete(x, y)) { if (boxComplete(x, y)) {
boxOwners[x][y] = player; boxOwners[x][y] = player;
...@@ -125,12 +77,6 @@ public class DotsAndBoxesGrid { ...@@ -125,12 +77,6 @@ public class DotsAndBoxesGrid {
} }
} }
/**
* "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) { public boolean drawHorizontal(int x, int y, int player) {
if (x >= width - 1 || x < 0) { 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)); throw new IndexOutOfBoundsException(String.format("x was %d, which is out of range. Range is 0 to %d", x, width - 1));
...@@ -139,11 +85,12 @@ public class DotsAndBoxesGrid { ...@@ -139,11 +85,12 @@ public class DotsAndBoxesGrid {
throw new IndexOutOfBoundsException(String.format("y was %d, which is out of range. Range is 0 to %d", y, height)); 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. if (horizontals[x][y]) {
throw new IllegalStateException("This line has already been drawn.");
}
this.horizontals[x][y] = true; this.horizontals[x][y] = true;
// Try to claim the north or south boxes
boolean claimN = claimBox(x, y-1, player); boolean claimN = claimBox(x, y-1, player);
boolean claimS = claimBox(x, y, player); boolean claimS = claimBox(x, y, player);
if (claimN || claimS) { if (claimN || claimS) {
...@@ -156,12 +103,6 @@ public class DotsAndBoxesGrid { ...@@ -156,12 +103,6 @@ public class DotsAndBoxesGrid {
} }
} }
/**
* "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) { public boolean drawVertical(int x, int y, int player) {
if (x >= width || x < 0) { 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)); throw new IndexOutOfBoundsException(String.format("x was %d, which is out of range. Range is 0 to %d", x, width));
...@@ -170,10 +111,12 @@ public class DotsAndBoxesGrid { ...@@ -170,10 +111,12 @@ public class DotsAndBoxesGrid {
throw new IndexOutOfBoundsException(String.format("y was %d, which is out of range. Range is 0 to %d", y, height - 1)); 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. if (verticals[x][y]) {
throw new IllegalStateException("This line has already been drawn.");
}
this.verticals[x][y] = true; this.verticals[x][y] = true;
// Try to claim the north or south boxes
boolean claimE = claimBox(x, y, player); boolean claimE = claimBox(x, y, player);
boolean claimW = claimBox(x-1, y, player); boolean claimW = claimBox(x-1, y, player);
if (claimE || claimW) { if (claimE || claimW) {
...@@ -184,14 +127,10 @@ public class DotsAndBoxesGrid { ...@@ -184,14 +127,10 @@ public class DotsAndBoxesGrid {
notifyObservers(); notifyObservers();
return false; return false;
} }
} }
public boolean gameComplete() { 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)); return Arrays.stream(boxOwners).allMatch((row) -> Arrays.stream(row).allMatch((owner) -> owner > 0));
} }
} }
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment