Deck generation uses CardPrinted

This commit is contained in:
Maxmtg
2012-04-07 06:57:12 +00:00
parent a76760ceca
commit 0d7a549bd1
19 changed files with 697 additions and 1419 deletions

2
.gitattributes vendored
View File

@@ -11623,9 +11623,11 @@ src/main/java/forge/deck/DeckBase.java -text
src/main/java/forge/deck/DeckGroup.java -text
src/main/java/forge/deck/DeckRecognizer.java -text
src/main/java/forge/deck/DeckSection.java -text
src/main/java/forge/deck/generate/CCnt.java -text
src/main/java/forge/deck/generate/Generate2ColorDeck.java svneol=native#text/plain
src/main/java/forge/deck/generate/Generate3ColorDeck.java svneol=native#text/plain
src/main/java/forge/deck/generate/Generate5ColorDeck.java svneol=native#text/plain
src/main/java/forge/deck/generate/GenerateColoredDeckBase.java -text
src/main/java/forge/deck/generate/GenerateDeckUtil.java -text
src/main/java/forge/deck/generate/GenerateThemeDeck.java svneol=native#text/plain
src/main/java/forge/deck/generate/package-info.java svneol=native#text/plain

View File

@@ -29,19 +29,10 @@ import forge.Constant;
*/
public final class CardColor implements Comparable<CardColor> {
/** The Constant WHITE. */
public static final byte WHITE = 1 << 1;
/** The Constant BLUE. */
public static final byte BLUE = 1 << 2;
/** The Constant BLACK. */
public static final byte BLACK = 1 << 3;
/** The Constant RED. */
public static final byte RED = 1 << 4;
/** The Constant GREEN. */
public static final byte GREEN = 1 << 5;
private final byte myColor;
@@ -56,8 +47,34 @@ public final class CardColor implements Comparable<CardColor> {
* the mana
*/
public CardColor(final CardManaCost mana) {
this.myColor = mana.getColorProfile();
this(mana.getColorProfile());
}
private CardColor(final byte mask) {
this.myColor = mask;
this.orderWeight = this.getOrderWeight();
}
public static CardColor fromMask(int mask) {
return new CardColor((byte)mask);
}
public static CardColor fromNames(String... colors) {
byte mask = 0;
for(String s : colors) {
if ( s.equalsIgnoreCase(Constant.Color.WHITE) || s.equalsIgnoreCase("w"))
mask |= WHITE;
if ( s.equalsIgnoreCase(Constant.Color.BLUE) || s.equalsIgnoreCase("u"))
mask |= BLUE;
if ( s.equalsIgnoreCase(Constant.Color.BLACK) || s.equalsIgnoreCase("b"))
mask |= BLACK;
if ( s.equalsIgnoreCase(Constant.Color.RED) || s.equalsIgnoreCase("r"))
mask |= RED;
if ( s.equalsIgnoreCase(Constant.Color.GREEN) || s.equalsIgnoreCase("g"))
mask |= GREEN;
}
return fromMask(mask);
}
private CardColor() {
@@ -66,7 +83,7 @@ public final class CardColor implements Comparable<CardColor> {
}
/** The null color. */
private static CardColor nullColor = new CardColor();
private static final CardColor nullColor = new CardColor();
/**
* Checks for any color.
@@ -75,7 +92,7 @@ public final class CardColor implements Comparable<CardColor> {
* the colormask
* @return true, if successful
*/
public boolean hasAnyColor(final byte colormask) {
public boolean hasAnyColor(final int colormask) {
return (this.myColor & colormask) != 0;
}
@@ -86,10 +103,21 @@ public final class CardColor implements Comparable<CardColor> {
* the colormask
* @return true, if successful
*/
public boolean hasAllColors(final byte colormask) {
public boolean hasAllColors(final int colormask) {
return (this.myColor & colormask) == colormask;
}
/** this has no other colors except defined by operand */
public boolean hasNoColorsExcept(final int colormask) {
return (this.myColor & ~colormask) == 0;
}
/** Operand has no other colors except defined by this */
public boolean containsAllColorsFrom(int colorProfile) {
return (~this.myColor & colorProfile) == 0;
}
/**
* Count colors.
*
@@ -254,6 +282,12 @@ public final class CardColor implements Comparable<CardColor> {
return this.isEqual(CardColor.GREEN);
}
public CardColor inverse() {
byte mask = this.myColor;
mask ^= ( WHITE | BLUE | BLACK | GREEN | RED );
return fromMask(mask);
}
/*
* (non-Javadoc)
*
@@ -291,16 +325,6 @@ public final class CardColor implements Comparable<CardColor> {
return CardColor.nullColor;
}
/**
* Sets the null color.
*
* @param nullColor0
* the nullColor to set
*/
public static void setNullColor(final CardColor nullColor0) {
CardColor.nullColor = nullColor0;
}
/**
* Shares color with.
*
@@ -308,27 +332,6 @@ public final class CardColor implements Comparable<CardColor> {
* @return true, if successful
*/
public boolean sharesColorWith(CardColor ccOther) {
if (this.isWhite() && ccOther.isWhite()) {
return true;
}
if (this.isBlue() && ccOther.isBlue()) {
return true;
}
if (this.isBlack() && ccOther.isBlack()) {
return true;
}
if (this.isRed() && ccOther.isRed()) {
return true;
}
if (this.isGreen() && ccOther.isGreen()) {
return true;
}
return false;
return ( this.myColor & ccOther.myColor ) != 0;
}
}

View File

@@ -22,6 +22,8 @@ import java.util.Collections;
import java.util.Iterator;
import java.util.List;
import forge.card.cost.CostMana;
/**
* <p>
* CardManaCost class.
@@ -40,14 +42,16 @@ public final class CardManaCost implements Comparable<CardManaCost> {
private Float compareWeight = null;
/** The Constant empty. */
public static final CardManaCost EMPTY = new CardManaCost();
public static final CardManaCost EMPTY = new CardManaCost(-1);
public static final CardManaCost ZERO = new CardManaCost(0);
public static final CardManaCost ONE = new CardManaCost(1);
// pass mana cost parser here
private CardManaCost() {
this.hasNoCost = true;
this.genericCost = 0;
this.stringValue = "";
private CardManaCost(int cmc) {
this.hasNoCost = cmc < 0;
this.genericCost = cmc < 0 ? 0 : cmc;
this.shards = Collections.unmodifiableList(new ArrayList<CardManaCostShard>());
this.stringValue = this.getSimpleString();
}
// public ctor, should give it a mana parser
@@ -208,4 +212,29 @@ public final class CardManaCost implements Comparable<CardManaCost> {
int getTotalColorlessCost();
}
/**
* TODO: Write javadoc for this method.
* @return
*/
public boolean hasPhyrexian() {
for(CardManaCostShard shard : shards) {
if ( shard.isPhyrexian() )
return true;
}
return false;
}
/**
* TODO: Write javadoc for this method.
* @return
*/
public int countX() {
int iX = 0;
for(CardManaCostShard shard : shards) {
if ( shard == CardManaCostShard.X )
iX++;
}
return iX;
}
}

View File

@@ -317,4 +317,12 @@ public class CardManaCostShard {
public String getImageKey() {
return this.imageKey;
}
/**
* TODO: Write javadoc for this method.
* @return
*/
public boolean isPhyrexian() {
return (this.shard & Atom.OR_2_LIFE) != 0;
}
}

View File

@@ -18,13 +18,12 @@
package forge.card;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;
import org.apache.commons.lang3.StringUtils;
import forge.util.Predicate;
@@ -809,6 +808,12 @@ public final class CardRules {
public static final Predicate<CardRules> IS_NON_CREATURE_SPELL = Predicate.compose(Presets.IS_CREATURE,
PredicatesOp.NOR, Presets.IS_LAND);
@SuppressWarnings("unchecked")
public static final Predicate<CardRules> isNonCreatureSpellForGenerator = Predicate.or( Arrays.asList(
Presets.IS_SORCERY, Presets.IS_INSTANT, Presets.IS_PLANESWALKER, Presets.IS_ENCHANTMENT,
Predicate.compose(Presets.IS_ARTIFACT, PredicatesOp.GT, Presets.IS_CREATURE ))
);
/** The Constant isWhite. */
public static final Predicate<CardRules> IS_WHITE = Predicates.isColor(CardColor.WHITE);

View File

@@ -0,0 +1,83 @@
package forge.deck.generate;
/*
* 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/>.
*/
/**
* <p>
* CCnt class.
* </p>
*
* @author Forge
* @version $Id: CCnt.java 12850 2011-12-26 14:55:09Z slapshot5 $
*/
public class CCnt {
/** The Color. */
public final String Color;
/** The Count. */
private int count;
/**
* <p>
* Constructor for CCnt.
* </p>
*
* @param clr
* a {@link java.lang.String} object.
* @param cnt
* a int.
*/
/**
* <p>
* deckColors class.
* </p>
*
* @param clr
* a {@link java.lang.String} object.
* @param cnt
* a int.
*/
public CCnt(final String clr, final int cnt) {
Color = clr;
this.setCount(cnt);
}
/**
* Gets the count.
*
* @return the count
*/
public int getCount() {
return this.count;
}
/**
* Sets the count.
*
* @param count0
* the count to set
*/
public void setCount(final int count0) {
this.count = count0;
}
public void increment() { this.count++; }
public void increment(int amount) { this.count += amount; }
}

View File

@@ -17,23 +17,17 @@
*/
package forge.deck.generate;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Map;
import java.util.Random;
import forge.AllZone;
import forge.Card;
import forge.CardList;
import forge.CardListFilter;
import forge.Constant;
import java.util.Arrays;
import java.util.List;
import forge.PlayerType;
import forge.Singletons;
import forge.card.CardColor;
import forge.card.CardRules;
import forge.deck.generate.GenerateDeckUtil.FilterCMC;
import forge.error.ErrorViewer;
import forge.properties.ForgePreferences.FPref;
import forge.item.CardPrinted;
import forge.item.ItemPool;
import forge.item.ItemPoolView;
import forge.properties.ForgeProps;
import forge.util.MyRandom;
import forge.util.Predicate;
/**
* <p>
@@ -43,15 +37,24 @@ import forge.util.Predicate;
* @author Forge
* @version $Id$
*/
public class Generate2ColorDeck {
private String color1 = "";
private String color2 = "";
private Random r = null;
private Map<String, String> clrMap = null;
private ArrayList<String> notColors = null;
private ArrayList<String> dL = null;
private Map<String, Integer> cardCounts = null;
private int maxDuplicates = 4;
public class Generate2ColorDeck extends GenerateColoredDeckBase {
final float landsPercentage = 0.42f;
final float creatPercentage = 0.34f;
final float spellPercentage = 0.24f;
final List<FilterCMC> cmcLevels = Arrays.asList(
new GenerateDeckUtil.FilterCMC(0, 2),
new GenerateDeckUtil.FilterCMC(3, 4),
new GenerateDeckUtil.FilterCMC(5, 6),
new GenerateDeckUtil.FilterCMC(7, 20));
final int[] cmcAmounts = {10, 8, 6, 2};
// mana curve of the card pool
// 20x 0 - 2
// 16x 3 - 4
// 12x 5 - 6
// 4x 7 - 20
// = 52x - card pool (before further random filtering)
/**
* <p>
@@ -64,361 +67,58 @@ public class Generate2ColorDeck {
* a {@link java.lang.String} object.
*/
public Generate2ColorDeck(final String clr1, final String clr2) {
this.r = MyRandom.getRandom();
this.cardCounts = new HashMap<String, Integer>();
this.clrMap = new HashMap<String, String>();
this.clrMap.put("white", "W");
this.clrMap.put("blue", "U");
this.clrMap.put("black", "B");
this.clrMap.put("red", "R");
this.clrMap.put("green", "G");
this.notColors = new ArrayList<String>();
this.notColors.add("white");
this.notColors.add("blue");
this.notColors.add("black");
this.notColors.add("red");
this.notColors.add("green");
if (Singletons.getModel().getPreferences().getPrefBoolean(FPref.DECKGEN_SINGLETONS)) {
this.maxDuplicates = 1;
}
if (clr1.equals("AI")) {
// choose first color
this.color1 = this.notColors.get(this.r.nextInt(5));
// choose second color
String c2 = this.notColors.get(this.r.nextInt(5));
while (c2.equals(this.color1)) {
c2 = this.notColors.get(this.r.nextInt(5));
}
this.color2 = c2;
int color1 = r.nextInt(5);
int color2 = ( color1 + 1 + r.nextInt(4) ) % 5 ;
colors = CardColor.fromMask(CardColor.WHITE << color1 | CardColor.WHITE << color2);
} else {
this.color1 = clr1;
this.color2 = clr2;
}
this.notColors.remove(this.color1);
this.notColors.remove(this.color2);
this.dL = GenerateDeckUtil.getDualLandList(this.clrMap.get(this.color1) + this.clrMap.get(this.color2));
for (int i = 0; i < this.dL.size(); i++) {
this.cardCounts.put(this.dL.get(i), 0);
}
}
/**
* <p>
* get2ColorDeck.
* </p>
*
* @param size
* a int.
* @param pt
* the pt
* @return a {@link forge.CardList} object.
*/
public final CardList get2ColorDeck(final int size, final PlayerType pt) {
int lc = 0; // loop counter to prevent infinite card selection loops
String tmpDeck = "";
final CardList tDeck = new CardList();
final int landsPercentage = 42;
final int creatPercentage = 34;
final int spellPercentage = 24;
// start with all cards
// remove cards that generated decks don't like
Predicate<Card> toUse = pt == PlayerType.HUMAN ? GenerateDeckUtil.humanCanPlay : GenerateDeckUtil.aiCanPlay;
CardList allCards = new CardList(toUse.select(AllZone.getCardFactory()));
// reduce to cards that match the colors
CardList cl1 = allCards.getColor(this.color1);
if (!Singletons.getModel().getPreferences().getPrefBoolean(FPref.DECKGEN_ARTIFACTS)) {
cl1.addAll(allCards.getColor(Constant.Color.COLORLESS));
}
CardList cl2 = allCards.getColor(this.color2);
// remove multicolor cards that don't match the colors
final CardListFilter clrF = new CardListFilter() {
@Override
public boolean addCard(final Card c) {
for (int i = 0; i < Generate2ColorDeck.this.notColors.size(); i++) {
if (c.getManaCost().contains(
Generate2ColorDeck.this.clrMap.get(Generate2ColorDeck.this.notColors.get(i)))) {
return false;
colors = CardColor.fromNames(clr1, clr2);
}
}
return true;
}
};
cl1 = cl1.filter(clrF);
cl2 = cl2.filter(clrF);
public final ItemPoolView<CardPrinted> get2ColorDeck(final int size, final PlayerType pt) {
List<CardPrinted> cards = selectCardsOfMatchingColorForPlayer(pt);
// build subsets based on type
final CardList cr1 = cl1.getType("Creature");
final CardList cr2 = cl2.getType("Creature");
final List<CardPrinted> creatures = CardRules.Predicates.Presets.IS_CREATURE.select(cards, CardPrinted.FN_GET_RULES);
final List<CardPrinted> spells = CardRules.Predicates.Presets.isNonCreatureSpellForGenerator.select(cards, CardPrinted.FN_GET_RULES);
final String[] ise = { "Instant", "Sorcery", "Enchantment", "Planeswalker", "Artifact.nonCreature" };
final CardList sp1 = cl1.getValidCards(ise, null, null);
final CardList sp2 = cl2.getValidCards(ise, null, null);
// final card pools
final CardList cr12 = new CardList();
final CardList sp12 = new CardList();
final ItemPool<CardPrinted> tDeck = new ItemPool<CardPrinted>(CardPrinted.class);
// used for mana curve in the card pool
final int[] minCMC = { 0 };
final int[] maxCMC = { 2 };
final CardListFilter cmcF = new CardListFilter() {
@Override
public boolean addCard(final Card c) {
final int cCMC = c.getCMC();
return (cCMC >= minCMC[0]) && (cCMC <= maxCMC[0]);
}
};
final int creatCnt = (int) (creatPercentage * size);
tmpDeck.append( "Creature Count:" + creatCnt + "\n" );
addCmcAdjusted(tDeck, creatures, creatCnt, cmcLevels, cmcAmounts);
// select cards to build card pools using a mana curve
for (int i = 4; i > 0; i--) {
if (i == 1) {
maxCMC[0] = 20; //the last category is open ended
i = 0; // this reduces the number of cards in the last category to 4
}
final CardList cr1CMC = cr1.filter(cmcF);
final CardList cr2CMC = cr2.filter(cmcF);
final CardList sp1CMC = sp1.filter(cmcF);
final CardList sp2CMC = sp2.filter(cmcF);
for (int j = 0; j < i + 1; j++) {
Card c = cr1CMC.get(this.r.nextInt(cr1CMC.size()));
cr12.add(c);
this.cardCounts.put(c.getName(), 0);
c = cr2CMC.get(this.r.nextInt(cr2CMC.size()));
cr12.add(c);
this.cardCounts.put(c.getName(), 0);
c = sp1CMC.get(this.r.nextInt(sp1CMC.size()));
sp12.add(c);
this.cardCounts.put(c.getName(), 0);
c = sp2CMC.get(this.r.nextInt(sp2CMC.size()));
sp12.add(c);
this.cardCounts.put(c.getName(), 0);
}
minCMC[0] += 2;
if (i == 4) {
minCMC[0] = 3;
}
maxCMC[0] += 2;
// resulting mana curve of the card pool
// 20x 0 - 2
// 16x 3 - 4
// 12x 5 - 6
// 4x 7 - 20
// =52x - card pool
}
// shuffle card pools
cr12.shuffle();
sp12.shuffle();
// calculate card counts
float p = (float) (creatPercentage * .01);
final int creatCnt = (int) (p * size);
tmpDeck += "Creature Count:" + creatCnt + "\n";
p = (float) (spellPercentage * .01);
final int spellCnt = (int) (p * size);
tmpDeck += "Spell Count:" + spellCnt + "\n";
// build deck from the card pools
for (int i = 0; i < creatCnt; i++) {
Card c = cr12.get(this.r.nextInt(cr12.size()));
lc = 0;
while ((this.cardCounts.get(c.getName()) > (this.maxDuplicates - 1)) || (lc > 100)) {
c = cr12.get(this.r.nextInt(cr12.size()));
lc++;
}
if (lc > 100) {
throw new RuntimeException("Generate2ColorDeck : get2ColorDeck -- looped too much -- Cr12");
}
tDeck.add(AllZone.getCardFactory().getCard(c.getName(), AllZone.getComputerPlayer()));
final int n = this.cardCounts.get(c.getName());
this.cardCounts.put(c.getName(), n + 1);
tmpDeck += c.getName() + " " + c.getManaCost() + "\n";
}
for (int i = 0; i < spellCnt; i++) {
Card c = sp12.get(this.r.nextInt(sp12.size()));
lc = 0;
while ((this.cardCounts.get(c.getName()) > (this.maxDuplicates - 1)) || (lc > 100)) {
c = sp12.get(this.r.nextInt(sp12.size()));
lc++;
}
if (lc > 100) {
throw new RuntimeException("Generate2ColorDeck : get2ColorDeck -- looped too much -- Sp12");
}
tDeck.add(AllZone.getCardFactory().getCard(c.getName(), AllZone.getComputerPlayer()));
final int n = this.cardCounts.get(c.getName());
this.cardCounts.put(c.getName(), n + 1);
tmpDeck += c.getName() + " " + c.getManaCost() + "\n";
}
final int spellCnt = (int) (spellPercentage * size);
tmpDeck.append( "Spell Count:" + spellCnt + "\n" );
addCmcAdjusted(tDeck, spells, spellCnt, cmcLevels, cmcAmounts);
// Add lands
int numLands = 0;
if (landsPercentage > 0) {
p = (float) (landsPercentage * .01);
numLands = (int) (p * size);
}
/*
* else { // otherwise, just fill in the rest of the deck with basic //
* lands numLands = size - tDeck.size(); }
*/
int numLands = landsPercentage > 0 ? (int) (landsPercentage * size) : size - tDeck.countAll();
tmpDeck += "numLands:" + numLands + "\n";
tmpDeck.append( "numLands:" + numLands + "\n");
final int nDLands = (numLands / 6);
for (int i = 0; i < nDLands; i++) {
String s = this.dL.get(this.r.nextInt(this.dL.size()));
// Add dual lands
lc = 0;
while ((this.cardCounts.get(s) > 3) || (lc > 20)) {
s = this.dL.get(this.r.nextInt(this.dL.size()));
lc++;
}
if (lc > 20) {
throw new RuntimeException("Generate2ColorDeck : get2ColorDeck -- looped too much -- DL");
List<String> duals = GenerateDeckUtil.getDualLandList(colors);
for(String s : duals) {
this.cardCounts.put(s, 0);
}
tDeck.add(AllZone.getCardFactory().getCard(s, AllZone.getHumanPlayer()));
final int n = this.cardCounts.get(s);
this.cardCounts.put(s, n + 1);
tmpDeck += s + "\n";
}
int dblsAdded = addSomeStr(tDeck, (numLands / 6), duals);
numLands -= dblsAdded;
numLands -= nDLands;
addBasicLand(tDeck, numLands);
tmpDeck.append( "DeckSize:" + tDeck.countAll() + "\n" );
if (numLands > 0) {
// attempt to optimize basic land counts according to
// color representation
final CCnt[] clrCnts = { new CCnt("Plains", 0), new CCnt("Island", 0), new CCnt("Swamp", 0),
new CCnt("Mountain", 0), new CCnt("Forest", 0) };
// count each card color using mana costs
// TODO count hybrid mana differently?
for (int i = 0; i < tDeck.size(); i++) {
final String mc = tDeck.get(i).getManaCost();
// count each mana symbol in the mana cost
for (int j = 0; j < mc.length(); j++) {
final char c = mc.charAt(j);
if (c == 'W') {
clrCnts[0].count++;
} else if (c == 'U') {
clrCnts[1].count++;
} else if (c == 'B') {
clrCnts[2].count++;
} else if (c == 'R') {
clrCnts[3].count++;
} else if (c == 'G') {
clrCnts[4].count++;
}
}
}
// total of all ClrCnts
int totalColor = 0;
for (int i = 0; i < 5; i++) {
totalColor += clrCnts[i].count;
tmpDeck += clrCnts[i].color + ":" + clrCnts[i].count + "\n";
}
tmpDeck += "totalColor:" + totalColor + "\n";
for (int i = 0; i < 5; i++) {
if (clrCnts[i].count > 0) { // calculate number of lands for
// each color
p = (float) clrCnts[i].count / (float) totalColor;
final int nLand = (int) (numLands * p);
tmpDeck += "nLand-" + clrCnts[i].color + ":" + nLand + "\n";
// just to prevent a null exception by the deck size fixing
// code
this.cardCounts.put(clrCnts[i].color, nLand);
for (int j = 0; j <= nLand; j++) {
tDeck.add(AllZone.getCardFactory().getCard(clrCnts[i].color, AllZone.getComputerPlayer()));
}
}
}
}
tmpDeck += "DeckSize:" + tDeck.size() + "\n";
// fix under-sized or over-sized decks, due to integer arithmetic
if (tDeck.size() < size) {
final int diff = size - tDeck.size();
for (int i = 0; i < diff; i++) {
Card c = tDeck.get(this.r.nextInt(tDeck.size()));
lc = 0;
while ((this.cardCounts.get(c.getName()) > 3) || (lc > size)) {
c = tDeck.get(this.r.nextInt(tDeck.size()));
lc++;
}
if (lc > size) {
throw new RuntimeException("Generate2ColorDeck : get2ColorDeck -- looped too much -- undersize");
}
final int n = this.cardCounts.get(c.getName());
tDeck.add(AllZone.getCardFactory().getCard(c.getName(), AllZone.getComputerPlayer()));
this.cardCounts.put(c.getName(), n + 1);
tmpDeck += "Added:" + c.getName() + "\n";
}
} else if (tDeck.size() > size) {
final int diff = tDeck.size() - size;
for (int i = 0; i < diff; i++) {
Card c = tDeck.get(this.r.nextInt(tDeck.size()));
while (c.isBasicLand()) { // don't remove basic lands
c = tDeck.get(this.r.nextInt(tDeck.size()));
}
tDeck.remove(c);
tmpDeck += "Removed:" + c.getName() + "\n";
}
}
tmpDeck += "DeckSize:" + tDeck.size() + "\n";
adjustDeckSize(tDeck, size);
tmpDeck.append( "DeckSize:" + tDeck.countAll() + "\n" );
if (ForgeProps.getProperty("showdeck/2color", "false").equals("true")) {
ErrorViewer.showError(tmpDeck);
ErrorViewer.showError(tmpDeck.toString());
}
return tDeck;
}
private class CCnt {
private final String color;
private int count;
public CCnt(final String clr, final int cnt) {
this.color = clr;
this.count = cnt;
}
}
}

View File

@@ -17,23 +17,17 @@
*/
package forge.deck.generate;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Map;
import java.util.Random;
import forge.AllZone;
import forge.Card;
import forge.CardList;
import forge.CardListFilter;
import forge.Constant;
import java.util.Arrays;
import java.util.List;
import forge.PlayerType;
import forge.Singletons;
import forge.card.CardColor;
import forge.card.CardRules;
import forge.deck.generate.GenerateDeckUtil.FilterCMC;
import forge.error.ErrorViewer;
import forge.properties.ForgePreferences.FPref;
import forge.item.CardPrinted;
import forge.item.ItemPool;
import forge.item.ItemPoolView;
import forge.properties.ForgeProps;
import forge.util.MyRandom;
import forge.util.Predicate;
/**
* <p>
@@ -43,16 +37,16 @@ import forge.util.Predicate;
* @author Forge
* @version $Id$
*/
public class Generate3ColorDeck {
private String color1 = "";
private String color2 = "";
private String color3 = "";
private Random r = null;
private Map<String, String> crMap = null;
private ArrayList<String> notColors = null;
private ArrayList<String> dL = null;
private Map<String, Integer> cardCounts = null;
private int maxDuplicates = 4;
public class Generate3ColorDeck extends GenerateColoredDeckBase {
private final float landsPercentage = .44f;
private final float creatPercentage = .34f;
private final float spellPercentage = .22f;
final List<FilterCMC> cmcLevels = Arrays.asList(
new GenerateDeckUtil.FilterCMC(0, 2),
new GenerateDeckUtil.FilterCMC(3, 5),
new GenerateDeckUtil.FilterCMC(6, 20) );
final int[] cmcAmounts = {12, 9, 3};
/**
* <p>
@@ -67,61 +61,13 @@ public class Generate3ColorDeck {
* a {@link java.lang.String} object.
*/
public Generate3ColorDeck(final String clr1, final String clr2, final String clr3) {
this.r = MyRandom.getRandom();
this.cardCounts = new HashMap<String, Integer>();
this.crMap = new HashMap<String, String>();
this.crMap.put("white", "W");
this.crMap.put("blue", "U");
this.crMap.put("black", "B");
this.crMap.put("red", "R");
this.crMap.put("green", "G");
this.notColors = new ArrayList<String>();
this.notColors.add("white");
this.notColors.add("blue");
this.notColors.add("black");
this.notColors.add("red");
this.notColors.add("green");
if (Singletons.getModel().getPreferences().getPrefBoolean(FPref.DECKGEN_SINGLETONS)) {
this.maxDuplicates = 1;
}
if (clr1.equals("AI")) {
// choose first color
this.color1 = this.notColors.get(this.r.nextInt(5));
// choose second color
String c2 = this.notColors.get(this.r.nextInt(5));
while (c2.equals(this.color1)) {
c2 = this.notColors.get(this.r.nextInt(5));
}
this.color2 = c2;
String c3 = this.notColors.get(this.r.nextInt(5));
while (c3.equals(this.color1) || c3.equals(this.color2)) {
c3 = this.notColors.get(this.r.nextInt(5));
}
this.color3 = c3;
int color1 = r.nextInt(5);
int color2 = ( color1 + 1 + r.nextInt(4) ) % 5 ;
colors = CardColor.fromMask(CardColor.WHITE << color1 | CardColor.WHITE << color2).inverse();
} else {
this.color1 = clr1;
this.color2 = clr2;
this.color3 = clr3;
colors = CardColor.fromNames(clr1, clr2, clr3);
}
this.notColors.remove(this.color1);
this.notColors.remove(this.color2);
this.notColors.remove(this.color3);
this.dL = GenerateDeckUtil.getDualLandList(this.crMap.get(this.color1) + this.crMap.get(this.color2)
+ this.crMap.get(this.color3));
for (int i = 0; i < this.dL.size(); i++) {
this.cardCounts.put(this.dL.get(i), 0);
}
}
/**
@@ -135,312 +81,46 @@ public class Generate3ColorDeck {
* the pt
* @return a {@link forge.CardList} object.
*/
public final CardList get3ColorDeck(final int size, final PlayerType pt) {
int lc = 0; // loop counter to prevent infinite card selection loops
String tmpDeck = "";
final CardList tDeck = new CardList();
final int landsPercentage = 44;
final int creatPercentage = 34;
final int spellPercentage = 22;
// start with all cards
// remove cards that generated decks don't like
Predicate<Card> toUse = pt == PlayerType.HUMAN ? GenerateDeckUtil.humanCanPlay : GenerateDeckUtil.aiCanPlay;
CardList allCards = new CardList(toUse.select(AllZone.getCardFactory()));
// reduce to cards that match the colors
CardList cl1 = allCards.getColor(this.color1);
if (!Singletons.getModel().getPreferences().getPrefBoolean(FPref.DECKGEN_ARTIFACTS)) {
cl1.addAll(allCards.getColor(Constant.Color.COLORLESS));
}
CardList cl2 = allCards.getColor(this.color2);
CardList cl3 = allCards.getColor(this.color3);
// remove multicolor cards that don't match the colors
final CardListFilter clrF = new CardListFilter() {
@Override
public boolean addCard(final Card c) {
for (int i = 0; i < Generate3ColorDeck.this.notColors.size(); i++) {
if (c.getManaCost().contains(
Generate3ColorDeck.this.crMap.get(Generate3ColorDeck.this.notColors.get(i)))) {
return false;
}
}
return true;
}
};
cl1 = cl1.filter(clrF);
cl2 = cl2.filter(clrF);
cl3 = cl3.filter(clrF);
public final ItemPoolView<CardPrinted> get3ColorDeck(final int size, final PlayerType pt) {
List<CardPrinted> cards = selectCardsOfMatchingColorForPlayer(pt);
// build subsets based on type
final CardList cr1 = cl1.getType("Creature");
final CardList cr2 = cl2.getType("Creature");
final CardList cr3 = cl3.getType("Creature");
final List<CardPrinted> creatures = CardRules.Predicates.Presets.IS_CREATURE.select(cards, CardPrinted.FN_GET_RULES);
final List<CardPrinted> spells = CardRules.Predicates.Presets.isNonCreatureSpellForGenerator.select(cards, CardPrinted.FN_GET_RULES);
final String[] ise = { "Instant", "Sorcery", "Enchantment", "Planeswalker", "Artifact.nonCreature" };
final CardList sp1 = cl1.getValidCards(ise, null, null);
final CardList sp2 = cl2.getValidCards(ise, null, null);
final CardList sp3 = cl3.getValidCards(ise, null, null);
// final card pools
final CardList cr123 = new CardList();
final CardList sp123 = new CardList();
final ItemPool<CardPrinted> tDeck = new ItemPool<CardPrinted>(CardPrinted.class);
// used for mana curve in the card pool
final int[] minCMC = { 0 };
final int[] maxCMC = { 2 };
final CardListFilter cmcF = new CardListFilter() {
@Override
public boolean addCard(final Card c) {
final int cCMC = c.getCMC();
return (cCMC >= minCMC[0]) && (cCMC <= maxCMC[0]);
}
};
final int creatCnt = (int) (creatPercentage * size);
tmpDeck.append( "Creature Count:" + creatCnt + "\n" );
addCmcAdjusted(tDeck, creatures, creatCnt, cmcLevels, cmcAmounts);
// select cards to build card pools using a mana curve
for (int i = 3; i > 0; i--) {
if (i == 1) {
maxCMC[0] = 20; //the last category is open ended
i = 0; // this reduces the number of cards in the last category to 6
}
final CardList cr1CMC = cr1.filter(cmcF);
final CardList cr2CMC = cr2.filter(cmcF);
final CardList cr3CMC = cr3.filter(cmcF);
final CardList sp1CMC = sp1.filter(cmcF);
final CardList sp2CMC = sp2.filter(cmcF);
final CardList sp3CMC = sp3.filter(cmcF);
for (int j = 0; j < i + 1; j++) {
Card c = cr1CMC.get(this.r.nextInt(cr1CMC.size()));
cr123.add(c);
this.cardCounts.put(c.getName(), 0);
c = cr2CMC.get(this.r.nextInt(cr2CMC.size()));
cr123.add(c);
this.cardCounts.put(c.getName(), 0);
c = cr3CMC.get(this.r.nextInt(cr3CMC.size()));
cr123.add(c);
this.cardCounts.put(c.getName(), 0);
c = sp1CMC.get(this.r.nextInt(sp1CMC.size()));
sp123.add(c);
this.cardCounts.put(c.getName(), 0);
c = sp2CMC.get(this.r.nextInt(sp2CMC.size()));
sp123.add(c);
this.cardCounts.put(c.getName(), 0);
c = sp3CMC.get(this.r.nextInt(sp3CMC.size()));
sp123.add(c);
this.cardCounts.put(c.getName(), 0);
}
minCMC[0] += 3;
maxCMC[0] += 3;
// resulting mana curve of the card pool
// 24x 0 - 2
// 18x 3 - 5
// 6x 6 - 20
// =58x - card pool
}
// shuffle card pools
cr123.shuffle();
sp123.shuffle();
// calculate card counts
float p = (float) (creatPercentage * .01);
final int creatCnt = (int) (p * size);
tmpDeck += "Creature Count:" + creatCnt + "\n";
p = (float) (spellPercentage * .01);
final int spellCnt = (int) (p * size);
tmpDeck += "Spell Count:" + spellCnt + "\n";
// build deck from the card pools
for (int i = 0; i < creatCnt; i++) {
Card c = cr123.get(this.r.nextInt(cr123.size()));
lc = 0;
while ((this.cardCounts.get(c.getName()) > (this.maxDuplicates - 1)) || (lc > 100)) {
c = cr123.get(this.r.nextInt(cr123.size()));
lc++;
}
if (lc > 100) {
throw new RuntimeException("Generate3ColorDeck : get3ColorDeck -- looped too much -- Cr123");
}
tDeck.add(AllZone.getCardFactory().getCard(c.getName(), AllZone.getComputerPlayer()));
final int n = this.cardCounts.get(c.getName());
this.cardCounts.put(c.getName(), n + 1);
tmpDeck += c.getName() + " " + c.getManaCost() + "\n";
}
for (int i = 0; i < spellCnt; i++) {
Card c = sp123.get(this.r.nextInt(sp123.size()));
lc = 0;
while ((this.cardCounts.get(c.getName()) > (this.maxDuplicates - 1)) || (lc > 100)) {
c = sp123.get(this.r.nextInt(sp123.size()));
lc++;
}
if (lc > 100) {
throw new RuntimeException("Generate3ColorDeck : get3ColorDeck -- looped too much -- Sp123");
}
tDeck.add(AllZone.getCardFactory().getCard(c.getName(), AllZone.getComputerPlayer()));
final int n = this.cardCounts.get(c.getName());
this.cardCounts.put(c.getName(), n + 1);
tmpDeck += c.getName() + " " + c.getManaCost() + "\n";
}
final int spellCnt = (int) (spellPercentage * size);
tmpDeck.append( "Spell Count:" + spellCnt + "\n" );
addCmcAdjusted(tDeck, spells, spellCnt, cmcLevels, cmcAmounts);
// Add lands
int numLands = 0;
if (landsPercentage > 0) {
p = (float) (landsPercentage * .01);
numLands = (int) (p * size);
int numLands = landsPercentage > 0 ? (int) (landsPercentage * size) : size - tDeck.countAll();
tmpDeck.append( "numLands:" + numLands + "\n");
// Add dual lands
List<String> duals = GenerateDeckUtil.getDualLandList(colors);
for(String s : duals) {
this.cardCounts.put(s, 0);
}
/*
* else { // otherwise, just fill in the rest of the deck with basic
* lands numLands = size - tDeck.size(); }
*/
int dblsAdded = addSomeStr(tDeck, (numLands / 4), duals);
numLands -= dblsAdded;
tmpDeck += "numLands:" + numLands + "\n";
addBasicLand(tDeck, numLands);
tmpDeck.append( "DeckSize:" + tDeck.countAll() + "\n" );
final int ndLands = (numLands / 4);
for (int i = 0; i < ndLands; i++) {
String s = this.dL.get(this.r.nextInt(this.dL.size()));
lc = 0;
while ((this.cardCounts.get(s) > 3) || (lc > 20)) {
s = this.dL.get(this.r.nextInt(this.dL.size()));
lc++;
}
if (lc > 20) {
throw new RuntimeException("Generate3ColorDeck : get3ColorDeck -- looped too much -- dL");
}
tDeck.add(AllZone.getCardFactory().getCard(s, AllZone.getHumanPlayer()));
final int n = this.cardCounts.get(s);
this.cardCounts.put(s, n + 1);
tmpDeck += s + "\n";
}
numLands -= ndLands;
if (numLands > 0) {
// attempt to optimize basic land counts according to
// color representation
final CCnt[] clrCnts = { new CCnt("Plains", 0), new CCnt("Island", 0), new CCnt("Swamp", 0),
new CCnt("Mountain", 0), new CCnt("Forest", 0) };
// count each card color using mana costs
// TODO count hybrid mana differently?
for (int i = 0; i < tDeck.size(); i++) {
final String mc = tDeck.get(i).getManaCost();
// count each mana symbol in the mana cost
for (int j = 0; j < mc.length(); j++) {
final char c = mc.charAt(j);
if (c == 'W') {
clrCnts[0].count++;
} else if (c == 'U') {
clrCnts[1].count++;
} else if (c == 'B') {
clrCnts[2].count++;
} else if (c == 'R') {
clrCnts[3].count++;
} else if (c == 'G') {
clrCnts[4].count++;
}
}
}
// total of all ClrCnts
int totalColor = 0;
for (int i = 0; i < 5; i++) {
totalColor += clrCnts[i].count;
tmpDeck += clrCnts[i].color + ":" + clrCnts[i].count + "\n";
}
tmpDeck += "totalColor:" + totalColor + "\n";
for (int i = 0; i < 5; i++) {
if (clrCnts[i].count > 0) { // calculate number of lands for
// each color
p = (float) clrCnts[i].count / (float) totalColor;
final int nLand = (int) (numLands * p);
tmpDeck += "nLand-" + clrCnts[i].color + ":" + nLand + "\n";
// just to prevent a null exception by the deck size fixing
// code
this.cardCounts.put(clrCnts[i].color, nLand);
for (int j = 0; j <= nLand; j++) {
tDeck.add(AllZone.getCardFactory().getCard(clrCnts[i].color, AllZone.getComputerPlayer()));
}
}
}
}
tmpDeck += "DeckSize:" + tDeck.size() + "\n";
// fix under-sized or over-sized decks, due to integer arithmetic
if (tDeck.size() < size) {
final int diff = size - tDeck.size();
for (int i = 0; i < diff; i++) {
Card c = tDeck.get(this.r.nextInt(tDeck.size()));
lc = 0;
while ((this.cardCounts.get(c.getName()) > 3) || (lc > size)) {
c = tDeck.get(this.r.nextInt(tDeck.size()));
lc++;
}
if (lc > size) {
throw new RuntimeException("Generate3ColorDeck : get3ColorDeck -- looped too much -- undersize");
}
final int n = this.cardCounts.get(c.getName());
tDeck.add(AllZone.getCardFactory().getCard(c.getName(), AllZone.getComputerPlayer()));
this.cardCounts.put(c.getName(), n + 1);
tmpDeck += "Added:" + c.getName() + "\n";
}
} else if (tDeck.size() > size) {
final int diff = tDeck.size() - size;
for (int i = 0; i < diff; i++) {
Card c = tDeck.get(this.r.nextInt(tDeck.size()));
while (c.isBasicLand()) {
// don't remove basic lands
c = tDeck.get(this.r.nextInt(tDeck.size()));
}
tDeck.remove(c);
tmpDeck += "Removed:" + c.getName() + "\n";
}
}
tmpDeck += "DeckSize:" + tDeck.size() + "\n";
adjustDeckSize(tDeck, size);
tmpDeck.append( "DeckSize:" + tDeck.countAll() + "\n" );
if (ForgeProps.getProperty("showdeck/3color", "false").equals("true")) {
ErrorViewer.showError(tmpDeck);
ErrorViewer.showError(tmpDeck.toString());
}
return tDeck;
}
private class CCnt {
private final String color;
private int count;
public CCnt(final String clr, final int cnt) {
this.color = clr;
this.count = cnt;
}
}
}

View File

@@ -17,23 +17,17 @@
*/
package forge.deck.generate;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Map;
import java.util.Random;
import forge.AllZone;
import forge.Card;
import forge.CardList;
import forge.CardListFilter;
import forge.Constant;
import java.util.Arrays;
import java.util.List;
import forge.PlayerType;
import forge.Singletons;
import forge.card.CardColor;
import forge.card.CardRules;
import forge.deck.generate.GenerateDeckUtil.FilterCMC;
import forge.error.ErrorViewer;
import forge.item.CardPrinted;
import forge.item.ItemPool;
import forge.item.ItemPoolView;
import forge.properties.ForgeProps;
import forge.properties.ForgePreferences.FPref;
import forge.util.MyRandom;
import forge.util.Predicate;
/**
* <p>
@@ -43,83 +37,28 @@ import forge.util.Predicate;
* @author Forge
* @version $Id$
*/
public class Generate5ColorDeck {
private String color1 = "white";
private String color2 = "blue";
private String color3 = "black";
private String color4 = "red";
private String color5 = "green";
private Random r = null;
private Map<String, String> colorMap = null;
private ArrayList<String> notColors = null;
private ArrayList<String> dualLands = null;
private Map<String, Integer> cardCounts = null;
private int maxDuplicates = 4;
public class Generate5ColorDeck extends GenerateColoredDeckBase {
private final float landsPercentage = .44f;
private final float creatPercentage = .34f;
private final float spellPercentage = .22f;
final List<FilterCMC> cmcLevels = Arrays.asList(
new GenerateDeckUtil.FilterCMC(0, 2),
new GenerateDeckUtil.FilterCMC(3, 5),
new GenerateDeckUtil.FilterCMC(6, 20) );
final int[] cmcAmounts = {15, 10, 5};
// resulting mana curve of the card pool
// 30x 0 - 2
// 20x 3 - 5
// 10x 6 - 20
// =60x - card pool
/**
* Instantiates a new generate5 color deck.
*/
public Generate5ColorDeck() {
this("white", "blue", "black", "red", "green");
}
/**
* <p>
* Constructor for Generate5ColorDeck.
* </p>
*
* @param color1
* a {@link java.lang.String} object.
* @param color2
* a {@link java.lang.String} object.
* @param color3
* a {@link java.lang.String} object.
* @param color4
* a {@link java.lang.String} object.
* @param color5
* a {@link java.lang.String} object.
*/
public Generate5ColorDeck(final String color1, final String color2, final String color3, final String color4,
final String color5) {
this.r = MyRandom.getRandom();
this.cardCounts = new HashMap<String, Integer>();
this.colorMap = new HashMap<String, String>();
this.colorMap.put("white", "W");
this.colorMap.put("blue", "U");
this.colorMap.put("black", "B");
this.colorMap.put("red", "R");
this.colorMap.put("green", "G");
this.notColors = new ArrayList<String>();
this.notColors.add("white");
this.notColors.add("blue");
this.notColors.add("black");
this.notColors.add("red");
this.notColors.add("green");
this.color1 = color1;
this.color2 = color2;
this.color3 = color3;
this.color4 = color4;
this.color5 = color5;
this.notColors.remove(this.color1);
this.notColors.remove(this.color2);
this.notColors.remove(this.color3);
this.notColors.remove(this.color4);
this.notColors.remove(this.color5);
if (Singletons.getModel().getPreferences().getPrefBoolean(FPref.DECKGEN_SINGLETONS)) {
this.maxDuplicates = 1;
}
this.dualLands = GenerateDeckUtil.getDualLandList("WUBRG");
for (int i = 0; i < this.dualLands.size(); i++) {
this.cardCounts.put(this.dualLands.get(i), 0);
}
colors = CardColor.fromMask(0).inverse();
}
/**
@@ -133,362 +72,46 @@ public class Generate5ColorDeck {
* a PlayerType
* @return a {@link forge.CardList} object.
*/
public final CardList get5ColorDeck(final int deckSize, final PlayerType playerType) {
int loopCounter = 0; // loop counter to prevent infinite card selection loops
String tmpDeckErrorMessage = "";
final CardList tempDeck = new CardList();
final int landsPercentage = 44;
final int creaturePercentage = 34;
final int spellPercentage = 22;
// start with all cards
// remove cards that generated decks don't like
Predicate<Card> toUse = playerType == PlayerType.HUMAN ? GenerateDeckUtil.humanCanPlay : GenerateDeckUtil.aiCanPlay;
CardList allCards = new CardList(toUse.select(AllZone.getCardFactory()));
// reduce to cards that match the colors
CardList cardList1 = allCards.getColor(this.color1);
if (!Singletons.getModel().getPreferences().getPrefBoolean(FPref.DECKGEN_ARTIFACTS)) {
cardList1.addAll(allCards.getColor(Constant.Color.COLORLESS));
}
CardList cardList2 = allCards.getColor(this.color2);
CardList cardList3 = allCards.getColor(this.color3);
CardList cardList4 = allCards.getColor(this.color4);
CardList cardList5 = allCards.getColor(this.color5);
// remove multicolor cards that don't match the colors
final CardListFilter cardListFilter = new CardListFilter() {
@Override
public boolean addCard(final Card c) {
for (int i = 0; i < Generate5ColorDeck.this.notColors.size(); i++) {
if (c.getManaCost().contains(
Generate5ColorDeck.this.colorMap.get(Generate5ColorDeck.this.notColors.get(i)))) {
return false;
}
}
return true;
}
};
cardList1 = cardList1.filter(cardListFilter);
cardList2 = cardList2.filter(cardListFilter);
cardList3 = cardList3.filter(cardListFilter);
cardList4 = cardList4.filter(cardListFilter);
cardList5 = cardList5.filter(cardListFilter);
public final ItemPoolView<CardPrinted> get5ColorDeck(final int size, final PlayerType pt) {
List<CardPrinted> cards = selectCardsOfMatchingColorForPlayer(pt);
// build subsets based on type
final CardList creatureCardList1 = cardList1.getType("Creature");
final CardList creatureCardList2 = cardList2.getType("Creature");
final CardList creatureCardList3 = cardList3.getType("Creature");
final CardList creatureCardList4 = cardList4.getType("Creature");
final CardList creatureCardList5 = cardList5.getType("Creature");
final List<CardPrinted> creatures = CardRules.Predicates.Presets.IS_CREATURE.select(cards, CardPrinted.FN_GET_RULES);
final List<CardPrinted> spells = CardRules.Predicates.Presets.isNonCreatureSpellForGenerator.select(cards, CardPrinted.FN_GET_RULES);
final String[] nonCreatureSpells = { "Instant", "Sorcery", "Enchantment", "Planeswalker", "Artifact.nonCreature" };
final CardList spellCardList1 = cardList1.getValidCards(nonCreatureSpells, null, null);
final CardList spellCardList2 = cardList2.getValidCards(nonCreatureSpells, null, null);
final CardList spellCardList3 = cardList3.getValidCards(nonCreatureSpells, null, null);
final CardList spellCardList4 = cardList4.getValidCards(nonCreatureSpells, null, null);
final CardList spellCardList5 = cardList5.getValidCards(nonCreatureSpells, null, null);
// final card pools
final CardList creatures12345 = new CardList();
final CardList spells12345 = new CardList();
final ItemPool<CardPrinted> tDeck = new ItemPool<CardPrinted>(CardPrinted.class);
// used for mana curve in the card pool
final int[] minConvertedManaCost = { 0 };
final int[] maxConvertedManaCost = { 2 };
final CardListFilter convertedManaCostFilter = new CardListFilter() {
@Override
public boolean addCard(final Card c) {
final int cardConvertedManaCost = c.getCMC();
return (cardConvertedManaCost >= minConvertedManaCost[0]) && (cardConvertedManaCost <= maxConvertedManaCost[0]);
}
};
final int creatCnt = (int) (creatPercentage * size);
tmpDeck.append( "Creature Count:" + creatCnt + "\n" );
addCmcAdjusted(tDeck, creatures, creatCnt, cmcLevels, cmcAmounts);
// select cards to build card pools using a mana curve
for (int i = 3; i > 0; i--) {
if (i == 1) {
maxConvertedManaCost[0] = 20; //the last category is open ended
}
final CardList creature1ConvertedManaCost = creatureCardList1.filter(convertedManaCostFilter);
final CardList creature2ConvertedManaCost = creatureCardList2.filter(convertedManaCostFilter);
final CardList creature3ConvertedManaCost = creatureCardList3.filter(convertedManaCostFilter);
final CardList creature4ConvertedManaCost = creatureCardList4.filter(convertedManaCostFilter);
final CardList creature5ConvertedManaCost = creatureCardList5.filter(convertedManaCostFilter);
final CardList spell1ConvertedManaCost = spellCardList1.filter(convertedManaCostFilter);
final CardList spell2ConvertedManaCost = spellCardList2.filter(convertedManaCostFilter);
final CardList spell3ConvertedManaCost = spellCardList3.filter(convertedManaCostFilter);
final CardList spell4ConvertedManaCost = spellCardList4.filter(convertedManaCostFilter);
final CardList spell5ConvertedManaCost = spellCardList5.filter(convertedManaCostFilter);
for (int j = 0; j < i; j++) {
Card c = creature1ConvertedManaCost.get(this.r.nextInt(creature1ConvertedManaCost.size()));
creatures12345.add(c);
this.cardCounts.put(c.getName(), 0);
c = creature2ConvertedManaCost.get(this.r.nextInt(creature2ConvertedManaCost.size()));
creatures12345.add(c);
this.cardCounts.put(c.getName(), 0);
c = creature3ConvertedManaCost.get(this.r.nextInt(creature3ConvertedManaCost.size()));
creatures12345.add(c);
this.cardCounts.put(c.getName(), 0);
c = creature4ConvertedManaCost.get(this.r.nextInt(creature4ConvertedManaCost.size()));
creatures12345.add(c);
this.cardCounts.put(c.getName(), 0);
c = creature5ConvertedManaCost.get(this.r.nextInt(creature5ConvertedManaCost.size()));
creatures12345.add(c);
this.cardCounts.put(c.getName(), 0);
c = spell1ConvertedManaCost.get(this.r.nextInt(spell1ConvertedManaCost.size()));
spells12345.add(c);
this.cardCounts.put(c.getName(), 0);
c = spell2ConvertedManaCost.get(this.r.nextInt(spell2ConvertedManaCost.size()));
spells12345.add(c);
this.cardCounts.put(c.getName(), 0);
c = spell3ConvertedManaCost.get(this.r.nextInt(spell3ConvertedManaCost.size()));
spells12345.add(c);
this.cardCounts.put(c.getName(), 0);
c = spell4ConvertedManaCost.get(this.r.nextInt(spell4ConvertedManaCost.size()));
spells12345.add(c);
this.cardCounts.put(c.getName(), 0);
c = spell5ConvertedManaCost.get(this.r.nextInt(spell5ConvertedManaCost.size()));
spells12345.add(c);
this.cardCounts.put(c.getName(), 0);
}
minConvertedManaCost[0] += 2;
maxConvertedManaCost[0] += 2;
// resulting mana curve of the card pool
// 30x 0 - 2
// 20x 3 - 5
// 10x 6 - 20
// =60x - card pool
}
// shuffle card pools
creatures12345.shuffle();
spells12345.shuffle();
// calculate card counts
float p = (float) (creaturePercentage * .01);
final int creatureCount = (int) (p * deckSize);
tmpDeckErrorMessage += "Creature Count:" + creatureCount + "\n";
p = (float) (spellPercentage * .01);
final int spellCount = (int) (p * deckSize);
tmpDeckErrorMessage += "Spell Count:" + spellCount + "\n";
// build deck from the card pools
for (int i = 0; i < creatureCount; i++) {
Card c = creatures12345.get(this.r.nextInt(creatures12345.size()));
loopCounter = 0;
while ((this.cardCounts.get(c.getName()) > (this.maxDuplicates - 1)) || (loopCounter > 100)) {
c = creatures12345.get(this.r.nextInt(creatures12345.size()));
loopCounter++;
}
if (loopCounter > 100) {
throw new RuntimeException("Generate5ColorDeck : get5ColorDeck -- looped too much -- Cr123");
}
tempDeck.add(AllZone.getCardFactory().getCard(c.getName(), AllZone.getComputerPlayer()));
final int n = this.cardCounts.get(c.getName());
this.cardCounts.put(c.getName(), n + 1);
tmpDeckErrorMessage += c.getName() + " " + c.getManaCost() + "\n";
}
for (int i = 0; i < spellCount; i++) {
Card c = spells12345.get(this.r.nextInt(spells12345.size()));
loopCounter = 0;
while ((this.cardCounts.get(c.getName()) > (this.maxDuplicates - 1)) || (loopCounter > 100)) {
c = spells12345.get(this.r.nextInt(spells12345.size()));
loopCounter++;
}
if (loopCounter > 100) {
throw new RuntimeException("Generate5ColorDeck : get5ColorDeck -- looped too much -- Sp123");
}
tempDeck.add(AllZone.getCardFactory().getCard(c.getName(), AllZone.getComputerPlayer()));
final int n = this.cardCounts.get(c.getName());
this.cardCounts.put(c.getName(), n + 1);
tmpDeckErrorMessage += c.getName() + " " + c.getManaCost() + "\n";
}
final int spellCnt = (int) (spellPercentage * size);
tmpDeck.append( "Spell Count:" + spellCnt + "\n" );
addCmcAdjusted(tDeck, spells, spellCnt, cmcLevels, cmcAmounts);
// Add lands
int numberOfLands = 0;
if (landsPercentage > 0) {
p = (float) (landsPercentage * .01);
numberOfLands = (int) (p * deckSize);
int numLands = landsPercentage > 0 ? (int) (landsPercentage * size) : size - tDeck.countAll();
tmpDeck.append( "numLands:" + numLands + "\n");
// Add dual lands
List<String> duals = GenerateDeckUtil.getDualLandList(colors);
for(String s : duals) {
this.cardCounts.put(s, 0);
}
/*
* else { // otherwise, just fill in the rest of the deck with basic //
* lands numLands = size - tDeck.size(); }
*/
int dblsAdded = addSomeStr(tDeck, (numLands / 4), duals);
numLands -= dblsAdded;
tmpDeckErrorMessage += "numLands:" + numberOfLands + "\n";
addBasicLand(tDeck, numLands);
tmpDeck.append( "DeckSize:" + tDeck.countAll() + "\n" );
final int numberOfDualLands = (numberOfLands / 4);
for (int i = 0; i < numberOfDualLands; i++) {
String s = this.dualLands.get(this.r.nextInt(this.dualLands.size()));
loopCounter = 0;
while ((this.cardCounts.get(s) > 3) || (loopCounter > 20)) {
s = this.dualLands.get(this.r.nextInt(this.dualLands.size()));
loopCounter++;
}
if (loopCounter > 20) {
throw new RuntimeException("Generate5ColorDeck : get5ColorDeck -- looped too much -- DL");
}
tempDeck.add(AllZone.getCardFactory().getCard(s, AllZone.getHumanPlayer()));
final int n = this.cardCounts.get(s);
this.cardCounts.put(s, n + 1);
tmpDeckErrorMessage += s + "\n";
}
numberOfLands -= numberOfDualLands;
if (numberOfLands > 0) {
// attempt to optimize basic land counts according to
// color representation
final ColorCount[] colorCounts = { new ColorCount("Plains", 0), new ColorCount("Island", 0), new ColorCount("Swamp", 0),
new ColorCount("Mountain", 0), new ColorCount("Forest", 0) };
// count each card color using mana costs
// TODO: count hybrid mana differently?
for (int i = 0; i < tempDeck.size(); i++) {
final String mc = tempDeck.get(i).getManaCost();
// count each mana symbol in the mana cost
for (int j = 0; j < mc.length(); j++) {
final char c = mc.charAt(j);
if (c == 'W') {
colorCounts[0].setCount(colorCounts[0].getCount() + 1);
} else if (c == 'U') {
colorCounts[1].setCount(colorCounts[1].getCount() + 1);
} else if (c == 'B') {
colorCounts[2].setCount(colorCounts[2].getCount() + 1);
} else if (c == 'R') {
colorCounts[3].setCount(colorCounts[3].getCount() + 1);
} else if (c == 'G') {
colorCounts[4].setCount(colorCounts[4].getCount() + 1);
}
}
}
// total of all ColorCounts
int totalColor = 0;
for (int i = 0; i < 5; i++) {
totalColor += colorCounts[i].getCount();
tmpDeckErrorMessage += colorCounts[i].getColor() + ":" + colorCounts[i].getCount() + "\n";
}
tmpDeckErrorMessage += "totalColor:" + totalColor + "\n";
for (int i = 0; i < 5; i++) {
if (colorCounts[i].getCount() > 0) { // calculate number of lands
// for each color
p = (float) colorCounts[i].getCount() / (float) totalColor;
final int nLand = (int) (numberOfLands * p);
tmpDeckErrorMessage += "nLand-" + colorCounts[i].getColor() + ":" + nLand + "\n";
// just to prevent a null exception by the deck size fixing
// code
this.cardCounts.put(colorCounts[i].getColor(), nLand);
for (int j = 0; j <= nLand; j++) {
tempDeck.add(AllZone.getCardFactory().getCard(colorCounts[i].getColor(), AllZone.getComputerPlayer()));
}
}
}
}
tmpDeckErrorMessage += "DeckSize:" + tempDeck.size() + "\n";
// fix under-sized or over-sized decks, due to integer arithmetic
if (tempDeck.size() < deckSize) {
final int diff = deckSize - tempDeck.size();
for (int i = 0; i < diff; i++) {
Card c = tempDeck.get(this.r.nextInt(tempDeck.size()));
loopCounter = 0;
while ((this.cardCounts.get(c.getName()) > 3) || (loopCounter > deckSize)) {
c = tempDeck.get(this.r.nextInt(tempDeck.size()));
loopCounter++;
}
if (loopCounter > deckSize) {
throw new RuntimeException("Generate5ColorDeck : get5ColorDeck -- looped too much -- undersize");
}
final int n = this.cardCounts.get(c.getName());
tempDeck.add(AllZone.getCardFactory().getCard(c.getName(), AllZone.getComputerPlayer()));
this.cardCounts.put(c.getName(), n + 1);
tmpDeckErrorMessage += "Added:" + c.getName() + "\n";
}
} else if (tempDeck.size() > deckSize) {
final int diff = tempDeck.size() - deckSize;
for (int i = 0; i < diff; i++) {
Card c = tempDeck.get(this.r.nextInt(tempDeck.size()));
while (c.isBasicLand()) { // don't remove basic lands
c = tempDeck.get(this.r.nextInt(tempDeck.size()));
}
tempDeck.remove(c);
tmpDeckErrorMessage += "Removed:" + c.getName() + "\n";
}
}
tmpDeckErrorMessage += "DeckSize:" + tempDeck.size() + "\n";
adjustDeckSize(tDeck, size);
tmpDeck.append( "DeckSize:" + tDeck.countAll() + "\n" );
if (ForgeProps.getProperty("showdeck/5color", "false").equals("true")) {
ErrorViewer.showError(tmpDeckErrorMessage);
ErrorViewer.showError(tmpDeck.toString());
}
return tempDeck;
}
private class ColorCount {
private final String color;
private int count;
public ColorCount(final String color, final int count) {
this.color = color;
this.count = count;
}
/**
*
* @return
*/
public String getColor() {
return this.color;
}
/**
*
* @return
*/
public int getCount() {
return this.count;
}
/**
*
* @param color
*/
public void setCount(final int count) {
this.count = count;
}
return tDeck;
}
}

View File

@@ -0,0 +1,225 @@
/*
* 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.deck.generate;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Random;
import com.google.common.base.Predicates;
import forge.PlayerType;
import forge.Singletons;
import forge.card.CardColor;
import forge.card.CardRules;
import forge.deck.generate.GenerateDeckUtil.FilterCMC;
import forge.item.CardDb;
import forge.item.CardPrinted;
import forge.item.ItemPool;
import forge.properties.ForgePreferences.FPref;
import forge.util.MyRandom;
import forge.util.Predicate;
/**
* <p>
* Generate2ColorDeck class.
* </p>
*
* @author Forge
* @version $Id: Generate2ColorDeck.java 14959 2012-03-28 14:03:43Z Chris H. $
*/
public abstract class GenerateColoredDeckBase {
protected final Random r = MyRandom.getRandom();
protected final Map<String, Integer> cardCounts = new HashMap<String, Integer>();
protected final int maxDuplicates;
protected CardColor colors;
StringBuilder tmpDeck = new StringBuilder();
// protected final float landsPercentage = 0.42f;
// protected float creatPercentage = 0.34f;
// protected float spellPercentage = 0.24f;
/**
* <p>
* Constructor for Generate2ColorDeck.
* </p>
*
* @param clr1
* a {@link java.lang.String} object.
* @param clr2
* a {@link java.lang.String} object.
*/
public GenerateColoredDeckBase() {
this.maxDuplicates = Singletons.getModel().getPreferences().getPrefBoolean(FPref.DECKGEN_SINGLETONS) ? 1 : 4;
}
protected void addSome(ItemPool<CardPrinted> tDeck, int cnt, List<CardPrinted> source) {
for (int i = 0; i < cnt; i++) {
CardPrinted c;
int lc = 0;
do {
c = source.get(this.r.nextInt(source.size()));
lc++;
} while ((this.cardCounts.get(c.getName()) > (this.maxDuplicates - 1)) || (lc > 100));
if (lc > 100) {
throw new RuntimeException("Generate2ColorDeck : get2ColorDeck -- looped too much -- Cr12");
}
tDeck.add(c);
final int n = this.cardCounts.get(c.getName());
this.cardCounts.put(c.getName(), n + 1);
tmpDeck.append(c.getName() + " " + c.getCard().getManaCost() + "\n");
}
}
protected int addSomeStr(ItemPool<CardPrinted> tDeck, int cnt, List<String> source) {
int res = 0;
for (int i = 0; i < cnt; i++) {
String s;
int lc = 0;
do {
s = source.get(this.r.nextInt(source.size()));
lc++;
} while ((this.cardCounts.get(s) > (this.maxDuplicates - 1)) || (lc > 20));
// not an error if looped too much - could play singleton mode, with 6 slots for 3 non-basic lands.
tDeck.add(CardDb.instance().getCard(s));
final int n = this.cardCounts.get(s);
this.cardCounts.put(s, n + 1);
tmpDeck.append(s + "\n");
}
return res;
}
protected void addBasicLand(ItemPool<CardPrinted> tDeck, int cnt) {
// attempt to optimize basic land counts according to colors of picked cards
final CCnt[] clrCnts = countLands(tDeck);
// total of all ClrCnts
int totalColor = 0;
for (int i = 0; i < 5; i++) {
totalColor += clrCnts[i].getCount();
tmpDeck.append( clrCnts[i].Color + ":" + clrCnts[i].getCount() + "\n");
}
tmpDeck.append( "totalColor:" + totalColor + "\n");
for (int i = 0; i < 5; i++) {
if (clrCnts[i].getCount() <= 0) continue;
// calculate number of lands for each color
float p = (float) clrCnts[i].getCount() / (float) totalColor;
final int nLand = (int) (cnt * p);
tmpDeck.append( "nLand-" + clrCnts[i].Color + ":" + nLand + "\n");
// just to prevent a null exception by the deck size fixing
// code
this.cardCounts.put(clrCnts[i].Color, nLand);
for (int j = 0; j <= nLand; j++) {
tDeck.add(CardDb.instance().getCard(clrCnts[i].Color));
}
}
}
protected void adjustDeckSize(ItemPool<CardPrinted> tDeck, int targetSize) {
// fix under-sized or over-sized decks, due to integer arithmetic
int actualSize = tDeck.countAll();
if (actualSize < targetSize) {
final int diff = targetSize - actualSize;
addSome(tDeck, diff, tDeck.toFlatList());
} else if (actualSize > targetSize) {
Predicate<CardRules> exceptBasicLand = Predicate.not(CardRules.Predicates.Presets.IS_BASIC_LAND);
for( int i = 0; i < 3 && actualSize > targetSize; i++ ) {
List<CardPrinted> toRemove = exceptBasicLand.random(tDeck.toFlatList(), CardPrinted.FN_GET_RULES, actualSize - targetSize);
tDeck.removeAllFlat(toRemove);
for(CardPrinted c: toRemove)
tmpDeck.append( "Removed:" + c.getName() + "\n" );
actualSize = tDeck.countAll();
}
}
}
protected void addCmcAdjusted(ItemPool<CardPrinted> tDeck, List<CardPrinted> source, int cnt, List<FilterCMC> cmcLevels, int[] cmcAmounts) {
final List<CardPrinted> curved = new ArrayList<CardPrinted>();
for(int i = 0; i < cmcAmounts.length; i++){
curved.addAll(cmcLevels.get(i).random(source, CardPrinted.FN_GET_RULES, cmcAmounts[i]));
}
for(CardPrinted c: curved)
this.cardCounts.put(c.getName(), 0);
addSome(tDeck, cnt, curved);
}
protected List<CardPrinted> selectCardsOfMatchingColorForPlayer(PlayerType pt)
{
// start with all cards
// remove cards that generated decks don't like
Predicate<CardRules> canPlay = pt == PlayerType.HUMAN ? GenerateDeckUtil.humanCanPlay : GenerateDeckUtil.aiCanPlay;
Predicate<CardRules> hasColor = new GenerateDeckUtil.ContainsAllColorsFrom(colors);
if (!Singletons.getModel().getPreferences().getPrefBoolean(FPref.DECKGEN_ARTIFACTS)) {
hasColor = Predicate.or( hasColor, GenerateDeckUtil.colorlessCards );
}
return Predicate.and(canPlay, hasColor).select(CardDb.instance().getAllCards(), CardPrinted.FN_GET_RULES);
}
protected static CCnt[] countLands(ItemPool<CardPrinted> outList) {
// attempt to optimize basic land counts according
// to color representation
final CCnt[] clrCnts = { new CCnt("Plains", 0), new CCnt("Island", 0), new CCnt("Swamp", 0),
new CCnt("Mountain", 0), new CCnt("Forest", 0) };
// count each card color using mana costs
// TODO: count hybrid mana differently?
for( Entry<CardPrinted, Integer> cpe : outList)
{
int profile = cpe.getKey().getCard().getManaCost().getColorProfile();
if ((profile & CardColor.WHITE) != 0 ) {
clrCnts[0].increment(cpe.getValue());
} else if ((profile & CardColor.BLUE) != 0 ) {
clrCnts[1].increment(cpe.getValue());
} else if ((profile & CardColor.BLACK) != 0 ) {
clrCnts[2].increment(cpe.getValue());
} else if ((profile & CardColor.RED) != 0 ) {
clrCnts[3].increment(cpe.getValue());
} else if ((profile & CardColor.GREEN) != 0 ) {
clrCnts[4].increment(cpe.getValue());
}
}
return clrCnts;
}
}

View File

@@ -18,8 +18,16 @@
package forge.deck.generate;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import forge.Card;
import forge.card.CardColor;
import forge.card.CardManaCost;
import forge.card.CardRules;
import forge.item.CardPrinted;
import forge.util.Predicate;
/**
@@ -32,99 +40,91 @@ import forge.util.Predicate;
*/
public class GenerateDeckUtil {
public static final Predicate<Card> aiCanPlay = new Predicate<Card>() {
public static final Predicate<CardRules> aiCanPlay = new Predicate<CardRules>() {
@Override
public boolean isTrue(Card c) {
return !c.getSVar("RemRandomDeck").equals("True") && !c.getSVar("RemAIDeck").equals("True");
public boolean isTrue(CardRules c) {
return !c.getRemAIDecks() && c.getRemRandomDecks();
}
};
public static final Predicate<Card> humanCanPlay = new Predicate<Card>() {
public static final Predicate<CardRules> humanCanPlay = new Predicate<CardRules>() {
@Override
public boolean isTrue(Card c) {
return !c.getSVar("RemRandomDeck").equals("True");
public boolean isTrue(CardRules c) {
return !c.getRemRandomDecks();
}
};
/**
*
* Arrays of dual and tri-land cards.
*
* @param colors
* a String
* @return ArrayList<String>
*/
public static ArrayList<String> getDualLandList(final String colors) {
final ArrayList<String> dLands = new ArrayList<String>();
public static final Predicate<CardRules> colorlessCards = new Predicate<CardRules>() {
@Override
public boolean isTrue(CardRules c) {
CardManaCost mc = c.getManaCost();
return mc.getColorProfile() == 0 && !mc.isEmpty();
}
};
if (colors.length() > 3) {
public static class ContainsAllColorsFrom extends Predicate<CardRules> {
private final CardColor allowedColor;
public ContainsAllColorsFrom(CardColor color) {
allowedColor = color;
}
@Override
public boolean isTrue(CardRules subject) {
return allowedColor.containsAllColorsFrom(subject.getManaCost().getColorProfile());
}
}
public static class FilterCMC extends Predicate<CardRules> {
private final int min;
private final int max;
public FilterCMC(int from, int to) {
min = from; max = to;
}
@Override
public boolean isTrue(CardRules c) {
CardManaCost mc = c.getManaCost();
int cmc = mc.getCMC();
return cmc >= min && cmc <= max && !mc.isEmpty();
}
}
private static Map<Integer, String[]> dualLands = new HashMap<Integer, String[]>();
static {
dualLands.put(CardColor.WHITE | CardColor.BLUE, new String[]{"Tundra", "Hallowed Fountain", "Flooded Strand"});
dualLands.put(CardColor.BLACK | CardColor.BLUE, new String[]{"Underground Sea", "Watery Grave", "Polluted Delta"});
dualLands.put(CardColor.BLACK | CardColor.RED, new String[]{"Badlands", "Blood Crypt", "Bloodstained Mire"});
dualLands.put(CardColor.GREEN | CardColor.RED, new String[]{"Taiga", "Stomping Ground", "Wooded Foothills"});
dualLands.put(CardColor.GREEN | CardColor.WHITE, new String[]{"Savannah", "Temple Garden", "Windswept Heath"});
dualLands.put(CardColor.WHITE | CardColor.BLACK, new String[]{"Scrubland", "Godless Shrine", "Marsh Flats"});
dualLands.put(CardColor.BLUE | CardColor.RED, new String[]{"Volcanic Island", "Steam Vents", "Scalding Tarn"});
dualLands.put(CardColor.BLACK | CardColor.GREEN, new String[]{"Bayou", "Overgrown Tomb", "Verdant Catacombs"});
dualLands.put(CardColor.WHITE | CardColor.RED, new String[]{"Plateau","Sacred Foundry","Arid Mesa"});
dualLands.put(CardColor.GREEN | CardColor.BLUE, new String[]{"Tropical Island", "Breeding Pool", "Misty Rainforest"});
}
public static List<String> getDualLandList(final CardColor color) {
final List<String> dLands = new ArrayList<String>();
if (color.countColors() > 3) {
dLands.add("Rupture Spire");
dLands.add("Undiscovered Paradise");
}
if (colors.length() > 2) {
if (color.countColors() > 2) {
dLands.add("Evolving Wilds");
dLands.add("Terramorphic Expanse");
}
if (colors.contains("W") && colors.contains("U")) {
dLands.add("Tundra");
dLands.add("Hallowed Fountain");
dLands.add("Flooded Strand");
for(Entry<Integer, String[]> dual : dualLands.entrySet()) {
if( color.hasAllColors(dual.getKey()) ) {
for(String s : dual.getValue())
dLands.add(s);
}
if (colors.contains("U") && colors.contains("B")) {
dLands.add("Underground Sea");
dLands.add("Watery Grave");
dLands.add("Polluted Delta");
}
if (colors.contains("B") && colors.contains("R")) {
dLands.add("Badlands");
dLands.add("Blood Crypt");
dLands.add("Bloodstained Mire");
}
if (colors.contains("R") && colors.contains("G")) {
dLands.add("Taiga");
dLands.add("Stomping Ground");
dLands.add("Wooded Foothills");
}
if (colors.contains("G") && colors.contains("W")) {
dLands.add("Savannah");
dLands.add("Temple Garden");
dLands.add("Windswept Heath");
}
if (colors.contains("W") && colors.contains("B")) {
dLands.add("Scrubland");
dLands.add("Godless Shrine");
dLands.add("Marsh Flats");
}
if (colors.contains("U") && colors.contains("R")) {
dLands.add("Volcanic Island");
dLands.add("Steam Vents");
dLands.add("Scalding Tarn");
}
if (colors.contains("B") && colors.contains("G")) {
dLands.add("Bayou");
dLands.add("Overgrown Tomb");
dLands.add("Verdant Catacombs");
}
if (colors.contains("R") && colors.contains("W")) {
dLands.add("Plateau");
dLands.add("Sacred Foundry");
dLands.add("Arid Mesa");
}
if (colors.contains("G") && colors.contains("U")) {
dLands.add("Tropical Island");
dLands.add("Breeding Pool");
dLands.add("Misty Rainforest");
}
return dLands;

View File

@@ -26,10 +26,11 @@ import java.util.HashMap;
import java.util.Map;
import java.util.Random;
import forge.AllZone;
import forge.Card;
import forge.CardList;
import forge.error.ErrorViewer;
import forge.item.CardDb;
import forge.item.CardPrinted;
import forge.item.ItemPool;
import forge.item.ItemPoolView;
import forge.util.MyRandom;
/**
@@ -40,7 +41,7 @@ import forge.util.MyRandom;
* @author Forge
* @version $Id$
*/
public class GenerateThemeDeck {
public class GenerateThemeDeck extends GenerateColoredDeckBase{
private BufferedReader in = null;
/**
@@ -95,8 +96,8 @@ public class GenerateThemeDeck {
* a int.
* @return a {@link forge.CardList} object.
*/
public final CardList getThemeDeck(final String themeName, final int size) {
final CardList tDeck = new CardList();
public final ItemPoolView<CardPrinted> getThemeDeck(final String themeName, final int size) {
final ItemPool<CardPrinted> tDeck = new ItemPool<CardPrinted>(CardPrinted.class);
final ArrayList<Grp> groups = new ArrayList<Grp>();
@@ -197,7 +198,7 @@ public class GenerateThemeDeck {
}
final int n = cardCounts.get(s);
tDeck.add(AllZone.getCardFactory().getCard(s, AllZone.getComputerPlayer()));
tDeck.add(CardDb.instance().getCard(s));
cardCounts.put(s, n + 1);
tmpDeck += s + "\n";
@@ -210,94 +211,18 @@ public class GenerateThemeDeck {
numBLands = (int) (p * size);
} else { // otherwise, just fill in the rest of the deck with basic
// lands
numBLands = size - tDeck.size();
numBLands = size - tDeck.countAll();
}
tmpDeck += "numBLands:" + numBLands + "\n";
if (numBLands > 0) {
// attempt to optimize basic land counts according to
// color representation
final CCnt[] clrCnts = { new CCnt("Plains", 0), new CCnt("Island", 0), new CCnt("Swamp", 0),
new CCnt("Mountain", 0), new CCnt("Forest", 0) };
addBasicLand(tDeck, numBLands);
// count each instance of a color in mana costs
// TODO count hybrid mana differently?
for (int i = 0; i < tDeck.size(); i++) {
final String mc = tDeck.get(i).getManaCost();
tmpDeck += "DeckSize:" + tDeck.countAll() + "\n";
for (int j = 0; j < mc.length(); j++) {
final char c = mc.charAt(j);
adjustDeckSize(tDeck, size);
if (c == 'W') {
clrCnts[0].count++;
} else if (c == 'U') {
clrCnts[1].count++;
} else if (c == 'B') {
clrCnts[2].count++;
} else if (c == 'R') {
clrCnts[3].count++;
} else if (c == 'G') {
clrCnts[4].count++;
}
}
}
int totalColor = 0;
for (int i = 0; i < 5; i++) {
totalColor += clrCnts[i].count;
tmpDeck += clrCnts[i].color + ":" + clrCnts[i].count + "\n";
}
tmpDeck += "totalColor:" + totalColor + "\n";
for (int i = 0; i < 5; i++) {
if (clrCnts[i].count > 0) { // calculate number of lands for
// each color
final float p = (float) clrCnts[i].count / (float) totalColor;
final int nLand = (int) (numBLands * p);
tmpDeck += "numLand-" + clrCnts[i].color + ":" + nLand + "\n";
cardCounts.put(clrCnts[i].color, 2);
for (int j = 0; j < nLand; j++) {
tDeck.add(AllZone.getCardFactory().getCard(clrCnts[i].color, AllZone.getComputerPlayer()));
}
}
}
}
tmpDeck += "DeckSize:" + tDeck.size() + "\n";
if (tDeck.size() < size) {
final int diff = size - tDeck.size();
for (int i = 0; i < diff; i++) {
s = tDeck.get(r.nextInt(tDeck.size())).getName();
while (cardCounts.get(s) >= 4) {
s = tDeck.get(r.nextInt(tDeck.size())).getName();
}
final int n = cardCounts.get(s);
tDeck.add(AllZone.getCardFactory().getCard(s, AllZone.getComputerPlayer()));
cardCounts.put(s, n + 1);
tmpDeck += "Added:" + s + "\n";
}
} else if (tDeck.size() > size) {
final int diff = tDeck.size() - size;
for (int i = 0; i < diff; i++) {
Card c = tDeck.get(r.nextInt(tDeck.size()));
while (c.isBasicLand()) {
c = tDeck.get(r.nextInt(tDeck.size()));
}
tDeck.remove(c);
tmpDeck += "Removed:" + s + "\n";
}
}
tmpDeck += "DeckSize:" + tDeck.size() + "\n";
tmpDeck += "DeckSize:" + tDeck.countAll() + "\n";
if (testing) {
ErrorViewer.showError(tmpDeck);
}
@@ -326,28 +251,6 @@ public class GenerateThemeDeck {
}
} // readLine(Card)
private class CCnt {
/** The Color. */
private final String color;
/** The Count. */
private int count;
/**
* Instantiates a new c cnt.
*
* @param clr
* the clr
* @param cnt
* the cnt
*/
public CCnt(final String clr, final int cnt) {
this.color = clr;
this.count = cnt;
}
}
private class Grp {
/** The Cardnames. */

View File

@@ -93,7 +93,7 @@ public final class MenuCommon extends MenuBase<Deck> {
}
final Deck genConstructed = new Deck();
genConstructed.getMain().add((new Generate2ColorDeck("AI", "AI")).get2ColorDeck(60, PlayerType.HUMAN));
genConstructed.getMain().addAll((new Generate2ColorDeck("AI", "AI")).get2ColorDeck(60, PlayerType.HUMAN));
this.getController().setModel(genConstructed);
}

View File

@@ -39,6 +39,7 @@ import forge.gui.OverlayUtils;
import forge.gui.home.ICSubmenu;
import forge.gui.toolbox.FLabel;
import forge.item.CardPrinted;
import forge.item.ItemPoolView;
import forge.properties.ForgePreferences;
import forge.properties.ForgePreferences.FPref;
import forge.quest.QuestController;
@@ -372,7 +373,7 @@ public enum CSubmenuConstructed implements ICSubmenu {
/** Generates deck from current list selection(s). */
private Deck generateDeck(final JList lst0, final PlayerType player0) {
CardList cards = null;
ItemPoolView<CardPrinted> cards = null;
final String[] selection = Arrays.copyOf(lst0.getSelectedValues(),
lst0.getSelectedValues().length, String[].class);
@@ -406,7 +407,7 @@ public enum CSubmenuConstructed implements ICSubmenu {
// After generating card lists, build deck.
deck = new Deck();
deck.getMain().add(cards);
deck.getMain().addAll(cards);
}
// Theme deck
@@ -416,7 +417,7 @@ public enum CSubmenuConstructed implements ICSubmenu {
// After generating card lists, build deck.
deck = new Deck();
deck.getMain().add(cards);
deck.getMain().addAll(cards);
}
else if (lst0.getName().equals(ESubmenuConstructedTypes.QUESTEVENTS.toString())) {
deck = quest.getDuelsManager().getEvent(selection[0]).getEventDeck();

View File

@@ -224,7 +224,14 @@ public class ItemPool<T extends InventoryItem> extends ItemPoolView<T> {
for (final Entry<T, Integer> e : map) {
this.remove(e.getKey(), e.getValue());
}
this.setListInSync(false);
// need not set out-of-sync: either remove did set, or nothing was removed
}
public void removeAllFlat(final Iterable<T> flat) {
for (final T e : flat) {
this.remove(e);
}
// need not set out-of-sync: either remove did set, or nothing was removed
}
/**

View File

@@ -57,7 +57,9 @@ public abstract class Predicate<T> {
/** The NOR. */
NOR,
/** The NAND. */
NAND
NAND,
GT,
LT
}
/**
@@ -1016,6 +1018,10 @@ class Node<T> extends Predicate<T> {
switch (this.operator) {
case AND:
return this.getFilter1().isTrue(card) && this.getFilter2().isTrue(card);
case GT:
return this.getFilter1().isTrue(card) && !this.getFilter2().isTrue(card);
case LT:
return !this.getFilter1().isTrue(card) && this.getFilter2().isTrue(card);
case NAND:
return !(this.getFilter1().isTrue(card) && this.getFilter2().isTrue(card));
case OR:

View File

@@ -3,7 +3,8 @@ package forge.deck.generate;
import org.testng.Assert;
import org.testng.annotations.Test;
import forge.CardList;
import forge.item.CardPrinted;
import forge.item.ItemPoolView;
/**
* Created by IntelliJ IDEA. User: dhudson
@@ -17,7 +18,7 @@ public class Generate2ColorDeckTest {
@Test(enabled = false)
public void generate2ColorDeckTest1() {
final Generate2ColorDeck gen = new Generate2ColorDeck("white", "blue");
final CardList cardList = gen.get2ColorDeck(60, null);
final ItemPoolView<CardPrinted> cardList = gen.get2ColorDeck(60, null);
Assert.assertNotNull(cardList);
}
}

View File

@@ -3,7 +3,8 @@ package forge.deck.generate;
import org.testng.Assert;
import org.testng.annotations.Test;
import forge.CardList;
import forge.item.CardPrinted;
import forge.item.ItemPoolView;
/**
* Created by IntelliJ IDEA. User: dhudson
@@ -17,7 +18,7 @@ public class Generate3ColorDeckTest {
@Test(timeOut = 1000, enabled = false)
public void generate3ColorDeckTest1() {
final Generate3ColorDeck gen = new Generate3ColorDeck("white", "blue", "black");
final CardList cardList = gen.get3ColorDeck(60, null);
final ItemPoolView<CardPrinted> cardList = gen.get3ColorDeck(60, null);
Assert.assertNotNull(cardList);
}
}

View File

@@ -3,7 +3,8 @@ package forge.deck.generate;
import org.testng.Assert;
import org.testng.annotations.Test;
import forge.CardList;
import forge.item.CardPrinted;
import forge.item.ItemPoolView;
/**
* Created by IntelliJ IDEA. User: dhudson
@@ -17,7 +18,7 @@ public class Generate5ColorDeckTest {
@Test(timeOut = 1000, enabled = false)
public void generate5ColorDeckTest1() {
final Generate5ColorDeck gen = new Generate5ColorDeck();
final CardList cardList = gen.get5ColorDeck(60, null);
final ItemPoolView<CardPrinted> cardList = gen.get5ColorDeck(60, null);
Assert.assertNotNull(cardList);
}
}