From df5c8ba6a4e0da574e8c56a9ce38ecd31ed0a621 Mon Sep 17 00:00:00 2001 From: Jonah Bauer Date: Thu, 25 Nov 2021 23:17:29 +0100 Subject: [PATCH] CLI Client #15 --- .../jonahbauer/wizard/client/cli/Client.java | 42 +++++++++++++++++++ .../client/cli/commands/MenuCommand.java | 14 ------- .../client/cli/commands/ShowCommand.java | 35 ++++++++++++---- .../wizard/client/cli/state/Game.java | 36 +++++++++++++--- 4 files changed, 100 insertions(+), 27 deletions(-) diff --git a/wizard-client/wizard-client-cli/src/main/java/eu/jonahbauer/wizard/client/cli/Client.java b/wizard-client/wizard-client-cli/src/main/java/eu/jonahbauer/wizard/client/cli/Client.java index fc8729c..21a181c 100644 --- a/wizard-client/wizard-client-cli/src/main/java/eu/jonahbauer/wizard/client/cli/Client.java +++ b/wizard-client/wizard-client-cli/src/main/java/eu/jonahbauer/wizard/client/cli/Client.java @@ -22,6 +22,8 @@ import java.util.Optional; import java.util.concurrent.atomic.AtomicReference; import java.util.concurrent.locks.Condition; import java.util.concurrent.locks.ReentrantLock; +import java.util.stream.Collectors; +import java.util.stream.IntStream; public class Client extends TimeoutContext implements Runnable { private LineReader reader; @@ -148,6 +150,46 @@ public class Client extends TimeoutContext implements Runna public void printfln(String format, Object...args) { reader.printAbove(format.formatted(args)); } + + public void print(String[]...columns) { + print(null, null, columns); + } + + public void print(String prefix, String suffix, String[]...columns) { + int[] length = new int[columns.length]; + + for (int i = 0; i < columns.length; i++) { + length[i] = 0; + for (int j = 0; j < columns[i].length; j++) { + if (columns[i][j] == null) columns[i][j] = "null"; + var str = columns[i][j].length(); + if (str > length[i]) { + length[i] = str; + } + } + } + + String format = IntStream.range(0, length.length) + .mapToObj(i -> "%" + (i + 1) + "$" + (length[i]) + "s") + .collect(Collectors.joining(" ")); + + StringBuilder builder = new StringBuilder(); + if (prefix != null) { + builder.append(prefix).append('\n'); + } + String[] row = new String[columns.length]; + for (int j = 0; j < columns[0].length; j++) { + for (int i = 0; i < columns.length; i++) { + row[i] = columns[i][j]; + } + builder.append(format.formatted((Object[]) row)).append('\n'); + } + if (suffix != null) { + builder.append(suffix); + } + + println(builder.toString()); + } // public void ready() { diff --git a/wizard-client/wizard-client-cli/src/main/java/eu/jonahbauer/wizard/client/cli/commands/MenuCommand.java b/wizard-client/wizard-client-cli/src/main/java/eu/jonahbauer/wizard/client/cli/commands/MenuCommand.java index 882e1ed..958aac7 100644 --- a/wizard-client/wizard-client-cli/src/main/java/eu/jonahbauer/wizard/client/cli/commands/MenuCommand.java +++ b/wizard-client/wizard-client-cli/src/main/java/eu/jonahbauer/wizard/client/cli/commands/MenuCommand.java @@ -29,18 +29,4 @@ public class MenuCommand { socket.connect(); return new AwaitingConnection(); } - - @Command(name = "dummy") - public Lobby dummy() { - CompletableFuture.runAsync(() -> { - try { - Thread.sleep(4000); - } catch (InterruptedException e) { - e.printStackTrace(); - } - - client.onClose(1000, "Test", false); - }); - return new Lobby(new SessionListMessage(List.of())); - } } diff --git a/wizard-client/wizard-client-cli/src/main/java/eu/jonahbauer/wizard/client/cli/commands/ShowCommand.java b/wizard-client/wizard-client-cli/src/main/java/eu/jonahbauer/wizard/client/cli/commands/ShowCommand.java index 6684468..cf049cc 100644 --- a/wizard-client/wizard-client-cli/src/main/java/eu/jonahbauer/wizard/client/cli/commands/ShowCommand.java +++ b/wizard-client/wizard-client-cli/src/main/java/eu/jonahbauer/wizard/client/cli/commands/ShowCommand.java @@ -5,7 +5,9 @@ import eu.jonahbauer.wizard.client.cli.state.Game; import eu.jonahbauer.wizard.client.cli.util.Pair; import eu.jonahbauer.wizard.common.model.Card; +import java.util.List; import java.util.Map; +import java.util.Objects; import java.util.UUID; import static picocli.CommandLine.Command; @@ -31,11 +33,17 @@ public class ShowCommand { @Command(name = "stack") public void stack() { - StringBuilder builder = new StringBuilder(); + var stack = game.getStack(); + String[] col0 = new String[stack.size()]; + String[] col1 = new String[stack.size()]; + int i = 0; for (Pair entry : game.getStack()) { - builder.append(entry.getValue()).append('\t').append(game.nameOf(entry.getKey())).append('\n'); + col0[i] = Objects.toString(entry.getValue()); + col1[i] = Objects.toString(game.nameOf(entry.getKey())); + i++; } - client.println(builder.toString()); + + client.print(col0, col1); } @Command(name = "hand") @@ -43,11 +51,24 @@ public class ShowCommand { client.println(game.getHands().get(game.getSelf())); } - @Command(name = "predictions") + @Command(name = "predictions", aliases = "tricks") public void predictions() { - StringBuilder builder = new StringBuilder(); - game.getPredictions().forEach((player, prediction) -> builder.append(game.nameOf(player)).append('\t').append(prediction).append('\n')); - client.println(builder.toString()); + var players = game.getPlayers().keySet(); + String[] col0 = new String[players.size() + 1]; + String[] col1 = new String[players.size() + 1]; + String[] col2 = new String[players.size() + 1]; + col0[0] = ""; + col1[0] = "Prediction"; + col2[0] = "Tricks"; + int i = 1; + for (UUID player : players) { + col0[i] = game.nameOf(player); + col1[i] = Objects.toString(game.getPredictions().get(player)); + col2[i] = Objects.toString(game.getTricks().getOrDefault(player, List.of()).stream().filter(l -> !l.contains(Card.BOMB)).count()); + i++; + } + + client.print(col0, col1, col2); } @Command(name = "trump") diff --git a/wizard-client/wizard-client-cli/src/main/java/eu/jonahbauer/wizard/client/cli/state/Game.java b/wizard-client/wizard-client-cli/src/main/java/eu/jonahbauer/wizard/client/cli/state/Game.java index 1008d0a..dbdf922 100644 --- a/wizard-client/wizard-client-cli/src/main/java/eu/jonahbauer/wizard/client/cli/state/Game.java +++ b/wizard-client/wizard-client-cli/src/main/java/eu/jonahbauer/wizard/client/cli/state/Game.java @@ -27,6 +27,7 @@ public final class Game extends BaseState { private int round = -1; private final Map predictions = new HashMap<>(); private final Map> hands = new HashMap<>(); + private final Map>> tricks = new HashMap<>(); private int trick = -1; private final List> stack = new ArrayList<>(); @@ -49,6 +50,7 @@ public final class Game extends BaseState { case "starting_round" -> { client.printfln("Round %d is starting...", ++round); predictions.clear(); + tricks.clear(); trumpSuit = null; trumpCard = null; stack.clear(); @@ -91,12 +93,21 @@ public final class Game extends BaseState { } } else if (observerMessage instanceof TrickMessage trick) { this.stack.clear(); + this.tricks.computeIfAbsent(trick.getPlayer(), player -> new ArrayList<>()) + .add(trick.getCards()); client.printfln("This trick %s goes to %s.", trick.getCards(), nameOf(trick.getPlayer())); } else if (observerMessage instanceof CardMessage card) { this.stack.add(Pair.of(card.getPlayer(), card.getCard())); var hand = this.hands.get(card.getPlayer()); - if (hand != null) hand.remove(card.getCard()); + if (hand != null) { + switch (card.getCard()) { + case CHANGELING_JESTER, CHANGELING_WIZARD -> hand.remove(Card.CHANGELING); + case JUGGLER_BLUE, JUGGLER_GREEN, JUGGLER_RED, JUGGLER_YELLOW -> hand.remove(Card.JUGGLER); + case CLOUD_BLUE, CLOUD_GREEN, CLOUD_RED, CLOUD_YELLOW -> hand.remove(Card.CLOUD); + default -> hand.remove(card.getCard()); + } + } if (card.getPlayer().equals(self)) { client.printfln("You played %s.", card.getCard()); @@ -105,11 +116,20 @@ public final class Game extends BaseState { } } else if (observerMessage instanceof ScoreMessage score) { score.getPoints().forEach((player, points) -> scores.merge(player, points, Integer::sum)); - StringBuilder builder = new StringBuilder("The scores are as follows:\n"); - scores.forEach((player, points) -> builder.append(nameOf(player)).append('\t').append(points).append('\n')); - client.println(builder.toString()); + + String[] col0 = new String[players.size()]; + String[] col1 = new String[players.size()]; + + int i = 0; + for (UUID player : players.keySet()) { + col0[i] = nameOf(player); + col1[i] = Objects.toString(scores.getOrDefault(player, 0)); + i++; + } + + client.print("The scores are as follows:", "", col0, col1); } else if (observerMessage instanceof UserInputMessage input) { - if (input.getPlayer().equals(self)) { + 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"; @@ -135,7 +155,11 @@ public final class Game extends BaseState { } public String nameOf(UUID player) { - return players.get(player); + if (player == null) { + return "all players"; + } else { + return players.get(player); + } } @Override