From 220022277daee0f8ac2e97d1b29a1c52caf3b901 Mon Sep 17 00:00:00 2001 From: Max Date: Mon, 6 May 2024 16:56:29 +0200 Subject: [PATCH] Game logic WIP --- src/ch/epfl/chacun/gui/BoardUI.java | 2 +- src/ch/epfl/chacun/gui/Main.java | 127 +++++++++++++++++++++++++--- 2 files changed, 117 insertions(+), 12 deletions(-) diff --git a/src/ch/epfl/chacun/gui/BoardUI.java b/src/ch/epfl/chacun/gui/BoardUI.java index f44401a..17e7e1b 100644 --- a/src/ch/epfl/chacun/gui/BoardUI.java +++ b/src/ch/epfl/chacun/gui/BoardUI.java @@ -108,7 +108,7 @@ public static Node create(int reach, ObservableValue gameStateO, if (event.getButton() == MouseButton.SECONDARY) { // Allow for clockwise and counter-clockwise rotation using the ALT key Rotation rotationToAdd = event.isAltDown() ? Rotation.RIGHT : Rotation.LEFT; - rotationToApply.accept(rotationO.getValue().add(rotationToAdd)); + rotationToApply.accept(rotationToAdd); } // Place the tile if (event.getButton() == MouseButton.PRIMARY) { diff --git a/src/ch/epfl/chacun/gui/Main.java b/src/ch/epfl/chacun/gui/Main.java index 2cd70a5..cdf9113 100644 --- a/src/ch/epfl/chacun/gui/Main.java +++ b/src/ch/epfl/chacun/gui/Main.java @@ -2,12 +2,16 @@ import ch.epfl.chacun.*; import javafx.application.Application; +import javafx.beans.property.SimpleObjectProperty; +import javafx.beans.value.ObservableValue; +import javafx.scene.Node; +import javafx.scene.Scene; +import javafx.scene.layout.BorderPane; +import javafx.scene.layout.VBox; import javafx.stage.Stage; -import java.util.ArrayList; -import java.util.Collections; -import java.util.List; -import java.util.Map; +import java.util.*; +import java.util.function.Consumer; import java.util.random.RandomGenerator; import java.util.random.RandomGeneratorFactory; import java.util.stream.Collectors; @@ -19,6 +23,9 @@ */ public class Main extends Application { + private static final int INITIAL_WIDTH = 1440; + private static final int INITIAL_HEIGHT = 1080; + public static void main(String[] args) { launch(args); } @@ -27,22 +34,120 @@ public static void main(String[] args) { public void start(Stage primaryStage) throws Exception { Parameters params = getParameters(); List playerNames = params.getUnnamed(); - String rawSeed = params.getNamed().get("seed"); + // Check if the number of players is valid Preconditions.checkArgument(playerNames.size() >= 2 && playerNames.size() <= 5); + // Create the player map + List playerColors = PlayerColor.ALL.subList(0, playerNames.size()); + Map players = new HashMap<>(); + for (int i = 0; i < playerNames.size(); ++i) { + players.put(playerColors.get(i), playerNames.get(i)); + } // Apply the seed to ALL tiles - long seed = Long.parseUnsignedLong(rawSeed); - RandomGenerator shuffler = RandomGeneratorFactory.getDefault().create(seed); + String rawSeed = params.getNamed().get("seed"); + RandomGeneratorFactory defaultRandomFactory = RandomGeneratorFactory.getDefault(); + + RandomGenerator shuffler; + if (rawSeed != null) { + long seed = Long.parseUnsignedLong(rawSeed); + shuffler = defaultRandomFactory.create(seed); + } else { + shuffler = defaultRandomFactory.create(); + } + List tiles = new ArrayList<>(Tiles.TILES); Collections.shuffle(tiles, shuffler); // Group tiles by kind to create the decks Map> decks = tiles.stream().collect(Collectors.groupingBy(Tile::kind)); TileDecks tileDecks = new TileDecks(decks); - TextMaker textMaker = new TextMakerFr(Map.of()); - MessageBoard messageBoard = new MessageBoard(textMaker, List.of()); - GameState gameState = new GameState(PlayerColor.ALL.subList(0, playerNames.size()), tileDecks, - null, Board.EMPTY, GameState.Action.START_GAME, messageBoard); + TextMaker textMaker = new TextMakerFr(players); + GameState gameState = GameState.initial(players.keySet().stream().toList(), tileDecks, textMaker); + + SimpleObjectProperty tileToPlaceRotationP = new SimpleObjectProperty<>(Rotation.NONE); + SimpleObjectProperty> visibleOccupantsP = new SimpleObjectProperty<>(Set.of()); + SimpleObjectProperty> highlightedTilesP = new SimpleObjectProperty<>(Set.of()); + SimpleObjectProperty textToDisplayP = new SimpleObjectProperty<>(""); + SimpleObjectProperty> actionsP = new SimpleObjectProperty<>(List.of()); + + SimpleObjectProperty gameStateO = new SimpleObjectProperty<>(gameState); + ObservableValue messageBoardO = gameStateO.map(GameState::messageBoard); + + gameStateO.set(gameState); + gameStateO.set(gameStateO.get().withStartingTilePlaced()); + + Consumer applyRotation = rotation -> { + tileToPlaceRotationP.set(tileToPlaceRotationP.get().add(rotation)); + }; + + Consumer placeTileAtPos = pos -> { + GameState state = gameStateO.get(); + PlacedTile placedTile = new PlacedTile( + state.tileToPlace(), state.currentPlayer(), tileToPlaceRotationP.get(), pos); + + if (state.board().canAddTile(placedTile)) { + ActionEncoder.StateAction stateAction = ActionEncoder.withPLacedTile(gameState, placedTile); + // Add action + List actions = new ArrayList<>(actionsP.get()); + actions.add(stateAction.action()); + actionsP.set(actions); + // Register action + gameStateO.set(stateAction.gameState()); + tileToPlaceRotationP.set(Rotation.NONE); + // Display potential occupants + Set occupantsToDisplay = new HashSet<>(visibleOccupantsP.get()); + occupantsToDisplay.addAll(gameStateO.get().lastTilePotentialOccupants()); + visibleOccupantsP.set(Set.copyOf(occupantsToDisplay)); + textToDisplayP.set(textMaker.clickToOccupy()); + } + }; + + Consumer selectOccupant = occupant -> { + ActionEncoder.StateAction stateAction = ActionEncoder.withNewOccupant(gameState, occupant); + // Add action + List actions = new ArrayList<>(actionsP.get()); + actions.add(stateAction.action()); + actionsP.set(actions); + // Register action + gameStateO.set(stateAction.gameState()); + // Reset properties + visibleOccupantsP.set(gameStateO.get().board().occupants()); + textToDisplayP.set(""); + }; + + Consumer applyAction = action -> { + ActionEncoder.StateAction stateAction = ActionEncoder.decodeAndApply(gameStateO.get(), action); + if (stateAction != null) { + List previousActions = actionsP.get(); + List newActions = new ArrayList<>(previousActions); + newActions.add(action); + actionsP.set(newActions); + } + }; + + + Node boardUI = BoardUI.create(Board.REACH, gameStateO, tileToPlaceRotationP, visibleOccupantsP, highlightedTilesP, applyRotation, placeTileAtPos, selectOccupant); + + Node playersUI = PlayersUI.create(gameStateO, textMaker); + Node messageBoardUI = MessageBoardUI.create(messageBoardO.map(MessageBoard::messages), highlightedTilesP); + + ObservableValue tileToPlaceO = gameStateO.map(GameState::tileToPlace); + ObservableValue decksO = gameStateO.map(GameState::tileDecks); + ObservableValue normalTilesSizeO = decksO.map(gameDecks -> gameDecks.normalTiles().size()); + ObservableValue menhirTilesSizeO = decksO.map(gameDecks -> gameDecks.menhirTiles().size()); + Node decksUI = DecksUI.create(tileToPlaceO, normalTilesSizeO, menhirTilesSizeO, textToDisplayP, selectOccupant); + + Node actionsUI = ActionsUI.create(actionsP, applyAction); + + BorderPane sidePanel = new BorderPane( + messageBoardUI, playersUI, null, new VBox(actionsUI, decksUI), null); + Scene scene = new Scene(new BorderPane(boardUI, null, sidePanel, null, null)); + + primaryStage.setScene(scene); + primaryStage.setWidth(INITIAL_WIDTH); + primaryStage.setHeight(INITIAL_HEIGHT); + primaryStage.setTitle("ChaCuN"); + primaryStage.show(); } }