diff --git a/.idea/misc.xml b/.idea/misc.xml index 69ace3f..9d2ecf0 100644 --- a/.idea/misc.xml +++ b/.idea/misc.xml @@ -1,4 +1,3 @@ - diff --git a/src/ch/epfl/chacun/Area.java b/src/ch/epfl/chacun/Area.java new file mode 100644 index 0000000..23b6dbd --- /dev/null +++ b/src/ch/epfl/chacun/Area.java @@ -0,0 +1,239 @@ +package ch.epfl.chacun; + +import java.util.*; +import java.util.stream.Collectors; + +/** + * Represents an area. + * + * @param zones the list of the zones constituting the area + * @param occupants the list of the colors of any player occupying the area, sorted by color + * @param openConnections the number of open connections of the area + * @param the type of the zone constituting the area + * @author Maxence Espagnet (sciper: 372808) + * @author Balthazar Baillat (sciper: 373420) + */ +public record Area(Set zones, List occupants, int openConnections) { + + /** + * Defensive copy of zones and occupants. Validates the number of open connections and sorts + * the occupants by color. + * + * @throws IllegalArgumentException if the number of open connections is negative + */ + public Area { + Preconditions.checkArgument(openConnections >= 0); + + zones = Set.copyOf(zones); + occupants = new ArrayList<>(occupants); + Collections.sort(occupants); + // Make occupants immutable + occupants = List.copyOf(occupants); + } + + /** + * Checks if a given forest area contains at least one menhir. + * + * @param forest the forest area to check + * @return {@code true} if the forest contains a menhir, {@code false} otherwise + */ + public static boolean hasMenhir(Area forest) { + return forest.zones.stream() + .anyMatch(zone -> zone.kind() == Zone.Forest.Kind.WITH_MENHIR); + } + + /** + * Counts the number of mushroom groups in a given forest area. + * + * @param forest the forest area to check + * @return the number of mushroom groups in the forest + */ + public static int mushroomGroupCount(Area forest) { + return (int) forest.zones.stream() + .filter(zone -> zone.kind() == Zone.Forest.Kind.WITH_MUSHROOMS).count(); + } + + /** + * Returns the set of animals in a given meadow area, excluding cancelled animals. + *

Cancelled animals can be, for example, deer eaten by smilodons. + * + * @param meadow the meadow area to count animals in + * @param cancelledAnimals the set of animals to exclude + * @return the set of animals in the meadow, excluding the cancelled animals + */ + public static Set animals(Area meadow, Set cancelledAnimals) { + return meadow.zones.stream() + .flatMap(zone -> zone.animals().stream()) + .filter(animal -> !cancelledAnimals.contains(animal)) + .collect(Collectors.toSet()); + } + + /** + * Counts the number of fish swimming in the given river or in any of the lakes at its ends + *

The fish in a given lake need only be counted once, even if a single lake ends the river at both ends + * + * @param river the river area to count fish in + * @return the total number of fish in the river, lakes included + */ + public static int riverFishCount(Area river) { + // Make sure a lake appears only once + Set lakes = river.zones.stream() + .filter(Zone.River::hasLake).map(Zone.River::lake).collect(Collectors.toSet()); + // Compute the number of fishes + int fishCountInLakes = lakes.stream().mapToInt(Zone.Lake::fishCount).sum(); + int fishCountInRivers = river.zones.stream().mapToInt(Zone.River::fishCount).sum(); + // Return the total number of fishes + return fishCountInLakes + fishCountInRivers; + } + + /** + * Counts the number of fish swimming in the given river system + * + * @param riverSystem the river system area to count fish in + * @return the total number of fish in the river system + */ + public static int riverSystemFishCount(Area riverSystem) { + return riverSystem.zones.stream().mapToInt(Zone.Water::fishCount).sum(); + } + + /** + * Counts the number of lakes in the given river system. + * + * @param riverSystem the river system area to count lakes in + * @return the total number of lakes in the river system + */ + public static int lakeCount(Area riverSystem) { + return (int) riverSystem.zones.stream().filter(Zone.Lake.class::isInstance).count(); + } + + /** + * Returns whether the area is closed or not. + * + * @return {@code true} if the area is closed or {@code else} if it isn't + */ + public boolean isClosed() { + return openConnections == 0; + } + + /** + * Returns whether the area is occupied or not. + * + * @return {@code true} if the area is occupied or {@code else} if it isn't + */ + public boolean isOccupied() { + return !occupants.isEmpty(); + } + + /** + * Returns the players that have the majority of occupants in the area. + * + * @return the players that have the majority of occupants in the area + */ + public Set majorityOccupants() { + // Special case: no occupants + if (occupants.isEmpty()) + return new HashSet<>(); + + int max = 0; + // Count occurrences of each player color + int[] occupantCount = new int[PlayerColor.ALL.size()]; + for (PlayerColor occupant : occupants) { + int newCount = ++occupantCount[occupant.ordinal()]; + if (max < newCount) + max = newCount; + } + // Find the majority occupants + Set majorityOccupants = new HashSet<>(); + for (int i = 0; i < occupantCount.length; i++) { + if (occupantCount[i] == max) { + majorityOccupants.add(PlayerColor.ALL.get(i)); + } + } + + return majorityOccupants; + } + + /** + * Returns the area resulting from the connection of the receiver (this) to the given area (that). + * + * @param newArea the new area to connect to + * @return the new area resulting from the connection + */ + public Area connectTo(Area newArea) { + Set zones = new HashSet<>(this.zones); + List occupants = new ArrayList<>(this.occupants); + // Calculate the new number of open connections + // The new area will have 2 less open connections, as each area had at least one open connection + int openConnections = this.openConnections - 2; + // Merge the zones of both areas into one + // Add the new occupants to the current ones + if(!this.equals(newArea)) { + zones.addAll(newArea.zones); + occupants.addAll(newArea.occupants); + // In case both areas are not the same, we need to add the open connections of the new area + openConnections += newArea.openConnections; + } + // Create the new area + return new Area<>(zones, occupants, openConnections); + } + + /** + * Returns an area identical to the receiver, except that it is occupied only by the given occupant. + * + * @param occupant the occupant to put into the new area + * @return an area identical to the receiver, except that it is occupied only by the given occupant + * @throws IllegalArgumentException if the area is already occupied + */ + public Area withInitialOccupant(PlayerColor occupant) { + Preconditions.checkArgument(occupants.isEmpty()); + return new Area<>(zones, List.of(occupant), openConnections); + } + + /** + * Returns an area identical to the receiver, except that an occupant of the given color is removed. + * + * @param occupant the color of the occupant to remove + * @return an area identical to the receiver, except that an occupant of the given color is removed + * @throws IllegalArgumentException if the area does not contain an occupant of the given color + */ + public Area withoutOccupant(PlayerColor occupant) { + Preconditions.checkArgument(occupants.contains(occupant)); + // Copy the list of occupant since this class is immutable + // and remove the first occurrence of the given occupant + List filteredOccupants = new ArrayList<>(occupants); + filteredOccupants.remove(occupant); + + return new Area<>(zones, filteredOccupants, openConnections); + } + + /** + * Returns an area identical to the receiver, except that all its occupants are removed. + * + * @return an area identical to the receiver, except that all its occupants are removed + */ + public Area withoutOccupants() { + return new Area<>(zones, new ArrayList<>(), openConnections); + } + + /** + * Returns the set of the ids of all the tiles containing the area. + * + * @return the set of the ids of all the tiles containing the area + */ + public Set tileIds() { + return zones.stream().map(Zone::tileId).collect(Collectors.toSet()); + + } + + /** + * Returns the zone of the area containing the given special power or null if it does not exist any + * special power. + * + * @param specialPower the special power + * @return the zone of the area containing the given special power + */ + public Zone zoneWithSpecialPower(Zone.SpecialPower specialPower) { + return zones.stream().filter(z -> z.specialPower() == specialPower).findAny().orElse(null); + } + +} diff --git a/src/ch/epfl/chacun/PlacedTile.java b/src/ch/epfl/chacun/PlacedTile.java index 2d66f1d..848d66a 100644 --- a/src/ch/epfl/chacun/PlacedTile.java +++ b/src/ch/epfl/chacun/PlacedTile.java @@ -81,7 +81,7 @@ public TileSide side(Direction direction) { } /** - * Returns the area of the placed tile whose id is given, or throws IllegalArgumentException + * Returns the area of the placed tile whose id is given, or throws {@link IllegalArgumentException} * if the tile has no area with this id. * * @param id the id of the placed tile diff --git a/src/ch/epfl/chacun/ZonePartition.java b/src/ch/epfl/chacun/ZonePartition.java new file mode 100644 index 0000000..f3bb3ff --- /dev/null +++ b/src/ch/epfl/chacun/ZonePartition.java @@ -0,0 +1,190 @@ +package ch.epfl.chacun; + +import java.util.ArrayList; +import java.util.HashSet; +import java.util.Set; + +/** + * Represents a partition of zones of a given kind. + * + * @param areas the set of areas forming the partition + * @param the kind of zones of the partition + * @author Maxence Espagnet (sciper: 372808) + * @author Balthazar Baillat (sciper: 373420) + */ +public record ZonePartition(Set> areas) { + + /** + * Defensive copy of the set of areas. + */ + public ZonePartition { + areas = Set.copyOf(areas); + } + + /** + * Additional constructor to construct a partition with an empty set of areas. + */ + public ZonePartition() { + this(new HashSet<>()); + } + + /** + * Returns the area containing the given zone, or throws an {@link IllegalArgumentException} if the + * given zone is not assigned to any area of the partition. + * + * @param zone the zone + * @return the area containing the given zone + * @throws IllegalArgumentException if the given zone is not assigned to any area of the partition + */ + public Area areaContaining(Z zone) { + return areas.stream().filter(a -> a.zones().contains(zone)).findFirst() + .orElseThrow(() -> new IllegalArgumentException("The zone is not assigned to any area.")); + } + + /** + * Represents the builder of ZonePartition. + * + * @param the zone type + * @author Maxence Espagnet (sciper: 372808) + * @author Balthazar Baillat (sciper: 373420) + */ + public static final class Builder { + // The set of areas constituting the partition + private final Set> areas; + + /** + * Initialises the builder's area set with the one of the given partition. + * + * @param zonePartition the partition + */ + public Builder(ZonePartition zonePartition) { + this.areas = new HashSet<>(zonePartition.areas); + } + + /** + * Adds to the partition under construction a new unoccupied area constituted of the given zone + * and the given number of open connections. + * + * @param zone the given zone + * @param openConnections the given number of open connections + */ + public void addSingleton(Z zone, int openConnections) { + areas.add(new Area<>(Set.of(zone), new ArrayList<>(), openConnections)); + } + + /** + * Checks the validity of a given zone and returns the area of the partition + * containing the given zone. + *

+ * Verifies if the given zone is already occupied or not assigned to any area of the partition + * and throws {@link IllegalArgumentException} if so. + * + * @param zone the zone to check + * @return the area of the partition containing the given zone + * @throws IllegalArgumentException if the zone is not available + */ + private Area findAreaContainingZone(Z zone) { + // Create a zone partition (needed to use areaContaining method) containing the set of areas + ZonePartition zonePartition = new ZonePartition<>(areas); + try { + return zonePartition.areaContaining(zone); + } catch (IllegalArgumentException e) { + throw new IllegalArgumentException("Zone is not assigned to any area of the partition."); + } + } + + private Area findAreaContainingZoneWithoutOccupant(Z zone) { + Area areaContainingZone = findAreaContainingZone(zone); + if (areaContainingZone.isOccupied()) { + throw new IllegalArgumentException("The area is already occupied."); + } + return areaContainingZone; + } + + + /** + * Adds to the area containing the given zone an initial occupant of the given color after checking + * if the given zone is available. + * + * @param zone the given zone + * @param color the given occupant color + */ + public void addInitialOccupant(Z zone, PlayerColor color) { + // Check if the zone is available in the partition and find the area containing the given zone + Area areaContainingZone = findAreaContainingZoneWithoutOccupant(zone); + // Create a new area without the occupant of the given color + Area newArea = areaContainingZone.withInitialOccupant(color); + // Replace the area containing the given zone by the new one in the set of areas + areas.remove(areaContainingZone); + areas.add(newArea); + } + + /** + * Removes from the area containing the given zone an occupant of the given color after checking + * if the given zone is available. + * + * @param zone the given zone + * @param color the given occupant color + */ + public void removeOccupant(Z zone, PlayerColor color) { + // Check if the zone is available in the partition and find the area containing the given zone + Area areaContainingZone = findAreaContainingZone(zone); + // Create a new area without the occupant of the given color + Area newArea = areaContainingZone.withoutOccupant(color); + // Replace the area containing the given zone by the new one in the set of areas + areas.remove(areaContainingZone); + areas.add(newArea); + } + + /** + * Removes all the occupants of a given area of the partition, or throws an + * {@link IllegalArgumentException} if the area is not part of the partition. + * + * @param area the area to be emptied of its occupants + * @throws IllegalArgumentException if the area is not part of the partition + */ + public void removeAllOccupantsOf(Area area) { + Preconditions.checkArgument(areas.contains(area)); + // Create a new area with no occupants + Area unoccupiedArea = area.withoutOccupants(); + // Replace the area containing the given zone by the new one in the set of areas + areas.remove(area); + areas.add(unoccupiedArea); + } + + /** + * Connects to each other two areas containing two zones, or throws {@link IllegalArgumentException} + * if at least one of the two zones is not assigned to any area of the partition + * + * @param zone1 the first zone + * @param zone2 the second zone + * @throws IllegalArgumentException if at least one of the two zones is not assigned to any area + * of the partition + */ + public void union(Z zone1, Z zone2) { + Area area1 = findAreaContainingZone(zone1); + Area area2 = findAreaContainingZone(zone2); + // If the two zones are not assigned to the same area, connect the two areas + // Otherwise connect the area to itself + if(!area1.equals(area2)) { + // Remove the two areas from the set of areas and add the new one + areas.remove(area1); + areas.remove(area2); + } else { + // Remove the area from the set of areas and add the new one + areas.remove(area1); + } + areas.add(area1.connectTo(area2)); + } + + /** + * Builds the final zone partition instance. + * + * @return the final zone partition + */ + public ZonePartition build() { + return new ZonePartition<>(this.areas); + } + + } +} diff --git a/src/ch/epfl/chacun/ZonePartitions.java b/src/ch/epfl/chacun/ZonePartitions.java new file mode 100644 index 0000000..dd59eef --- /dev/null +++ b/src/ch/epfl/chacun/ZonePartitions.java @@ -0,0 +1,37 @@ +package ch.epfl.chacun; + +public record ZonePartitions(ZonePartition forests, ZonePartition meadows, + ZonePartition rivers, ZonePartition lakes, + ZonePartition riverSystems) { + public final static ZonePartitions EMPTY = new ZonePartitions(new ZonePartition<>(), new ZonePartition<>(), new ZonePartition<>(), new ZonePartition<>(), new ZonePartition<>()); + + + public static final class Builder { + + private ZonePartition.Builder forests; + private ZonePartition.Builder meadows; + private ZonePartition.Builder rivers; + private ZonePartition.Builder lakes; + + public Builder(ZonePartitions initial) { + this.forests = new ZonePartition.Builder<>(initial.forests); + this.meadows = new ZonePartition.Builder<>(initial.meadows); + this.rivers = new ZonePartition.Builder<>(initial.rivers); + this.lakes = new ZonePartition.Builder<>(initial.lakes); + } + + public void addTile(Tile tile) { + int[] openConnections = new int[10]; + for (TileSide side : tile.sides()) { + for (Zone zone : side.zones()) { + ++openConnections[zone.id()]; + } + } + + // if (tile.zones().stream().some) + + } + + } + +} diff --git a/src/ch/epfl/sigcheck/SignatureChecks_3.java b/src/ch/epfl/sigcheck/SignatureChecks_3.java new file mode 100644 index 0000000..98039c5 --- /dev/null +++ b/src/ch/epfl/sigcheck/SignatureChecks_3.java @@ -0,0 +1,85 @@ +package ch.epfl.sigcheck; + +// Attention : cette classe n'est *pas* un test JUnit, et son code n'est pas +// destiné à être exécuté. Son seul but est de vérifier, autant que possible, +// que les noms et les types des différentes entités à définir pour cette +// étape du projet sont corrects. + +final class SignatureChecks_3 { + private SignatureChecks_3() {} + + void checkArea() throws Exception { + v01 = new ch.epfl.chacun.Area<>(v02, v03, v04); + v06 = ch.epfl.chacun.Area.animals(v05, v06); + v08 = ch.epfl.chacun.Area.hasMenhir(v07); + v04 = ch.epfl.chacun.Area.lakeCount(v09); + v04 = ch.epfl.chacun.Area.mushroomGroupCount(v07); + v04 = ch.epfl.chacun.Area.riverFishCount(v10); + v04 = ch.epfl.chacun.Area.riverSystemFishCount(v09); + v11 = v01.connectTo(v11); + v08 = v01.equals(v12); + v04 = v01.hashCode(); + v08 = v01.isClosed(); + v08 = v01.isOccupied(); + v13 = v01.majorityOccupants(); + v14 = v01.occupants(); + v04 = v01.openConnections(); + v15 = v01.tileIds(); + v16 = v01.toString(); + v11 = v01.withInitialOccupant(v17); + v11 = v01.withoutOccupant(v17); + v11 = v01.withoutOccupants(); + v19 = v01.zoneWithSpecialPower(v18); + v20 = v01.zones(); + } + + void checkZonePartition() throws Exception { + v21 = new ch.epfl.chacun.ZonePartition<>(v02a); + v21 = new ch.epfl.chacun.ZonePartition<>(); + v23 = v21.areaContaining(v22); + v24 = v21.areas(); + v08 = v21.equals(v12); + v04 = v21.hashCode(); + v16 = v21.toString(); + } + + void checkZonePartition_Builder() throws Exception { + v25 = new ch.epfl.chacun.ZonePartition.Builder<>(v26); + v25.addInitialOccupant(v27, v17); + v25.addSingleton(v27, v04); + v26 = v25.build(); + v25.removeAllOccupantsOf(v28); + v25.removeOccupant(v27, v17); + v25.union(v27, v27); + } + + ch.epfl.chacun.Area v01; + java.util.Set v02; + java.util.Set> v02a; + java.util.List v03; + int v04; + ch.epfl.chacun.Area v05; + java.util.Set v06; + ch.epfl.chacun.Area v07; + boolean v08; + ch.epfl.chacun.Area v09; + ch.epfl.chacun.Area v10; + ch.epfl.chacun.Area v11; + Object v12; + java.util.Set v13; + java.util.List v14; + java.util.Set v15; + String v16; + ch.epfl.chacun.PlayerColor v17; + ch.epfl.chacun.Zone.SpecialPower v18; + ch.epfl.chacun.Zone v19; + java.util.Set v20; + ch.epfl.chacun.ZonePartition v21; + ch.epfl.chacun.Zone v22; + ch.epfl.chacun.Area v23; + java.util.Set> v24; + ch.epfl.chacun.ZonePartition.Builder v25; + ch.epfl.chacun.ZonePartition v26; + ch.epfl.chacun.Zone v27; + ch.epfl.chacun.Area v28; +} diff --git a/test/ch/epfl/chacun/AreaTest.java b/test/ch/epfl/chacun/AreaTest.java new file mode 100644 index 0000000..9e8e996 --- /dev/null +++ b/test/ch/epfl/chacun/AreaTest.java @@ -0,0 +1,349 @@ +package ch.epfl.chacun; + +import org.junit.jupiter.api.Test; + +import java.util.ArrayList; +import java.util.HashSet; +import java.util.List; +import java.util.Set; + +import static ch.epfl.chacun.Zone.*; +import static org.junit.jupiter.api.Assertions.*; + +public class AreaTest { + @Test + void areaThrowsOnNegativeNumberOfOccupants() { + Set forestZones = new HashSet<>(); + forestZones.add(new Forest(0, Forest.Kind.PLAIN)); + List occupants = new ArrayList<>(); + occupants.add(0, PlayerColor.RED); + + assertThrows(IllegalArgumentException.class, + () -> new Area<>(forestZones, occupants, -2)); + } + + @Test + void occupantsSortingWorks() { + Set forestZones = new HashSet<>(); + forestZones.add(new Forest(0, Forest.Kind.PLAIN)); + List occupants = new ArrayList<>(); + occupants.add(PlayerColor.RED); + occupants.add(PlayerColor.PURPLE); + occupants.add(PlayerColor.GREEN); + + List expectedSortedOccupants = new ArrayList<>(); + expectedSortedOccupants.add(PlayerColor.RED); + expectedSortedOccupants.add(PlayerColor.GREEN); + expectedSortedOccupants.add(PlayerColor.PURPLE); + + Area forestArea = new Area<>(forestZones, occupants, 3); + + assertEquals(expectedSortedOccupants, forestArea.occupants()); + } + + @Test + void hasMenhirWorksWithMenhir() { + Set forestZones = new HashSet<>(); + forestZones.add(new Forest(0, Forest.Kind.WITH_MENHIR)); + List occupants = new ArrayList<>(); + Area forestArea = new Area<>(forestZones, occupants, 3); + assertTrue(Area.hasMenhir(forestArea)); + } + + @Test + void hasMenhirWorksWithOutMenhir() { + Set forestZones = new HashSet<>(); + forestZones.add(new Forest(0, Forest.Kind.PLAIN)); + List occupants = new ArrayList<>(); + Area forestArea = new Area<>(forestZones, occupants, 3); + assertFalse(Area.hasMenhir(forestArea)); + } + + @Test + void mushroomGroupCountWorksWhenMushrooms() { + Set forestZones = new HashSet<>(); + forestZones.add(new Forest(0, Forest.Kind.WITH_MUSHROOMS)); + List occupants = new ArrayList<>(); + Area forestArea = new Area<>(forestZones, occupants, 3); + + assertEquals(1, Area.mushroomGroupCount(forestArea)); + } + + @Test + void mushroomGroupCountWorksWhenNoMushrooms() { + Set forestZones = new HashSet<>(); + forestZones.add(new Forest(0, Forest.Kind.PLAIN)); + List occupants = new ArrayList<>(); + Area forestArea = new Area<>(forestZones, occupants, 3); + + assertEquals(0, Area.mushroomGroupCount(forestArea)); + } + + @Test + void animalsWorksWithNoCancelledAnimals() { + Set meadowZones = new HashSet<>(); + List animals = new ArrayList<>(List.of(new Animal(0, Animal.Kind.AUROCHS))); + meadowZones.add(new Meadow(0, animals, null)); + List occupants = new ArrayList<>(); + Area medowArea = new Area<>(meadowZones, occupants, 3); + Set expectedAnimals = new HashSet<>(List.of(new Animal(0, Animal.Kind.AUROCHS))); + Set cancelledAnimals = new HashSet<>(); + assertEquals(expectedAnimals, Area.animals(medowArea, cancelledAnimals)); + } + + @Test + void animalsWorksWithCancelledAnimals() { + Set meadowZones = new HashSet<>(); + List animals = new ArrayList<>(List.of(new Animal(0, Animal.Kind.AUROCHS))); + meadowZones.add(new Meadow(0, animals, null)); + List occupants = new ArrayList<>(); + Area medowArea = new Area<>(meadowZones, occupants, 3); + Set expectedAnimals = new HashSet<>(List.of(new Animal(0, Animal.Kind.AUROCHS))); + Set cancelledAnimals = new HashSet<>(List.of(new Animal(1, Animal.Kind.DEER))); + assertEquals(expectedAnimals, Area.animals(medowArea, cancelledAnimals)); + } + + @Test + void riverFishCountWorksWithTwoDistinctLakes() { + Set riverZones = new HashSet<>(); + Lake lake1 = new Lake(0, 2, null); + Lake lake2 = new Lake(1, 2, null); + riverZones.add(new River(2, 1, lake1)); + riverZones.add(new River(3, 1, lake2)); + List occupants = new ArrayList<>(); + Area riverArea = new Area<>(riverZones, occupants, 0); + + assertEquals(6, Area.riverFishCount(riverArea)); + } + + @Test + void riverFishCountWorksWithSingleLake() { + Set riverZones = new HashSet<>(); + Lake lake1 = new Lake(0, 2, null); + River river1 = new River(1, 1, lake1); + River river2 = new River(2, 1, null); + River river3 = new River(3, 1, lake1); + riverZones.add(river1); + riverZones.add(river2); + riverZones.add(river3); + List occupants = new ArrayList<>(); + Area riverArea = new Area<>(riverZones, occupants, 0); + + assertEquals(5, Area.riverFishCount(riverArea)); + } + + @Test + void riverSystemFishCountWorks() { + Set riverSystemZones = new HashSet<>(); + Lake lake1 = new Lake(0, 2, null); + River river1 = new River(1, 1, lake1); + River river2 = new River(2, 1, null); + River river3 = new River(3, 1, lake1); + riverSystemZones.add(lake1); + riverSystemZones.add(river1); + riverSystemZones.add(river2); + riverSystemZones.add(river3); + List occupants = new ArrayList<>(); + Area riverSystem = new Area<>(riverSystemZones, occupants, 0); + + assertEquals(5, Area.riverSystemFishCount(riverSystem)); + } + + @Test + void lakeCountWorks() { + Set riverSystemZones = new HashSet<>(); + Lake lake1 = new Lake(0, 2, null); + Lake lake2 = new Lake(1, 2, null); + River river1 = new River(2, 1, lake1); + River river2 = new River(3, 1, null); + riverSystemZones.add(lake1); + riverSystemZones.add(lake2); + riverSystemZones.add(river1); + riverSystemZones.add(river2); + List occupants = new ArrayList<>(); + Area riverSystem = new Area<>(riverSystemZones, occupants, 0); + + assertEquals(2, Area.lakeCount(riverSystem)); + } + + @Test + void isClosedWorksOnClosedArea() { + Set riverZones = new HashSet<>(); + Lake lake1 = new Lake(0, 2, null); + Lake lake2 = new Lake(1, 2, null); + riverZones.add(new River(2, 1, lake1)); + riverZones.add(new River(3, 1, lake2)); + List occupants = new ArrayList<>(); + Area riverArea = new Area<>(riverZones, occupants, 0); + + assertTrue(riverArea.isClosed()); + } + + @Test + void isClosedWorksOnOpenArea() { + Set forestZones = new HashSet<>(); + forestZones.add(new Forest(0, Forest.Kind.PLAIN)); + List occupants = new ArrayList<>(); + Area forestArea = new Area<>(forestZones, occupants, 3); + + assertFalse(forestArea.isClosed()); + } + + @Test + void isOccupiedWorksOnOccupiedArea() { + Set forestZones = new HashSet<>(); + forestZones.add(new Forest(0, Forest.Kind.PLAIN)); + List occupants = new ArrayList<>(List.of(PlayerColor.RED)); + Area forestArea = new Area<>(forestZones, occupants, 3); + + assertTrue(forestArea.isOccupied()); + } + + @Test + void isOccupiedWorksOnUnoccupiedArea() { + Set forestZones = new HashSet<>(); + forestZones.add(new Forest(0, Forest.Kind.PLAIN)); + List occupants = new ArrayList<>(); + Area forestArea = new Area<>(forestZones, occupants, 3); + + assertFalse(forestArea.isOccupied()); + } + + @Test + void majorityOccupantsWorks() { + Set forestZones = new HashSet<>(); + forestZones.add(new Forest(0, Forest.Kind.PLAIN)); + List occupants = new ArrayList<>(); + occupants.add(PlayerColor.BLUE); + occupants.add(PlayerColor.BLUE); + occupants.add(PlayerColor.YELLOW); + occupants.add(PlayerColor.YELLOW); + occupants.add(PlayerColor.PURPLE); + Area forestArea = new Area<>(forestZones, occupants, 3); + + assertEquals(Set.of(PlayerColor.BLUE, PlayerColor.YELLOW), forestArea.majorityOccupants()); + } + + @Test + void majorityOccupantsWorksWithoutOccupants() { + List occupants = new ArrayList<>(); + Area forestArea = new Area<>(new HashSet<>(), occupants, 3); + + assertEquals(Set.of(), forestArea.majorityOccupants()); + } + + @Test + void connectToWorksWithOtherArea() { + Set forestZones1 = new HashSet<>(); + Set forestZones2 = new HashSet<>(); + Set forestZones3 = new HashSet<>(); + forestZones1.add(new Forest(0, Forest.Kind.PLAIN)); + forestZones2.add(new Forest(1, Forest.Kind.PLAIN)); + forestZones3.add(new Forest(0, Forest.Kind.PLAIN)); + forestZones3.add(new Forest(1, Forest.Kind.PLAIN)); + List occupants = new ArrayList<>(); + Area forestArea1 = new Area<>(forestZones1, occupants, 4); + Area forestArea2 = new Area<>(forestZones2, occupants, 4); + Area forestArea3 = new Area<>(forestZones3, occupants, 6); + + assertEquals(forestArea3, forestArea1.connectTo(forestArea2)); + + } + + @Test + void connectToWorksWithItself() { + Set forestZones1 = new HashSet<>(); + Set forestZones2 = new HashSet<>(); + forestZones1.add(new Forest(0, Forest.Kind.PLAIN)); + forestZones1.add(new Forest(1, Forest.Kind.PLAIN)); + forestZones1.add(new Forest(2, Forest.Kind.PLAIN)); + forestZones1.add(new Forest(3, Forest.Kind.PLAIN)); + forestZones2.add(new Forest(0, Forest.Kind.PLAIN)); + forestZones2.add(new Forest(1, Forest.Kind.PLAIN)); + forestZones2.add(new Forest(2, Forest.Kind.PLAIN)); + forestZones2.add(new Forest(3, Forest.Kind.PLAIN)); + List occupants = new ArrayList<>(); + Area forestArea1 = new Area<>(forestZones1, occupants, 10); + Area forestArea2 = new Area<>(forestZones2, occupants, 8); + + + assertEquals(forestArea2, forestArea1.connectTo(forestArea1)); + + } + + @Test + void withInitialOccupantThrowsOnOccupiedArea() { + Set forestZones = new HashSet<>(); + forestZones.add(new Forest(0, Forest.Kind.PLAIN)); + List occupants = new ArrayList<>(List.of(PlayerColor.RED)); + Area forestArea = new Area<>(forestZones, occupants, 3); + + assertThrows(IllegalArgumentException.class, () -> forestArea.withInitialOccupant(PlayerColor.BLUE)); + + } + + @Test + void withInitialOccupantWorks() { + Set forestZones = new HashSet<>(); + forestZones.add(new Forest(0, Forest.Kind.PLAIN)); + List occupants1 = new ArrayList<>(); + List occupants2 = new ArrayList<>(List.of(PlayerColor.YELLOW)); + Area forestArea1 = new Area<>(forestZones, occupants1, 3); + Area forestArea2 = new Area<>(forestZones, occupants2, 3); + + assertEquals(forestArea2, forestArea1.withInitialOccupant(PlayerColor.YELLOW)); + } + + @Test + void withoutOccupantThrowsWhenNoOccupantOfGivenColor() { + Set forestZones = new HashSet<>(); + forestZones.add(new Forest(0, Forest.Kind.PLAIN)); + List occupants = new ArrayList<>(List.of(PlayerColor.RED)); + Area forestArea = new Area<>(forestZones, occupants, 3); + assertThrows(IllegalArgumentException.class, () -> forestArea.withoutOccupant(PlayerColor.YELLOW)); + } + + @Test + void withoutOccupantWorks() { + Set forestZones = new HashSet<>(); + forestZones.add(new Forest(0, Forest.Kind.PLAIN)); + List occupants1 = new ArrayList<>(List.of(PlayerColor.YELLOW)); + List occupants2 = new ArrayList<>(); + Area forestArea1 = new Area<>(forestZones, occupants1, 3); + Area forestArea2 = new Area<>(forestZones, occupants2, 3); + + assertEquals(forestArea2, forestArea1.withoutOccupant(PlayerColor.YELLOW)); + } + + @Test + void zoneWithSpecialPowerReturnsNullWhenNoSpecialPower() { + Set meadows = new HashSet<>(); + meadows.add(new Meadow(0, new ArrayList<>(), null)); + List occupants1 = new ArrayList<>(List.of(PlayerColor.YELLOW)); + Area meadowArea = new Area<>(meadows, occupants1, 3); + + assertNull(meadowArea.zoneWithSpecialPower(SpecialPower.HUNTING_TRAP)); + } + + @Test + void zoneWithSpecialPowerReturnsNullWhenDifferentSpecialPower() { + Set meadows = new HashSet<>(); + meadows.add(new Meadow(0, new ArrayList<>(), SpecialPower.HUNTING_TRAP)); + List occupants1 = new ArrayList<>(List.of(PlayerColor.YELLOW)); + Area meadowArea = new Area<>(meadows, occupants1, 3); + + assertNull(meadowArea.zoneWithSpecialPower(SpecialPower.LOGBOAT)); + } + + @Test + void zoneWithSpecialPowerWorks() { + Set meadows = new HashSet<>(); + Meadow meadowWithSpecialPower = new Meadow(0, new ArrayList<>(), SpecialPower.HUNTING_TRAP); + meadows.add(meadowWithSpecialPower); + List occupants1 = new ArrayList<>(List.of(PlayerColor.YELLOW)); + Area meadowArea = new Area<>(meadows, occupants1, 3); + + assertEquals(meadowWithSpecialPower, meadowArea.zoneWithSpecialPower(SpecialPower.HUNTING_TRAP)); + } + +} diff --git a/test/ch/epfl/chacun/PlacedTileTest.java b/test/ch/epfl/chacun/PlacedTileTest.java index 14ec483..4d93585 100644 --- a/test/ch/epfl/chacun/PlacedTileTest.java +++ b/test/ch/epfl/chacun/PlacedTileTest.java @@ -6,7 +6,7 @@ import java.util.List; import java.util.Set; -import static org.junit.Assert.assertThrows; +import static org.junit.jupiter.api.Assertions.assertThrows; import static org.junit.jupiter.api.Assertions.assertDoesNotThrow; import static org.junit.jupiter.api.Assertions.assertEquals; diff --git a/test/ch/epfl/chacun/TileDecksTest.java b/test/ch/epfl/chacun/TileDecksTest.java index b628945..05bcd00 100644 --- a/test/ch/epfl/chacun/TileDecksTest.java +++ b/test/ch/epfl/chacun/TileDecksTest.java @@ -5,8 +5,7 @@ import java.util.ArrayList; import java.util.List; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertThrows; +import static org.junit.jupiter.api.Assertions.*; public class TileDecksTest { @Test diff --git a/test/ch/epfl/chacun/TileTest.java b/test/ch/epfl/chacun/TileTest.java index 7ce9d45..639bad5 100644 --- a/test/ch/epfl/chacun/TileTest.java +++ b/test/ch/epfl/chacun/TileTest.java @@ -6,7 +6,7 @@ import java.util.List; import java.util.Set; -import static org.junit.Assert.assertEquals; +import static org.junit.jupiter.api.Assertions.assertEquals; public class TileTest { diff --git a/test/ch/epfl/chacun/ZonePartitionTest.java b/test/ch/epfl/chacun/ZonePartitionTest.java new file mode 100644 index 0000000..92443ba --- /dev/null +++ b/test/ch/epfl/chacun/ZonePartitionTest.java @@ -0,0 +1,197 @@ +package ch.epfl.chacun; + +import org.junit.jupiter.api.Test; + +import java.util.ArrayList; +import java.util.HashSet; +import java.util.List; +import java.util.Set; + +import static ch.epfl.chacun.Zone.Forest; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertThrows; + +public class ZonePartitionTest { + @Test + void areaContainingThrowsOnUnassignedZone() { + Set forestZones = new HashSet<>(); + forestZones.add(new Forest(0, Forest.Kind.PLAIN)); + List occupants = new ArrayList<>(List.of(PlayerColor.RED)); + Area forestArea = new Area<>(forestZones, occupants, 3); + ZonePartition zonePartition = new ZonePartition<>(Set.of(forestArea)); + + assertThrows(IllegalArgumentException.class + , () -> zonePartition.areaContaining(new Forest(1, Forest.Kind.PLAIN))); + } + + @Test + void areaContainingWorks() { + Set forestZones = new HashSet<>(); + Forest forest = new Forest(0, Forest.Kind.PLAIN); + forestZones.add(forest); + List occupants = new ArrayList<>(List.of(PlayerColor.RED)); + Area forestArea = new Area<>(forestZones, occupants, 3); + ZonePartition zonePartition = new ZonePartition<>(Set.of(forestArea)); + + assertEquals(forestArea, zonePartition.areaContaining(forest)); + } + + @Test + void addSingletonWorks() { + Set forestZones = new HashSet<>(); + forestZones.add(new Forest(0, Forest.Kind.PLAIN)); + List occupants = new ArrayList<>(List.of(PlayerColor.RED)); + Area forestArea = new Area<>(forestZones, occupants, 3); + ZonePartition zonePartition = new ZonePartition<>(Set.of(forestArea)); + ZonePartition.Builder builder = new ZonePartition.Builder<>(zonePartition); + + Set newForestZones = new HashSet<>(); + Forest newForest = new Forest(1, Forest.Kind.WITH_MUSHROOMS); + newForestZones.add(newForest); + List newOccupants = new ArrayList<>(); + Area newForestArea = new Area<>(newForestZones, newOccupants, 1); + + builder.addSingleton(newForest, 1); + ZonePartition buildedZonePartition = builder.build(); + + Set expectedAreas = new HashSet<>(); + expectedAreas.add(forestArea); + expectedAreas.add(newForestArea); + + assertEquals(expectedAreas, buildedZonePartition.areas()); + } + + @Test + void addInitialOccupantThrowsOnUnAssignedZone() { + Set forestZones = new HashSet<>(); + forestZones.add(new Forest(0, Forest.Kind.PLAIN)); + List occupants = new ArrayList<>(); + Area forestArea = new Area<>(forestZones, occupants, 3); + ZonePartition zonePartition = new ZonePartition<>(Set.of(forestArea)); + ZonePartition.Builder builder = new ZonePartition.Builder(zonePartition); + + assertThrows(IllegalArgumentException.class + , () -> builder.addInitialOccupant(new Forest(1, Forest.Kind.WITH_MENHIR), PlayerColor.BLUE)); + } + + @Test + void addInitialOccupantThrowsOnOccupiedArea() { + Set forestZones = new HashSet<>(); + Forest forest = new Forest(0, Forest.Kind.PLAIN); + forestZones.add(forest); + List occupants = new ArrayList<>(List.of(PlayerColor.YELLOW)); + Area forestArea = new Area<>(forestZones, occupants, 3); + ZonePartition zonePartition = new ZonePartition<>(Set.of(forestArea)); + ZonePartition.Builder builder = new ZonePartition.Builder(zonePartition); + + assertThrows(IllegalArgumentException.class + , () -> builder.addInitialOccupant(forest, PlayerColor.BLUE)); + } + + @Test + void addInitialOccupantWorks() { + Set forestZones = new HashSet<>(); + Forest forest = new Forest(0, Forest.Kind.PLAIN); + forestZones.add(forest); + List occupants = new ArrayList<>(); + Area forestArea = new Area<>(forestZones, occupants, 3); + ZonePartition zonePartition = new ZonePartition<>(Set.of(forestArea)); + ZonePartition.Builder builder = new ZonePartition.Builder<>(zonePartition); + + List newOccupants = new ArrayList<>(List.of(PlayerColor.YELLOW)); + Area newForestArea = new Area<>(forestZones, newOccupants, 3); + + builder.addInitialOccupant(forest, PlayerColor.YELLOW); + Set expectedAreas = new HashSet<>(); + expectedAreas.add(newForestArea); + + assertEquals(expectedAreas, builder.build().areas()); + } + + @Test + void removeOccupantWorks() { + Set forestZones = new HashSet<>(); + Forest forest = new Forest(0, Forest.Kind.PLAIN); + forestZones.add(forest); + List occupants = new ArrayList<>(List.of(PlayerColor.YELLOW)); + Area forestArea = new Area<>(forestZones, occupants, 3); + ZonePartition zonePartition = new ZonePartition<>(Set.of(forestArea)); + ZonePartition.Builder builder = new ZonePartition.Builder<>(zonePartition); + + List newOccupants = new ArrayList<>(); + Area newForestArea = new Area<>(forestZones, newOccupants, 3); + + builder.removeOccupant(forest, PlayerColor.YELLOW); + Set expectedAreas = new HashSet<>(); + expectedAreas.add(newForestArea); + + assertEquals(expectedAreas, builder.build().areas()); + } + + @Test + void removeAllOccupantsOfThrowsOnUnknownArea() { + Set forestZones = new HashSet<>(); + Forest forest = new Forest(0, Forest.Kind.PLAIN); + forestZones.add(forest); + List occupants = new ArrayList<>(List.of(PlayerColor.YELLOW)); + Area forestArea = new Area<>(forestZones, occupants, 3); + + ZonePartition zonePartition = new ZonePartition<>(Set.of(forestArea)); + ZonePartition.Builder builder = new ZonePartition.Builder<>(zonePartition); + + Forest unknownForest = new Forest(1, Forest.Kind.WITH_MENHIR); + Area unknownArea = new Area<>(Set.of(unknownForest), occupants, 2); + + assertThrows(IllegalArgumentException.class, () -> builder.removeAllOccupantsOf(unknownArea)); + } + + @Test + void removeAllOccupantsOfWorks() { + Set forestZones = new HashSet<>(); + Forest forest = new Forest(0, Forest.Kind.PLAIN); + forestZones.add(forest); + List occupants = new ArrayList<>(List.of(PlayerColor.YELLOW, PlayerColor.GREEN)); + Area forestArea = new Area<>(forestZones, occupants, 3); + ZonePartition zonePartition = new ZonePartition<>(Set.of(forestArea)); + ZonePartition.Builder builder = new ZonePartition.Builder<>(zonePartition); + + List newOccupants = new ArrayList<>(); + Area newForestArea = new Area<>(forestZones, newOccupants, 3); + + builder.removeAllOccupantsOf(forestArea); + Set expectedAreas = new HashSet<>(); + expectedAreas.add(newForestArea); + + assertEquals(expectedAreas, builder.build().areas()); + } + @Test + void unionWorksWithDifferentAreas() { + Set forestZones1 = new HashSet<>(); + Forest forest1 = new Forest(0, Forest.Kind.PLAIN); + forestZones1.add(forest1); + List occupants1 = new ArrayList<>(List.of(PlayerColor.YELLOW)); + Area forestArea1 = new Area<>(forestZones1, occupants1, 3); + + Set forestZones2 = new HashSet<>(); + Forest forest2 = new Forest(1, Forest.Kind.WITH_MENHIR); + forestZones2.add(forest2); + List occupants2 = new ArrayList<>(List.of(PlayerColor.RED)); + Area forestArea2 = new Area<>(forestZones2, occupants2, 3); + + ZonePartition zonePartition = new ZonePartition<>(Set.of(forestArea1, forestArea2)); + ZonePartition.Builder builder = new ZonePartition.Builder<>(zonePartition); + + Set expectedForestZones = new HashSet<>(); + expectedForestZones.add(forest1); + expectedForestZones.add(forest2); + List expectedOccupants = new ArrayList<>(); + expectedOccupants.add(PlayerColor.YELLOW); + expectedOccupants.add(PlayerColor.RED); + Area expectedArea = new Area<>(expectedForestZones, expectedOccupants, 4); + + builder.union(forest1, forest2); + + assertEquals(Set.of(expectedArea), builder.build().areas()); + } + +}