From 62c9ec2d288994174fd60d60f92a855914f3b033 Mon Sep 17 00:00:00 2001 From: Jonah Bauer Date: Mon, 10 Jan 2022 20:21:30 +0100 Subject: [PATCH] changes to sync --- .../jonahbauer/wizard/core/machine/Game.java | 5 ++++- .../wizard/core/machine/GameState.java | 10 ++++++++++ .../wizard/core/machine/states/GameData.java | 5 +++++ .../wizard/core/machine/states/SyncState.java | 15 ++++++++------- .../core/machine/states/TransientState.java | 4 ++++ .../core/machine/states/round/Dealing.java | 7 ++++--- .../states/round/DeterminingTrump.java | 2 +- .../machine/states/round/StartingRound.java | 12 +++++++----- .../machine/states/round/TrumpDetermined.java | 19 ------------------- .../machine/states/trick/StartingTrick.java | 11 +++++++---- .../states/round/DeterminingTrumpTest.java | 11 ++++++----- .../core/machine/states/round/RoundTest.java | 8 ++++---- 12 files changed, 60 insertions(+), 49 deletions(-) create mode 100644 wizard-core/src/main/java/eu/jonahbauer/wizard/core/machine/states/TransientState.java delete mode 100644 wizard-core/src/main/java/eu/jonahbauer/wizard/core/machine/states/round/TrumpDetermined.java diff --git a/wizard-core/src/main/java/eu/jonahbauer/wizard/core/machine/Game.java b/wizard-core/src/main/java/eu/jonahbauer/wizard/core/machine/Game.java index 10e2e88..30058c1 100644 --- a/wizard-core/src/main/java/eu/jonahbauer/wizard/core/machine/Game.java +++ b/wizard-core/src/main/java/eu/jonahbauer/wizard/core/machine/Game.java @@ -4,6 +4,7 @@ import eu.jonahbauer.wizard.common.machine.TimeoutContext; import eu.jonahbauer.wizard.common.messages.observer.ObserverMessage; import eu.jonahbauer.wizard.common.messages.observer.StateMessage; import eu.jonahbauer.wizard.common.messages.player.PlayerMessage; +import eu.jonahbauer.wizard.core.machine.states.TransientState; import eu.jonahbauer.wizard.core.machine.states.game.Created; import eu.jonahbauer.wizard.core.machine.states.game.Error; import eu.jonahbauer.wizard.core.messages.Observer; @@ -57,7 +58,9 @@ public final class Game extends TimeoutContext { @Override protected void onTransition(GameState from, GameState to) { - notify(new StateMessage(to != null ? Util.toSnakeCase(to.getClass().getSimpleName()) : "null")); + if (!(to instanceof TransientState)) { + notify(new StateMessage(to != null ? Util.toSnakeCase(to.getClass().getSimpleName()) : "null")); + } } @Override diff --git a/wizard-core/src/main/java/eu/jonahbauer/wizard/core/machine/GameState.java b/wizard-core/src/main/java/eu/jonahbauer/wizard/core/machine/GameState.java index ae49259..5722073 100644 --- a/wizard-core/src/main/java/eu/jonahbauer/wizard/core/machine/GameState.java +++ b/wizard-core/src/main/java/eu/jonahbauer/wizard/core/machine/GameState.java @@ -3,12 +3,14 @@ package eu.jonahbauer.wizard.core.machine; import eu.jonahbauer.wizard.common.machine.TimeoutState; import eu.jonahbauer.wizard.common.messages.player.PlayerMessage; import eu.jonahbauer.wizard.core.machine.states.GameData; +import eu.jonahbauer.wizard.core.machine.states.SyncState; import lombok.Getter; import org.jetbrains.annotations.Unmodifiable; import java.util.List; import java.util.Optional; import java.util.UUID; +import java.util.function.Function; import static eu.jonahbauer.wizard.core.machine.states.GameData.CURRENT_PLAYER; import static eu.jonahbauer.wizard.core.machine.states.GameData.PLAYERS; @@ -44,6 +46,14 @@ public abstract class GameState implements TimeoutState { protected final long getSyncTimeout(Game game, boolean absolute) { return (absolute ? System.currentTimeMillis() : 0) + game.getConfig().syncTimeout(); } + + protected final Optional sync(Function state) { + return sync(getData(), state); + } + + protected final Optional sync(GameData data, Function state) { + return Optional.of(new SyncState(data, state)); + } // public Optional onMessage(Game game, UUID player, PlayerMessage message) { diff --git a/wizard-core/src/main/java/eu/jonahbauer/wizard/core/machine/states/GameData.java b/wizard-core/src/main/java/eu/jonahbauer/wizard/core/machine/states/GameData.java index 0a4e2cd..4e221c9 100644 --- a/wizard-core/src/main/java/eu/jonahbauer/wizard/core/machine/states/GameData.java +++ b/wizard-core/src/main/java/eu/jonahbauer/wizard/core/machine/states/GameData.java @@ -205,6 +205,11 @@ public final class GameData { return this; } + public GameData keepAll() { + Arrays.fill(required, true); + return this; + } + /** * Returns {@code this} if this map contains a mapping for each of the specified keys or throws a * {@link NoSuchElementException} otherwise. diff --git a/wizard-core/src/main/java/eu/jonahbauer/wizard/core/machine/states/SyncState.java b/wizard-core/src/main/java/eu/jonahbauer/wizard/core/machine/states/SyncState.java index b706d0a..38126d1 100644 --- a/wizard-core/src/main/java/eu/jonahbauer/wizard/core/machine/states/SyncState.java +++ b/wizard-core/src/main/java/eu/jonahbauer/wizard/core/machine/states/SyncState.java @@ -11,15 +11,18 @@ import java.util.HashSet; import java.util.Optional; import java.util.Set; import java.util.UUID; +import java.util.function.Function; import static eu.jonahbauer.wizard.common.messages.observer.UserInputMessage.Action.SYNC; import static eu.jonahbauer.wizard.core.machine.states.GameData.PLAYERS; -public abstract class SyncState extends GameState { +public final class SyncState extends GameState implements TransientState { private final transient Set ready = new HashSet<>(); + private final Function nextState; - public SyncState(GameData data) { - super(data); + public SyncState(GameData data, Function nextState) { + super(data.keepAll()); + this.nextState = nextState; } @Override @@ -34,7 +37,7 @@ public abstract class SyncState extends GameState { ready.add(player); if (ready.size() == get(PLAYERS).size()) { - return Optional.of(getNextState()); + return Optional.of(nextState.apply(getData())); } else { return Optional.empty(); } @@ -46,8 +49,6 @@ public abstract class SyncState extends GameState { @Override public Optional onTimeout(Game game) { game.notify(new TimeoutMessage()); - return Optional.of(getNextState()); + return Optional.of(nextState.apply(getData())); } - - protected abstract GameState getNextState(); } diff --git a/wizard-core/src/main/java/eu/jonahbauer/wizard/core/machine/states/TransientState.java b/wizard-core/src/main/java/eu/jonahbauer/wizard/core/machine/states/TransientState.java new file mode 100644 index 0000000..277db74 --- /dev/null +++ b/wizard-core/src/main/java/eu/jonahbauer/wizard/core/machine/states/TransientState.java @@ -0,0 +1,4 @@ +package eu.jonahbauer.wizard.core.machine.states; + +public interface TransientState { +} diff --git a/wizard-core/src/main/java/eu/jonahbauer/wizard/core/machine/states/round/Dealing.java b/wizard-core/src/main/java/eu/jonahbauer/wizard/core/machine/states/round/Dealing.java index 7d8bb3f..86d8f7d 100644 --- a/wizard-core/src/main/java/eu/jonahbauer/wizard/core/machine/states/round/Dealing.java +++ b/wizard-core/src/main/java/eu/jonahbauer/wizard/core/machine/states/round/Dealing.java @@ -37,11 +37,12 @@ public final class Dealing extends RoundState { } Card trumpCard = deck.draw(); - return transition(new DeterminingTrump( + return sync( getData().with( HANDS, Map.copyOf(hands), TRUMP_CARD, trumpCard - ) - )); + ), + DeterminingTrump::new + ); } } diff --git a/wizard-core/src/main/java/eu/jonahbauer/wizard/core/machine/states/round/DeterminingTrump.java b/wizard-core/src/main/java/eu/jonahbauer/wizard/core/machine/states/round/DeterminingTrump.java index f4f9e01..05aff71 100644 --- a/wizard-core/src/main/java/eu/jonahbauer/wizard/core/machine/states/round/DeterminingTrump.java +++ b/wizard-core/src/main/java/eu/jonahbauer/wizard/core/machine/states/round/DeterminingTrump.java @@ -103,6 +103,6 @@ public final class DeterminingTrump extends RoundState { } else { game.notify(new TrumpMessage(get(TRUMP_CARD), trumpSuit)); } - return transition(new TrumpDetermined(data)); + return sync(data, Predicting::new); } } diff --git a/wizard-core/src/main/java/eu/jonahbauer/wizard/core/machine/states/round/StartingRound.java b/wizard-core/src/main/java/eu/jonahbauer/wizard/core/machine/states/round/StartingRound.java index a60ca8a..08c3649 100644 --- a/wizard-core/src/main/java/eu/jonahbauer/wizard/core/machine/states/round/StartingRound.java +++ b/wizard-core/src/main/java/eu/jonahbauer/wizard/core/machine/states/round/StartingRound.java @@ -1,17 +1,19 @@ package eu.jonahbauer.wizard.core.machine.states.round; +import eu.jonahbauer.wizard.core.machine.Game; import eu.jonahbauer.wizard.core.machine.GameState; import eu.jonahbauer.wizard.core.machine.states.GameData; -import eu.jonahbauer.wizard.core.machine.states.SyncState; -public final class StartingRound extends SyncState { +import java.util.Optional; + +public final class StartingRound extends RoundState { public StartingRound(GameData data) { - super(RoundState.requirements(data)); + super(data); } @Override - protected GameState getNextState() { - return new Dealing(getData()); + public Optional onEnter(Game context) { + return sync(Dealing::new); } } diff --git a/wizard-core/src/main/java/eu/jonahbauer/wizard/core/machine/states/round/TrumpDetermined.java b/wizard-core/src/main/java/eu/jonahbauer/wizard/core/machine/states/round/TrumpDetermined.java deleted file mode 100644 index efae7a4..0000000 --- a/wizard-core/src/main/java/eu/jonahbauer/wizard/core/machine/states/round/TrumpDetermined.java +++ /dev/null @@ -1,19 +0,0 @@ -package eu.jonahbauer.wizard.core.machine.states.round; - -import eu.jonahbauer.wizard.core.machine.GameState; -import eu.jonahbauer.wizard.core.machine.states.GameData; -import eu.jonahbauer.wizard.core.machine.states.SyncState; - -import static eu.jonahbauer.wizard.core.machine.states.GameData.*; - -public final class TrumpDetermined extends SyncState { - - public TrumpDetermined(GameData data) { - super(RoundState.requirements(data).requireEach(PLAYERS, HANDS).require(PREDICTIONS, TRUMP_SUIT, CURRENT_PLAYER)); - } - - @Override - protected GameState getNextState() { - return new Predicting(getData()); - } -} diff --git a/wizard-core/src/main/java/eu/jonahbauer/wizard/core/machine/states/trick/StartingTrick.java b/wizard-core/src/main/java/eu/jonahbauer/wizard/core/machine/states/trick/StartingTrick.java index 1b75870..48a0e0c 100644 --- a/wizard-core/src/main/java/eu/jonahbauer/wizard/core/machine/states/trick/StartingTrick.java +++ b/wizard-core/src/main/java/eu/jonahbauer/wizard/core/machine/states/trick/StartingTrick.java @@ -1,18 +1,21 @@ package eu.jonahbauer.wizard.core.machine.states.trick; +import eu.jonahbauer.wizard.core.machine.Game; import eu.jonahbauer.wizard.core.machine.GameState; import eu.jonahbauer.wizard.core.machine.states.GameData; import eu.jonahbauer.wizard.core.machine.states.SyncState; import eu.jonahbauer.wizard.core.machine.states.round.RoundState; -public final class StartingTrick extends SyncState { +import java.util.Optional; + +public final class StartingTrick extends TrickState { public StartingTrick(GameData data) { - super(RoundState.requirements(TrickState.requirements(data))); + super(data); } @Override - protected GameState getNextState() { - return new PlayingCard(getData()); + public Optional onEnter(Game context) { + return sync(PlayingCard::new); } } diff --git a/wizard-core/src/test/java/eu/jonahbauer/wizard/core/machine/states/round/DeterminingTrumpTest.java b/wizard-core/src/test/java/eu/jonahbauer/wizard/core/machine/states/round/DeterminingTrumpTest.java index be99ac6..7f85963 100644 --- a/wizard-core/src/test/java/eu/jonahbauer/wizard/core/machine/states/round/DeterminingTrumpTest.java +++ b/wizard-core/src/test/java/eu/jonahbauer/wizard/core/machine/states/round/DeterminingTrumpTest.java @@ -8,6 +8,7 @@ import eu.jonahbauer.wizard.common.model.Card; import eu.jonahbauer.wizard.core.machine.Game; import eu.jonahbauer.wizard.core.machine.MessageQueue; import eu.jonahbauer.wizard.core.machine.states.GameData; +import eu.jonahbauer.wizard.core.machine.states.SyncState; import eu.jonahbauer.wizard.core.machine.states.game.Finished; import eu.jonahbauer.wizard.core.model.GameConfiguration; import eu.jonahbauer.wizard.core.model.Configurations; @@ -38,7 +39,7 @@ public class DeterminingTrumpTest { @SuppressWarnings("SameParameterValue") private Game performTest(GameConfiguration configuration, int round, Map> hands, Card trumpCard, MessageQueue queue) { Game game = spy(new Game(configuration, queue)); - doFinish().when(game).transition(any(TrumpDetermined.class)); + doFinish().when(game).transition(any(SyncState.class)); queue.setGame(game); var playerList = List.of(players); @@ -76,7 +77,7 @@ public class DeterminingTrumpTest { InOrder order = inOrder(game); order.verify(game).notify(any(StateMessage.class)); // determining trump order.verify(game).notify(argThat(msg -> msg instanceof TrumpMessage trump && trump.getCard() == Card.YELLOW_1 && trump.getSuit() == Card.Suit.YELLOW)); - order.verify(game).transition(any(TrumpDetermined.class)); // round is finished + order.verify(game).transition(any(SyncState.class)); // round is finished order.verify(game).notify(any(StateMessage.class)); // finish order.verify(game, never()).notify(any()); order.verify(game, never()).notify(any(), any()); @@ -100,7 +101,7 @@ public class DeterminingTrumpTest { InOrder order = inOrder(game); order.verify(game).notify(any(StateMessage.class)); // determining trump order.verify(game).notify(argThat(msg -> msg instanceof TrumpMessage trump && trump.getCard() == Card.GREEN_JESTER && trump.getSuit() == Card.Suit.NONE)); - order.verify(game).transition(any(TrumpDetermined.class)); + order.verify(game).transition(any(SyncState.class)); order.verify(game).notify(any(StateMessage.class)); // finish order.verify(game, never()).notify(any()); order.verify(game, never()).notify(any(), any()); @@ -127,7 +128,7 @@ public class DeterminingTrumpTest { order.verify(game).notify(argThat(msg -> msg instanceof TrumpMessage trump && trump.getCard() == Card.BLUE_WIZARD && trump.getSuit() == null)); order.verify(game).notify(any(UserInputMessage.class)); // user input request order.verify(game).notify(argThat(msg -> msg instanceof TrumpMessage trump && trump.getCard() == Card.BLUE_WIZARD && trump.getSuit() == Card.Suit.GREEN)); - order.verify(game).transition(any(TrumpDetermined.class)); + order.verify(game).transition(any(SyncState.class)); order.verify(game).notify(any(StateMessage.class)); // finish order.verify(game, never()).notify(any()); order.verify(game, never()).notify(any(), any()); @@ -156,7 +157,7 @@ public class DeterminingTrumpTest { order.verify(game).notify(any(UserInputMessage.class)); // user input request order.verify(game).notify(argThat(msg -> msg instanceof TrumpMessage trump && trump.getCard() == Card.WEREWOLF && trump.getSuit() == Card.Suit.YELLOW)); order.verify(game).notify(eq(players[3]), any(HandMessage.class)); // swap trump card and werewolf - order.verify(game).transition(any(TrumpDetermined.class)); + order.verify(game).transition(any(SyncState.class)); order.verify(game).notify(any(StateMessage.class)); // finish order.verify(game, never()).notify(any()); order.verify(game, never()).notify(any(), any()); diff --git a/wizard-core/src/test/java/eu/jonahbauer/wizard/core/machine/states/round/RoundTest.java b/wizard-core/src/test/java/eu/jonahbauer/wizard/core/machine/states/round/RoundTest.java index 87aab6b..d4e62f6 100644 --- a/wizard-core/src/test/java/eu/jonahbauer/wizard/core/machine/states/round/RoundTest.java +++ b/wizard-core/src/test/java/eu/jonahbauer/wizard/core/machine/states/round/RoundTest.java @@ -55,8 +55,9 @@ public class RoundTest { @Test public void run_Simple() throws ExecutionException, InterruptedException { MessageQueue queue = new MessageQueue() - .sync(players) - .sync(players) + .sync(players) // starting_round + .sync(players) // dealing + .sync(players) // determining_trump .addPrediction(players[3], 3) .addPrediction(players[0], 0) .addPrediction(players[1], 3) @@ -114,7 +115,6 @@ public class RoundTest { order.verify(game, atLeast(4)).notify(any(), any(HandMessage.class)); // hands order.verify(game).notify(any(StateMessage.class)); // determining_trump order.verify(game).notify(any(TrumpMessage.class)); // trump - order.verify(game).notify(any(StateMessage.class)); // trump_determined for (int i = 0; i < players.length; i++) { order.verify(game).notify(any(StateMessage.class)); // predicting order.verify(game).notify(any(UserInputMessage.class)); // user input @@ -148,6 +148,7 @@ public class RoundTest { @Test public void run_Anniversary() throws ExecutionException, InterruptedException { MessageQueue queue = new MessageQueue() + .sync(players) .sync(players) .addPickTrump(players[2], Card.Suit.YELLOW) .sync(players) @@ -242,7 +243,6 @@ public class RoundTest { order.verify(game).notify(any(UserInputMessage.class)); // user input order.verify(game).notify(any(TrumpMessage.class)); // trump order.verify(game).notify(any(), any(HandMessage.class)); // update hand - order.verify(game).notify(any(StateMessage.class)); // trump_determined for (int i = 0; i < players.length; i++) { order.verify(game).notify(any(StateMessage.class)); order.verify(game).notify(any(UserInputMessage.class));