forge.limited.BoosterDraft.java Source code

Java tutorial

Introduction

Here is the source code for forge.limited.BoosterDraft.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 com.google.common.base.Supplier;
import forge.card.CardEdition;
import forge.card.IUnOpenedProduct;
import forge.card.UnOpenedProduct;
import forge.deck.CardPool;
import forge.deck.Deck;
import forge.item.PaperCard;
import forge.item.SealedProduct;
import forge.model.CardBlock;
import forge.model.FModel;
import forge.properties.ForgeConstants;
import forge.properties.ForgePreferences;
import forge.util.FileUtil;
import forge.util.ItemPool;
import forge.util.gui.SGuiChoose;
import forge.util.gui.SOptionPane;
import forge.util.storage.IStorage;
import org.apache.commons.lang3.ArrayUtils;

import java.io.File;
import java.util.*;

/**
 * Booster Draft Format.
 */
public class BoosterDraft implements IBoosterDraft {
    private final BoosterDraftAI draftAI = new BoosterDraftAI();
    private static final int N_PLAYERS = 8;
    public static final String FILE_EXT = ".draft";

    protected int nextBoosterGroup = 0;
    private int currentBoosterSize = 0;
    private int currentBoosterPick = 0;
    private List<List<PaperCard>> pack; // size 8

    /** The draft picks. */
    private final Map<String, Float> draftPicks = new TreeMap<>();
    protected LimitedPoolType draftFormat;

    protected final List<Supplier<List<PaperCard>>> product = new ArrayList<>();

    public static BoosterDraft createDraft(final LimitedPoolType draftType) {
        final BoosterDraft draft = new BoosterDraft(draftType);
        if (!draft.generateProduct()) {
            return null;
        }
        return draft;
    }

    protected boolean generateProduct() {
        switch (this.draftFormat) {
        case Full: // Draft from all cards in Forge
            final Supplier<List<PaperCard>> s = new UnOpenedProduct(SealedProduct.Template.genericBooster);

            for (int i = 0; i < 3; i++) {
                this.product.add(s);
            }
            IBoosterDraft.LAND_SET_CODE[0] = CardEdition.Predicates
                    .getRandomSetWithAllBasicLands(FModel.getMagicDb().getEditions());
            break;

        case Block: // Draft from cards by block or set
        case FantasyBlock:
            final List<CardBlock> blocks = new ArrayList<>();
            final IStorage<CardBlock> storage = this.draftFormat == LimitedPoolType.Block ? FModel.getBlocks()
                    : FModel.getFantasyBlocks();

            for (final CardBlock b : storage) {
                if (b.getCntBoostersDraft() > 0) {
                    blocks.add(b);
                }
            }

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

            final List<CardEdition> cardSets = block.getSets();
            if (cardSets.isEmpty()) {
                SOptionPane.showErrorDialog(block.toString() + " does not contain any set combinations.");
                return false;
            }

            final Stack<String> sets = new Stack<>();
            for (int k = cardSets.size() - 1; k >= 0; k--) {
                sets.add(cardSets.get(k).getCode());
            }

            for (final String setCode : block.getMetaSetNames()) {
                if (block.getMetaSet(setCode).isDraftable()) {
                    sets.push(setCode); // to the beginning
                }
            }

            final int nPacks = block.getCntBoostersDraft();

            if (sets.size() > 1) {
                final Object p = SGuiChoose.oneOrNone("Choose Set Combination", getSetCombos(sets));
                if (p == null) {
                    return false;
                }

                final String[] pp = p.toString().split("/");
                for (int i = 0; i < nPacks; i++) {
                    this.product.add(block.getBooster(pp[i]));
                }
            } else {
                final IUnOpenedProduct product1 = block.getBooster(sets.get(0));

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

            IBoosterDraft.LAND_SET_CODE[0] = block.getLandSet();
            break;

        case Custom:
            final List<CustomLimited> myDrafts = loadCustomDrafts();

            if (myDrafts.isEmpty()) {
                SOptionPane.showMessageDialog("No custom draft files found.");
            } else {
                final CustomLimited customDraft = SGuiChoose.oneOrNone("Choose Custom Draft", myDrafts);
                if (customDraft == null) {
                    return false;
                }

                this.setupCustomDraft(customDraft);
            }
            break;

        default:
            throw new NoSuchElementException("Draft for mode " + this.draftFormat + " has not been set up!");
        }

        this.pack = this.get8BoosterPack();
        return true;
    }

    public static BoosterDraft createDraft(final LimitedPoolType draftType, final CardBlock block,
            final String[] boosters) {
        final BoosterDraft draft = new BoosterDraft(draftType);

        for (String booster : boosters) {
            draft.product.add(block.getBooster(booster));
        }

        IBoosterDraft.LAND_SET_CODE[0] = block.getLandSet();

        draft.pack = draft.get8BoosterPack();
        return draft;
    }

    protected BoosterDraft() {
        this.draftFormat = LimitedPoolType.Full;
    }

    /**
     * <p>
     * Constructor for BoosterDraft_1.
     * </p>
     *
     * @param draftType
     *            a {@link java.lang.String} object.
     */
    protected BoosterDraft(final LimitedPoolType draftType) {
        this.draftAI.setBd(this);
        this.draftFormat = draftType;
    }

    private void setupCustomDraft(final CustomLimited draft) {
        final ItemPool<PaperCard> dPool = draft.getCardPool();
        if (dPool == null) {
            throw new RuntimeException("BoosterGenerator : deck not found");
        }

        final SealedProduct.Template tpl = draft.getSealedProductTemplate();

        final UnOpenedProduct toAdd = new UnOpenedProduct(tpl, dPool);
        toAdd.setLimitedPool(draft.isSingleton());
        for (int i = 0; i < draft.getNumPacks(); i++) {
            this.product.add(toAdd);
        }

        IBoosterDraft.LAND_SET_CODE[0] = FModel.getMagicDb().getEditions().get(draft.getLandSetCode());
    }

    /** Looks for draft files, reads them, returns a list. */
    private static List<CustomLimited> loadCustomDrafts() {
        String[] dList;
        final List<CustomLimited> customs = new ArrayList<>();

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

        if (!dFolder.isDirectory()) {
            throw new RuntimeException("BoosterDraft : 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.DRAFT_DIR + element);
                customs.add(CustomLimited.parse(dfData, FModel.getDecks().getCubes()));
            }
        }
        return customs;
    }

    /**
     * <p>
     * nextChoice.
     * </p>
     *
     * @return a {@link forge.deck.CardPool} object.
     */
    @Override
    public CardPool nextChoice() {
        if (this.pack.get(this.getCurrentBoosterIndex()).isEmpty()) {
            this.pack = this.get8BoosterPack();
        }

        this.computerChoose();
        final CardPool result = new CardPool();
        result.addAllFlat(this.pack.get(this.getCurrentBoosterIndex()));
        return result;
    }

    /**
     * <p>
     * get8BoosterPack.
     * </p>
     *
     * @return an array of {@link forge.deck.CardPool} objects.
     */
    public List<List<PaperCard>> get8BoosterPack() {
        if (this.nextBoosterGroup >= this.product.size()) {
            return null;
        }

        final List<List<PaperCard>> list = new ArrayList<>();
        for (int i = 0; i < 8; i++) {
            list.add(this.product.get(this.nextBoosterGroup).get());
        }

        this.nextBoosterGroup++;
        this.currentBoosterSize = list.get(0).size();
        this.currentBoosterPick = 0;
        return list;
    }

    // size 7, all the computers decks

    /**
     * <p>
     * getDecks.
     * </p>
     *
     * @return an array of {@link forge.deck.Deck} objects.
     */
    @Override
    public Deck[] getDecks() {
        return this.draftAI.getDecks();
    }

    protected void computerChoose() {
        final int iHumansBooster = this.getCurrentBoosterIndex();
        int iPlayer = 0;
        for (int i = 1; i < this.pack.size(); i++) {
            final List<PaperCard> booster = this.pack.get((iHumansBooster + i) % this.pack.size());
            final PaperCard aiPick = this.draftAI.choose(booster, iPlayer++);
            booster.remove(aiPick);
        }
    } // computerChoose()

    /**
     *
     * Get the current booster index.
     * @return int
     */
    public int getCurrentBoosterIndex() {
        return this.currentBoosterPick % BoosterDraft.N_PLAYERS;
    }

    /**
     * <p>
     * hasNextChoice.
     * </p>
     *
     * @return a boolean.
     */
    @Override
    public boolean hasNextChoice() {
        final boolean isLastGroup = this.nextBoosterGroup >= this.product.size();
        final boolean isBoosterDepleted = this.currentBoosterPick >= this.currentBoosterSize;
        final boolean noMoreCards = isLastGroup && isBoosterDepleted;
        return !noMoreCards;
    }

    /** {@inheritDoc} */
    @Override
    public void setChoice(final PaperCard c) {
        final List<PaperCard> thisBooster = this.pack.get(this.getCurrentBoosterIndex());

        if (!thisBooster.contains(c)) {
            throw new RuntimeException("BoosterDraft : setChoice() error - card not found - " + c
                    + " - booster pack = " + thisBooster);
        }

        if (ForgePreferences.UPLOAD_DRAFT) {
            for (int i = 0; i < thisBooster.size(); i++) {
                final PaperCard cc = thisBooster.get(i);
                final String cnBk = cc.getName() + "|" + cc.getEdition();

                float pickValue;
                if (cc.equals(c)) {
                    pickValue = thisBooster.size()
                            * (1f - (((float) this.currentBoosterPick / this.currentBoosterSize) * 2f));
                } else {
                    pickValue = 0;
                }

                if (!this.draftPicks.containsKey(cnBk)) {
                    this.draftPicks.put(cnBk, pickValue);
                } else {
                    final float curValue = this.draftPicks.get(cnBk);
                    final float newValue = (curValue + pickValue) / 2;
                    this.draftPicks.put(cnBk, newValue);
                }
            }
        }

        thisBooster.remove(c);
        this.currentBoosterPick++;
    } // setChoice()

    @Override
    public boolean isPileDraft() {
        return false;
    }

    private static List<String> getSetCombos(final List<String> setz) {
        final String[] sets = setz.toArray(ArrayUtils.EMPTY_STRING_ARRAY);
        final List<String> setCombos = new ArrayList<>();
        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[0], sets[0], sets[1]));
            setCombos.add(String.format("%s/%s/%s", sets[0], sets[1], sets[1]));
            if (sets.length >= 3) {
                setCombos.add(String.format("%s/%s/%s", sets[0], sets[1], sets[2]));
                setCombos.add(String.format("%s/%s/%s", sets[0], sets[2], sets[2]));
            }
            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("%s/%s/%s", sets[1], sets[1], sets[1]));
            if (sets.length >= 3) {
                setCombos.add(String.format("%s/%s/%s", sets[1], sets[1], sets[2]));
                setCombos.add(String.format("%s/%s/%s", sets[1], sets[2], sets[2]));
            }
        }
        if (sets.length >= 3) {
            setCombos.add(String.format("%s/%s/%s", sets[2], sets[1], sets[0]));
            setCombos.add(String.format("%s/%s/%s", sets[2], sets[2], sets[0]));
            setCombos.add(String.format("%s/%s/%s", sets[2], sets[2], sets[1]));
            setCombos.add(String.format("%s/%s/%s", sets[2], sets[2], sets[2]));
        } // Beyond 3, skimp on the choice configurations, or the list will be enormous!
        if (sets.length >= 4) {
            setCombos.add(String.format("%s/%s/%s", sets[3], sets[1], sets[0]));
            setCombos.add(String.format("%s/%s/%s", sets[3], sets[2], sets[1]));
        }
        if (sets.length >= 5) {
            setCombos.add(String.format("%s/%s/%s", sets[4], sets[1], sets[0]));
            setCombos.add(String.format("%s/%s/%s", sets[4], sets[3], sets[2]));
            setCombos.add(String.format("%s/%s/%s", sets[4], sets[2], sets[0]));
        }
        if (sets.length >= 6) {
            setCombos.add(String.format("%s/%s/%s", sets[5], sets[1], sets[0]));
            setCombos.add(String.format("%s/%s/%s", sets[5], sets[3], sets[2]));
            setCombos.add(String.format("%s/%s/%s", sets[5], sets[4], sets[3]));
            setCombos.add(String.format("%s/%s/%s", sets[5], sets[2], sets[0]));
        }
        if (sets.length >= 7) {
            setCombos.add(String.format("%s/%s/%s", sets[6], sets[1], sets[0]));
            setCombos.add(String.format("%s/%s/%s", sets[6], sets[3], sets[2]));
            setCombos.add(String.format("%s/%s/%s", sets[6], sets[5], sets[4]));
            setCombos.add(String.format("%s/%s/%s", sets[6], sets[3], sets[0]));
        }
        if (sets.length >= 8) {
            setCombos.add(String.format("%s/%s/%s", sets[7], sets[1], sets[0]));
            setCombos.add(String.format("%s/%s/%s", sets[7], sets[3], sets[2]));
            setCombos.add(String.format("%s/%s/%s", sets[7], sets[5], sets[4]));
            setCombos.add(String.format("%s/%s/%s", sets[7], sets[6], sets[5]));
            setCombos.add(String.format("%s/%s/%s", sets[7], sets[3], sets[0]));
        }
        if (sets.length >= 9) {
            setCombos.add(String.format("%s/%s/%s", sets[8], sets[1], sets[0]));
            setCombos.add(String.format("%s/%s/%s", sets[8], sets[3], sets[2]));
            setCombos.add(String.format("%s/%s/%s", sets[8], sets[5], sets[4]));
            setCombos.add(String.format("%s/%s/%s", sets[8], sets[7], sets[6]));
            setCombos.add(String.format("%s/%s/%s", sets[8], sets[4], sets[0]));
        }
        return setCombos;
    }
}