package com.vdom.core; import java.io.IOException; import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; import java.util.Comparator; import java.util.LinkedHashMap; import java.util.LinkedList; import java.util.List; import java.util.Map; import com.vdom.api.ActionCard; import com.vdom.api.Card; import com.vdom.api.CurseCard; import com.vdom.api.GameEvent; import com.vdom.api.TreasureCard; import com.vdom.core.Cards.Type; public class Util { public static String cardArrayToString(Card[] cards) { String str = ""; boolean first = true; for (Card card : cards) { if (first) { first = false; } else { str += ", "; } str += card.getName(); } if (str.equals("")) { return "(empty)"; } return str; } public static String cardArrayToString(CardList cards) { String str = ""; boolean first = true; for (Card card : cards) { if (first) { first = false; } else { str += ", "; } str += card.getName(); } if (str.equals("")) { return "(empty)"; } return str; } public static void log(String s) { System.out.println("<VDOM CORE> " + s); } public static void log(Throwable t) { t.printStackTrace(); } /** * Player did something invalid. */ public static void playerError(Player player, String err) { playerError(player, err, false); } /** * Player did something invalid. */ public static void playerError(Player player, String err, boolean dumpStack) { if (!Game.ignoreAllPlayerErrors) { if (Game.ignoreSomePlayerErrors) { if (Game.ignoreList.contains(player.getPlayerName())) { return; } } log(player.getPlayerName() + ":ERROR: " + err); if (dumpStack) { Thread.dumpStack(); } } } /** * Player did something invalid. */ public static void playerError(Player player, Throwable t) { if (!Game.ignoreAllPlayerErrors) { if (Game.ignoreSomePlayerErrors) { if (Game.ignoreList.contains(player.getPlayerName())) { return; } } log(player.getPlayerName() + ":ERROR: " + "Exception during player call"); t.printStackTrace(); } } /** * Print out a message prefixed by the player's name if in debug mode. */ public static void debug(Player player, String msg) { debug(player, msg, false); } /** * Print out a message prefixed by the player's name if either in debug mode, or in interactive mode and * interactiveAsWell is true. As with debug(msg, showInteractive), this is not always a "debug" message, * but it still seems to make sense to use the term. */ public static void debug(Player player, String msg, boolean interactiveAsWell) { debug(player.getPlayerName() + ":" + msg, interactiveAsWell); } /** * Print out a message if in debug mode. */ public static void debug(String msg) { debug(msg, false); } /** * Print out a message if either in debug mode, or in interactive mode and interactiveAsWell is true. This * is not always a "debug" message, but it still seems to make sense to use the term. */ public static void debug(String msg, boolean interactiveAsWell) { if (Game.debug || Game.junit) { log(msg); } } /** * Show a debug out only if the game is not being played interactively, or if the player is the current * player. Used for "private" information that an interactive player needs to know about for themselves, * but shouldn't know about other players. */ public static void sensitiveDebug(Player player, String msg, boolean interactiveAsWell) { // if (!Game.interactive || (player == Game.players[Game.playersTurn]) { debug(player, msg, interactiveAsWell); // } } /** * Make the user hit enter. If they enter a dot, then show the current game state and card details. Used * when playing in interactive mode. */ static void hitEnter(MoveContext context) { boolean valid = false; while (!valid) { valid = true; boolean dumpState = false; System.out.print("Hit enter >"); try { do { int input = System.in.read(); if (input == '.') { dumpState = true; } if (input == '`') { System.exit(0); } } while (System.in.available() != 0); } catch (IOException e) { e.printStackTrace(); } if (dumpState && context != null) { valid = false; dumpGameState(context); } } } protected static String readString() { StringBuilder sb = new StringBuilder(); try { do { int input = System.in.read(); if (input != -1 && input != 10 && input != 13) { sb.append((char) input); } } while (System.in.available() != 0); } catch (IOException e) { e.printStackTrace(); } return sb.toString(); } public static void dumpGameState(MoveContext context) { Player player = context.getPlayer(); log(""); Card[] cards = context.getCardsInGame(); int cost = 0; while (cost < 10) { for (Card card : cards) { if (card.getCost(context) == cost) { log("" + context.getCardsLeftInPile(card) + ":" + getLongText(card)); log(""); } } cost++; } log(""); log("Deck:" + player.getDeckSize() + " PirateShip:" + player.getPirateShipTreasure() + " NativeVillage:" + cardArrayToString(player.getNativeVillage()) + " Island:" + cardArrayToString(player.getIsland())); log(""); } public static String getLongText(Card card) { String cardText = card.getName() + " " + card.getStats(); String descr = card.getDescription(); if (descr != null && !descr.equals("")) { cardText += " \"" + descr + "\""; } return cardText; } public static String getShortText(Card card) { StringBuilder cardText = new StringBuilder(); cardText.append(card.getName()); int padding = CardImpl.maxNameLen - card.getName().length(); for (int i = 0; i < padding; i++) { cardText.append(" "); } cardText.append("\t"); cardText.append(card.getStats()); String descr = card.getDescription(); if (descr != null && !descr.equals("")) { cardText.append(" (...)"); } return cardText.toString(); } static boolean isDefendedFromAttack(Game game, Player player, Card responsible) { boolean defended = false; // TODO - pass some context about attack? MoveContext context = new MoveContext(game, player); if (game.hasLighthouse(player)) { defended = true; GameEvent event = new GameEvent(GameEvent.Type.PlayerDefended, context); event.card = Cards.lighthouse; game.broadcastEvent(event); } Card reactionCard = null; while ((reactionCard = player.controlPlayer.getAttackReaction(context, responsible, defended, reactionCard)) != null) { GameEvent event = new GameEvent(GameEvent.Type.CardRevealed, context); event.card = reactionCard; game.broadcastEvent(event); if (reactionCard.equals(Cards.secretChamber)) doSecretChamber(context, game, player, responsible); else if (reactionCard.equals(Cards.horseTraders)) doHorseTraders(context, game, player, responsible); else if (reactionCard.equals(Cards.beggar)) doBeggar(context, game, player, responsible); else if (reactionCard.equals(Cards.moat)) { defended = true; event = new GameEvent(GameEvent.Type.PlayerDefended, context); event.card = reactionCard; game.broadcastEvent(event); } } return defended; } static boolean doSecretChamber(MoveContext context, Game game, Player player, Card responsible) { boolean found = false; for (Card card : player.hand) { if (card.equals(Cards.secretChamber)) { found = true; } } if (found) { // GameEvent event = new GameEvent(GameEvent.Type.PlayingAction, context); // event.card = Cards.secretChamber; // game.broadcastEvent(event); // // event = new GameEvent(GameEvent.Type.CardRevealed, context); // event.card = Cards.secretChamber; // game.broadcastEvent(event); game.drawToHand(player, responsible); game.drawToHand(player, responsible); if (player.hand.size() > 0) { Card[] cards = player.controlPlayer.secretChamber_cardsToPutOnDeck(context); boolean bad = false; if (cards == null || cards.length > 2 || (cards.length < 2 && cards.length != player.hand.size())) { bad = true; } else { ArrayList<Card> copy = copy(player.hand); for (Card card : cards) { if (card == null || !copy.remove(card)) { bad = true; } } } if (bad) { playerError(player, "Secret Chamber cards to put on deck error, putting first two cards in hand back.", false); if (player.hand.size() < 2) { cards = new Card[player.hand.size()]; } else { cards = new Card[2]; } for (int i = 0; i < cards.length; i++) { cards[i] = player.hand.get(i); } } for (int i = cards.length - 1; i >= 0; i--) { player.putOnTopOfDeck(cards[i]); player.hand.remove(cards[i]); } } } return found; } static boolean doHorseTraders(MoveContext context, Game game, Player player, Card responsible) { Card horseTraders = null; for (Card card : player.hand) { if (card.equals(Cards.horseTraders)) { horseTraders = card; } } if (horseTraders != null) { // GameEvent event = new GameEvent(GameEvent.Type.PlayingAction, context); // event.card = Cards.horseTraders; // game.broadcastEvent(event); // // event = new GameEvent(GameEvent.Type.CardRevealed, context); // event.card = Cards.horseTraders; // game.broadcastEvent(event); player.hand.remove(horseTraders); player.horseTraders.add(horseTraders); return true; } return false; } static boolean doBeggar(MoveContext context, Game game, Player player, Card responsible) { Card beggar = null; for (Card card : player.hand) { if (card.equals(Cards.beggar)) { beggar = card; } } if (beggar != null) { if (player.controlPlayer.beggar_shouldDiscard(context)) { player.hand.remove(player.hand.indexOf(beggar), false); player.discard(beggar, responsible, context); player.gainNewCard(Cards.silver, beggar, context); player.gainNewCard(Cards.silver, beggar, context); } context.beggarSilverIsOnTop = 0; return true; } return false; } public static ArrayList<Card> copy(CardList cards) { if (cards == null) { return null; } ArrayList<Card> copy = new ArrayList<Card>(); for (Card card : cards) { copy.add(card); } return copy; } public static int getCardCount(CardList cards, Card card) { int count = 0; for (Card thisCard : cards) { if (thisCard.equals(card)) { count++; } } return count; } public static int getCardCount(ArrayList<Card> cards, Card card) { int count = 0; for (Card thisCard : cards) { if (thisCard.equals(card)) { count++; } } return count; } public static Card getLeastExpensiveCard(Card[] cards) { if (cards == null || cards.length == 0) { return null; } Arrays.sort(cards, new CardCostComparator()); return cards[0]; } public static Card getMostExpensiveCard(Card[] cards) { if (cards == null || cards.length == 0) { return null; } Arrays.sort(cards, new CardCostComparator()); return cards[cards.length - 1]; } public static Card randomCard(ArrayList<Card> list) { if(list == null || list.size() == 0) { return null; } return list.get(Game.rand.nextInt(list.size())); } public static Card randomCard(CardList list) { if(list == null || list.size() == 0) { return null; } return list.get(Game.rand.nextInt(list.size())); } public static Card randomCard(Card[] list) { if(list == null || list.length == 0) { return null; } return list[Game.rand.nextInt(list.length)]; } /** * Comparator for sorting by multiple attributes: * Compares with first Comparator if not equal return result * if equal use second one and repeat. * Repeat this pattern until last Comparator tried. */ static public class MultilevelComparator<T> implements Comparator<T> { private List<Comparator<T>> comps; public MultilevelComparator(List<Comparator<T>> comparators) { comps = comparators; } @Override public int compare(T arg0, T arg1) { int ret = 0; for(Comparator<T> cmp: comps) { ret = cmp.compare(arg0, arg1); if(ret != 0) { return ret; } } return ret; } } public static <K, V extends Comparable<? super V>> Map<K, V> sortByValue( Map<K, V> map ) { List<Map.Entry<K, V>> list = new LinkedList<Map.Entry<K, V>>( map.entrySet() ); Collections.sort( list, new Comparator<Map.Entry<K, V>>() { public int compare( Map.Entry<K, V> o1, Map.Entry<K, V> o2 ) { return (o1.getValue()).compareTo( o2.getValue() ); } } ); Map<K, V> result = new LinkedHashMap<K, V>(); for (Map.Entry<K, V> entry : list) { result.put( entry.getKey(), entry.getValue() ); } return result; } static public class CardNameComparator implements Comparator<Card> { @Override public int compare(Card card0, Card card1) { return card0.getName().compareTo(card1.getName()); } } static public class CardCostComparator implements Comparator<Card> { @Override public int compare(Card card0, Card card1) { if(card0.getCost(null) < card1.getCost(null)) { return -1; } else if(card0.getCost(null) > card1.getCost(null)) { return 1; } else { return 0; } } } static public class CardCostComparatorDesc implements Comparator<Card> { @Override public int compare(Card card0, Card card1) { CardCostComparator comp = new CardCostComparator(); return comp.compare(card1, card0); } } static public class CardValueComparator implements Comparator<Card> { @Override public int compare(Card card0, Card card1) { if ( !(card0 instanceof TreasureCard) || !(card1 instanceof TreasureCard) ) return 0; TreasureCard tcard0 = (TreasureCard) card0; TreasureCard tcard1 = (TreasureCard) card1; if (tcard0.getValue() < tcard1.getValue()) { return -1; } else if(tcard0.getValue() > tcard1.getValue()) { return 1; } else { return 0; } } } static public class CardValueComparatorDesc implements Comparator<Card> { @Override public int compare(Card card0, Card card1) { CardValueComparator comp = new CardValueComparator(); return comp.compare(card1, card0); } } static public class CardPotionComparator implements Comparator<Card> { @Override public int compare(Card card0, Card card1) { if(card0.costPotion()) { if(card1.costPotion()) { return 0; } else { return 1; } } else if(card1.costPotion()) { return -1; } else { return 0; } } } static public class CardTypeComparator implements Comparator<Card> { @Override public int compare(Card card0, Card card1) { if(card0 instanceof ActionCard) { if(card1 instanceof ActionCard) { return 0; } else { return -1; } } else if(card1 instanceof ActionCard) { return 1; } else if(card0 instanceof TreasureCard || card0.getType() == Type.Potion) { if(card1 instanceof TreasureCard || card1.getType() == Type.Potion) { return 0; } else { return -1; } } else if(card1 instanceof TreasureCard || card1.getType() == Type.Potion) { return 1; } else if(card0 instanceof CurseCard) { if(card1 instanceof CurseCard) { return 0; } else { return -1; } } else if(card1 instanceof CurseCard) { return 1; } else { return 0; } } } /** * Comparator for sorting cards by cost and then by name * Used for sorting on table */ static public class CardCostNameComparator extends MultilevelComparator<Card> { private static final ArrayList<Comparator<Card>> cmps = new ArrayList<Comparator<Card>>(); static { cmps.add(new CardCostComparator()); cmps.add(new CardNameComparator()); } public CardCostNameComparator() { super(cmps); } } /** * Comparator for sorting cards in hand. * Sort by type then by cost and last by name */ static public class CardHandComparator extends MultilevelComparator<Card> { private static final ArrayList<Comparator<Card>> cmps = new ArrayList<Comparator<Card>>(); static { cmps.add(new CardTypeComparator()); cmps.add(new CardValueComparatorDesc()); cmps.add(new CardCostComparatorDesc()); cmps.add(new CardNameComparator()); } public CardHandComparator() { super(cmps); } } }