Commit 8a5345d8 authored by Will Billingsley's avatar Will Billingsley Committed by nreeves5
Browse files

Basic game works except for deliberately introduced bug

parent 5dbb9270
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);
......
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment