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 05aff71..108e263 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 @@ -1,26 +1,17 @@ package eu.jonahbauer.wizard.core.machine.states.round; -import eu.jonahbauer.wizard.common.messages.observer.TimeoutMessage; import eu.jonahbauer.wizard.common.model.Card; import eu.jonahbauer.wizard.core.machine.states.GameData; import eu.jonahbauer.wizard.core.machine.Game; -import eu.jonahbauer.wizard.common.messages.observer.HandMessage; import eu.jonahbauer.wizard.common.messages.observer.TrumpMessage; -import eu.jonahbauer.wizard.common.messages.observer.UserInputMessage; -import eu.jonahbauer.wizard.common.messages.player.PickTrumpMessage; -import eu.jonahbauer.wizard.common.messages.player.PlayerMessage; import eu.jonahbauer.wizard.core.machine.GameState; import eu.jonahbauer.wizard.core.model.card.GameCards; -import org.jetbrains.annotations.NotNull; import java.util.*; import static eu.jonahbauer.wizard.core.machine.states.GameData.*; -import static eu.jonahbauer.wizard.common.messages.observer.UserInputMessage.Action.PICK_TRUMP; public final class DeterminingTrump extends RoundState { - private transient UUID player; - private transient boolean werewolf; public DeterminingTrump(GameData data) { super(data.require(TRUMP_CARD).requireEach(PLAYERS, HANDS)); @@ -35,74 +26,31 @@ public final class DeterminingTrump extends RoundState { var player = entry.getKey(); var hand = entry.getValue(); if (hand.contains(Card.WEREWOLF)) { - this.player = player; - this.werewolf = true; game.notify(new TrumpMessage(trumpCard, null)); game.notify(new TrumpMessage(Card.WEREWOLF, null)); - game.notify(new UserInputMessage(this.player, PICK_TRUMP, getTimeout(game, true))); - return timeout(game); + + var data = getData().with(CURRENT_PLAYER, player); + return sync(data, DeterminingTrumpUserInput::new); } } // default trump handling Card.Suit trumpSuit = trumpCard != null ? GameCards.get(trumpCard).getTrumpSuit() : Card.Suit.NONE; if (trumpSuit == null) { - this.player = getDealer(); + var player = getDealer(); game.notify(new TrumpMessage(trumpCard, null)); - game.notify(new UserInputMessage(this.player, PICK_TRUMP, getTimeout(game, true))); - return timeout(game); - } else { - return transition(game, trumpSuit); - } - } - - @Override - public Optional onTimeout(Game game) { - game.notify(new TimeoutMessage()); - Card.Suit[] suits; - if (werewolf) { - suits = new Card.Suit[]{Card.Suit.BLUE, Card.Suit.GREEN, Card.Suit.RED, Card.Suit.YELLOW, Card.Suit.NONE}; - } else { - suits = new Card.Suit[]{Card.Suit.BLUE, Card.Suit.GREEN, Card.Suit.RED, Card.Suit.YELLOW}; - } - return transition(game, suits[game.getRandom().nextInt(suits.length)]); - } - @Override - public Optional onMessage(Game game, UUID player, PlayerMessage message) { - if (this.player.equals(player) && message instanceof PickTrumpMessage trumpMessage) { - checkTrumpSuit(trumpMessage.getTrumpSuit()); - return transition(game, trumpMessage.getTrumpSuit()); + var data = getData().with(CURRENT_PLAYER, player); + return sync(data, DeterminingTrumpUserInput::new); } else { - return super.onMessage(game, player, message); - } - } + var data = getData().with( + TRUMP_SUIT, trumpSuit, + CURRENT_PLAYER, getNextPlayer(getDealer()) + ); - private void checkTrumpSuit(Card.Suit suit) { - if (!werewolf && suit == Card.Suit.NONE) { - throw new IllegalArgumentException("Trump suit must not be " + Card.Suit.NONE + "."); - } else if (suit == null) { - throw new IllegalArgumentException("Trump suit must not be null."); - } - } - - private Optional transition(Game game, @NotNull Card.Suit trumpSuit) { - GameData data = getData().with( - TRUMP_SUIT, trumpSuit, - CURRENT_PLAYER, getNextPlayer(getDealer()) - ); - - if (werewolf) { - var mutableHands = new HashMap<>(get(HANDS)); - var mutableHand = new ArrayList<>(mutableHands.get(player)); - mutableHand.set(mutableHand.indexOf(Card.WEREWOLF), get(TRUMP_CARD)); - mutableHands.put(player, List.copyOf(mutableHand)); - data = data.with(HANDS, Map.copyOf(mutableHands)); - game.notify(new TrumpMessage(Card.WEREWOLF, trumpSuit)); - game.notify(player, new HandMessage(player, mutableHands.get(player))); - } else { game.notify(new TrumpMessage(get(TRUMP_CARD), trumpSuit)); + + return sync(data, Predicting::new); } - return sync(data, Predicting::new); } } diff --git a/wizard-core/src/main/java/eu/jonahbauer/wizard/core/machine/states/round/DeterminingTrumpUserInput.java b/wizard-core/src/main/java/eu/jonahbauer/wizard/core/machine/states/round/DeterminingTrumpUserInput.java new file mode 100644 index 0000000..0c3328d --- /dev/null +++ b/wizard-core/src/main/java/eu/jonahbauer/wizard/core/machine/states/round/DeterminingTrumpUserInput.java @@ -0,0 +1,89 @@ +package eu.jonahbauer.wizard.core.machine.states.round; + +import eu.jonahbauer.wizard.common.messages.observer.HandMessage; +import eu.jonahbauer.wizard.common.messages.observer.TimeoutMessage; +import eu.jonahbauer.wizard.common.messages.observer.TrumpMessage; +import eu.jonahbauer.wizard.common.messages.observer.UserInputMessage; +import eu.jonahbauer.wizard.common.messages.player.PickTrumpMessage; +import eu.jonahbauer.wizard.common.messages.player.PlayerMessage; +import eu.jonahbauer.wizard.common.model.Card; +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.TransientState; +import org.jetbrains.annotations.NotNull; + +import java.util.*; + +import static eu.jonahbauer.wizard.common.messages.observer.UserInputMessage.Action.PICK_TRUMP; +import static eu.jonahbauer.wizard.core.machine.states.GameData.*; +import static eu.jonahbauer.wizard.core.machine.states.GameData.TRUMP_CARD; + +public final class DeterminingTrumpUserInput extends RoundState implements TransientState { + private final transient UUID player; + private final transient boolean werewolf; + + public DeterminingTrumpUserInput(GameData data) { + super(data.require(TRUMP_CARD).requireEach(PLAYERS, HANDS).require(CURRENT_PLAYER)); + + this.player = get(CURRENT_PLAYER); + this.werewolf = get(HANDS).get(this.player).contains(Card.WEREWOLF); + } + + @Override + public Optional onEnter(Game game) { + game.notify(new UserInputMessage(this.player, PICK_TRUMP, getTimeout(game, true))); + return timeout(game); + } + + @Override + public Optional onTimeout(Game game) { + game.notify(new TimeoutMessage()); + + Card.Suit[] suits; + if (werewolf) { + suits = new Card.Suit[] {Card.Suit.BLUE, Card.Suit.GREEN, Card.Suit.RED, Card.Suit.YELLOW, Card.Suit.NONE}; + } else { + suits = new Card.Suit[] {Card.Suit.BLUE, Card.Suit.GREEN, Card.Suit.RED, Card.Suit.YELLOW}; + } + return transition(game, suits[game.getRandom().nextInt(suits.length)]); + } + + @Override + public Optional onMessage(Game game, UUID player, PlayerMessage message) { + if (this.player.equals(player) && message instanceof PickTrumpMessage trumpMessage) { + checkTrumpSuit(trumpMessage.getTrumpSuit()); + return transition(game, trumpMessage.getTrumpSuit()); + } else { + return super.onMessage(game, player, message); + } + } + + private void checkTrumpSuit(Card.Suit suit) { + if (!werewolf && suit == Card.Suit.NONE) { + throw new IllegalArgumentException("Trump suit must not be " + Card.Suit.NONE + "."); + } else if (suit == null) { + throw new IllegalArgumentException("Trump suit must not be null."); + } + } + + private Optional transition(Game game, @NotNull Card.Suit trumpSuit) { + GameData data = getData().with( + TRUMP_SUIT, trumpSuit, + CURRENT_PLAYER, getNextPlayer(getDealer()) + ); + + if (werewolf) { + var mutableHands = new HashMap<>(get(HANDS)); + var mutableHand = new ArrayList<>(mutableHands.get(player)); + mutableHand.set(mutableHand.indexOf(Card.WEREWOLF), get(TRUMP_CARD)); + mutableHands.put(player, List.copyOf(mutableHand)); + data = data.with(HANDS, Map.copyOf(mutableHands)); + game.notify(new TrumpMessage(Card.WEREWOLF, trumpSuit)); + game.notify(player, new HandMessage(player, mutableHands.get(player))); + } else { + game.notify(new TrumpMessage(get(TRUMP_CARD), trumpSuit)); + } + return sync(data, Predicting::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 678735f..727dbf5 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 @@ -38,7 +38,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(SyncState.class)); + doFinish().when(game).transition(argThat(argument -> argument instanceof SyncState && argument.getData().has(TRUMP_SUIT))); queue.setGame(game); var playerList = List.of(players); @@ -92,7 +92,8 @@ public class DeterminingTrumpTest { ); // play cards in given order - MessageQueue queue = new MessageQueue(); + MessageQueue queue = new MessageQueue() + .sync(players); Game game = performTest(Configurations.ANNIVERSARY_2021, 0, hands, Card.GREEN_JESTER, queue); @@ -117,6 +118,7 @@ public class DeterminingTrumpTest { // play cards in given order MessageQueue queue = new MessageQueue() + .sync(players) .addPickTrump(players[0], Card.Suit.GREEN); Game game = performTest(Configurations.ANNIVERSARY_2021, 0, hands, Card.BLUE_WIZARD, queue); @@ -144,6 +146,7 @@ public class DeterminingTrumpTest { // play cards in given order MessageQueue queue = new MessageQueue() + .sync(players) .addPickTrump(players[3], Card.Suit.YELLOW); Game game = performTest(Configurations.ANNIVERSARY_2021, 0, hands, Card.GREEN_1, queue); 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 d4e62f6..8965f4b 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 @@ -148,10 +148,11 @@ public class RoundTest { @Test public void run_Anniversary() throws ExecutionException, InterruptedException { MessageQueue queue = new MessageQueue() - .sync(players) - .sync(players) + .sync(players) // starting_round + .sync(players) // dealing + .sync(players) // determining_trump .addPickTrump(players[2], Card.Suit.YELLOW) - .sync(players) + .sync(players) // determining_trump .addPrediction(players[3], 2) .addPrediction(players[0], 2) .addPrediction(players[1], 2)