added sync at start of round and trick
This commit is contained in:
parent
421cae2ace
commit
10ca1ac9db
@ -3,8 +3,10 @@ package eu.jonahbauer.wizard.client.cli.state;
|
||||
import eu.jonahbauer.wizard.client.cli.Client;
|
||||
import eu.jonahbauer.wizard.client.cli.commands.GameCommand;
|
||||
import eu.jonahbauer.wizard.client.cli.util.Pair;
|
||||
import eu.jonahbauer.wizard.common.messages.client.InteractionMessage;
|
||||
import eu.jonahbauer.wizard.common.messages.data.PlayerData;
|
||||
import eu.jonahbauer.wizard.common.messages.observer.*;
|
||||
import eu.jonahbauer.wizard.common.messages.player.ContinueMessage;
|
||||
import eu.jonahbauer.wizard.common.messages.server.AckMessage;
|
||||
import eu.jonahbauer.wizard.common.messages.server.GameMessage;
|
||||
import eu.jonahbauer.wizard.common.messages.server.NackMessage;
|
||||
@ -133,20 +135,25 @@ public final class Game extends BaseState {
|
||||
|
||||
client.print("The scores are as follows:", "", col0, col1);
|
||||
} else if (observerMessage instanceof UserInputMessage input) {
|
||||
if (self.equals(input.getPlayer())) {
|
||||
if (input.getAction() == UserInputMessage.Action.SYNC) {
|
||||
client.send(new InteractionMessage(new ContinueMessage()));
|
||||
} else if (self.equals(input.getPlayer())) {
|
||||
client.printfln("It is your turn to %s. You have time until %s.", switch (input.getAction()) {
|
||||
case CHANGE_PREDICTION -> "change your prediction";
|
||||
case JUGGLE_CARD -> "juggle a card";
|
||||
case PLAY_CARD -> "play a card";
|
||||
case PICK_TRUMP -> "pick the trump suit";
|
||||
case MAKE_PREDICTION -> "make a prediction";
|
||||
default -> throw new AssertionError();
|
||||
}, LocalDateTime.ofInstant(Instant.ofEpochMilli(input.getTimeout()), ZoneId.systemDefault()));
|
||||
} else {
|
||||
client.printfln(
|
||||
"Waiting for input %s from %s. (times out at %s)",
|
||||
input.getAction(),
|
||||
nameOf(input.getPlayer()),
|
||||
LocalDateTime.ofInstant(Instant.ofEpochMilli(input.getTimeout()), ZoneId.systemDefault())
|
||||
LocalDateTime.ofInstant(Instant.ofEpochMilli(input.getTimeout()),
|
||||
ZoneId.systemDefault()
|
||||
)
|
||||
);
|
||||
}
|
||||
} else if (observerMessage instanceof TimeoutMessage) {
|
||||
|
@ -1,4 +1,7 @@
|
||||
package eu.jonahbauer.wizard.common.messages.observer;
|
||||
|
||||
/**
|
||||
* A {@link TimeoutMessage} is sent when an user input times out.
|
||||
*/
|
||||
public final class TimeoutMessage extends ObserverMessage {
|
||||
}
|
||||
|
@ -58,6 +58,7 @@ public final class UserInputMessage extends ObserverMessage {
|
||||
* An action that indicates that a player should pick a trump suit. A {@link UserInputMessage} with this
|
||||
* {@link UserInputMessage#getAction()} should be responded to with a {@link PickTrumpMessage}.
|
||||
*/
|
||||
PICK_TRUMP
|
||||
PICK_TRUMP,
|
||||
SYNC
|
||||
}
|
||||
}
|
||||
|
@ -0,0 +1,4 @@
|
||||
package eu.jonahbauer.wizard.common.messages.player;
|
||||
|
||||
public final class ContinueMessage extends PlayerMessage {
|
||||
}
|
@ -7,7 +7,7 @@ import eu.jonahbauer.wizard.common.util.SealedClassTypeAdapterFactory;
|
||||
import lombok.EqualsAndHashCode;
|
||||
|
||||
@EqualsAndHashCode
|
||||
public abstract sealed class PlayerMessage permits JuggleMessage, PickTrumpMessage, PlayCardMessage, PredictMessage {
|
||||
public abstract sealed class PlayerMessage permits ContinueMessage, JuggleMessage, PickTrumpMessage, PlayCardMessage, PredictMessage {
|
||||
private static final Gson GSON = new GsonBuilder()
|
||||
.registerTypeAdapterFactory(SealedClassTypeAdapterFactory.of(PlayerMessage.class, "Message"))
|
||||
.create();
|
||||
|
@ -28,6 +28,11 @@ public abstract class GameState implements TimeoutState<GameState, Game> {
|
||||
return Optional.empty();
|
||||
}
|
||||
|
||||
protected final Optional<GameState> syncTimeout(Game game) {
|
||||
game.timeout(this, getSyncTimeout(game, false));
|
||||
return Optional.empty();
|
||||
}
|
||||
|
||||
protected final Optional<GameState> transition(GameState state) {
|
||||
return Optional.of(state);
|
||||
}
|
||||
@ -35,6 +40,10 @@ public abstract class GameState implements TimeoutState<GameState, Game> {
|
||||
protected final long getTimeout(Game game, boolean absolute) {
|
||||
return (absolute ? System.currentTimeMillis() : 0) + game.getConfig().timeout();
|
||||
}
|
||||
|
||||
protected final long getSyncTimeout(Game game, boolean absolute) {
|
||||
return (absolute ? System.currentTimeMillis() : 0) + game.getConfig().syncTimeout();
|
||||
}
|
||||
//</editor-fold>
|
||||
|
||||
public Optional<GameState> onMessage(Game game, UUID player, PlayerMessage message) {
|
||||
|
@ -1,18 +1,52 @@
|
||||
package eu.jonahbauer.wizard.core.machine.states.round;
|
||||
|
||||
import eu.jonahbauer.wizard.core.machine.states.GameData;
|
||||
import eu.jonahbauer.wizard.common.messages.observer.TimeoutMessage;
|
||||
import eu.jonahbauer.wizard.common.messages.observer.UserInputMessage;
|
||||
import eu.jonahbauer.wizard.common.messages.player.ContinueMessage;
|
||||
import eu.jonahbauer.wizard.common.messages.player.PlayerMessage;
|
||||
import eu.jonahbauer.wizard.core.machine.Game;
|
||||
import eu.jonahbauer.wizard.core.machine.GameState;
|
||||
import eu.jonahbauer.wizard.core.machine.states.GameData;
|
||||
|
||||
import java.util.HashSet;
|
||||
import java.util.Optional;
|
||||
import java.util.Set;
|
||||
import java.util.UUID;
|
||||
|
||||
import static eu.jonahbauer.wizard.common.messages.observer.UserInputMessage.Action.SYNC;
|
||||
import static eu.jonahbauer.wizard.core.machine.states.GameData.PLAYERS;
|
||||
|
||||
public final class StartingRound extends RoundState {
|
||||
private final transient Set<UUID> ready = new HashSet<>();
|
||||
|
||||
public StartingRound(GameData data) {
|
||||
super(data);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Optional<GameState> onEnter(Game game) {
|
||||
return transition(new Dealing(getData()));
|
||||
game.notify(new UserInputMessage(null, SYNC, getSyncTimeout(game, true)));
|
||||
return syncTimeout(game);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Optional<GameState> onMessage(Game game, UUID player, PlayerMessage message) {
|
||||
if (message instanceof ContinueMessage) {
|
||||
ready.add(player);
|
||||
|
||||
if (ready.size() == get(PLAYERS).size()) {
|
||||
return Optional.of(new Dealing(getData()));
|
||||
} else {
|
||||
return Optional.empty();
|
||||
}
|
||||
} else {
|
||||
return super.onMessage(game, player, message);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Optional<GameState> onTimeout(Game game) {
|
||||
game.notify(new TimeoutMessage());
|
||||
return Optional.of(new Dealing(getData()));
|
||||
}
|
||||
}
|
||||
|
@ -1,18 +1,52 @@
|
||||
package eu.jonahbauer.wizard.core.machine.states.trick;
|
||||
|
||||
import eu.jonahbauer.wizard.common.messages.observer.TimeoutMessage;
|
||||
import eu.jonahbauer.wizard.common.messages.observer.UserInputMessage;
|
||||
import eu.jonahbauer.wizard.common.messages.player.ContinueMessage;
|
||||
import eu.jonahbauer.wizard.common.messages.player.PlayerMessage;
|
||||
import eu.jonahbauer.wizard.core.machine.Game;
|
||||
import eu.jonahbauer.wizard.core.machine.states.GameData;
|
||||
import eu.jonahbauer.wizard.core.machine.GameState;
|
||||
|
||||
import java.util.HashSet;
|
||||
import java.util.Optional;
|
||||
import java.util.Set;
|
||||
import java.util.UUID;
|
||||
|
||||
import static eu.jonahbauer.wizard.common.messages.observer.UserInputMessage.Action.SYNC;
|
||||
import static eu.jonahbauer.wizard.core.machine.states.GameData.PLAYERS;
|
||||
|
||||
public final class StartingTrick extends TrickState {
|
||||
private final transient Set<UUID> ready = new HashSet<>();
|
||||
|
||||
public StartingTrick(GameData data) {
|
||||
super(data);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Optional<GameState> onEnter(Game game) {
|
||||
return transition(new PlayingCard(getData()));
|
||||
game.notify(new UserInputMessage(null, SYNC, getSyncTimeout(game, true)));
|
||||
return syncTimeout(game);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Optional<GameState> onMessage(Game game, UUID player, PlayerMessage message) {
|
||||
if (message instanceof ContinueMessage) {
|
||||
ready.add(player);
|
||||
|
||||
if (ready.size() == get(PLAYERS).size()) {
|
||||
return Optional.of(new PlayingCard(getData()));
|
||||
} else {
|
||||
return Optional.empty();
|
||||
}
|
||||
} else {
|
||||
return super.onMessage(game, player, message);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Optional<GameState> onTimeout(Game game) {
|
||||
game.notify(new TimeoutMessage());
|
||||
return Optional.of(new PlayingCard(getData()));
|
||||
}
|
||||
}
|
||||
|
@ -16,4 +16,9 @@ public class GameConfiguration {
|
||||
Set<Card> cards;
|
||||
boolean allowExactPredictions;
|
||||
@With long timeout;
|
||||
@With long syncTimeout;
|
||||
|
||||
public GameConfiguration(Set<Card> cards, boolean allowExactPredictions, long timeout) {
|
||||
this(cards, allowExactPredictions, timeout, 10_000);
|
||||
}
|
||||
}
|
||||
|
@ -13,7 +13,7 @@ public class GameTest {
|
||||
public void runDefault(RepetitionInfo repetitionInfo) throws InterruptedException, ExecutionException {
|
||||
Game game = new Game(
|
||||
repetitionInfo.getCurrentRepetition(),
|
||||
Configurations.DEFAULT.withTimeout(0),
|
||||
Configurations.DEFAULT.withTimeout(0).withSyncTimeout(0),
|
||||
(player, msg) -> System.out.println(msg)
|
||||
);
|
||||
var players = List.of(
|
||||
@ -31,7 +31,7 @@ public class GameTest {
|
||||
public void runAnniversary2016(RepetitionInfo repetitionInfo) throws InterruptedException, ExecutionException {
|
||||
Game game = new Game(
|
||||
repetitionInfo.getCurrentRepetition(),
|
||||
Configurations.ANNIVERSARY_2016.withTimeout(0),
|
||||
Configurations.ANNIVERSARY_2016.withTimeout(0).withSyncTimeout(0),
|
||||
(player, msg) -> System.out.println(msg)
|
||||
);
|
||||
var players = List.of(
|
||||
@ -49,7 +49,7 @@ public class GameTest {
|
||||
public void runAnniversary2021(RepetitionInfo repetitionInfo) throws InterruptedException, ExecutionException {
|
||||
Game game = new Game(
|
||||
repetitionInfo.getCurrentRepetition(),
|
||||
Configurations.ANNIVERSARY_2021.withTimeout(0),
|
||||
Configurations.ANNIVERSARY_2021.withTimeout(0).withSyncTimeout(0),
|
||||
(player, msg) -> System.out.println(msg)
|
||||
);
|
||||
var players = List.of(
|
||||
|
@ -107,6 +107,15 @@ public class MessageQueue implements Observer {
|
||||
return this;
|
||||
}
|
||||
|
||||
public MessageQueue sync(UUID... players) {
|
||||
var bulk = new BulkQueuedMessage();
|
||||
Arrays.stream(players)
|
||||
.map(player -> new SingleQueuedMessage(player, UserInputMessage.Action.SYNC, new ContinueMessage()))
|
||||
.forEach(bulk.getMessages()::add);
|
||||
messages.add(bulk);
|
||||
return this;
|
||||
}
|
||||
|
||||
public void doNotify(ObserverMessage om) {
|
||||
try {
|
||||
System.out.println(om);
|
||||
|
@ -55,41 +55,49 @@ public class RoundTest {
|
||||
@Test
|
||||
public void run_Simple() throws ExecutionException, InterruptedException {
|
||||
MessageQueue queue = new MessageQueue()
|
||||
.sync(players)
|
||||
.addPrediction(players[3], 3)
|
||||
.addPrediction(players[0], 0)
|
||||
.addPrediction(players[1], 3)
|
||||
.addPrediction(players[2], 1)
|
||||
// trick 0
|
||||
.sync(players)
|
||||
.addCard(players[3], Card.RED_7)
|
||||
.addCard(players[0], Card.GREEN_WIZARD)
|
||||
.addCard(players[1], Card.GREEN_10)
|
||||
.addCard(players[2], Card.RED_1)
|
||||
// trick 1
|
||||
.sync(players)
|
||||
.addCard(players[0], Card.RED_9)
|
||||
.addCard(players[1], Card.YELLOW_WIZARD)
|
||||
.addCard(players[2], Card.RED_3)
|
||||
.addCard(players[3], Card.RED_10)
|
||||
// trick 2
|
||||
.sync(players)
|
||||
.addCard(players[1], Card.YELLOW_JESTER)
|
||||
.addCard(players[2], Card.GREEN_12)
|
||||
.addCard(players[3], Card.GREEN_5)
|
||||
.addCard(players[0], Card.BLUE_7)
|
||||
// trick 3
|
||||
.sync(players)
|
||||
.addCard(players[2], Card.GREEN_1)
|
||||
.addCard(players[3], Card.YELLOW_10)
|
||||
.addCard(players[0], Card.BLUE_5)
|
||||
.addCard(players[1], Card.GREEN_2)
|
||||
// trick 4
|
||||
.sync(players)
|
||||
.addCard(players[1], Card.GREEN_7)
|
||||
.addCard(players[2], Card.GREEN_3)
|
||||
.addCard(players[3], Card.YELLOW_5)
|
||||
.addCard(players[0], Card.RED_13)
|
||||
// trick 5
|
||||
.sync(players)
|
||||
.addCard(players[1], Card.YELLOW_8)
|
||||
.addCard(players[2], Card.BLUE_9)
|
||||
.addCard(players[3], Card.YELLOW_9)
|
||||
.addCard(players[0], Card.GREEN_JESTER)
|
||||
// trick 5
|
||||
.sync(players)
|
||||
.addCard(players[3], Card.YELLOW_2)
|
||||
.addCard(players[0], Card.BLUE_2)
|
||||
.addCard(players[1], Card.BLUE_10)
|
||||
@ -138,6 +146,7 @@ public class RoundTest {
|
||||
@Test
|
||||
public void run_Anniversary() throws ExecutionException, InterruptedException {
|
||||
MessageQueue queue = new MessageQueue()
|
||||
.sync(players)
|
||||
.addPickTrump(players[2], Card.Suit.YELLOW)
|
||||
.addPrediction(players[3], 2)
|
||||
.addPrediction(players[0], 2)
|
||||
@ -147,6 +156,7 @@ public class RoundTest {
|
||||
.addPrediction(players[2], 3)
|
||||
.end()
|
||||
// trick 0
|
||||
.sync(players)
|
||||
.begin()
|
||||
.addCard(players[3], Card.RED_11).assertThrows(IllegalArgumentException.class)
|
||||
.addCard(players[3], Card.BLUE_2)
|
||||
@ -157,6 +167,7 @@ public class RoundTest {
|
||||
.addCard(players[1], Card.BLUE_9)
|
||||
.addCard(players[2], Card.GREEN_WIZARD)
|
||||
// trick 1
|
||||
.sync(players)
|
||||
.begin()
|
||||
.addCard(players[3], Card.RED_11).assertThrows(IllegalStateException.class)
|
||||
.addCard(players[2], Card.YELLOW_4)
|
||||
@ -165,6 +176,7 @@ public class RoundTest {
|
||||
.addCard(players[0], Card.YELLOW_WIZARD)
|
||||
.addCard(players[1], Card.BOMB)
|
||||
// trick 2
|
||||
.sync(players)
|
||||
.addCard(players[0], Card.RED_3)
|
||||
.begin()
|
||||
.addCard(players[3], Card.RED_11).assertThrows(IllegalStateException.class)
|
||||
@ -173,6 +185,7 @@ public class RoundTest {
|
||||
.addCard(players[2], Card.RED_2)
|
||||
.addCard(players[3], Card.DRAGON)
|
||||
// trick 3
|
||||
.sync(players)
|
||||
.addCard(players[3], Card.BLUE_13)
|
||||
.begin()
|
||||
.addCard(players[0], Card.CLOUD).assertThrows(IllegalArgumentException.class)
|
||||
@ -183,6 +196,7 @@ public class RoundTest {
|
||||
.end()
|
||||
.addCard(players[2], Card.BLUE_1)
|
||||
// trick 4
|
||||
.sync(players)
|
||||
.addCard(players[1], Card.RED_7)
|
||||
.addCard(players[2], Card.YELLOW_11)
|
||||
.begin()
|
||||
@ -193,11 +207,13 @@ public class RoundTest {
|
||||
.addCard(players[0], Card.CHANGELING_WIZARD)
|
||||
.end()
|
||||
// trick 5
|
||||
.sync(players)
|
||||
.addCard(players[0], Card.GREEN_7)
|
||||
.addCard(players[1], Card.FAIRY)
|
||||
.addCard(players[2], Card.YELLOW_7)
|
||||
.addCard(players[3], Card.BLUE_6)
|
||||
// trick 6
|
||||
.sync(players)
|
||||
.addCard(players[2], Card.BLUE_4)
|
||||
.addCard(players[3], Card.BLUE_11)
|
||||
.addCard(players[0], Card.GREEN_1)
|
||||
|
@ -72,6 +72,7 @@ public class TrickTest {
|
||||
|
||||
// play cards in given order
|
||||
MessageQueue queue = new MessageQueue()
|
||||
.sync(players)
|
||||
.addCards(List.of(players), hands, 0);
|
||||
|
||||
Game game = performTest(Configurations.DEFAULT, 0, 0, hands, Card.Suit.BLUE, queue);
|
||||
@ -102,6 +103,7 @@ public class TrickTest {
|
||||
|
||||
// play cards in given order
|
||||
MessageQueue queue = new MessageQueue()
|
||||
.sync(players)
|
||||
.addCard(players[0], Card.RED_1)
|
||||
.begin()
|
||||
.addCard(players[2], Card.GREEN_1).assertThrows(IllegalStateException.class)
|
||||
@ -150,6 +152,7 @@ public class TrickTest {
|
||||
|
||||
// play cards in given order
|
||||
MessageQueue queue = new MessageQueue()
|
||||
.sync(players)
|
||||
.addCard(players[0], Card.RED_1)
|
||||
.addCard(players[1], Card.CLOUD_BLUE)
|
||||
.addCard(players[2], Card.GREEN_1)
|
||||
@ -188,6 +191,7 @@ public class TrickTest {
|
||||
|
||||
// play cards in given order
|
||||
MessageQueue queue = new MessageQueue()
|
||||
.sync(players)
|
||||
.addCard(players[0], Card.RED_1)
|
||||
.addCard(players[1], Card.JUGGLER_RED)
|
||||
.addCard(players[2], Card.GREEN_1)
|
||||
@ -238,6 +242,7 @@ public class TrickTest {
|
||||
|
||||
// play cards in given order
|
||||
MessageQueue queue = new MessageQueue()
|
||||
.sync(players)
|
||||
.addCard(players[0], Card.CHANGELING_JESTER)
|
||||
.addCard(players[1], Card.RED_1)
|
||||
.addCard(players[2], Card.GREEN_1)
|
||||
@ -279,6 +284,7 @@ public class TrickTest {
|
||||
|
||||
// play cards in given order
|
||||
MessageQueue queue = new MessageQueue()
|
||||
.sync(players)
|
||||
.addCard(players[0], Card.CHANGELING_WIZARD)
|
||||
.addCard(players[1], Card.RED_1)
|
||||
.addCard(players[2], Card.GREEN_WIZARD)
|
||||
|
Loading…
x
Reference in New Issue
Block a user