changes to sync
This commit is contained in:
parent
7b7b5a902d
commit
62c9ec2d28
@ -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.ObserverMessage;
|
||||||
import eu.jonahbauer.wizard.common.messages.observer.StateMessage;
|
import eu.jonahbauer.wizard.common.messages.observer.StateMessage;
|
||||||
import eu.jonahbauer.wizard.common.messages.player.PlayerMessage;
|
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.Created;
|
||||||
import eu.jonahbauer.wizard.core.machine.states.game.Error;
|
import eu.jonahbauer.wizard.core.machine.states.game.Error;
|
||||||
import eu.jonahbauer.wizard.core.messages.Observer;
|
import eu.jonahbauer.wizard.core.messages.Observer;
|
||||||
@ -57,7 +58,9 @@ public final class Game extends TimeoutContext<GameState, Game> {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void onTransition(GameState from, GameState to) {
|
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
|
@Override
|
||||||
|
@ -3,12 +3,14 @@ package eu.jonahbauer.wizard.core.machine;
|
|||||||
import eu.jonahbauer.wizard.common.machine.TimeoutState;
|
import eu.jonahbauer.wizard.common.machine.TimeoutState;
|
||||||
import eu.jonahbauer.wizard.common.messages.player.PlayerMessage;
|
import eu.jonahbauer.wizard.common.messages.player.PlayerMessage;
|
||||||
import eu.jonahbauer.wizard.core.machine.states.GameData;
|
import eu.jonahbauer.wizard.core.machine.states.GameData;
|
||||||
|
import eu.jonahbauer.wizard.core.machine.states.SyncState;
|
||||||
import lombok.Getter;
|
import lombok.Getter;
|
||||||
import org.jetbrains.annotations.Unmodifiable;
|
import org.jetbrains.annotations.Unmodifiable;
|
||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Optional;
|
import java.util.Optional;
|
||||||
import java.util.UUID;
|
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.CURRENT_PLAYER;
|
||||||
import static eu.jonahbauer.wizard.core.machine.states.GameData.PLAYERS;
|
import static eu.jonahbauer.wizard.core.machine.states.GameData.PLAYERS;
|
||||||
@ -44,6 +46,14 @@ public abstract class GameState implements TimeoutState<GameState, Game> {
|
|||||||
protected final long getSyncTimeout(Game game, boolean absolute) {
|
protected final long getSyncTimeout(Game game, boolean absolute) {
|
||||||
return (absolute ? System.currentTimeMillis() : 0) + game.getConfig().syncTimeout();
|
return (absolute ? System.currentTimeMillis() : 0) + game.getConfig().syncTimeout();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected final Optional<GameState> sync(Function<GameData, GameState> state) {
|
||||||
|
return sync(getData(), state);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected final Optional<GameState> sync(GameData data, Function<GameData, GameState> state) {
|
||||||
|
return Optional.of(new SyncState(data, state));
|
||||||
|
}
|
||||||
//</editor-fold>
|
//</editor-fold>
|
||||||
|
|
||||||
public Optional<GameState> onMessage(Game game, UUID player, PlayerMessage message) {
|
public Optional<GameState> onMessage(Game game, UUID player, PlayerMessage message) {
|
||||||
|
@ -205,6 +205,11 @@ public final class GameData {
|
|||||||
return this;
|
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
|
* Returns {@code this} if this map contains a mapping for each of the specified keys or throws a
|
||||||
* {@link NoSuchElementException} otherwise.
|
* {@link NoSuchElementException} otherwise.
|
||||||
|
@ -11,15 +11,18 @@ import java.util.HashSet;
|
|||||||
import java.util.Optional;
|
import java.util.Optional;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
import java.util.UUID;
|
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.common.messages.observer.UserInputMessage.Action.SYNC;
|
||||||
import static eu.jonahbauer.wizard.core.machine.states.GameData.PLAYERS;
|
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<UUID> ready = new HashSet<>();
|
private final transient Set<UUID> ready = new HashSet<>();
|
||||||
|
private final Function<GameData, GameState> nextState;
|
||||||
|
|
||||||
public SyncState(GameData data) {
|
public SyncState(GameData data, Function<GameData, GameState> nextState) {
|
||||||
super(data);
|
super(data.keepAll());
|
||||||
|
this.nextState = nextState;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -34,7 +37,7 @@ public abstract class SyncState extends GameState {
|
|||||||
ready.add(player);
|
ready.add(player);
|
||||||
|
|
||||||
if (ready.size() == get(PLAYERS).size()) {
|
if (ready.size() == get(PLAYERS).size()) {
|
||||||
return Optional.of(getNextState());
|
return Optional.of(nextState.apply(getData()));
|
||||||
} else {
|
} else {
|
||||||
return Optional.empty();
|
return Optional.empty();
|
||||||
}
|
}
|
||||||
@ -46,8 +49,6 @@ public abstract class SyncState extends GameState {
|
|||||||
@Override
|
@Override
|
||||||
public Optional<GameState> onTimeout(Game game) {
|
public Optional<GameState> onTimeout(Game game) {
|
||||||
game.notify(new TimeoutMessage());
|
game.notify(new TimeoutMessage());
|
||||||
return Optional.of(getNextState());
|
return Optional.of(nextState.apply(getData()));
|
||||||
}
|
}
|
||||||
|
|
||||||
protected abstract GameState getNextState();
|
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,4 @@
|
|||||||
|
package eu.jonahbauer.wizard.core.machine.states;
|
||||||
|
|
||||||
|
public interface TransientState {
|
||||||
|
}
|
@ -37,11 +37,12 @@ public final class Dealing extends RoundState {
|
|||||||
}
|
}
|
||||||
|
|
||||||
Card trumpCard = deck.draw();
|
Card trumpCard = deck.draw();
|
||||||
return transition(new DeterminingTrump(
|
return sync(
|
||||||
getData().with(
|
getData().with(
|
||||||
HANDS, Map.copyOf(hands),
|
HANDS, Map.copyOf(hands),
|
||||||
TRUMP_CARD, trumpCard
|
TRUMP_CARD, trumpCard
|
||||||
)
|
),
|
||||||
));
|
DeterminingTrump::new
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -103,6 +103,6 @@ public final class DeterminingTrump extends RoundState {
|
|||||||
} else {
|
} else {
|
||||||
game.notify(new TrumpMessage(get(TRUMP_CARD), trumpSuit));
|
game.notify(new TrumpMessage(get(TRUMP_CARD), trumpSuit));
|
||||||
}
|
}
|
||||||
return transition(new TrumpDetermined(data));
|
return sync(data, Predicting::new);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,17 +1,19 @@
|
|||||||
package eu.jonahbauer.wizard.core.machine.states.round;
|
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.GameState;
|
||||||
import eu.jonahbauer.wizard.core.machine.states.GameData;
|
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) {
|
public StartingRound(GameData data) {
|
||||||
super(RoundState.requirements(data));
|
super(data);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected GameState getNextState() {
|
public Optional<GameState> onEnter(Game context) {
|
||||||
return new Dealing(getData());
|
return sync(Dealing::new);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -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());
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,18 +1,21 @@
|
|||||||
package eu.jonahbauer.wizard.core.machine.states.trick;
|
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.GameState;
|
||||||
import eu.jonahbauer.wizard.core.machine.states.GameData;
|
import eu.jonahbauer.wizard.core.machine.states.GameData;
|
||||||
import eu.jonahbauer.wizard.core.machine.states.SyncState;
|
import eu.jonahbauer.wizard.core.machine.states.SyncState;
|
||||||
import eu.jonahbauer.wizard.core.machine.states.round.RoundState;
|
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) {
|
public StartingTrick(GameData data) {
|
||||||
super(RoundState.requirements(TrickState.requirements(data)));
|
super(data);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected GameState getNextState() {
|
public Optional<GameState> onEnter(Game context) {
|
||||||
return new PlayingCard(getData());
|
return sync(PlayingCard::new);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -8,6 +8,7 @@ import eu.jonahbauer.wizard.common.model.Card;
|
|||||||
import eu.jonahbauer.wizard.core.machine.Game;
|
import eu.jonahbauer.wizard.core.machine.Game;
|
||||||
import eu.jonahbauer.wizard.core.machine.MessageQueue;
|
import eu.jonahbauer.wizard.core.machine.MessageQueue;
|
||||||
import eu.jonahbauer.wizard.core.machine.states.GameData;
|
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.machine.states.game.Finished;
|
||||||
import eu.jonahbauer.wizard.core.model.GameConfiguration;
|
import eu.jonahbauer.wizard.core.model.GameConfiguration;
|
||||||
import eu.jonahbauer.wizard.core.model.Configurations;
|
import eu.jonahbauer.wizard.core.model.Configurations;
|
||||||
@ -38,7 +39,7 @@ public class DeterminingTrumpTest {
|
|||||||
@SuppressWarnings("SameParameterValue")
|
@SuppressWarnings("SameParameterValue")
|
||||||
private Game performTest(GameConfiguration configuration, int round, Map<UUID, List<Card>> hands, Card trumpCard, MessageQueue queue) {
|
private Game performTest(GameConfiguration configuration, int round, Map<UUID, List<Card>> hands, Card trumpCard, MessageQueue queue) {
|
||||||
Game game = spy(new Game(configuration, 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);
|
queue.setGame(game);
|
||||||
|
|
||||||
var playerList = List.of(players);
|
var playerList = List.of(players);
|
||||||
@ -76,7 +77,7 @@ public class DeterminingTrumpTest {
|
|||||||
InOrder order = inOrder(game);
|
InOrder order = inOrder(game);
|
||||||
order.verify(game).notify(any(StateMessage.class)); // determining trump
|
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).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).notify(any(StateMessage.class)); // finish
|
||||||
order.verify(game, never()).notify(any());
|
order.verify(game, never()).notify(any());
|
||||||
order.verify(game, never()).notify(any(), any());
|
order.verify(game, never()).notify(any(), any());
|
||||||
@ -100,7 +101,7 @@ public class DeterminingTrumpTest {
|
|||||||
InOrder order = inOrder(game);
|
InOrder order = inOrder(game);
|
||||||
order.verify(game).notify(any(StateMessage.class)); // determining trump
|
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).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).notify(any(StateMessage.class)); // finish
|
||||||
order.verify(game, never()).notify(any());
|
order.verify(game, never()).notify(any());
|
||||||
order.verify(game, never()).notify(any(), 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(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(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).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).notify(any(StateMessage.class)); // finish
|
||||||
order.verify(game, never()).notify(any());
|
order.verify(game, never()).notify(any());
|
||||||
order.verify(game, never()).notify(any(), 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(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(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).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).notify(any(StateMessage.class)); // finish
|
||||||
order.verify(game, never()).notify(any());
|
order.verify(game, never()).notify(any());
|
||||||
order.verify(game, never()).notify(any(), any());
|
order.verify(game, never()).notify(any(), any());
|
||||||
|
@ -55,8 +55,9 @@ public class RoundTest {
|
|||||||
@Test
|
@Test
|
||||||
public void run_Simple() throws ExecutionException, InterruptedException {
|
public void run_Simple() throws ExecutionException, InterruptedException {
|
||||||
MessageQueue queue = new MessageQueue()
|
MessageQueue queue = new MessageQueue()
|
||||||
.sync(players)
|
.sync(players) // starting_round
|
||||||
.sync(players)
|
.sync(players) // dealing
|
||||||
|
.sync(players) // determining_trump
|
||||||
.addPrediction(players[3], 3)
|
.addPrediction(players[3], 3)
|
||||||
.addPrediction(players[0], 0)
|
.addPrediction(players[0], 0)
|
||||||
.addPrediction(players[1], 3)
|
.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, atLeast(4)).notify(any(), any(HandMessage.class)); // hands
|
||||||
order.verify(game).notify(any(StateMessage.class)); // determining_trump
|
order.verify(game).notify(any(StateMessage.class)); // determining_trump
|
||||||
order.verify(game).notify(any(TrumpMessage.class)); // 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++) {
|
for (int i = 0; i < players.length; i++) {
|
||||||
order.verify(game).notify(any(StateMessage.class)); // predicting
|
order.verify(game).notify(any(StateMessage.class)); // predicting
|
||||||
order.verify(game).notify(any(UserInputMessage.class)); // user input
|
order.verify(game).notify(any(UserInputMessage.class)); // user input
|
||||||
@ -148,6 +148,7 @@ public class RoundTest {
|
|||||||
@Test
|
@Test
|
||||||
public void run_Anniversary() throws ExecutionException, InterruptedException {
|
public void run_Anniversary() throws ExecutionException, InterruptedException {
|
||||||
MessageQueue queue = new MessageQueue()
|
MessageQueue queue = new MessageQueue()
|
||||||
|
.sync(players)
|
||||||
.sync(players)
|
.sync(players)
|
||||||
.addPickTrump(players[2], Card.Suit.YELLOW)
|
.addPickTrump(players[2], Card.Suit.YELLOW)
|
||||||
.sync(players)
|
.sync(players)
|
||||||
@ -242,7 +243,6 @@ public class RoundTest {
|
|||||||
order.verify(game).notify(any(UserInputMessage.class)); // user input
|
order.verify(game).notify(any(UserInputMessage.class)); // user input
|
||||||
order.verify(game).notify(any(TrumpMessage.class)); // trump
|
order.verify(game).notify(any(TrumpMessage.class)); // trump
|
||||||
order.verify(game).notify(any(), any(HandMessage.class)); // update hand
|
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++) {
|
for (int i = 0; i < players.length; i++) {
|
||||||
order.verify(game).notify(any(StateMessage.class));
|
order.verify(game).notify(any(StateMessage.class));
|
||||||
order.verify(game).notify(any(UserInputMessage.class));
|
order.verify(game).notify(any(UserInputMessage.class));
|
||||||
|
Loading…
x
Reference in New Issue
Block a user