diff --git a/src/ch/epfl/chacun/Board.java b/src/ch/epfl/chacun/Board.java index 75c3ff7..7eb34b0 100644 --- a/src/ch/epfl/chacun/Board.java +++ b/src/ch/epfl/chacun/Board.java @@ -5,14 +5,18 @@ /** * Represents the board of the game. + *
+ * This board will have a size of 625 (25×25) elements, and will be organized in reading order,
+ * starting from the cell at the top left of the board, and going through the rows before the columns.
*
* @author Maxence Espagnet (sciper: 372808)
* @author Balthazar Baillat (sciper: 373420)
*/
-public class Board {
+public final class Board {
public static final int REACH = 12;
- public static final Board EMPTY = new Board();
+ public static final Board EMPTY = new Board(new PlacedTile[625], new int[0], ZonePartitions.EMPTY, Set.of());
+ private static final int SIZE = 25;
private final PlacedTile[] placedTiles;
private final int[] tileIndices;
private final ZonePartitions zonePartitions;
@@ -21,74 +25,286 @@ public class Board {
/**
* Private constructor of the board to initialize values.
*/
- private Board() {
- this.placedTiles = new PlacedTile[625];
- this.tileIndices = new int[0];
- this.zonePartitions = ZonePartitions.EMPTY;
- this.cancelledAnimals = new HashSet<>();
+ private Board(PlacedTile[] placedTiles, int[] tileIndices, ZonePartitions zonePartitions, Set Cancelled animals can be, for example, deer eaten by smilodons.
+ *
+ * @return the set of cancelled animals
+ */
public Set An insertion position is a position on the board where a tile can be placed.
+ *
+ * @return the set of all insertion positions on the board
+ */
public Set
+ * It can be the starting tile if the first normal tile has not yet been placed, or null if the board is empty
+ *
+ * @return the last placed tile on the board
+ */
+ public PlacedTile lastPlacedTile() {
+ if (tileIndices.length > 0) {
+ return placedTiles[tileIndices[tileIndices.length - 1]];
+ }
+ return null;
+ }
+
+ public Set> forestsClosedByLastTile() {
+ PlacedTile lastTile = lastPlacedTile();
+ // TODO: implement this method
+ return Set.of();
+ }
+
+ public Set> riversClosedByLastTile() {
+ // TODO: implement this method
+ return Set.of();
+ }
+
+ /**
+ * Returns true if the given placed tile can be added to the board.
+ *
+ * i.e. if its position is an insertion position and every edge of the tile that touches
+ * an edge of a tile already placed is of the same kind as it.
+ *
+ * @param tile the placed tile to check
+ * @return true if the given placed tile can be added to the board
+ */
+ public boolean canAddTile(PlacedTile tile) {
+ // Check if the tile cannot be placed on the board
+ if (!insertionPositions().contains(tile.pos())) {
+ return false;
+ }
+ // Check for potential conflicts with adjacent tiles
+ for (Direction direction : Direction.ALL) {
+ Pos neighbor = tile.pos().neighbor(direction);
+ PlacedTile neighborTile = tileAt(neighbor);
+ if (neighborTile != null) {
+ TileSide neighborSide = neighborTile.side(direction.opposite());
+ TileSide tileSide = tile.side(direction);
+ if (!tileSide.isSameKindAs(neighborSide)) {
+ return false;
+ }
+ }
+ }
+ return true;
+ }
+
+ public boolean couldPlaceTile(Tile tile) {
+ // TODO: implement this method
+ return false;
+ }
+
+ /**
+ * Returns an identical board, but with the given tile in addition.
+ *
+ * @param tile the tile to place
+ * @return an identical board, but with the given tile in addition
+ * @throws IllegalArgumentException if the board is not empty and the given tile cannot be added to the board
+ */
+ public Board withNewTile(PlacedTile tile) {
+ // Check if the tile can be placed on the board
+ if (placedTiles.length != 0 && !canAddTile(tile)) {
+ throw new IllegalArgumentException("The tile cannot be placed on the board.");
+ }
+ // Create the new placed tiles array
+ int newTileIndex = calculateRowMajorIndex(tile.pos());
+ PlacedTile[] newPlacedTiles = placedTiles.clone();
+ newPlacedTiles[newTileIndex] = tile;
+ // Create the new tile indices array
+ int[] newTileIndices = new int[tileIndices.length + 1];
+ System.arraycopy(tileIndices, 0, newTileIndices, 0, tileIndices.length);
+ newTileIndices[tileIndices.length] = newTileIndex;
+ // Create a new board with the new tile
+ return new Board(newPlacedTiles, newTileIndices, zonePartitions, Set.copyOf(cancelledAnimals));
+ }
+
+ public Board withOccupant(Occupant occupant) {
+ // TODO: implement this method
return null;
}
}
\ No newline at end of file
diff --git a/src/ch/epfl/chacun/ZonePartitions.java b/src/ch/epfl/chacun/ZonePartitions.java
index fe1c70f..a82dcbb 100644
--- a/src/ch/epfl/chacun/ZonePartitions.java
+++ b/src/ch/epfl/chacun/ZonePartitions.java
@@ -69,19 +69,24 @@ public void addTile(Tile tile) {
switch (zone) {
case Zone.Forest f -> forests.addSingleton(f, openConnections[zone.localId()]);
case Zone.Meadow m -> meadows.addSingleton(m, openConnections[zone.localId()]);
- case Zone.River r when !r.hasLake() ->
- rivers.addSingleton(r, openConnections[r.localId()]);
case Zone.River r -> {
- // If a river has a lake, the river has in fact one less open connection
- rivers.addSingleton(r, openConnections[r.localId()] - 1);
- riverSystems.addSingleton(r, openConnections[r.localId()]);
- // Prevent the same lake from being added twice
- if (!lakes.contains(r.lake())) {
- riverSystems.addSingleton(r.lake(), openConnections[r.lake().localId()]);
- lakes.add(r.lake());
+ // Check if the river has a lake
+ if (r.hasLake()) {
+ // If a river has a lake, the river has in fact one less open connection
+ rivers.addSingleton(r, openConnections[r.localId()] - 1);
+ riverSystems.addSingleton(r, openConnections[r.localId()]);
+ // Prevent the same lake from being added twice
+ if (!lakes.contains(r.lake())) {
+ riverSystems.addSingleton(r.lake(), openConnections[r.lake().localId()]);
+ lakes.add(r.lake());
+ }
+ // Create the union between the river and the lake
+ riverSystems.union(r, r.lake());
+ }
+ else {
+ rivers.addSingleton(r, openConnections[r.localId()]);
+ riverSystems.addSingleton(r, openConnections[r.localId()]);
}
- // Create the union between the river and the lake
- riverSystems.union(r, r.lake());
}
// A lake should not be in the side zones
default -> throw new IllegalArgumentException("A lake shouldn't be in the side zones");
@@ -96,7 +101,6 @@ public void addTile(Tile tile) {
* @param s2 the second tile side
* @throws IllegalArgumentException if the two given tile sides are not of the same kind
*/
-
public void connectSides(TileSide s1, TileSide s2) {
switch (s1) {
case TileSide.Meadow(Zone.Meadow m1) when s2 instanceof TileSide.Meadow(Zone.Meadow m2) -> {
@@ -108,6 +112,7 @@ public void connectSides(TileSide s1, TileSide s2) {
case TileSide.River(
Zone.Meadow m3, Zone.River r1, Zone.Meadow m4
) when s2 instanceof TileSide.River(Zone.Meadow m5, Zone.River r2, Zone.Meadow m6) -> {
+ riverSystems.union(r1, r2);
rivers.union(r1, r2);
meadows.union(m3, m6);
meadows.union(m4, m5);
diff --git a/test/ch/epfl/chacun/BoardTest.java b/test/ch/epfl/chacun/BoardTest.java
new file mode 100644
index 0000000..5025be7
--- /dev/null
+++ b/test/ch/epfl/chacun/BoardTest.java
@@ -0,0 +1,19 @@
+package ch.epfl.chacun;
+
+import org.junit.jupiter.api.Test;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertNull;
+
+public class BoardTest {
+
+ @Test
+ void tileAt() {
+ Board board = Board.EMPTY;
+ assertNull(board.tileAt(Pos.ORIGIN));
+ assertNull(board.tileAt(new Pos(28, 28)));
+ assertNull(board.tileAt(new Pos(-28, -28)));
+ assertNull(board.tileAt(new Pos(-1, 28)));
+ }
+
+}