Skip to content

Commit

Permalink
Bugfix text maker not filtering tigers and WIP
Browse files Browse the repository at this point in the history
  • Loading branch information
Max committed Apr 23, 2024
1 parent 1da598e commit 54ffba8
Show file tree
Hide file tree
Showing 8 changed files with 219 additions and 10 deletions.
2 changes: 1 addition & 1 deletion resources/decks.css
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@
}

#next-tile {
-fx-padding: 3;
-fx-padding: 0 0 5 0;
}

#next-tile Text {
Expand Down
2 changes: 2 additions & 0 deletions src/ch/epfl/chacun/TextMakerFr.java
Original file line number Diff line number Diff line change
Expand Up @@ -116,6 +116,8 @@ private String joinPlayerNames(Set<PlayerColor> playerColors) {
*/
private String joinAnimalsWithQuantities(Map<Animal.Kind, Integer> animals) {
return humanizedJoin(animals.entrySet().stream()
// Tigers should never be mentioned since their only purpose is to eat deer
.filter(entry -> entry.getKey() != Animal.Kind.TIGER)
.sorted(Map.Entry.comparingByKey())
.map(e -> accord(animalNames.get(e.getKey()), e.getValue()))
.toList());
Expand Down
11 changes: 5 additions & 6 deletions src/ch/epfl/chacun/gui/BoardUI.java
Original file line number Diff line number Diff line change
Expand Up @@ -17,8 +17,7 @@
import java.util.Set;
import java.util.function.Consumer;

import static ch.epfl.chacun.gui.ImageLoader.MARKER_PIXEL_SIZE;
import static ch.epfl.chacun.gui.ImageLoader.NORMAL_TILE_FIT_SIZE;
import static ch.epfl.chacun.gui.ImageLoader.*;

/**
* Helper class to display the board.
Expand Down Expand Up @@ -81,7 +80,7 @@ public static Node create(int reach, ObservableValue<GameState> gameStateO, Obse
// Handle tile rotation and placement
tileContainer.setOnMouseClicked(event -> {
// Prevent the player from interacting with the tile when it has been placed
if (placedTileO.getValue() != null) {
if (placedTileO.getValue() == null) {
// Rotate the tile
if (event.getButton() == MouseButton.SECONDARY) {
// Allow for clockwise and counter-clockwise rotation using the ALT key
Expand All @@ -102,10 +101,10 @@ public static Node create(int reach, ObservableValue<GameState> gameStateO, Obse
for (Animal animal : meadowZone.animals()) {
ImageView markerView = new ImageView();
// Style the marker
markerView.setFitHeight(MARKER_PIXEL_SIZE);
markerView.setFitWidth(MARKER_PIXEL_SIZE);
markerView.setFitHeight(MARKER_FIT_SIZE);
markerView.setFitWidth(MARKER_FIT_SIZE);
markerView.getStyleClass().add("marker");
markerView.setId(STR."marker_\{animal.tileId()}");
markerView.setId(STR."marker_\{animal.id()}");
// Hide the marker when not needed
ObservableValue<Boolean> isCancelledO = gameStateO
.map(gameState -> gameState.board().cancelledAnimals().contains(animal));
Expand Down
208 changes: 208 additions & 0 deletions src/ch/epfl/chacun/gui/ChaCuNUITest.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,208 @@
package ch.epfl.chacun.gui;

import ch.epfl.chacun.*;
import ch.epfl.chacun.tile.Tiles;
import javafx.application.Application;
import javafx.beans.property.SimpleObjectProperty;
import javafx.scene.Scene;
import javafx.scene.control.ScrollPane;
import javafx.scene.layout.BorderPane;
import javafx.scene.layout.HBox;
import javafx.scene.layout.Priority;
import javafx.scene.layout.VBox;
import javafx.stage.Stage;

import java.util.*;
import java.util.function.Function;
import java.util.stream.Collectors;
import java.util.stream.Stream;

public final class ChaCuNUITest extends Application {
public static void main(String[] args) { launch(args); }

@Override
public void start(Stage primaryStage) throws InterruptedException {
var playerNames = Map.of(PlayerColor.BLUE, "Bernard", PlayerColor.RED, "Rose",
PlayerColor.GREEN, "Balthazar", PlayerColor.YELLOW, "Max"
);
var playerColors = playerNames.keySet().stream()
.sorted()
.toList();

var tilesByKind = Tiles.TILES.stream()
.collect(Collectors.groupingBy(Tile::kind));
var tileDecks =
new TileDecks(tilesByKind.get(Tile.Kind.START),
tilesByKind.get(Tile.Kind.NORMAL),
tilesByKind.get(Tile.Kind.MENHIR));

var tileToPlaceRotationP =
new SimpleObjectProperty<>(Rotation.NONE);
var visibleOccupantsP =
new SimpleObjectProperty<>(Set.<Occupant>of());
var highlightedTilesP =
new SimpleObjectProperty<>(Set.<Integer>of());

var textMaker = new TextMakerFr(playerNames);
var positions = Map.ofEntries(
Map.entry(34, new Pos(-3, -1)),
Map.entry(67, new Pos(-2, -1)),
Map.entry(31, new Pos(-1, -1)),
Map.entry(61, new Pos(0, -1)),
Map.entry(62, new Pos(-3, 0)),
Map.entry(18, new Pos(-2, 0)),
Map.entry(51, new Pos(-1, 0)),
Map.entry(1, new Pos(-3, 1)),
Map.entry(3, new Pos(-2, 1)),
Map.entry(49, new Pos(-1, 1)),
Map.entry(55, new Pos(0, 1)));

var occupants = Map.of(
61, new Occupant(Occupant.Kind.PAWN, 61_0), // hunter (RED)
55, new Occupant(Occupant.Kind.PAWN, 55_3), // fisher (BLUE)
51, new Occupant(Occupant.Kind.PAWN, 51_1), // fisher (GREEN)
18, new Occupant(Occupant.Kind.PAWN, 18_2), // hunter (YELLOW)
1, new Occupant(Occupant.Kind.HUT, 1_8), // fisher's hut (RED)
34, new Occupant(Occupant.Kind.PAWN, 34_1), // hunter (BLUE)
3, new Occupant(Occupant.Kind.PAWN, 3_5), // fisher (PURPLE)
49, new Occupant(Occupant.Kind.PAWN, 49_2) // hunter (RED)
);

var unoccupyableTiles = Set.of(62);
var normalTilesIds = List.of(61, 55, 51, 18, 62, 1, 34, 67, 31, 3, 49);
var gameStateO = new SimpleObjectProperty<>(initialGameState(playerNames, normalTilesIds, List.of()));
var playersNode = PlayersUI.create(gameStateO, textMaker);
var messagesNode = MessageBoardUI.create(gameStateO.map(g -> g.messageBoard().messages()), new SimpleObjectProperty<>(Set.of()));
var decksNode = DecksUI.create(gameStateO.map(GameState::tileToPlace), gameStateO.map(g -> g.tileDecks().normalTiles().size()), gameStateO.map(g -> g.tileDecks().menhirTiles().size()), new SimpleObjectProperty<>(""), o -> {});
var boardNode = (ScrollPane)BoardUI
.create(Board.REACH,
gameStateO,
tileToPlaceRotationP,
visibleOccupantsP,
highlightedTilesP,
r -> System.out.println("Rotate: " + r),
t -> System.out.println("Place: " + t),
o -> System.out.println("Select: " + o));

var sideBar = new VBox(playersNode, messagesNode, decksNode);
VBox.setVgrow(messagesNode, Priority.ALWAYS);

boardNode.setFitToHeight(true);
boardNode.setFitToWidth(true);
boardNode.setMinWidth(720);
boardNode.maxHeightProperty().bind(primaryStage.heightProperty());
boardNode.maxWidthProperty().bind(primaryStage.widthProperty().map(w -> w.doubleValue() - sideBar.getWidth()));
boardNode.setHvalue(.5);
boardNode.setVvalue(.5);

var rootNode= new HBox(boardNode, sideBar);
HBox.setHgrow(sideBar, Priority.NEVER);
HBox.setHgrow(boardNode, Priority.ALWAYS);
primaryStage.setScene(new Scene(rootNode));

primaryStage.setTitle("ChaCuN test");
primaryStage.show();

gameStateO.setValue(truncateDeck(gameStateO.getValue(), Tile.Kind.NORMAL, normalTilesIds.size() - 1));

var players = gameStateO.getValue().players();
var playersIt = Stream.generate(() -> players)
.flatMap(Collection::stream)
.iterator();

var nextPlacedTile = (Function<GameState, PlacedTile>) s -> {
var t = s.tileToPlace();
return new PlacedTile(t, playersIt.next(), Rotation.NONE, positions.get(t.id()));
};

// Place all tiles
for (int i = 0; i < positions.size() - 1; i += 1) {
var placedTile = nextPlacedTile.apply(gameStateO.getValue());
gameStateO.setValue(gameStateO.getValue().withPlacedTile(placedTile));
if (!unoccupyableTiles.contains(placedTile.id())) {
gameStateO.setValue(gameStateO.getValue().withNewOccupant(occupants.get(placedTile.id())));
visibleOccupantsP.set(gameStateO.get().board().occupants());
}
}
}

private static GameState initialGameState(Map<PlayerColor, String> players,
List<Integer> firstNormalTiles,
List<Integer> firstMenhirTiles) {
var tileDecks = tileDecks(firstNormalTiles, firstMenhirTiles);

var startingTile = tileDecks.topTile(Tile.Kind.START);
var firstTileToPlace = tileDecks.topTile(Tile.Kind.NORMAL);
var tileDecks1 = tileDecks
.withTopTileDrawn(Tile.Kind.START)
.withTopTileDrawn(Tile.Kind.NORMAL);
var placedStartingTile = new PlacedTile(startingTile, null, Rotation.NONE, Pos.ORIGIN);
var board = Board.EMPTY.withNewTile(placedStartingTile);
var messageBoard = new MessageBoard(new TextMakerFr(players), List.of());
return new GameState(List.copyOf(players.keySet()), tileDecks1, firstTileToPlace, board, GameState.Action.PLACE_TILE, messageBoard);
}

private static GameState truncateDeck(GameState state, Tile.Kind deckKind, int deckSize) {
var decks1 = switch (state.tileDecks()) {
case TileDecks(List<Tile> s, List<Tile> n, List<Tile> m) when deckKind == Tile.Kind.NORMAL ->
new TileDecks(s, n.subList(0, deckSize), m);
case TileDecks(List<Tile> s, List<Tile> n, List<Tile> m) when deckKind == Tile.Kind.MENHIR ->
new TileDecks(s, n, m.subList(0, deckSize));
default -> throw new Error("cannot truncate that deck");
};
return new GameState(
state.players(),
decks1,
state.tileToPlace(),
state.board(),
state.nextAction(),
state.messageBoard());
}

private static TileDecks shuffledTileDecks() {
return shuffledTileDecks(2024);
}

private static TileDecks shuffledTileDecks(long shufflingSeed) {
var tileDecks = tileDecks(List.of(), List.of());
var random = new Random(shufflingSeed);

var shuffledNormalTiles = new ArrayList<>(tileDecks.normalTiles());
Collections.shuffle(shuffledNormalTiles, random);

var shuffledMenhirTiles = new ArrayList<>(tileDecks.menhirTiles());
Collections.shuffle(shuffledMenhirTiles, random);

return new TileDecks(
tileDecks.startTiles(),
List.copyOf(shuffledNormalTiles),
List.copyOf(shuffledMenhirTiles));
}

private static TileDecks tileDecks(List<Integer> firstNormalTiles, List<Integer> firstMenhirTiles) {
var partitionedTiles = Tiles.TILES.stream()
.collect(Collectors.groupingBy(Tile::kind));

var normalTiles = moveTilesToFront(partitionedTiles.get(Tile.Kind.NORMAL), firstNormalTiles);
var menhirTiles = moveTilesToFront(partitionedTiles.get(Tile.Kind.MENHIR), firstMenhirTiles);

return new TileDecks(
List.copyOf(partitionedTiles.get(Tile.Kind.START)),
List.copyOf(normalTiles),
List.copyOf(menhirTiles));
}

private static List<Tile> moveTilesToFront(List<Tile> tiles, List<Integer> tileIds) {
var reorderedTiles = new ArrayList<Tile>(Collections.nCopies(tileIds.size(), null));
for (var t : tiles) {
var i = tileIds.indexOf(t.id());
if (i == -1)
reorderedTiles.add(t);
else {
var oldTile = reorderedTiles.set(i, t);
assert oldTile == null;
}
}
return List.copyOf(reorderedTiles);
}
}
1 change: 0 additions & 1 deletion src/ch/epfl/chacun/gui/DecksUI.java
Original file line number Diff line number Diff line change
Expand Up @@ -80,7 +80,6 @@ private static StackPane createDeckCover(Tile.Kind kind, ObservableValue<Integer
view.setId(kind.toString());
// Configure the text
tileCount.textProperty().bind(sizeO.map(String::valueOf));
tileCount.visibleProperty().bind(sizeO.map(size -> size > 0));
tileCount.setWrappingWidth(TILE_COUNT_WRAPPING_FACTOR * NORMAL_TILE_FIT_SIZE);

return new StackPane(view, tileCount);
Expand Down
2 changes: 1 addition & 1 deletion src/ch/epfl/chacun/gui/ImageLoader.java
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ public final class ImageLoader {
/**
* Display size of the marker, in pixels.
*/
public final int MARKER_FIT_SIZE = 48;
public static final int MARKER_FIT_SIZE = 48;

/**
* Non-instantiable class constructor
Expand Down
1 change: 1 addition & 0 deletions src/ch/epfl/chacun/gui/PlayersUI.java
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
import javafx.beans.value.ObservableValue;
import javafx.scene.Node;
import javafx.scene.layout.HBox;
import javafx.scene.layout.Priority;
import javafx.scene.layout.VBox;
import javafx.scene.shape.Circle;
import javafx.scene.text.Text;
Expand Down
2 changes: 1 addition & 1 deletion src/ch/epfl/chacun/gui/PlayersUITest.java
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,7 @@ public void start(Stage primaryStage) throws InterruptedException {
var gameStateO = new SimpleObjectProperty<>(initialGameState(playerNames, normalTilesIds, List.of()));
var playersNode = PlayersUI.create(gameStateO, textMaker);
var messagesNode = MessageBoardUI.create(gameStateO.map(g -> g.messageBoard().messages()), new SimpleObjectProperty<>(Set.of()));
var decksNode = DecksUI.create(new SimpleObjectProperty<>(gameStateO.getValue().tileToPlace()), new SimpleObjectProperty<>(normalTilesIds.size()), new SimpleObjectProperty<>(0), new SimpleObjectProperty<>("Lorem ipsum dolor sit amet"), o -> {});
var decksNode = DecksUI.create(gameStateO.map(GameState::tileToPlace), gameStateO.map(g -> g.tileDecks().normalTiles().size()), gameStateO.map(g -> g.tileDecks().menhirTiles().size()), new SimpleObjectProperty<>(""), o -> {});
var rootNode = new VBox(playersNode, messagesNode, decksNode);
primaryStage.setScene(new Scene(rootNode, 271, 720));

Expand Down

0 comments on commit 54ffba8

Please sign in to comment.