diff --git a/.gitattributes b/.gitattributes
index ba0eb7ed176..e1b47fd6356 100644
--- a/.gitattributes
+++ b/.gitattributes
@@ -19750,6 +19750,8 @@ forge-gui/src/main/java/forge/limited/DraftRankCache.java -text
forge-gui/src/main/java/forge/limited/GauntletMini.java -text
forge-gui/src/main/java/forge/limited/IBoosterDraft.java svneol=native#text/plain
forge-gui/src/main/java/forge/limited/LimitedDeckBuilder.java -text
+forge-gui/src/main/java/forge/limited/LimitedPlayer.java -text
+forge-gui/src/main/java/forge/limited/LimitedPlayerAI.java -text
forge-gui/src/main/java/forge/limited/LimitedPoolType.java -text
forge-gui/src/main/java/forge/limited/LimitedWinLoseController.java -text
forge-gui/src/main/java/forge/limited/ReadDraftRankings.java -text
diff --git a/forge-gui-desktop/src/test/java/forge/BoosterDraftTest.java b/forge-gui-desktop/src/test/java/forge/BoosterDraftTest.java
index 47ea68649e5..441e7fbdf87 100644
--- a/forge-gui-desktop/src/test/java/forge/BoosterDraftTest.java
+++ b/forge-gui-desktop/src/test/java/forge/BoosterDraftTest.java
@@ -7,6 +7,7 @@ import forge.game.card.Card;
import forge.item.PaperCard;
import forge.item.SealedProduct;
import forge.limited.IBoosterDraft;
+import forge.limited.LimitedPlayer;
import forge.model.FModel;
import org.testng.annotations.Test;
@@ -24,29 +25,14 @@ import java.util.List;
@Test(groups = { "UnitTest" }, timeOut = 1000, enabled = false)
public class BoosterDraftTest implements IBoosterDraft {
- /** The n. */
private int n = 3;
- /**
- *
- * getDecks.
- *
- *
- * @return an array of {@link forge.deck.Deck} objects.
- */
@Override
@Test(timeOut = 1000)
public Deck[] getDecks() {
return null;
}
- /**
- *
- * nextChoice.
- *
- *
- * @return a {@link forge.CardList} object.
- */
@Override
public CardPool nextChoice() {
this.n--;
@@ -62,13 +48,6 @@ public class BoosterDraftTest implements IBoosterDraft {
System.out.println(c.getName());
}
- /**
- *
- * hasNextChoice.
- *
- *
- * @return a boolean.
- */
@Override
public boolean hasNextChoice() {
return this.n > 0;
@@ -79,24 +58,10 @@ public class BoosterDraftTest implements IBoosterDraft {
return hasNextChoice();
}
- /**
- *
- * getChosenCards.
- *
- *
- * @return a {@link forge.CardList} object.
- */
public List getChosenCards() {
return null;
}
- /**
- *
- * getUnchosenCards.
- *
- *
- * @return a {@link forge.CardList} object.
- */
public List getUnchosenCards() {
return null;
}
diff --git a/forge-gui/src/main/java/forge/limited/BoosterDraft.java b/forge-gui/src/main/java/forge/limited/BoosterDraft.java
index df77335a1bd..44b83b228e4 100644
--- a/forge-gui/src/main/java/forge/limited/BoosterDraft.java
+++ b/forge-gui/src/main/java/forge/limited/BoosterDraft.java
@@ -43,18 +43,16 @@ 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";
+ private final List players = new ArrayList<>();
+ private LimitedPlayer localPlayer;
protected int nextBoosterGroup = 0;
private int currentBoosterSize = 0;
private int currentBoosterPick = 0;
- private int[] draftingBooster;
+ private int packsInDraft;
- private List> pack; // size 8
-
- /** The draft picks. */
private final Map draftPicks = new TreeMap<>();
protected LimitedPoolType draftFormat;
@@ -63,6 +61,7 @@ public class BoosterDraft implements IBoosterDraft {
public static BoosterDraft createDraft(final LimitedPoolType draftType) {
final BoosterDraft draft = new BoosterDraft(draftType);
if (!draft.generateProduct()) { return null; }
+ draft.initializeBoosters();
return draft;
}
@@ -115,7 +114,7 @@ public class BoosterDraft implements IBoosterDraft {
if (sets.size() > 1) {
Object p;
- if (nPacks == 3) {
+ if (nPacks == 3 && sets.size() < 4) {
p = SGuiChoose.oneOrNone("Choose Set Combination", getSetCombos(sets));
} else {
p = choosePackByPack(sets, nPacks);
@@ -158,7 +157,6 @@ public class BoosterDraft implements IBoosterDraft {
throw new NoSuchElementException("Draft for mode " + this.draftFormat + " has not been set up!");
}
- this.pack = this.get8BoosterPack();
return true;
}
@@ -172,16 +170,26 @@ public class BoosterDraft implements IBoosterDraft {
IBoosterDraft.LAND_SET_CODE[0] = block.getLandSet();
IBoosterDraft.CUSTOM_RANKINGS_FILE[0] = null;
- draft.pack = draft.get8BoosterPack();
+ draft.initializeBoosters();
return draft;
}
protected BoosterDraft() {
- this.draftFormat = LimitedPoolType.Full;
+ this(LimitedPoolType.Full);
}
protected BoosterDraft(final LimitedPoolType draftType) {
- this.draftAI.setBd(this);
this.draftFormat = draftType;
+
+ localPlayer = new LimitedPlayer(0);
+ players.add(localPlayer);
+ for(int i = 1; i < N_PLAYERS; i++) {
+ players.add(new LimitedPlayerAI(i));
+ }
+ }
+
+ @Override
+ public boolean isPileDraft() {
+ return false;
}
private void setupCustomDraft(final CustomLimited draft) {
@@ -228,19 +236,12 @@ public class BoosterDraft implements IBoosterDraft {
return customs;
}
- /**
- *
- * nextChoice.
- *
- *
- * @return a {@link forge.deck.CardPool} object.
- */
@Override
public CardPool nextChoice() {
+ // Primary draft loop - Computer Chooses from their packs, you choose form your packs
if (this.isRoundOver()) {
- // If all packs are depleted crack 8 new packs
- this.pack = this.get8BoosterPack();
- if (this.pack == null) {
+ // If this round is over, try to start the next round
+ if (!startRound()) {
return null;
}
}
@@ -248,7 +249,7 @@ public class BoosterDraft implements IBoosterDraft {
this.computerChoose();
final CardPool result = new CardPool();
- result.addAllFlat(this.pack.get(this.getCurrentBoosterIndex()));
+ result.addAllFlat(localPlayer.nextChoice());
if (result.isEmpty()) {
// Can't set a card, since none are available. Just pass "empty" packs.
@@ -260,129 +261,95 @@ public class BoosterDraft implements IBoosterDraft {
return result;
}
- /**
- *
- * get8BoosterPack.
- *
- *
- * @return an array of {@link forge.deck.CardPool} objects.
- */
- public List> get8BoosterPack() {
- if (this.nextBoosterGroup >= this.product.size()) {
- return null;
- }
-
- final List> list = new ArrayList<>();
- for (int i = 0; i < 8; i++) {
- list.add(this.product.get(this.nextBoosterGroup).get());
+ public void initializeBoosters() {
+ for(Supplier> boosterRound : this.product) {
+ for (int i = 0; i < N_PLAYERS; i++) {
+ this.players.get(i).receiveUnopenedPack(boosterRound.get());
+ }
}
+ startRound();
+ }
+ public boolean startRound() {
this.nextBoosterGroup++;
- this.currentBoosterSize = list.get(0).size();
this.currentBoosterPick = 0;
- draftingBooster = new int[]{0, 1, 2, 3, 4, 5, 6, 7};
- return list;
+ packsInDraft = this.players.size();
+ LimitedPlayer firstPlayer = this.players.get(0);
+ if (firstPlayer.unopenedPacks.isEmpty()) {
+ return false;
+ }
+
+ for(LimitedPlayer pl : this.players) {
+ pl.newPack();
+ }
+ this.currentBoosterSize = firstPlayer.packQueue.peek().size();
+ return true;
}
- public void addSingleBoosterPack(int player, boolean random) {
- // TODO Lore Seeker
- }
-
- // size 7, all the computers decks
@Override
public Deck[] getDecks() {
- return this.draftAI.getDecks();
+ Deck decks[] = new Deck[7];
+ for (int i = 1; i < N_PLAYERS; i++) {
+ decks[i-1] = ((LimitedPlayerAI)this.players.get(i)).buildDeck();
+ }
+ return decks;
}
public void passPacks() {
// Alternate direction of pack passing
int adjust = this.nextBoosterGroup % 2 == 1 ? 1 : -1;
for(int i = 0; i < N_PLAYERS; i++) {
- draftingBooster[i] = (draftingBooster[i] + adjust + pack.size()) % pack.size();
+ List passingPack = this.players.get(i).passPack();
+
+ if (!passingPack.isEmpty()) {
+ // TODO Canal Dredger for passing a pack with a single card in it
+
+ int passTo = (i + adjust + N_PLAYERS) % N_PLAYERS;
+ this.players.get(passTo).receiveOpenedPack(passingPack);
+ this.players.get(passTo).adjustPackNumber(adjust, packsInDraft);
+ } else {
+ packsInDraft--;
+ }
}
}
protected void computerChoose() {
// Loop through players 1-7 to draft their current pack
for (int i = 1; i < N_PLAYERS; i++) {
- final List booster = this.pack.get(this.draftingBooster[i]);
-
- // Empty boosters can happen in a Conspiracy draft
- if (!booster.isEmpty()) {
- booster.remove(this.draftAI.choose(booster, i-1));
- }
+ LimitedPlayer pl = this.players.get(i);
+ pl.draftCard(pl.chooseCard());
}
- } // computerChoose()
+ }
- /**
- *
- * Get the current booster index for the Human
- * @return int
- */
public int getCurrentBoosterIndex() {
- return this.draftingBooster[0];
+ return localPlayer.currentPack;
}
@Override
public boolean isRoundOver() {
- for(List singlePack : this.pack) {
- if (!singlePack.isEmpty()) {
- return false;
- }
- }
-
- return true;
+ return packsInDraft == 0;
}
-
@Override
public boolean hasNextChoice() {
- return this.nextBoosterGroup < this.product.size() || !this.isRoundOver();
+ return !this.isRoundOver() || !this.localPlayer.unopenedPacks.isEmpty();
}
/** {@inheritDoc} */
@Override
public void setChoice(final PaperCard c) {
- final List thisBooster = this.pack.get(this.getCurrentBoosterIndex());
+ final List thisBooster = this.localPlayer.nextChoice();
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();
+ recordDraftPick(thisBooster, c);
- 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.localPlayer.draftCard(c);
this.currentBoosterPick++;
this.passPacks();
- } // setChoice()
-
- @Override
- public boolean isPileDraft() {
- return false;
}
@@ -403,7 +370,6 @@ public class BoosterDraft implements IBoosterDraft {
return sb.toString();
}
-
private static List getSetCombos(final List setz) {
final String[] sets = setz.toArray(ArrayUtils.EMPTY_STRING_ARRAY);
final List setCombos = new ArrayList<>();
@@ -466,4 +432,31 @@ public class BoosterDraft implements IBoosterDraft {
}
return setCombos;
}
+
+ private void recordDraftPick(final List thisBooster, PaperCard c) {
+ 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);
+ }
+ }
+ }
+ }
}
diff --git a/forge-gui/src/main/java/forge/limited/BoosterDraftAI.java b/forge-gui/src/main/java/forge/limited/BoosterDraftAI.java
index 59ad4d2aad0..3ac539038de 100644
--- a/forge-gui/src/main/java/forge/limited/BoosterDraftAI.java
+++ b/forge-gui/src/main/java/forge/limited/BoosterDraftAI.java
@@ -35,12 +35,8 @@ import forge.properties.ForgePreferences;
*/
public class BoosterDraftAI {
- /** The bd. */
+ // TODO When WinstonDraft gets related changes that BoosterDraft gets, this can be deleted
private IBoosterDraft bd = null;
-
- /**
- * Constant nDecks=7.
- */
protected static final int N_DECKS = 7;
// holds all the cards for each of the computer's decks
@@ -83,13 +79,6 @@ public class BoosterDraftAI {
return bestPick;
}
- /**
- *
- * getDecks.
- *
- *
- * @return an array of {@link forge.deck.Deck} objects.
- */
public Deck[] getDecks() {
final Deck[] out = new Deck[this.decks.size()];
@@ -103,11 +92,6 @@ public class BoosterDraftAI {
return out;
} // getDecks()
- /**
- *
- * Constructor for BoosterDraftAI.
- *
- */
public BoosterDraftAI() {
// Initialize deck array and playerColors list
for (int i = 0; i < N_DECKS; i++) {
@@ -116,21 +100,9 @@ public class BoosterDraftAI {
}
} // BoosterDraftAI()
- /**
- * Gets the bd.
- *
- * @return the bd
- */
public IBoosterDraft getBd() {
return this.bd;
}
-
- /**
- * Sets the bd.
- *
- * @param bd0
- * the bd to set
- */
public void setBd(final IBoosterDraft bd0) {
this.bd = bd0;
}
diff --git a/forge-gui/src/main/java/forge/limited/IBoosterDraft.java b/forge-gui/src/main/java/forge/limited/IBoosterDraft.java
index 103d2afa965..3797aea5c73 100644
--- a/forge-gui/src/main/java/forge/limited/IBoosterDraft.java
+++ b/forge-gui/src/main/java/forge/limited/IBoosterDraft.java
@@ -31,49 +31,15 @@ import forge.item.PaperCard;
* @version $Id$
*/
public interface IBoosterDraft {
- /**
- *
- * nextChoice.
- *
- *
- * @return a {@link CardPool} object.
- */
+
CardPool nextChoice();
-
- /**
- *
- * setChoice.
- *
- *
- * @param c
- * a {@link forge.game.card.Card} object.
- */
void setChoice(PaperCard c);
-
- /**
- *
- * hasNextChoice.
- *
- *
- * @return a boolean.
- */
boolean hasNextChoice();
boolean isRoundOver();
-
- /**
- *
- * getDecks.
- *
- *
- * @return an array of {@link forge.deck.Deck} objects.
- */
Deck[] getDecks(); // size 7, all the computers decks
- /** Constant LandSetCode="{}". */
CardEdition[] LAND_SET_CODE = { null };
-
String[] CUSTOM_RANKINGS_FILE = { null };
-
boolean isPileDraft();
}
diff --git a/forge-gui/src/main/java/forge/limited/LimitedPlayer.java b/forge-gui/src/main/java/forge/limited/LimitedPlayer.java
new file mode 100644
index 00000000000..3f3cd6f9ec6
--- /dev/null
+++ b/forge-gui/src/main/java/forge/limited/LimitedPlayer.java
@@ -0,0 +1,148 @@
+package forge.limited;
+
+import com.google.common.collect.Lists;
+import forge.deck.CardPool;
+import forge.deck.Deck;
+import forge.deck.DeckSection;
+import forge.item.PaperCard;
+import forge.limited.powers.DraftPower;
+
+import java.util.*;
+
+public class LimitedPlayer {
+ // A Player class for inside some type of limited environment, like Draft.
+ final protected int order;
+ protected int currentPack;
+ protected int draftedThisRound;
+ protected Deck deck;
+
+ protected Queue> packQueue;
+ protected Queue> unopenedPacks;
+
+ // WIP - Draft Matters cards
+ /*
+ private static int CantDraftThisRound = 1,
+ SpyNextCardDrafted = 1 << 1,
+ ReceiveLastCard = 1 << 2,
+ CanRemoveAfterDraft = 1 << 3,
+ CanTradeAfterDraft = 1 << 4;
+
+ private static int MAXFLAGS = CantDraftThisRound | ReceiveLastCard | CanRemoveAfterDraft | SpyNextCardDrafted
+ | CanTradeAfterDraft;
+
+
+ private int playerFlags = 0;
+
+ private List revealed = Lists.newArrayList();
+ private Map> noted = new HashMap<>();
+ private Map powers = new HashMap<>();
+ */
+
+ public LimitedPlayer(int seatingOrder) {
+ order = seatingOrder;
+ deck = new Deck();
+
+ packQueue = new LinkedList<>();
+ unopenedPacks = new LinkedList<>();
+ }
+
+ public PaperCard chooseCard() {
+ // A basic LimitedPlayer chooses cards via the UI instead of this function
+ return null;
+ }
+
+ public boolean draftCard(PaperCard bestPick) {
+ return draftCard(bestPick, DeckSection.Sideboard);
+ }
+ public boolean draftCard(PaperCard bestPick, DeckSection section) {
+ if (bestPick == null) {
+ return false;
+ }
+
+ List chooseFrom = packQueue.peek();
+ if (chooseFrom == null) {
+ return false;
+ }
+
+ chooseFrom.remove(bestPick);
+
+
+
+ CardPool pool = deck.getOrCreate(section);
+ pool.add(bestPick);
+ draftedThisRound++;
+
+ // TODO Note Lurking Automaton
+ // TODO Note Paliano, the High City
+ // TODO Note Aether Searcher
+ // TODO Note Custodi Peacepeeper
+ // TODO Note Paliano Vanguard
+ // TODO Note Garbage Fire
+
+ return true;
+ }
+
+ public List nextChoice() {
+ return packQueue.peek();
+ }
+
+ public void newPack() {
+ currentPack = order;
+ draftedThisRound = 0;
+ packQueue.add(unopenedPacks.poll());
+ }
+ public void adjustPackNumber(int adjust, int numPacks) {
+ currentPack = (currentPack + adjust + numPacks) % numPacks;
+ }
+
+ public List passPack() {
+ return packQueue.poll();
+ }
+
+ public void receiveUnopenedPack(List pack) {
+ unopenedPacks.add(pack);
+ }
+
+ public void receiveOpenedPack(List pack) {
+ packQueue.add(pack);
+ }
+
+ /*
+ public void addSingleBoosterPack(boolean random) {
+ // TODO Lore Seeker
+ // Generate booster pack then, "receive" that pack
+ }
+
+ public boolean activatePower(DraftPower power) {
+ if (!powers.containsKey(power)) {
+ return false;
+ }
+
+ int i = (int)powers.get(power);
+ if (i == 1) {
+ powers.remove(power);
+ } else {
+ powers.put(power, i-1);
+ }
+
+ power.activate(this);
+
+
+ return true;
+ }
+
+ public boolean noteObject(String cardName, Object notedObj) {
+ // Returns boolean based on creation of new mapped param
+ boolean alreadyContained = noted.containsKey(cardName);
+
+ if (alreadyContained) {
+ noted.get(cardName).add(notedObj);
+ } else {
+ noted.put(cardName, Lists.newArrayList(notedObj));
+ }
+
+ return !alreadyContained;
+ }
+ */
+}
+
diff --git a/forge-gui/src/main/java/forge/limited/LimitedPlayerAI.java b/forge-gui/src/main/java/forge/limited/LimitedPlayerAI.java
new file mode 100644
index 00000000000..cb8927345f7
--- /dev/null
+++ b/forge-gui/src/main/java/forge/limited/LimitedPlayerAI.java
@@ -0,0 +1,58 @@
+package forge.limited;
+
+import forge.card.ColorSet;
+import forge.deck.CardPool;
+import forge.deck.Deck;
+import forge.deck.DeckSection;
+import forge.item.PaperCard;
+import forge.properties.ForgePreferences;
+
+import java.util.List;
+
+public class LimitedPlayerAI extends LimitedPlayer {
+ protected DeckColors deckCols;
+
+ public LimitedPlayerAI(int seatingOrder) {
+ super(seatingOrder);
+ deckCols = new DeckColors();
+
+ }
+
+ @Override
+ public PaperCard chooseCard() {
+ if (packQueue.isEmpty()) {
+ return null;
+ }
+
+ List chooseFrom = packQueue.peek();
+ if (chooseFrom.isEmpty()) {
+ return null;
+ }
+
+ CardPool pool = deck.getOrCreate(DeckSection.Sideboard);
+ if (ForgePreferences.DEV_MODE) {
+ System.out.println("Player[" + order + "] pack: " + chooseFrom.toString());
+ }
+
+ final ColorSet chosenColors = deckCols.getChosenColors();
+ final boolean canAddMoreColors = deckCols.canChoseMoreColors();
+
+ List rankedCards = CardRanker.rankCardsInPack(chooseFrom, pool.toFlatList(), chosenColors, canAddMoreColors);
+ PaperCard bestPick = rankedCards.get(0);
+
+ if (canAddMoreColors) {
+ deckCols.addColorsOf(bestPick);
+ }
+
+ if (ForgePreferences.DEV_MODE) {
+ System.out.println("Player[" + order + "] picked: " + bestPick);
+ }
+
+ return bestPick;
+ }
+
+ public Deck buildDeck() {
+ CardPool section = deck.getOrCreate(DeckSection.Sideboard);
+ return new BoosterDeckBuilder(section.toFlatList(), deckCols).buildDeck();
+ }
+}