package forge.quest.data; import forge.Card; import forge.CardFilter; import forge.Constant; import forge.properties.NewConstants; import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; import java.util.NoSuchElementException; import net.slightlymagic.braids.util.generator.GeneratorFunctions; import com.google.code.jyield.Generator; // The BoosterPack generates cards for the Card Pool in Quest Mode /** * <p>QuestBoosterPack class.</p> * * @author Forge * @version $Id: $ */ public class QuestBoosterPack implements NewConstants { ArrayList<String> choices; /** * <p>Constructor for QuestBoosterPack.</p> */ public QuestBoosterPack() { choices = new ArrayList<String>(); choices.add("Multicolor"); for (String s : Constant.Color.Colors) { choices.add(s); choices.add(s); } } /** * <p> * getQuestStarterDeck. * </p> * * @param allCards * the card pool from which we can generate the deck * * @param numCommon * a int. * * @param numUncommon * a int. * * @param numRare * a int. * * @param standardPool * whether to restrict the card pool to what is currently * considered the Standard block. To update the sets that are * considered standard, modify this method. * * @return a {@link java.util.ArrayList} object. */ public ArrayList<String> getQuestStarterDeck(Generator<Card> allCards, int numCommon, int numUncommon, int numRare, boolean standardPool) { ArrayList<String> names = new ArrayList<String>(); // Each color should have around the same amount of monocolored cards // There should be 3 Colorless cards for every 4 cards in a single color // There should be 1 Multicolor card for every 4 cards in a single color ArrayList<String> started = new ArrayList<String>(); started.add("Multicolor"); for (int i = 0; i < 4; i++) { if (i != 2) started.add(Constant.Color.Colorless); started.addAll(Arrays.asList(Constant.Color.onlyColors)); } if (standardPool) { // filter Cards for cards appearing in Standard Sets ArrayList<String> sets = new ArrayList<String>(); //TODO: It would be handy if the list of any sets can be chosen // ... Huh? // TODO: Braids: "It would also be handy if comments were written // in clear English." sets.add("NPH"); sets.add("MBS"); sets.add("SOM"); sets.add("M11"); sets.add("ROE"); sets.add("WWK"); sets.add("ZEN"); allCards = CardFilter.getSets(allCards, sets); /* * Here we force the generator to evaluate (solidify) into a * temporary ArrayList. This list only contains cards from 7 sets, * so it doesn't have nearly as much heap impact as an array of all * cards. Plus, we need to scan this array 3 times in the code * below. Braids thinks it's better to have the temporary list than * to force evaluation of the original generator three times, * because the original generator examines every card in the * database. */ allCards = GeneratorFunctions.solidify(allCards); } // We don't bother solidifying here, because allCards could be // equal to the set of ALL cards. names.addAll(generateCards(allCards, numCommon, Constant.Rarity.Common, null, started)); names.addAll(generateCards(allCards, numUncommon, Constant.Rarity.Uncommon, null, started)); names.addAll(generateCards(allCards, numRare, Constant.Rarity.Rare, null, started)); return names; } /** * Create the list of card names at random from the given pool. * * @param allCards the card pool to use * @param num how many card names to add to the result * @param rarity only allow cards of this rarity * @param color may be null; if not null, only cards of this color may be added * @param colorOrder we shuffle this as a side effect of calling this method * @return a list of card names */ public ArrayList<String> generateCards(Generator<Card> allCards, int num, String rarity, String color, ArrayList<String> colorOrder) { // If color is null, use colorOrder progression to grab cards ArrayList<String> names = new ArrayList<String>(); int size = colorOrder.size(); Collections.shuffle(colorOrder); allCards = CardFilter.getRarity(allCards, rarity); int count = 0, i = 0; if (num > 1) { // Force evaluation (solidify) the generator because we've applied // a filter to it, and we're about to use it more than once. allCards = GeneratorFunctions.solidify(allCards); } while (count < num) { String name; if (color == null) name = getCardName(allCards, colorOrder.get(i % size)); else name = getCardName(allCards); if (name != null && !names.contains(name)) { names.add(name); count++; } i++; } return names; } /** * Convenience for generateCards(cards, num, rarity, color, this.choices); * * @see #generateCards(Generator, int, String, String, ArrayList) */ public ArrayList<String> generateCards(Generator<Card> cards, int num, String rarity, String color) { return generateCards(cards, num, rarity, color, choices); } /** * Retrieve a card name at random from the given pool of cards; * the card must have a specific color. * * This forces one evaluation of the allCards Generator. * * @param allCards the card pool to use * @param color a {@link java.lang.String} object. * @return a random card name with the given color from allCards */ public String getCardName(Generator<Card> allCards, String color) { return getCardName(CardFilter.getColor(allCards, color)); } /** * Fetch a random card name from the given pool. * * This forces one evaluation of the cards Generator. * * @param cards the card pool from which to select * @return a card name from cards */ public String getCardName(Generator<Card> cards) { Card selected = null; try { selected = GeneratorFunctions.selectRandom(cards); } catch (NoSuchElementException ignored) { ; } if (selected == null) { // Previously, it was thought that this // Only should happen if something is programmed wrong // But empirical evidence contradicts this. return null; } return selected.getName(); } }