/* * Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved. * * Redistribution and use in source and binary forms, with or without modification, are * permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright notice, this list of * conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright notice, this list * of conditions and the following disclaimer in the documentation and/or other materials * provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * * The views and conclusions contained in the software and documentation are those of the * authors and should not be interpreted as representing official policies, either expressed * or implied, of BetaSteward_at_googlemail.com. */ package mage.sets; import mage.Constants.CardType; import mage.Constants.ColoredManaSymbol; import mage.Mana; import mage.cache.Cache; import mage.cache.CacheDataHelper; import mage.cards.Card; import mage.cards.CardImpl; import mage.cards.ExpansionSet; import mage.cards.decks.Deck; import mage.cards.decks.DeckCardLists; import org.apache.log4j.Logger; import java.io.FileNotFoundException; import java.io.PrintWriter; import java.lang.reflect.Constructor; import java.util.*; /** * * @author BetaSteward_at_googlemail.com */ public class Sets extends HashMap { private final static Logger logger = Logger.getLogger(Sets.class); private static final Sets fINSTANCE = new Sets(); private static Set names; private static Set nonLandNames; private static Set creatureTypes; private static List cards; private static Map cardMap; protected static Random rnd = new Random(); private static final String NAMES_CACHE_OBJECT_NAME = "card_names"; private static final String NAMES_KEY = "card_names_key"; private static final String CREATURE_TYPES_CACHE_OBJECT_NAME = "creature_types"; private static final String CREATURE_TYPES_KEY = "creature_types_key"; private static final String NONLAND_NAMES_CACHE_OBJECT_NAME = "nonland_names"; private static final String NONLAND_NAMES_KEY = "nonland_names_key"; private static final int CACHE_VERSION = 1; public static Sets getInstance() { return fINSTANCE; } private Sets() { names = new TreeSet(); nonLandNames = new TreeSet(); cards = new ArrayList(); cardMap = new HashMap(); creatureTypes = new TreeSet(); this.addSet(AlaraReborn.getInstance()); this.addSet(Apocalypse.getInstance()); this.addSet(AvacynRestored.getInstance()); this.addSet(BetrayersOfKamigawa.getInstance()); this.addSet(ChampionsOfKamigawa.getInstance()); this.addSet(Conflux.getInstance()); this.addSet(DarkAscension.getInstance()); this.addSet(Darksteel.getInstance()); this.addSet(Dissension.getInstance()); this.addSet(EighthEdition.getInstance()); this.addSet(ElspethvsTezzeret.getInstance()); this.addSet(Eventide.getInstance()); this.addSet(FifthDawn.getInstance()); this.addSet(FifthEdition.getInstance()); this.addSet(FutureSight.getInstance()); this.addSet(Guildpact.getInstance()); this.addSet(Guru.getInstance()); this.addSet(Innistrad.getInstance()); this.addSet(Invasion.getInstance()); this.addSet(Lorwyn.getInstance()); this.addSet(Magic2010.getInstance()); this.addSet(Magic2011.getInstance()); this.addSet(Magic2012.getInstance()); this.addSet(MagicPlayerRewards.getInstance()); this.addSet(Mirrodin.getInstance()); this.addSet(MirrodinBesieged.getInstance()); this.addSet(Morningtide.getInstance()); this.addSet(NewPhyrexia.getInstance()); this.addSet(NinthEdition.getInstance()); this.addSet(Onslaught.getInstance()); this.addSet(PlanarChaos.getInstance()); this.addSet(Planechase.getInstance()); this.addSet(Planeshift.getInstance()); this.addSet(RavnicaCityOfGuilds.getInstance()); this.addSet(RiseOfTheEldrazi.getInstance()); this.addSet(SaviorsOfKamigawa.getInstance()); this.addSet(ScarsOfMirrodin.getInstance()); this.addSet(ShardsOfAlara.getInstance()); this.addSet(Shadowmoor.getInstance()); this.addSet(Tenth.getInstance()); this.addSet(Tempest.getInstance()); this.addSet(TimeSpiral.getInstance()); this.addSet(TimeSpiralTimeshifted.getInstance()); this.addSet(UrzasSaga.getInstance()); this.addSet(UrzasLegacy.getInstance()); this.addSet(Weatherlight.getInstance()); this.addSet(Worldwake.getInstance()); this.addSet(Zendikar.getInstance()); loadCardNames(); loadCreatureTypes(); loadNonLandNames(); } private void addSet(ExpansionSet set) { this.put(set.getCode(), set); cards.addAll(set.getCards()); /* for (Card card : set.getCards()) { names.add(card.getName()); if (card.getCardType().contains(CardType.CREATURE)) { for (String type : card.getSubtype()) { creatureTypes.add(type); if (type.equals("")) { throw new IllegalStateException("Card with empty subtype: " + card.getName()); } } } if (!card.getCardType().contains(CardType.LAND)) nonLandNames.add(card.getName()); } if (creatureTypes.contains("")) { creatureTypes.remove(""); }*/ } private void loadCardNames() { Cache cache = CacheDataHelper.getCachedObject(NAMES_CACHE_OBJECT_NAME); if (cache == null || cache.getVersion() != CACHE_VERSION) { for (Card card : cards) { names.add(card.getName()); } cache = new Cache(NAMES_CACHE_OBJECT_NAME, CACHE_VERSION); cache.getCacheObjects().put(NAMES_KEY, names); CacheDataHelper.cacheObject(cache, NAMES_CACHE_OBJECT_NAME); } else { Set cachedNames = (Set) cache.getCacheObjects().get(NAMES_KEY); names.addAll(cachedNames); } } private void loadCreatureTypes() { Cache cache = CacheDataHelper.getCachedObject(CREATURE_TYPES_CACHE_OBJECT_NAME); if (cache == null || cache.getVersion() != CACHE_VERSION) { for (Card card : cards) { if (card.getCardType().contains(CardType.CREATURE)) { for (String type : card.getSubtype()) { creatureTypes.add(type); if (type.equals("")) { throw new IllegalStateException("Card with empty subtype: " + card.getName()); } } } } cache = new Cache(CREATURE_TYPES_CACHE_OBJECT_NAME, CACHE_VERSION); cache.getCacheObjects().put(CREATURE_TYPES_KEY, creatureTypes); CacheDataHelper.cacheObject(cache, CREATURE_TYPES_CACHE_OBJECT_NAME); } else { Set cachedCreatureTypes = (Set) cache.getCacheObjects().get(CREATURE_TYPES_KEY); creatureTypes.addAll(cachedCreatureTypes); } } private void loadNonLandNames() { Cache cache = CacheDataHelper.getCachedObject(NONLAND_NAMES_CACHE_OBJECT_NAME); if (cache == null || cache.getVersion() != CACHE_VERSION) { for (Card card : cards) { if (!card.getCardType().contains(CardType.LAND)) nonLandNames.add(card.getName()); } cache = new Cache(NONLAND_NAMES_CACHE_OBJECT_NAME, CACHE_VERSION); cache.getCacheObjects().put(NONLAND_NAMES_KEY, nonLandNames); CacheDataHelper.cacheObject(cache, NONLAND_NAMES_CACHE_OBJECT_NAME); } else { Set cachedNonLandNames = (Set) cache.getCacheObjects().get(NONLAND_NAMES_KEY); nonLandNames.addAll(cachedNonLandNames); } } /*private static void loadCards() { if (cards.isEmpty()) { System.out.println("Loading cards..."); long t1 = System.currentTimeMillis(); for (ExpansionSet set : getInstance().values()) { cards.addAll(set.getCards()); for (Card card : set.getCards()) { names.add(card.getName()); if (card.getCardType().contains(CardType.CREATURE)) { for (String type : card.getSubtype()) { creatureTypes.add(type); if (type.equals("")) { throw new IllegalStateException("Card with empty subtype: " + card.getName()); } } } if (!card.getCardType().contains(CardType.LAND)) nonLandNames.add(card.getName()); } } if (creatureTypes.contains("")) { creatureTypes.remove(""); } System.out.println("It took " + (System.currentTimeMillis() - t1) / 1000 + " ms to load all cards."); } }*/ public static Set getCardNames() { /*if (names.isEmpty()) { loadCards(); }*/ return names; } public static Set getNonLandCardNames() { /*if (nonLandNames.isEmpty()) { loadCards(); }*/ return nonLandNames; } public static Set getCreatureTypes() { /*if (creatureTypes.isEmpty()) { loadCards(); }*/ return creatureTypes; } public static Card getRandomCard() { /*if (cards.isEmpty()) { loadCards(); }*/ return cards.get(rnd.nextInt(cards.size())); } /** * Generates card pool of cardsCount cards that have manacost of allowed colors. * * @param cardsCount * @param allowedColors * @return */ public static List generateRandomCardPool(int cardsCount, List allowedColors) { List cardPool = new ArrayList(); int count = 0; int tries = 0; while (count < cardsCount) { Card card = getRandomCard(); if (!card.getCardType().contains(CardType.LAND)) { if (cardFitsChosenColors(card, allowedColors)) { cardPool.add(card); count++; } } tries++; if (tries > 4096) { // to avoid infinite loop throw new IllegalStateException("Not enough cards for chosen colors to generate deck: " + allowedColors); } } return cardPool; } /** * Check that card can be played using chosen (allowed) colors. * * @param card * @param allowedColors * @return */ private static boolean cardFitsChosenColors(Card card, List allowedColors) { if (card.getCardType().contains(CardType.LAND)) { if (!card.getSupertype().contains("Basic")) { int score = 0; for (Mana mana : card.getMana()) { for (ColoredManaSymbol color : allowedColors) { score += mana.getColor(color); } } if (score > 1) { return true; } } } else { for (String symbol : card.getManaCost().getSymbols()) { boolean found = false; symbol = symbol.replace("{", "").replace("}", ""); if (isColoredMana(symbol)) { for (ColoredManaSymbol allowed : allowedColors) { if (allowed.toString().equals(symbol)) { found = true; break; } } if (!found) { return false; } } } return true; } return false; } protected static boolean isColoredMana(String symbol) { return symbol.equals("W") || symbol.equals("G") || symbol.equals("U") || symbol.equals("B") || symbol.equals("R"); } public static Deck generateDeck() { List allowedColors = new ArrayList(); int numColors = rnd.nextInt(2) + 1; int cardPoolSize = 60; if (numColors > 2) { cardPoolSize += 20; } Deck deck = new Deck(); return deck; } public static Card findCard(String name) { for (ExpansionSet set: fINSTANCE.values()) { Card card = set.findCard(name); if (card != null) return card; } return null; } public static Card findCard(String name, boolean random) { if (!random) { return findCard(name); } else { List cardsFound = new ArrayList(); for (ExpansionSet set: fINSTANCE.values()) { Card card = set.findCard(name, true); if (card != null) { cardsFound.add(card); } } if (cardsFound.size() > 0) { Card card = cardsFound.get(rnd.nextInt(cardsFound.size())); String cardClassName = card.getClass().getName(); return CardImpl.createCard(cardClassName); } } return null; } public static Card findCard(String expansionsetCode, int cardNum) { if (cardMap.containsKey(expansionsetCode + Integer.toString(cardNum))) { return cardMap.get(expansionsetCode + Integer.toString(cardNum)); } if (fINSTANCE.containsKey(expansionsetCode)) { ExpansionSet set = fINSTANCE.get(expansionsetCode); Card card = set.findCard(cardNum); if (card != null) { cardMap.put(expansionsetCode + Integer.toString(cardNum), card); return card; } } logger.warn("Could not find card: set=" + expansionsetCode + "cardNum=" + Integer.toString(cardNum)); return null; } public static Card createCard(Class clazz) { try { Constructor con = clazz.getConstructor(new Class[]{UUID.class}); return (Card) con.newInstance(new Object[] {null}); } catch (Exception ex) { logger.fatal("Error creating card:" + clazz.getName(), ex); return null; } } public static ExpansionSet findSet(String code) { if (fINSTANCE.containsKey(code)) return fINSTANCE.get(code); return null; } public static void saveDeck(String file, DeckCardLists deck) throws FileNotFoundException { PrintWriter out = new PrintWriter(file); Map deckCards = new HashMap(); Map sideboard = new HashMap(); try { if (deck.getName() != null && deck.getName().length() > 0) out.println("NAME:" + deck.getName()); if (deck.getAuthor() != null && deck.getAuthor().length() > 0) out.println("AUTHOR:" + deck.getAuthor()); for (String cardClass: deck.getCards()) { if (deckCards.containsKey(cardClass)) { deckCards.put(cardClass, deckCards.get(cardClass) + 1); } else { deckCards.put(cardClass, 1); } } for (String cardClass: deck.getSideboard()) { if (sideboard.containsKey(cardClass)) { sideboard.put(cardClass, sideboard.get(cardClass) + 1); } else { sideboard.put(cardClass, 1); } } for (Map.Entry entry: deckCards.entrySet()) { Card card = CardImpl.createCard(entry.getKey()); if (card != null) { out.printf("%d [%s:%d] %s%n", entry.getValue(), card.getExpansionSetCode(), card.getCardNumber(), card.getName()); } } for (Map.Entry entry: sideboard.entrySet()) { Card card = CardImpl.createCard(entry.getKey()); if (card != null) { out.printf("SB: %d [%s:%d] %s%n", entry.getValue(), card.getExpansionSetCode(), card.getCardNumber(), card.getName()); } } } finally { out.close(); } } public ExpansionSet[] getSortedByReleaseDate() { ExpansionSet[] sets = Sets.getInstance().values().toArray(new ExpansionSet[0]); Arrays.sort(sets, new Comparator() { @Override public int compare(ExpansionSet o1, ExpansionSet o2) { return o2.getReleaseDate().compareTo(o1.getReleaseDate()); } }); return sets; } }