Skip to content
Snippets Groups Projects
Commit 204ac68c authored by Will Billingsley's avatar Will Billingsley
Browse files

Basic game works except for deliberately introduced bug

parent a52252e2
No related branches found
No related tags found
No related merge requests found
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.
......@@ -43,15 +46,60 @@ public class DotsAndBoxesGrid {
/** Which owner (if any) claimed any given box. */
private int[][] boxOwners;
public DotsAndBoxesGrid(int width, int height) {
/** 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
......@@ -59,11 +107,8 @@ public class DotsAndBoxesGrid {
* @return true if all four sides have been drawn.
*/
public boolean boxComplete(int x, int y) {
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 - 1|| y < 0) {
throw new IndexOutOfBoundsException(String.format("y was %d, which is out of range. Range is 0 to %d", y, height - 1));
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.
......@@ -71,6 +116,16 @@ public class DotsAndBoxesGrid {
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
......@@ -88,10 +143,16 @@ public class DotsAndBoxesGrid {
// FIXME: You need to throw an exception if the line was already drawn.
this.horizontals[x][y] = true;
if (boxComplete(x, y)) {
boxOwners[x][y] = player;
// 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;
}
}
......@@ -113,12 +174,18 @@ public class DotsAndBoxesGrid {
// You need to throw an exception if the line was already drawn.
this.verticals[x][y] = true;
if (boxComplete(x, y)) {
boxOwners[x][y] = player;
// 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() {
......
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 {
......@@ -14,17 +16,48 @@ public class DotsAndBoxesUI {
final DotsAndBoxesGrid grid;
final AnchorPane anchorPane;
final Label label;
public DotsAndBoxesUI(DotsAndBoxesGrid grid) {
/** 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++) {
......@@ -32,7 +65,21 @@ public class DotsAndBoxesUI {
line.setStrokeWidth(dotDiameter);
line.setStroke(Color.DARKGREY);
line.setOnMouseClicked((evt) -> line.setStroke(Color.RED));
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
}});
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));
......@@ -47,7 +94,21 @@ public class DotsAndBoxesUI {
line.setStrokeWidth(dotDiameter);
line.setStroke(Color.DARKGREY);
line.setOnMouseClicked((evt) -> line.setStroke(Color.RED));
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));
......@@ -67,8 +128,6 @@ public class DotsAndBoxesUI {
}
}
}
......
......@@ -9,7 +9,7 @@ import javafx.stage.Stage;
/** Our main class that launches the app. */
public class Main extends Application {
DotsAndBoxesGrid grid = new DotsAndBoxesGrid(15, 8);
DotsAndBoxesGrid grid = new DotsAndBoxesGrid(15, 8, 2);
@Override
public void start(Stage primaryStage) throws Exception {
......@@ -18,11 +18,12 @@ public class Main extends Application {
Label label = new Label("My label");
BorderPane borderPane = new BorderPane();
borderPane.setTop(label);
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);
......
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