From 842db2439ac26d86528c77519456b7df537abbf5 Mon Sep 17 00:00:00 2001 From: punchready Date: Tue, 1 Jun 2021 15:43:04 +0200 Subject: [PATCH] breaking: remove observable pattern, make methods return events directly --- .../marvelous/gamelibrary/entities/NPC.java | 9 ++++ .../gamelibrary/gamelogic/EntityManager.java | 2 +- .../gamelibrary/gamelogic/GameInstance.java | 53 ++++++------------- .../gamelibrary/gamelogic/GameLogic.java | 51 ++++++++++++------ .../gamelogic/GameStateManager.java | 21 ++++---- .../gamelibrary/gamelogic/GameLogicTest.java | 48 ++++++++--------- 6 files changed, 92 insertions(+), 92 deletions(-) diff --git a/src/main/java/uulm/teamname/marvelous/gamelibrary/entities/NPC.java b/src/main/java/uulm/teamname/marvelous/gamelibrary/entities/NPC.java index 55238ae..15b784b 100644 --- a/src/main/java/uulm/teamname/marvelous/gamelibrary/entities/NPC.java +++ b/src/main/java/uulm/teamname/marvelous/gamelibrary/entities/NPC.java @@ -64,4 +64,13 @@ public class NPC extends Entity { } return clone; } + + @Override + public String toString() { + return "NPC{" + + "mp=" + mp + + ", inventory=" + inventory + + ", position=" + position + + '}'; + } } diff --git a/src/main/java/uulm/teamname/marvelous/gamelibrary/gamelogic/EntityManager.java b/src/main/java/uulm/teamname/marvelous/gamelibrary/gamelogic/EntityManager.java index 2178435..2799e74 100644 --- a/src/main/java/uulm/teamname/marvelous/gamelibrary/gamelogic/EntityManager.java +++ b/src/main/java/uulm/teamname/marvelous/gamelibrary/gamelogic/EntityManager.java @@ -167,6 +167,6 @@ public class EntityManager { * @return An array containing every {@link Entity} */ Entity[] export() { - return (Entity[])entities.toArray(); + return entities.toArray(new Entity[0]); } } diff --git a/src/main/java/uulm/teamname/marvelous/gamelibrary/gamelogic/GameInstance.java b/src/main/java/uulm/teamname/marvelous/gamelibrary/gamelogic/GameInstance.java index bfe99ce..e93bd0d 100644 --- a/src/main/java/uulm/teamname/marvelous/gamelibrary/gamelogic/GameInstance.java +++ b/src/main/java/uulm/teamname/marvelous/gamelibrary/gamelogic/GameInstance.java @@ -8,7 +8,6 @@ import uulm.teamname.marvelous.gamelibrary.json.config.ScenarioConfig; import uulm.teamname.marvelous.gamelibrary.requests.Request; import java.util.ArrayList; -import java.util.Observer; /** Represents a game instance. */ public class GameInstance { @@ -21,9 +20,6 @@ public class GameInstance { /** The {@link GameStateManager} managing the {@link GameState} of the instance */ private final GameStateManager manager; - /** The {@link EventEmitter} for {@link Event}s resulting from {@link Request}s */ - private final EventEmitter emitter = new EventEmitter(); - /** Constructs a new {@link GameInstance}. */ public GameInstance(PartyConfig partyConfig, CharacterConfig characterConfig, ScenarioConfig scenarioConfig) { _state = new GameState(partyConfig, characterConfig, scenarioConfig); @@ -34,20 +30,16 @@ public class GameInstance { /** * Checks an array of {@link Request}s for validity and automatically applies them if valid. * @param requests The requests to check - * @return Whether or not the given set of requests was valid + * @return The list of resulting {@link Event}s or `null` if the check failed */ - public boolean checkRequestsAndApply(Request... requests) { + public ArrayList checkRequestsAndApply(Request... requests) { if(manager.processRequests(requests, true)) { - emit(manager.apply()); - - Event[] result = manager.checkPostPhase(); - if(result.length > 0) { - emit(result); - } - - return true; + ArrayList result = manager.apply(); + result.addAll(manager.checkPostPhase()); + return result; } - return false; + + return null; } /** @@ -55,7 +47,7 @@ public class GameInstance { * @param requests The requests to check * @return Whether or not the given set of requests is valid */ - public boolean checkRequestsSilent(Request... requests) { + public boolean checkRequests(Request... requests) { return manager.processRequests(requests, false); } @@ -63,10 +55,14 @@ public class GameInstance { * Initializes and starts the game. Selected characters are given as a list of indices from the {@link CharacterConfig#characters} array. * @param selectedCharacters1 The characters selected by player 1 * @param selectedCharacters2 The characters selected by player 2 + * @return The list of resulting {@link Event}s */ - public void startGame(ArrayList selectedCharacters1, ArrayList selectedCharacters2) { - emit(manager.initGame(selectedCharacters1, selectedCharacters2)); - emit(manager.startGame()); + public ArrayList startGame(ArrayList selectedCharacters1, ArrayList selectedCharacters2) { + ArrayList result = manager.initGame(selectedCharacters1, selectedCharacters2); + manager.applyEvents(result); + result.addAll(manager.startGame()); + + return result; } /** @@ -89,24 +85,7 @@ public class GameInstance { * Applies an array of {@link Event}s to the game state. * @param events The events to apply. */ - public void applyEvents(Event... events) { + public void applyEvents(ArrayList events) { manager.applyEvents(events); } - - /** - * Adds an {@link Observer} for events. - * @param observer The observer to add - */ - public void addObserver(Observer observer) { - emitter.addObserver(observer); - } - - /** - * Instructs the emitter to emit an array of {@link Event}s. - * @param events The events to emit - */ - private void emit(Event... events) { - manager.applyEvents(events); - emitter.update(events); - } } diff --git a/src/main/java/uulm/teamname/marvelous/gamelibrary/gamelogic/GameLogic.java b/src/main/java/uulm/teamname/marvelous/gamelibrary/gamelogic/GameLogic.java index f3e6b36..e690445 100644 --- a/src/main/java/uulm/teamname/marvelous/gamelibrary/gamelogic/GameLogic.java +++ b/src/main/java/uulm/teamname/marvelous/gamelibrary/gamelogic/GameLogic.java @@ -188,7 +188,7 @@ class GameLogic { public static Event buildGameStateEvent(GameState state) { return new EventBuilder(EventType.GamestateEvent) .withEntities(state.entities.export()) - .withTurnOrder((EntityID[])state.turnOrder.toArray()) + .withTurnOrder(state.turnOrder.toArray(new EntityID[0])) .withMapSize(state.mapSize) .withActiveCharacter(state.activeCharacter) .withStoneCooldowns(state.stoneCooldown.export()) @@ -562,9 +562,7 @@ class GameLogic { for(int x = 0; x < state.mapSize.getX(); x++) { for(int y = 0; y < state.mapSize.getY(); y++) { if(state.scenarioConfig.scenario[y][x] == FieldType.ROCK) { - result.add(new EventBuilder(EventType.SpawnEntityEvent) - .withEntity(new Rock(new EntityID(EntityType.Rocks, rockIndex++), new IntVector2(x, y), 100)) - .buildEntityEvent()); + state.entities.addEntity(new Rock(new EntityID(EntityType.Rocks, rockIndex++), new IntVector2(x, y), 100)); }else { free.add(new IntVector2(x, y)); } @@ -585,22 +583,22 @@ class GameLogic { int selected = characters.get(i); EntityID id = new EntityID(i < p1 ? EntityType.P1 : EntityType.P2, i % p1); - result.add(new EventBuilder(EventType.SpawnEntityEvent) - .withEntity(new Character( - id, position, - state.characterConfig.characters[selected].name, - state.characterConfig.characters[selected].HP, - state.characterConfig.characters[selected].MP, - state.characterConfig.characters[selected].AP, - state.characterConfig.characters[selected].attackRange, - state.characterConfig.characters[selected].rangedDamage, - state.characterConfig.characters[selected].meleeDamage - )) - .buildEntityEvent()); + state.entities.addEntity(new Character( + id, position, + state.characterConfig.characters[selected].name, + state.characterConfig.characters[selected].HP, + state.characterConfig.characters[selected].MP, + state.characterConfig.characters[selected].AP, + state.characterConfig.characters[selected].attackRange, + state.characterConfig.characters[selected].rangedDamage, + state.characterConfig.characters[selected].meleeDamage + )); state.turnOrder.add(id); } + result.add(buildGameStateEvent(state)); + return result; } @@ -849,7 +847,28 @@ class GameLogic { public static ArrayList handleThanos(GameState state, NPC thanos) { ArrayList result = new ArrayList<>(); + if(thanos.inventory.getFreeSlots() > 0) { + IntVector2 picked = null; + float lowestDistance = Integer.MAX_VALUE; + for(int x = 0; x < state.mapSize.getX(); x++) { + for(int y = 0; y < state.mapSize.getY(); y++) { + IntVector2 pos = new IntVector2(x, y); + for(Entity e: state.entities.findByPosition(pos)) { + if(e instanceof InfinityStone || (e instanceof Character && ((Character)e).inventory.getSize() > 0)) { + float distance = thanos.getPosition().distanceChebyshev(pos); + if(distance < lowestDistance) { + picked = pos; + lowestDistance = distance; + break; + } + } + } + } + } + // + + } return result; } diff --git a/src/main/java/uulm/teamname/marvelous/gamelibrary/gamelogic/GameStateManager.java b/src/main/java/uulm/teamname/marvelous/gamelibrary/gamelogic/GameStateManager.java index 72cab13..394b11b 100644 --- a/src/main/java/uulm/teamname/marvelous/gamelibrary/gamelogic/GameStateManager.java +++ b/src/main/java/uulm/teamname/marvelous/gamelibrary/gamelogic/GameStateManager.java @@ -49,8 +49,8 @@ class GameStateManager { * Handles events that happen after a turn phase. * @return The optionally resulting {@link Event}s */ - public Event[] checkPostPhase() { - return (Event[])GameLogic.checkTurnEnd(state).toArray(); + public ArrayList checkPostPhase() { + return GameLogic.checkTurnEnd(state); } /** @@ -59,23 +59,23 @@ class GameStateManager { * @param selectedCharacters2 The characters selected by player 2 * @return The resulting {@link Event}s */ - public Event[] initGame(ArrayList selectedCharacters1, ArrayList selectedCharacters2) { - return GameLogic.startGame(state, selectedCharacters1, selectedCharacters2).toArray(new Event[0]); + public ArrayList initGame(ArrayList selectedCharacters1, ArrayList selectedCharacters2) { + return GameLogic.startGame(state, selectedCharacters1, selectedCharacters2); } /** * Starts the game. * @return The resulting {@link Event}s */ - public Event[] startGame() { - return GameLogic.handleRoundStart(state).toArray(new Event[0]); + public ArrayList startGame() { + return GameLogic.handleRoundStart(state); } /** * Applies an array of {@link Event}s to the game state. * @param events The events to apply */ - public void applyEvents(Event... events) { + public void applyEvents(ArrayList events) { for(Event event: events) { GameLogic.applyEvent(state, event); } @@ -85,13 +85,12 @@ class GameStateManager { * Applies the result of the last processRequests call. * @return A list of applied events */ - public Event[] apply() { - Event[] toReturn = new Event[queue.size()]; + public ArrayList apply() { + ArrayList toReturn = new ArrayList(queue.size()); Event current; - int i = 0; while ((current = queue.poll()) != null) { GameLogic.applyEvent(state, current); - toReturn[i++] = current; + toReturn.add(current); } return toReturn; } diff --git a/src/test/java/uulm/teamname/marvelous/gamelibrary/gamelogic/GameLogicTest.java b/src/test/java/uulm/teamname/marvelous/gamelibrary/gamelogic/GameLogicTest.java index ee229e3..0670465 100644 --- a/src/test/java/uulm/teamname/marvelous/gamelibrary/gamelogic/GameLogicTest.java +++ b/src/test/java/uulm/teamname/marvelous/gamelibrary/gamelogic/GameLogicTest.java @@ -7,6 +7,8 @@ import uulm.teamname.marvelous.gamelibrary.IntVector2; import uulm.teamname.marvelous.gamelibrary.entities.*; import uulm.teamname.marvelous.gamelibrary.entities.Character; import uulm.teamname.marvelous.gamelibrary.events.Event; +import uulm.teamname.marvelous.gamelibrary.events.EventBuilder; +import uulm.teamname.marvelous.gamelibrary.events.EventType; import uulm.teamname.marvelous.gamelibrary.json.config.*; import uulm.teamname.marvelous.gamelibrary.requests.*; @@ -16,6 +18,7 @@ import java.util.List; import java.util.concurrent.ThreadLocalRandom; import static org.junit.jupiter.api.Assertions.*; +import static org.mockito.Mockito.*; class GameLogicTest { private static final Iterator randomIntegers = ThreadLocalRandom.current().ints().iterator(); @@ -24,6 +27,9 @@ class GameLogicTest { private static CharacterConfig characterConfig; private static ScenarioConfig scenarioConfig; + private static ArrayList player1Selection = new ArrayList<>(); + private static ArrayList player2Selection = new ArrayList<>(); + @BeforeAll static void setUp() { partyConfig = new PartyConfig(); @@ -55,6 +61,14 @@ class GameLogicTest { } } } + + for(int i = 0; i < 6; i++) { + player1Selection.add(i); + } + + for(int i = 6; i < 12; i++) { + player2Selection.add(i); + } } private static String generateName(int length) { @@ -87,16 +101,7 @@ class GameLogicTest { void testGeneration() { GameInstance game = new GameInstance(partyConfig, characterConfig, scenarioConfig); - ArrayList selected1 = new ArrayList<>(); - for(int i = 0; i < 6; i++) { - selected1.add(i); - } - ArrayList selected2 = new ArrayList<>(); - for(int i = 6; i < 12; i++) { - selected2.add(i); - } - - game.startGame(selected1, selected2); + game.startGame(player1Selection, player2Selection); int n = 0; @@ -114,7 +119,7 @@ class GameLogicTest { n = 0; - for(Integer i: selected1) { + for(Integer i: player1Selection) { Entity found = game.state.getEntities().findEntity(new EntityID(EntityType.P1, n)); assertNotEquals(null, found, "Character Entity "+n+" for Player 1 should exist"); Character c = (Character)found; @@ -129,7 +134,7 @@ class GameLogicTest { n = 0; - for(Integer i: selected2) { + for(Integer i: player2Selection) { Entity found = game.state.getEntities().findEntity(new EntityID(EntityType.P2, n)); assertNotEquals(null, found, "Character Entity "+n+" for Player 2 should exist"); Character c = (Character)found; @@ -165,26 +170,15 @@ class GameLogicTest { void testGame() { GameInstance game = new GameInstance(partyConfig, characterConfig, scenarioConfig); - game.addObserver(new EventObserver() { - @Override - protected void handle(Event[] events) { + ArrayList result = game.startGame(player1Selection, player2Selection); - } - }); + assertTrue(result.size() > 0, "Start game should return at least one event"); - ArrayList selected1 = new ArrayList<>(); - for(int i = 0; i < 6; i++) { - selected1.add(i); - } - ArrayList selected2 = new ArrayList<>(); - for(int i = 6; i < 12; i++) { - selected2.add(i); - } + Event actual = result.get(0); - game.startGame(selected1, selected2); + assertEquals(EventType.GamestateEvent, actual.type, "First event should be a GameStateEvent"); } - // @Provide("gamestate") // Arbitrary gamestate() { // var states = Arbitraries.integers()