forge.limited.SealedCardPoolGenerator.java Source code

Java tutorial

Introduction

Here is the source code for forge.limited.SealedCardPoolGenerator.java

Source

/*
 * Forge: Play Magic: the Gathering.
 * Copyright (C) 2011  Forge Team
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 * 
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 * 
 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */
package forge.limited;

import forge.assets.FSkinProp;
import forge.card.CardEdition;
import forge.card.IUnOpenedProduct;
import forge.card.MagicColor;
import forge.card.UnOpenedProduct;
import forge.deck.CardPool;
import forge.deck.Deck;
import forge.deck.DeckGroup;
import forge.deck.DeckSection;
import forge.item.PaperCard;
import forge.item.SealedProduct;
import forge.model.CardBlock;
import forge.model.FModel;
import forge.model.UnOpenedMeta;
import forge.properties.ForgeConstants;
import forge.properties.ForgePreferences.FPref;
import forge.util.FileUtil;
import forge.util.MyRandom;
import forge.util.TextUtil;
import forge.util.gui.SGuiChoose;
import forge.util.gui.SOptionPane;
import forge.util.storage.IStorage;

import org.apache.commons.lang3.ArrayUtils;
import org.apache.commons.lang3.StringUtils;

import java.io.File;
import java.util.ArrayList;
import java.util.List;
import java.util.Stack;
import java.util.Map.Entry;

/**
 * <p>
 * SealedDeckFormat class.
 * </p>
 * 
 * @author Forge
 * @version $Id: SealedCardPoolGenerator.java 30279 2015-10-12 01:43:03Z friarsol $
 * @since 1.0.15
 */
public class SealedCardPoolGenerator {
    public static final String FILE_EXT = ".sealed";

    private final List<IUnOpenedProduct> product = new ArrayList<IUnOpenedProduct>();

    /** The Land set code. */
    private String landSetCode = null;

    public static DeckGroup generateSealedDeck(final boolean addBasicLands) {
        final String prompt = "Choose Sealed Deck Format";
        final LimitedPoolType poolType = SGuiChoose.oneOrNone(prompt, LimitedPoolType.values());
        if (poolType == null) {
            return null;
        }

        SealedCardPoolGenerator sd = new SealedCardPoolGenerator(poolType);
        if (sd.isEmpty()) {
            return null;
        }

        final CardPool humanPool = sd.getCardPool(true);
        if (humanPool == null) {
            return null;
        }

        // Just assume 7 opponents, allow to play any/all later
        int rounds = 7;

        final String sDeckName = SOptionPane.showInputDialog("Save this card pool as:", "Save Card Pool",
                FSkinProp.ICO_QUESTION);

        if (StringUtils.isBlank(sDeckName)) {
            return null;
        }

        final IStorage<DeckGroup> sealedDecks = FModel.getDecks().getSealed();
        if (sealedDecks.contains(sDeckName)) {
            if (!SOptionPane.showConfirmDialog("'" + sDeckName + "' already exists. Do you want to replace it?",
                    "Sealed Deck Game Exists")) {
                return null;
            }
            sealedDecks.delete(sDeckName);
        }

        final Deck deck = new Deck(sDeckName);
        deck.getOrCreate(DeckSection.Sideboard).addAll(humanPool);

        if (addBasicLands) {
            final int landsCount = 10;

            final boolean isZendikarSet = sd.getLandSetCode().equals("ZEN"); // we want to generate one kind of Zendikar lands at a time only
            final boolean zendikarSetMode = MyRandom.getRandom().nextBoolean();

            for (final String element : MagicColor.Constant.BASIC_LANDS) {
                int numArt = FModel.getMagicDb().getCommonCards().getArtCount(element, sd.getLandSetCode());
                int minArtIndex = isZendikarSet ? (zendikarSetMode ? 1 : 5) : 1;
                int maxArtIndex = isZendikarSet ? minArtIndex + 3 : numArt;

                if (FModel.getPreferences().getPrefBoolean(FPref.UI_RANDOM_ART_IN_POOLS)) {
                    for (int i = minArtIndex; i <= maxArtIndex; i++) {
                        deck.get(DeckSection.Sideboard).add(element, sd.getLandSetCode(), i,
                                numArt > 1 ? landsCount : 30);
                    }
                } else {
                    deck.get(DeckSection.Sideboard).add(element, sd.getLandSetCode(), 30);
                }
            }
        }

        final DeckGroup sealed = new DeckGroup(sDeckName);
        deck.setDirectory(sealedDecks.getName());
        sealed.setHumanDeck(deck);
        for (int i = 0; i < rounds; i++) {
            // Generate other decks for next N opponents
            final CardPool aiPool = sd.getCardPool(false);
            if (aiPool == null) {
                return null;
            }

            sealed.addAiDeck(new SealedDeckBuilder(aiPool.toFlatList()).buildDeck(sd.getLandSetCode()));
        }

        // Rank the AI decks
        sealed.rankAiDecks(new SealedDeckComparer());

        FModel.getDecks().getSealed().add(sealed);
        return sealed;
    }

    /**
     * <p>
     * Constructor for SealedDeck.
     * </p>
     * 
     * @param poolType
     *            a {@link java.lang.String} object.
     */
    private SealedCardPoolGenerator(final LimitedPoolType poolType) {
        switch (poolType) {
        case Full:
            // Choose number of boosters
            if (!chooseNumberOfBoosters(new UnOpenedProduct(SealedProduct.Template.genericBooster))) {
                return;
            }
            landSetCode = CardEdition.Predicates.getRandomSetWithAllBasicLands(FModel.getMagicDb().getEditions())
                    .getCode();
            break;

        case Block:
        case FantasyBlock:
            List<CardBlock> blocks = new ArrayList<CardBlock>();
            Iterable<CardBlock> src = poolType == LimitedPoolType.Block ? FModel.getBlocks()
                    : FModel.getFantasyBlocks();
            for (CardBlock b : src) {
                blocks.add(b);
            }

            final CardBlock block = SGuiChoose.oneOrNone("Choose Block", blocks);
            if (block == null) {
                return;
            }

            final int nPacks = block.getCntBoostersSealed();
            final Stack<String> sets = new Stack<String>();

            for (CardEdition edition : block.getSets()) {
                sets.add(edition.getCode());
            }

            for (String ms : block.getMetaSetNames()) {
                sets.push(ms);
            }

            if (sets.size() > 1) {
                final List<String> setCombos = getSetCombos(sets, nPacks);
                if (setCombos == null || setCombos.isEmpty()) {
                    throw new RuntimeException(
                            "Unsupported amount of packs (" + nPacks + ") in a Sealed Deck block!");
                }

                final String p = setCombos.size() > 1 ? SGuiChoose.oneOrNone("Choose packs to play with", setCombos)
                        : setCombos.get(0);
                if (p == null) {
                    return;
                }

                for (String pz : TextUtil.split(p, ',')) {
                    String[] pps = TextUtil.splitWithParenthesis(pz.trim(), ' ');
                    String setCode = pps[pps.length - 1];
                    int nBoosters = pps.length > 1 ? Integer.parseInt(pps[0]) : 1;
                    while (nBoosters-- > 0) {
                        this.product.add(block.getBooster(setCode));
                    }
                }
            } else {
                IUnOpenedProduct prod = block.getBooster(sets.get(0));
                for (int i = 0; i < nPacks; i++) {
                    this.product.add(prod);
                }
            }

            landSetCode = block.getLandSet().getCode();
            break;

        case Custom:
            String[] dList;
            final List<CustomLimited> customs = new ArrayList<CustomLimited>();

            // get list of custom draft files
            final File dFolder = new File(ForgeConstants.SEALED_DIR);
            if (!dFolder.exists()) {
                throw new RuntimeException(
                        "GenerateSealed : folder not found -- folder is " + dFolder.getAbsolutePath());
            }

            if (!dFolder.isDirectory()) {
                throw new RuntimeException("GenerateSealed : not a folder -- " + dFolder.getAbsolutePath());
            }

            dList = dFolder.list();

            for (final String element : dList) {
                if (element.endsWith(FILE_EXT)) {
                    final List<String> dfData = FileUtil.readFile(ForgeConstants.SEALED_DIR + element);
                    final CustomLimited cs = CustomLimited.parse(dfData, FModel.getDecks().getCubes());
                    if (cs.getSealedProductTemplate().getNumberOfCardsExpected() > 5) { // Do not allow too small cubes to be played as 'stand-alone'!
                        customs.add(cs);
                    }
                }
            }

            // present list to user
            if (customs.isEmpty()) {
                SOptionPane.showMessageDialog("No custom sealed files found.");
                return;
            }

            final CustomLimited draft = SGuiChoose.oneOrNone("Choose Custom Sealed Pool", customs);
            if (draft == null) {
                return;
            }

            UnOpenedProduct toAdd = new UnOpenedProduct(draft.getSealedProductTemplate(), draft.getCardPool());
            toAdd.setLimitedPool(draft.isSingleton());
            if (!chooseNumberOfBoosters(toAdd)) {
                return;
            }

            landSetCode = draft.getLandSetCode();
            break;
        }
    }

    private boolean chooseNumberOfBoosters(final IUnOpenedProduct product1) {
        Integer boosterCount = SGuiChoose.getInteger("How many booster packs?", 3, 12);
        if (boosterCount == null) {
            return false;
        }

        for (int i = 0; i < boosterCount; i++) {
            this.product.add(product1);
        }
        return true;
    }

    /**
     * <p>
     * getSetCombos.
     * </p>
     * 
     * @return an ArrayList of the set choices.
     */
    private static List<String> getSetCombos(final List<String> setz, final int nPacks) {
        // TODO These permutations really should be completely generated
        String[] sets = setz.toArray(ArrayUtils.EMPTY_STRING_ARRAY);
        List<String> setCombos = new ArrayList<String>();

        if (nPacks == 3) {
            if (sets.length >= 2) {
                setCombos.add(String.format("%s, %s, %s", sets[0], sets[0], sets[0]));
                setCombos.add(String.format("%s, %s, %s", sets[1], sets[0], sets[0]));
                setCombos.add(String.format("%s, %s, %s", sets[1], sets[1], sets[0]));
                setCombos.add(String.format("3 %s", sets[1]));
            }
            if (sets.length >= 3) {
                setCombos.add(String.format("%s, %s, %s", sets[2], sets[0], sets[0]));
                setCombos.add(String.format("%s, %s, %s", sets[0], sets[2], sets[0]));
                setCombos.add(String.format("%s, %s, %s", sets[2], sets[2], sets[2]));
                setCombos.add(String.format("%s, %s, %s", sets[2], sets[1], sets[0]));
            }
        } else if (nPacks == 4) {
            if (sets.length >= 2) {
                setCombos.add(String.format("%s, %s, %s, %s", sets[0], sets[0], sets[0], sets[0]));
                setCombos.add(String.format("%s, %s, %s, %s", sets[1], sets[0], sets[0], sets[0]));
                setCombos.add(String.format("%s, %s, %s, %s", sets[1], sets[1], sets[0], sets[0]));
            }
            if (sets.length >= 3) {
                setCombos.add(String.format("%s, %s, %s, %s", sets[2], sets[2], sets[0], sets[0]));
                setCombos.add(String.format("%s, %s, %s, %s", sets[2], sets[1], sets[0], sets[0]));
            }
            if (sets.length >= 4) {
                setCombos.add(String.format("%s, %s, %s, %s", sets[3], sets[2], sets[1], sets[0]));
            }
        } else if (nPacks == 5) {
            if (sets.length == 1 || !sets[0].equals(sets[1])) {
                setCombos.add(String.format("5 %s", sets[0]));
            }

            if (sets.length >= 2 && !sets[0].equals(sets[1])) {
                setCombos.add(String.format("3 %s, 2 %s", sets[0], sets[1]));
                setCombos.add(String.format("2 %s, 3 %s", sets[0], sets[1]));
            }
            if (sets.length >= 3 && !sets[0].equals(sets[2])) {
                setCombos.add(String.format("3 %s, 2 %s", sets[0], sets[2]));
                setCombos.add(String.format("3 %s, %s, %s", sets[0], sets[1], sets[2]));
                setCombos.add(String.format("2 %s, 2 %s, %s", sets[0], sets[1], sets[2]));
            }
            if (sets.length >= 4) {
                if (sets[1].equals(sets[2]) && sets[1].equals(sets[0])) {
                    setCombos.add(String.format("%s, 4 %s", sets[3], sets[0])); // for guild sealed
                } else {
                    setCombos.add(String.format("%s, %s, %s, 2 %s", sets[3], sets[2], sets[1], sets[0]));
                }
            }
            if (sets.length >= 5) {
                setCombos.add(String.format("%s, %s, %s, %s, %s", sets[4], sets[3], sets[2], sets[1], sets[0]));
            }
        } else if (nPacks == 7 && (sets.length == 4 || sets.length >= 7)) {
            // Sorry. This whole function is awful, it really needs to be rewritten to just generate permutations
            if (sets.length >= 7) {
                setCombos.add(String.format("%s, %s, %s, %s, %s, %s, %s", sets[6], sets[5], sets[4], sets[3],
                        sets[2], sets[1], sets[0]));
                setCombos.add(String.format("%s, %s, %s, %s, %s, %s, %s", sets[5], sets[4], sets[3], sets[2],
                        sets[1], sets[0], sets[0]));
                setCombos.add(String.format("%s, %s, %s, %s, %s, %s, %s", sets[4], sets[3], sets[2], sets[1],
                        sets[1], sets[0], sets[0]));
                setCombos.add(String.format("%s, %s, %s, %s, %s, %s, %s", sets[4], sets[3], sets[2], sets[1],
                        sets[0], sets[0], sets[0]));
                setCombos.add(String.format("%s, %s, %s, %s, %s, %s, %s", sets[3], sets[2], sets[2], sets[1],
                        sets[1], sets[0], sets[0]));
                setCombos.add(String.format("%s, %s, %s, %s, %s, %s, %s", sets[3], sets[2], sets[1], sets[1],
                        sets[0], sets[0], sets[0]));
                setCombos.add(String.format("%s, %s, %s, %s, %s, %s, %s", sets[3], sets[2], sets[1], sets[0],
                        sets[0], sets[0], sets[0]));
                setCombos.add(String.format("%s, %s, %s, %s, %s, %s, %s", sets[2], sets[2], sets[1], sets[1],
                        sets[0], sets[0], sets[0]));
                setCombos.add(String.format("%s, %s, %s, %s, %s, %s, %s", sets[2], sets[1], sets[1], sets[0],
                        sets[0], sets[0], sets[0]));
                setCombos.add(String.format("%s, %s, %s, %s, %s, %s, %s", sets[2], sets[2], sets[2], sets[0],
                        sets[0], sets[0], sets[0]));
                setCombos.add(String.format("%s, %s, %s, %s, %s, %s, %s", sets[1], sets[1], sets[1], sets[0],
                        sets[0], sets[0], sets[0]));
                setCombos.add(String.format("%s, %s, %s, %s, %s, %s, %s", sets[0], sets[0], sets[0], sets[0],
                        sets[0], sets[0], sets[0]));
            } else if (sets.length == 4) {
                if (sets[1].equals(sets[2]) && sets[1].equals(sets[0])) {
                    setCombos.add(String.format("%s, 6 %s", sets[3], sets[0])); // for origins sealed
                } else {
                    setCombos.add(String.format("%s, 2 %s, 2 %s, 2 %s", sets[3], sets[2], sets[1], sets[0]));
                }
            }
        } else if (nPacks == 8 && sets.length >= 8) {
            setCombos.add(String.format("%s, %s, %s, %s, %s, %s, %s, %s", sets[7], sets[6], sets[5], sets[4],
                    sets[3], sets[2], sets[1], sets[0]));
            setCombos.add(String.format("%s, %s, %s, %s, %s, %s, %s, %s", sets[6], sets[5], sets[4], sets[3],
                    sets[2], sets[1], sets[0], sets[0]));
            setCombos.add(String.format("%s, %s, %s, %s, %s, %s, %s, %s", sets[5], sets[4], sets[3], sets[2],
                    sets[1], sets[1], sets[0], sets[0]));
            setCombos.add(String.format("%s, %s, %s, %s, %s, %s, %s, %s", sets[5], sets[4], sets[3], sets[2],
                    sets[1], sets[0], sets[0], sets[0]));
            setCombos.add(String.format("%s, %s, %s, %s, %s, %s, %s, %s", sets[4], sets[3], sets[2], sets[2],
                    sets[1], sets[1], sets[0], sets[0]));
            setCombos.add(String.format("%s, %s, %s, %s, %s, %s, %s, %s", sets[4], sets[3], sets[2], sets[1],
                    sets[1], sets[0], sets[0], sets[0]));
            setCombos.add(String.format("%s, %s, %s, %s, %s, %s, %s, %s", sets[4], sets[3], sets[2], sets[1],
                    sets[0], sets[0], sets[0], sets[0]));
            setCombos.add(String.format("%s, %s, %s, %s, %s, %s, %s, %s", sets[3], sets[3], sets[2], sets[2],
                    sets[1], sets[1], sets[0], sets[0]));
            setCombos.add(String.format("%s, %s, %s, %s, %s, %s, %s, %s", sets[3], sets[2], sets[2], sets[1],
                    sets[1], sets[0], sets[0], sets[0]));
            setCombos.add(String.format("%s, %s, %s, %s, %s, %s, %s, %s", sets[3], sets[2], sets[1], sets[1],
                    sets[0], sets[0], sets[0], sets[0]));
            setCombos.add(String.format("%s, %s, %s, %s, %s, %s, %s, %s", sets[3], sets[2], sets[1], sets[0],
                    sets[0], sets[0], sets[0], sets[0]));
            setCombos.add(String.format("%s, %s, %s, %s, %s, %s, %s, %s", sets[2], sets[2], sets[1], sets[1],
                    sets[0], sets[0], sets[0], sets[0]));
            setCombos.add(String.format("%s, %s, %s, %s, %s, %s, %s, %s", sets[2], sets[2], sets[2], sets[2],
                    sets[0], sets[0], sets[0], sets[0]));
            setCombos.add(String.format("%s, %s, %s, %s, %s, %s, %s, %s", sets[1], sets[1], sets[1], sets[1],
                    sets[0], sets[0], sets[0], sets[0]));
            setCombos.add(String.format("%s, %s, %s, %s, %s, %s, %s, %s", sets[0], sets[0], sets[0], sets[0],
                    sets[0], sets[0], sets[0], sets[0]));
        } else if (nPacks == 9 && sets.length >= 9) {
            setCombos.add(String.format("%s, %s, %s, %s, %s, %s, %s, %s, %s", sets[8], sets[7], sets[6], sets[5],
                    sets[4], sets[3], sets[2], sets[1], sets[0]));
            setCombos.add(String.format("%s, %s, %s, %s, %s, %s, %s, %s, %s", sets[7], sets[6], sets[5], sets[4],
                    sets[3], sets[2], sets[1], sets[0], sets[0]));
            setCombos.add(String.format("%s, %s, %s, %s, %s, %s, %s, %s, %s", sets[6], sets[5], sets[4], sets[3],
                    sets[2], sets[1], sets[1], sets[0], sets[0]));
            setCombos.add(String.format("%s, %s, %s, %s, %s, %s, %s, %s, %s", sets[6], sets[5], sets[4], sets[3],
                    sets[2], sets[1], sets[0], sets[0], sets[0]));
            setCombos.add(String.format("%s, %s, %s, %s, %s, %s, %s, %s, %s", sets[4], sets[3], sets[3], sets[2],
                    sets[2], sets[1], sets[1], sets[0], sets[0]));
            setCombos.add(String.format("%s, %s, %s, %s, %s, %s, %s, %s, %s", sets[4], sets[3], sets[2], sets[2],
                    sets[1], sets[1], sets[0], sets[0], sets[0]));
            setCombos.add(String.format("%s, %s, %s, %s, %s, %s, %s, %s, %s", sets[4], sets[3], sets[2], sets[1],
                    sets[1], sets[1], sets[0], sets[0], sets[0]));
            setCombos.add(String.format("%s, %s, %s, %s, %s, %s, %s, %s, %s", sets[4], sets[3], sets[2], sets[2],
                    sets[1], sets[1], sets[0], sets[0], sets[0]));
            setCombos.add(String.format("%s, %s, %s, %s, %s, %s, %s, %s, %s", sets[4], sets[3], sets[2], sets[1],
                    sets[1], sets[0], sets[0], sets[0], sets[0]));
            setCombos.add(String.format("%s, %s, %s, %s, %s, %s, %s, %s, %s", sets[4], sets[3], sets[2], sets[1],
                    sets[0], sets[0], sets[0], sets[0], sets[0]));
            setCombos.add(String.format("%s, %s, %s, %s, %s, %s, %s, %s, %s", sets[3], sets[3], sets[2], sets[2],
                    sets[1], sets[1], sets[0], sets[0], sets[0]));
            setCombos.add(String.format("%s, %s, %s, %s, %s, %s, %s, %s, %s", sets[3], sets[2], sets[2], sets[1],
                    sets[1], sets[1], sets[0], sets[0], sets[0]));
            setCombos.add(String.format("%s, %s, 2 %s, 5 %s", sets[3], sets[2], sets[1], sets[0]));
            setCombos.add(String.format("3 %s, 3 %s, 3 %s", sets[2], sets[1], sets[0]));
            setCombos.add(String.format("2 %s, 2 %s, 5 %s", sets[2], sets[1], sets[0]));
            setCombos.add(String.format("%s, %s, 7 %s", sets[2], sets[1], sets[0]));
            setCombos.add(String.format("4 %s, 5 %s", sets[2], sets[0]));
            setCombos.add(String.format("4 %s, 5 %s", sets[1], sets[0]));
            setCombos.add(String.format("9 %s", sets[0]));
        } else { // Default to 6 packs
            if (sets.length == 1 || !sets[0].equals(sets[1])) {
                setCombos.add(String.format("6 %s", sets[0]));
            }

            if (sets.length >= 2 && !sets[0].equals(sets[1])) {
                setCombos.add(String.format("4 %s, 2 %s", sets[0], sets[1]));
                setCombos.add(String.format("3 %s, 3 %s", sets[0], sets[1]));
            }
            if (sets.length >= 3 && !sets[0].equals(sets[2])) {
                setCombos.add(String.format("3 %s, 3 %s", sets[0], sets[2]));
                setCombos.add(String.format("2 %s, 2 %s, 2 %s", sets[0], sets[1], sets[2]));
            }
            if (sets.length >= 4) {
                if (sets[1].equals(sets[2]) && sets[1].equals(sets[0])) {
                    setCombos.add(String.format("%s, 5 %s", sets[3], sets[0])); // for guild sealed
                } else {
                    setCombos.add(String.format("%s, %s, %s, 3 %s", sets[3], sets[2], sets[1], sets[0]));
                    setCombos.add(String.format("%s, %s, 2 %s, 2 %s", sets[3], sets[2], sets[1], sets[0]));
                }
            }
            if (sets.length >= 5) {
                setCombos.add(String.format("%s, %s, %s, %s, 2 %s", sets[4], sets[3], sets[2], sets[1], sets[0]));
            }
            if (sets.length >= 6) {
                setCombos.add(String.format("%s, %s, %s, %s, %s, %s", sets[5], sets[4], sets[3], sets[2], sets[1],
                        sets[0]));
            }
        }
        return setCombos;
    }

    /**
     * <p>
     * getCardpool.
     * </p>
     * 
     * @param isHuman
     *      boolean, get pool for human (possible choices)
     * @return a {@link forge.CardList} object.
     */
    public CardPool getCardPool(final boolean isHuman) {
        final CardPool pool = new CardPool();

        for (IUnOpenedProduct prod : product) {
            if (prod instanceof UnOpenedMeta) {
                List<PaperCard> cards = ((UnOpenedMeta) prod).open(isHuman, true);
                if (cards == null) {
                    return null; //return null if user canceled
                }
                pool.addAllFlat(cards);
            } else {
                pool.addAllFlat(prod.get());
            }
        }
        return pool;
    }

    /**
     * Gets the land set code.
     * 
     * @return the landSetCode
     */
    public String getLandSetCode() {
        return this.landSetCode;
    }

    public boolean isEmpty() {
        return product.isEmpty();
    }

    private static class SealedDeckComparer implements java.util.Comparator<Deck> {
        public double getDraftValue(Deck d) {
            double value = 0;
            double divider = 0;

            if (d.getMain().isEmpty()) {
                return 0;
            }

            double best = 1.0;

            for (Entry<PaperCard, Integer> kv : d.getMain()) {
                PaperCard evalCard = kv.getKey();
                int count = kv.getValue();
                if (DraftRankCache.getRanking(evalCard.getName(), evalCard.getEdition()) != null) {
                    double add = DraftRankCache.getRanking(evalCard.getName(), evalCard.getEdition());
                    // System.out.println(evalCard.getName() + " is worth " + add);
                    value += add * count;
                    divider += count;
                    if (best > add) {
                        best = add;
                    }
                }
            }

            if (divider == 0 || value == 0) {
                return 0;
            }

            value /= divider;

            return (20.0 / (best + (2 * value)));
        }

        @Override
        public int compare(Deck o1, Deck o2) {
            double delta = getDraftValue(o1) - getDraftValue(o2);
            if (delta > 0)
                return 1;
            if (delta < 0)
                return -1;
            return 0;
        }
    }
}