From 08231884798f3ee7a289dfd26271d91d0eed2a2d Mon Sep 17 00:00:00 2001
From: Chris Kearney <chris@kearneymail.com>
Date: Sun, 14 Aug 2016 10:45:51 -0700
Subject: [PATCH] checking in some progress on blackjack, a compare command and
 a cards command

---
 .../comandante/creeper/ConfigureCommands.java |   2 +
 .../com/comandante/creeper/CreeperUtils.java  |  86 +++++++++++++++
 .../creeper/blackjack/BlackJack.java          |  68 ++++++++++++
 .../comandante/creeper/blackjack/Deck.java    | 104 ++++++++++++++++++
 .../creeper/command/CardsCommand.java         |  34 ++++++
 .../creeper/command/CompareCommand.java       |  60 ++++++++++
 .../creeper/command/MovementCommand.java      |   2 +-
 .../creeper/managers/GameManager.java         |   3 +-
 .../com/comandante/creeper/player/Player.java |   5 +-
 .../comandante/creeper/CreeperUtilsTest.java  |  37 +++++++
 10 files changed, 395 insertions(+), 6 deletions(-)
 create mode 100644 src/main/java/com/comandante/creeper/CreeperUtils.java
 create mode 100644 src/main/java/com/comandante/creeper/blackjack/BlackJack.java
 create mode 100644 src/main/java/com/comandante/creeper/blackjack/Deck.java
 create mode 100644 src/main/java/com/comandante/creeper/command/CardsCommand.java
 create mode 100644 src/main/java/com/comandante/creeper/command/CompareCommand.java
 create mode 100644 src/test/com/comandante/creeper/CreeperUtilsTest.java

diff --git a/src/main/java/com/comandante/creeper/ConfigureCommands.java b/src/main/java/com/comandante/creeper/ConfigureCommands.java
index 10961f8c..5c989f2d 100755
--- a/src/main/java/com/comandante/creeper/ConfigureCommands.java
+++ b/src/main/java/com/comandante/creeper/ConfigureCommands.java
@@ -91,5 +91,7 @@ public class ConfigureCommands {
         creeperCommandRegistry.addCommand(new DelCommand(gameManager));
         creeperCommandRegistry.addCommand(new OpCommand(gameManager));
         creeperCommandRegistry.addCommand(new KillTallyCommand(gameManager));
+        creeperCommandRegistry.addCommand(new CompareCommand(gameManager));
+        creeperCommandRegistry.addCommand(new CardsCommand(gameManager));
     }
 }
diff --git a/src/main/java/com/comandante/creeper/CreeperUtils.java b/src/main/java/com/comandante/creeper/CreeperUtils.java
new file mode 100644
index 00000000..1b1c557f
--- /dev/null
+++ b/src/main/java/com/comandante/creeper/CreeperUtils.java
@@ -0,0 +1,86 @@
+package com.comandante.creeper;
+
+import com.google.common.collect.Lists;
+
+import java.util.List;
+import java.util.function.Consumer;
+import java.util.function.Function;
+import java.util.stream.Collectors;
+
+public class CreeperUtils {
+    /*  Prints things "next" to each other, like this:
+   ┌─────────┐   ┌─────────┐   ┌─────────┐   ┌─────────┐
+   │4        │   │2        │   │5        │   │5        │
+   │         │   │         │   │         │   │         │
+   │         │   │         │   │         │   │         │
+   │   ♦     │   │   ♠     │   │   ♣     │   │   ♦     │
+   │         │   │         │   │         │   │         │
+   │         │   │         │   │         │   │         │
+   │       4 │   │       2 │   │       5 │   │       5 │
+   └─────────┘   └─────────┘   └─────────┘   └─────────┘
+   */
+    public static String printStringsNextToEachOther(List<String> strings, String seperator) {
+        // Find the "longest", meaning most newlines string.
+        final String[] maxHeightLine = {strings.get(0)};
+        strings.stream().forEach(s -> {
+            int height = s.split("[\\r\\n]+").length;
+            if (maxHeightLine[0] != null && height > maxHeightLine[0].split("[\\r\\n]+").length) {
+                maxHeightLine[0] = s;
+            }
+        });
+
+        final int[] maxLineLength = {0};
+        // Split all of the strings, to create a List of a List Of Strings
+        // Make them all even length.  This is terrible streams api usage.
+        List<List<String>> textToJoin = strings.stream()
+                .map((Function<String, List<String>>) s -> Lists.newArrayList(s.split("[\\r\\n]+"))).map(strings1 -> {
+                    strings1.forEach(s -> {
+                        if (s.length() > maxLineLength[0]) {
+                            maxLineLength[0] = s.replaceAll("\u001B\\[[;\\d]*m", "").length();
+                        }
+                    });
+                    List<String> newStrings = Lists.newArrayList();
+                    strings1.forEach(s -> {
+                        int diff = maxLineLength[0] - s.replaceAll("\u001B\\[[;\\d]*m", "").length();
+                        for (int i = 0; i < diff; i++) {
+                            s += " ";
+                        }
+                        newStrings.add(s);
+                    });
+                    return newStrings;
+                })
+                .collect(Collectors.toList());
+
+
+        // Go through and piece together the lines, by removing the top of each list and concatenating it
+        final StringBuilder[] sb = {new StringBuilder()};
+        List<String> splitLines = Lists.newArrayList(maxHeightLine[0].split("[\\r\\n]+"));
+        splitLines
+                .forEach(new Consumer<String>() {
+                    @Override
+                    public void accept(String s) {
+                        textToJoin.forEach(ss -> {
+                            if (ss.size() > 0) {
+                                sb[0].append(ss.remove(0)).append(seperator);
+                            }
+                        });
+                        sb[0].append("\r\n");
+                        String finalformatted = sb[0].toString();
+                        sb[0] = new StringBuilder(replaceLast(finalformatted, seperator + "\r\n", "\r\n"));
+                    }
+                });
+        return sb[0].toString();
+    }
+
+    public static String replaceLast(String string, String toReplace, String replacement) {
+        int pos = string.lastIndexOf(toReplace);
+        if (pos > -1) {
+            return string.substring(0, pos)
+                    + replacement
+                    + string.substring(pos + toReplace.length(), string.length());
+        } else {
+            return string;
+        }
+    }
+
+}
diff --git a/src/main/java/com/comandante/creeper/blackjack/BlackJack.java b/src/main/java/com/comandante/creeper/blackjack/BlackJack.java
new file mode 100644
index 00000000..c8efce59
--- /dev/null
+++ b/src/main/java/com/comandante/creeper/blackjack/BlackJack.java
@@ -0,0 +1,68 @@
+package com.comandante.creeper.blackjack;
+
+
+import com.comandante.creeper.CreeperUtils;
+import com.google.common.collect.Lists;
+
+import java.text.MessageFormat;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.stream.Collectors;
+
+public class BlackJack {
+
+    public static class Card {
+
+        public final Deck.Type type;
+        public final Deck.Suit suit;
+
+        public Card(Deck.Suit suit, Deck.Type type) {
+            this.type = type;
+            this.suit = suit;
+        }
+    }
+
+    public static String templateCard =
+            "   ┌─────────┐\n" +
+                    "   │{0}        │\n" +
+                    "   │         │\n" +
+                    "   │         │\n" +
+                    "   │   {1}     │\n" +
+                    "   │         │\n" +
+                    "   │         │\n" +
+                    "   │       {0} │\n" +
+                    "   └─────────┘\n";
+
+    public static String getAsciiPlayingCardHand(List<Card> card) {
+        List<String> asciiCards = card.stream().map(BlackJack::getAsciiPlayingCard).collect(Collectors.toList());
+        return CreeperUtils.printStringsNextToEachOther(asciiCards, "");
+    }
+
+
+    public static String getAsciiPlayingCard(Card card) {
+        String rawTemplate = templateCard;
+        if (card.type.textRepresentation.length() == 2) {
+            StringBuilder sb = new StringBuilder();
+            ArrayList<String> strings = Lists.newArrayList(templateCard.split("[\\r\\n]+"));
+            strings.stream().map(s -> {
+                if (s.contains("{0}")) {
+                    return s.replace("{0} ", "{0}");
+                }
+                return s;
+            }).forEach((str) -> sb.append(str).append("\r\n"));
+            rawTemplate = sb.toString();
+        }
+
+        MessageFormat messageFormat = new MessageFormat(rawTemplate);
+        return messageFormat.format(Lists.newArrayList(card.type.textRepresentation, card.suit.textRepresentation).toArray());
+    }
+
+    public static void main(String[] args) {
+        Deck deck = new Deck();
+        deck.shuffle();
+        List<Card> cards = Lists.newArrayList(deck.next(), deck.next(), deck.next(), deck.next());
+        String asciiPlayingCardHand = getAsciiPlayingCardHand(cards);
+        System.out.println(asciiPlayingCardHand);
+    }
+
+}
diff --git a/src/main/java/com/comandante/creeper/blackjack/Deck.java b/src/main/java/com/comandante/creeper/blackjack/Deck.java
new file mode 100644
index 00000000..8ebc0a5d
--- /dev/null
+++ b/src/main/java/com/comandante/creeper/blackjack/Deck.java
@@ -0,0 +1,104 @@
+package com.comandante.creeper.blackjack;
+
+import com.google.common.collect.Lists;
+import org.apache.commons.lang3.StringUtils;
+
+import java.util.*;
+
+public class Deck implements Iterator<BlackJack.Card> {
+
+    enum Type {
+        ACE(1, "A"),
+        KING(10, "K"),
+        QUEEN(10, "Q"),
+        JACK(10, "J"),
+        TWO(2),
+        THREE(3),
+        FOUR(4),
+        FIVE(5),
+        SIX(6),
+        SEVEN(7),
+        EIGHT(8),
+        NINE(9),
+        TEN(10);
+
+
+        public final int value;
+        public final String textRepresentation;
+
+        Type(int value, String textRepresentation) {
+            this.value = value;
+            this.textRepresentation = textRepresentation;
+        }
+
+
+        Type(int value) {
+            this.value = value;
+            this.textRepresentation = String.valueOf(value);
+        }
+    }
+
+    enum Suit {
+        SPADES("â™ "),
+        HEARTS("♥"),
+        DIAMONDS("♦"),
+        CLUBS("♣");
+
+        public final String textRepresentation;
+
+        Suit(String textRepresentation) {
+            this.textRepresentation = textRepresentation;
+        }
+
+        public String getName() {
+            return StringUtils.capitalize(this.name().toLowerCase());
+        }
+    }
+
+
+    private List<BlackJack.Card> deckCards = Lists.newArrayList();
+    private Iterator<BlackJack.Card> delegate = deckCards.iterator();
+
+    public Deck() {
+        Arrays.stream(Deck.Suit.values())
+                .forEach(suit ->
+                        Arrays.stream(Deck.Type.values())
+                                .forEach(type ->
+                                        deckCards.add(new BlackJack.Card(suit, type))));
+    }
+
+    public void shuffle() {
+        Collections.shuffle(deckCards);
+    }
+
+    @Override
+    public boolean hasNext() {
+        return delegate.hasNext();
+    }
+
+    @Override
+    public BlackJack.Card next() {
+        BlackJack.Card next = deckCards.iterator().next();
+        ArrayList<BlackJack.Card> copy = Lists.newArrayList(deckCards);
+        copy.remove(next);
+        deckCards = copy;
+        delegate = copy.iterator();
+        return next;
+    }
+
+    public BlackJack.Card deal() {
+        return next();
+    }
+
+
+    public void addCard(BlackJack.Card card) {
+        ArrayList<BlackJack.Card> copy = Lists.newArrayList(deckCards);
+        copy.add(card);
+        deckCards = copy;
+        delegate = copy.iterator();
+    }
+
+    public int size() {
+        return deckCards.size();
+    }
+}
diff --git a/src/main/java/com/comandante/creeper/command/CardsCommand.java b/src/main/java/com/comandante/creeper/command/CardsCommand.java
new file mode 100644
index 00000000..c1555594
--- /dev/null
+++ b/src/main/java/com/comandante/creeper/command/CardsCommand.java
@@ -0,0 +1,34 @@
+package com.comandante.creeper.command;
+
+import com.comandante.creeper.blackjack.BlackJack;
+import com.comandante.creeper.blackjack.Deck;
+import com.comandante.creeper.managers.GameManager;
+import com.google.common.collect.Lists;
+import org.jboss.netty.channel.ChannelHandlerContext;
+import org.jboss.netty.channel.MessageEvent;
+
+import java.util.Arrays;
+import java.util.List;
+
+public class CardsCommand extends Command {
+
+    final static List<String> validTriggers = Arrays.asList("cards");
+    final static String description = "Display Random Cards";
+    final static String correctUsage = "cards";
+
+    public CardsCommand(GameManager gameManager) {
+        super(gameManager, validTriggers, description, correctUsage);
+    }
+
+    @Override
+    public void messageReceived(ChannelHandlerContext ctx, MessageEvent e) throws Exception {
+        execCommand(ctx, e, () -> {
+            Deck deck = new Deck();
+            deck.shuffle();
+            List<BlackJack.Card> cards = Lists.newArrayList(deck.next(), deck.next(), deck.next(), deck.next(), deck.deal());
+            String asciiPlayingCardHand = BlackJack.getAsciiPlayingCardHand(cards);
+            write(asciiPlayingCardHand + "\r\n");
+        });
+    }
+
+}
diff --git a/src/main/java/com/comandante/creeper/command/CompareCommand.java b/src/main/java/com/comandante/creeper/command/CompareCommand.java
new file mode 100644
index 00000000..98979d91
--- /dev/null
+++ b/src/main/java/com/comandante/creeper/command/CompareCommand.java
@@ -0,0 +1,60 @@
+package com.comandante.creeper.command;
+
+import com.comandante.creeper.CreeperUtils;
+import com.comandante.creeper.managers.GameManager;
+import com.comandante.creeper.npc.Npc;
+import com.comandante.creeper.player.Levels;
+import com.comandante.creeper.player.Player;
+import com.google.common.base.Joiner;
+import com.google.common.collect.Lists;
+import org.jboss.netty.channel.ChannelHandlerContext;
+import org.jboss.netty.channel.MessageEvent;
+
+import java.util.Arrays;
+import java.util.List;
+import java.util.Set;
+
+public class CompareCommand extends Command {
+
+    final static List<String> validTriggers = Arrays.asList("compare", "c");
+    final static String description = "Compare yourself to another player or npc.";
+    final static String correctUsage = "compare <playerName>||<npc>";
+
+    public CompareCommand(GameManager gameManager) {
+        super(gameManager, validTriggers, description, correctUsage);
+    }
+
+    @Override
+    public void messageReceived(ChannelHandlerContext ctx, MessageEvent e) throws Exception {
+        execCommand(ctx, e, () -> {
+            if (originalMessageParts.size() == 1) {
+                printCurrentRoomInformation();
+                return;
+            }
+            originalMessageParts.remove(0);
+            String target = Joiner.on(" ").join(originalMessageParts);
+            String selfLookStrong = player.getLookString();
+            //Players
+            Set<Player> presentPlayers = roomManager.getPresentPlayers(currentRoom);
+            for (Player presentPlayer : presentPlayers) {
+                if (presentPlayer != null && presentPlayer.getPlayerName().equals(target)) {
+                    String targetLookString = presentPlayer.getLookString();
+                    write(CreeperUtils.printStringsNextToEachOther(Lists.newArrayList(selfLookStrong, targetLookString), "  ")+ "\r\n");
+                    if (!presentPlayer.getPlayerId().equals(playerId)) {
+                        channelUtils.write(presentPlayer.getPlayerId(), player.getPlayerName() + " compares themself to you.", true);
+                    }
+                }
+            }
+
+            //NPCS
+            Set<String> npcIds = currentRoom.getNpcIds();
+            for (String npcId : npcIds) {
+                Npc currentNpc = gameManager.getEntityManager().getNpcEntity(npcId);
+                if (currentNpc.getValidTriggers().contains(target)) {
+                    String npcLookString = gameManager.getLookString(currentNpc, Levels.getLevel(gameManager.getStatsModifierFactory().getStatsModifier(player).getExperience()));
+                    write(Lists.newArrayList(selfLookStrong, npcLookString) + "\r\n");
+                }
+            }
+        });
+    }
+}
diff --git a/src/main/java/com/comandante/creeper/command/MovementCommand.java b/src/main/java/com/comandante/creeper/command/MovementCommand.java
index 6fac2a96..82b6cd62 100644
--- a/src/main/java/com/comandante/creeper/command/MovementCommand.java
+++ b/src/main/java/com/comandante/creeper/command/MovementCommand.java
@@ -88,7 +88,7 @@ public class MovementCommand extends Command {
             }
             player.movePlayer(playerMovement);
             if (playerMovement != null) {
-                player.setReturnDirection(Optional.of(playerMovement.getReturnDirection()));
+                player.setReturnDirection(java.util.Optional.of(playerMovement.getReturnDirection()));
                 MovementCommand.this.printCurrentRoomInformation(roomManager.getRoom(playerMovement.getDestinationRoomId()));
             }
         });
diff --git a/src/main/java/com/comandante/creeper/managers/GameManager.java b/src/main/java/com/comandante/creeper/managers/GameManager.java
index 5a263378..24cdbc13 100755
--- a/src/main/java/com/comandante/creeper/managers/GameManager.java
+++ b/src/main/java/com/comandante/creeper/managers/GameManager.java
@@ -25,7 +25,6 @@ import com.comandante.creeper.stat.Stats;
 import com.comandante.creeper.stat.StatsBuilder;
 import com.comandante.creeper.world.*;
 import com.google.api.client.util.Lists;
-import com.google.common.base.Optional;
 import com.google.common.collect.ImmutableSet;
 import com.google.common.collect.Interner;
 import com.google.common.collect.Interners;
@@ -634,7 +633,7 @@ public class GameManager {
             Map.Entry<String, Long> damageEntry = iterator.next();
             totalDamageDone += damageEntry.getValue();
             PlayerMetadata playerMetadata = getPlayerManager().getPlayerMetadata(damageEntry.getKey());
-            java.util.Optional<Room> playerCurrentRoom = getRoomManager().getPlayerCurrentRoom(playerMetadata.getPlayerId());
+            Optional<Room> playerCurrentRoom = getRoomManager().getPlayerCurrentRoom(playerMetadata.getPlayerId());
             if (!playerCurrentRoom.isPresent()) {
                 iterator.remove();
             } else if (!Objects.equals(npcCurrentRoom.getRoomId(), playerCurrentRoom.get().getRoomId())) {
diff --git a/src/main/java/com/comandante/creeper/player/Player.java b/src/main/java/com/comandante/creeper/player/Player.java
index cd9bf0a5..ad9b14d7 100755
--- a/src/main/java/com/comandante/creeper/player/Player.java
+++ b/src/main/java/com/comandante/creeper/player/Player.java
@@ -17,7 +17,6 @@ import com.comandante.creeper.stat.Stats;
 import com.comandante.creeper.stat.StatsBuilder;
 import com.comandante.creeper.stat.StatsHelper;
 import com.comandante.creeper.world.Room;
-import com.google.common.base.Optional;
 import com.google.common.collect.*;
 import org.apache.commons.codec.binary.Base64;
 import org.apache.log4j.Logger;
@@ -38,7 +37,7 @@ public class Player extends CreeperEntity {
     private final Random random = new Random();
     private String playerName;
     private Channel channel;
-    private Optional<String> returnDirection = Optional.absent();
+    private Optional<String> returnDirection = Optional.empty();
     private Room currentRoom;
     private SortedMap<Long, ActiveFight> activeFights = Collections.synchronizedSortedMap(new TreeMap<Long, ActiveFight>());
     private Set<CoolDown> coolDowns = Collections.synchronizedSet(new HashSet<CoolDown>());
@@ -803,7 +802,7 @@ public class Player extends CreeperEntity {
     }
 
     public String buildEquipmentString() {
-        org.nocrala.tools.texttablefmt.Table t = new Table(2, BorderStyle.CLASSIC_COMPATIBLE,
+        Table t = new Table(2, BorderStyle.CLASSIC_COMPATIBLE,
                 ShownBorders.NONE);
         t.setColumnWidth(0, 16, 20);
 
diff --git a/src/test/com/comandante/creeper/CreeperUtilsTest.java b/src/test/com/comandante/creeper/CreeperUtilsTest.java
new file mode 100644
index 00000000..24a8484b
--- /dev/null
+++ b/src/test/com/comandante/creeper/CreeperUtilsTest.java
@@ -0,0 +1,37 @@
+package com.comandante.creeper;
+
+import com.comandante.creeper.managers.GameManager;
+import com.comandante.creeper.player.*;
+import com.google.common.collect.Lists;
+import com.google.common.collect.Maps;
+import com.google.common.collect.Sets;
+import org.junit.Test;
+import org.mockito.Matchers;
+
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
+
+public class CreeperUtilsTest {
+
+    @Test
+    public void testCombineStrings() throws Exception {
+        PlayerMetadata playerMetadata = new PlayerMetadata("usertest", "Testtest", Main.createPlayerId("usertest"), PlayerStats.DEFAULT_PLAYER.createStats(), 0, Sets.newHashSet(PlayerRole.MORTAL), new String[0], 0, new String[0], Maps.newHashMap());
+        GameManager gameManager = mock(GameManager.class);
+        StatsModifierFactory statsModifierFactory = mock(StatsModifierFactory.class);
+        when(statsModifierFactory.getStatsModifier(Matchers.any())).thenReturn(PlayerStats.DEFAULT_PLAYER.createStats());
+        when(gameManager.getStatsModifierFactory()).thenReturn(statsModifierFactory);
+        PlayerManager playerManager = mock(PlayerManager.class);
+        when(playerManager.getPlayerMetadata(Matchers.any())).thenReturn(playerMetadata);
+        when(gameManager.getPlayerManager()).thenReturn(playerManager);
+
+
+        String usertest = new Player("usertest", gameManager).getLookString();
+
+        String s = CreeperUtils.printStringsNextToEachOther(Lists.newArrayList(usertest, usertest), " | ");
+
+        System.out.println(s);
+
+
+    }
+
+}
\ No newline at end of file
-- 
GitLab