mirror of
https://github.com/Card-Forge/forge.git
synced 2025-11-19 04:08:01 +00:00
deck generation moved to core
This commit is contained in:
138
forge-core/src/main/java/forge/deck/DeckGroup.java
Normal file
138
forge-core/src/main/java/forge/deck/DeckGroup.java
Normal file
@@ -0,0 +1,138 @@
|
||||
/*
|
||||
* Forge: Play Magic: the Gathering.
|
||||
* Copyright (C) 2011 Nate
|
||||
*
|
||||
* 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;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.Comparator;
|
||||
import java.util.List;
|
||||
|
||||
import com.google.common.base.Function;
|
||||
|
||||
/**
|
||||
* TODO: Write javadoc for this type.
|
||||
*
|
||||
*/
|
||||
public class DeckGroup extends DeckBase {
|
||||
|
||||
/**
|
||||
* Instantiates a new deck group.
|
||||
*
|
||||
* @param name0 the name0
|
||||
*/
|
||||
public DeckGroup(final String name0) {
|
||||
super(name0);
|
||||
}
|
||||
|
||||
private static final long serialVersionUID = -1628725522049635829L;
|
||||
private Deck humanDeck;
|
||||
private List<Deck> aiDecks = new ArrayList<Deck>();
|
||||
|
||||
/**
|
||||
* Gets the human deck.
|
||||
*
|
||||
* @return the human deck
|
||||
*/
|
||||
public final Deck getHumanDeck() {
|
||||
return this.humanDeck;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the ai decks.
|
||||
*
|
||||
* @return the ai decks
|
||||
*/
|
||||
public final List<Deck> getAiDecks() {
|
||||
return this.aiDecks;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the human deck.
|
||||
*
|
||||
* @param humanDeck the new human deck
|
||||
*/
|
||||
public final void setHumanDeck(final Deck humanDeck) {
|
||||
this.humanDeck = humanDeck;
|
||||
}
|
||||
|
||||
/**
|
||||
* Evaluate and 'rank' the ai decks.
|
||||
*
|
||||
*
|
||||
*/
|
||||
public final void rankAiDecks(Comparator<Deck> comparator) {
|
||||
if (this.aiDecks.size() < 2) {
|
||||
return;
|
||||
}
|
||||
Collections.sort(aiDecks, comparator);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void cloneFieldsTo(final DeckBase clone) {
|
||||
super.cloneFieldsTo(clone);
|
||||
|
||||
DeckGroup myClone = (DeckGroup) clone;
|
||||
myClone.setHumanDeck((Deck) this.getHumanDeck().copyTo(this.getHumanDeck().getName()));
|
||||
|
||||
for (int i = 0; i < this.getAiDecks().size(); i++) {
|
||||
Deck src = this.getAiDecks().get(i);
|
||||
myClone.addAiDeck((Deck) src.copyTo(src.getName()));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds the ai deck.
|
||||
*
|
||||
* @param aiDeck the ai deck
|
||||
*/
|
||||
public final void addAiDeck(final Deck aiDeck) {
|
||||
if (aiDeck == null) {
|
||||
return;
|
||||
}
|
||||
this.aiDecks.add(aiDeck);
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds the ai decks.
|
||||
*
|
||||
* @param computer the computer
|
||||
*/
|
||||
public void addAiDecks(final Deck[] computer) {
|
||||
for (final Deck element : computer) {
|
||||
this.aiDecks.add(element);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
*
|
||||
* @see forge.deck.DeckBase#newInstance(java.lang.String)
|
||||
*/
|
||||
@Override
|
||||
protected DeckBase newInstance(final String name0) {
|
||||
return new DeckGroup(name0);
|
||||
}
|
||||
|
||||
public static final Function<DeckGroup, String> FN_NAME_SELECTOR = new Function<DeckGroup, String>() {
|
||||
@Override
|
||||
public String apply(DeckGroup arg1) {
|
||||
return arg1.getName();
|
||||
}
|
||||
};
|
||||
|
||||
}
|
||||
286
forge-core/src/main/java/forge/deck/DeckRecognizer.java
Normal file
286
forge-core/src/main/java/forge/deck/DeckRecognizer.java
Normal file
@@ -0,0 +1,286 @@
|
||||
/*
|
||||
* 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;
|
||||
|
||||
import java.util.Calendar;
|
||||
import java.util.Date;
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
|
||||
import forge.card.CardDb;
|
||||
import forge.card.ICardDatabase;
|
||||
import forge.item.PaperCard;
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* DeckRecognizer class.
|
||||
* </p>
|
||||
*
|
||||
* @author Forge
|
||||
* @version $Id: DeckRecognizer.java 10499 2011-09-17 15:08:47Z Max mtg $
|
||||
*
|
||||
*/
|
||||
public class DeckRecognizer {
|
||||
|
||||
/**
|
||||
* The Enum TokenType.
|
||||
*/
|
||||
public enum TokenType {
|
||||
|
||||
/** The Known card. */
|
||||
KnownCard,
|
||||
|
||||
/** The Unknown card. */
|
||||
UnknownCard,
|
||||
|
||||
/** The Section name. */
|
||||
SectionName,
|
||||
|
||||
/** The Comment. */
|
||||
Comment,
|
||||
|
||||
/** The Unknown text. */
|
||||
UnknownText
|
||||
}
|
||||
|
||||
/**
|
||||
* The Class Token.
|
||||
*/
|
||||
public static class Token {
|
||||
private final TokenType type;
|
||||
private final PaperCard card;
|
||||
private final int number;
|
||||
private final String text;
|
||||
|
||||
/**
|
||||
* Known card.
|
||||
*
|
||||
* @param theCard
|
||||
* the the card
|
||||
* @param count
|
||||
* the count
|
||||
* @return the token
|
||||
*/
|
||||
public static Token knownCard(final PaperCard theCard, final int count) {
|
||||
return new Token(theCard, TokenType.KnownCard, count, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Unknown card.
|
||||
*
|
||||
* @param cardNme
|
||||
* the card nme
|
||||
* @param count
|
||||
* the count
|
||||
* @return the token
|
||||
*/
|
||||
public static Token unknownCard(final String cardNme, final int count) {
|
||||
return new Token(null, TokenType.UnknownCard, count, cardNme);
|
||||
}
|
||||
|
||||
private Token(final PaperCard knownCard, final TokenType type1, final int count, final String message) {
|
||||
this.card = knownCard;
|
||||
this.number = count;
|
||||
this.type = type1;
|
||||
this.text = message;
|
||||
}
|
||||
|
||||
/**
|
||||
* Instantiates a new token.
|
||||
*
|
||||
* @param type1
|
||||
* the type1
|
||||
* @param count
|
||||
* the count
|
||||
* @param message
|
||||
* the message
|
||||
*/
|
||||
public Token(final TokenType type1, final int count, final String message) {
|
||||
this(null, type1, count, message);
|
||||
if ((type1 == TokenType.KnownCard) || (type1 == TokenType.UnknownCard)) {
|
||||
throw new IllegalArgumentException("Use factory methods for recognized card lines");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the text.
|
||||
*
|
||||
* @return the text
|
||||
*/
|
||||
public final String getText() {
|
||||
return this.text;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the card.
|
||||
*
|
||||
* @return the card
|
||||
*/
|
||||
public final PaperCard getCard() {
|
||||
return this.card;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the type.
|
||||
*
|
||||
* @return the type
|
||||
*/
|
||||
public final TokenType getType() {
|
||||
return this.type;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the number.
|
||||
*
|
||||
* @return the number
|
||||
*/
|
||||
public final int getNumber() {
|
||||
return this.number;
|
||||
}
|
||||
}
|
||||
|
||||
// Let's think about it numbers in the back later
|
||||
// private static final Pattern searchNumbersInBack =
|
||||
// Pattern.compile("(.*)[^A-Za-wyz]*\\s+([\\d]{1,2})");
|
||||
private static final Pattern SEARCH_NUMBERS_IN_FRONT = Pattern.compile("([\\d]{1,2})[^A-Za-wyz]*\\s+(.*)");
|
||||
//private static final Pattern READ_SEPARATED_EDITION = Pattern.compile("[[\\(\\{]([a-zA-Z0-9]){1,3})[]*\\s+(.*)");
|
||||
|
||||
|
||||
private final boolean useLastSet;
|
||||
private final ICardDatabase db;
|
||||
private Date recognizeCardsPrintedBefore = null;
|
||||
|
||||
public DeckRecognizer(boolean fromLatestSet, CardDb db) {
|
||||
useLastSet = fromLatestSet;
|
||||
this.db = db;
|
||||
}
|
||||
|
||||
public Token recognizeLine(final String rawLine) {
|
||||
if (StringUtils.isBlank(rawLine)) {
|
||||
return new Token(TokenType.Comment, 0, rawLine);
|
||||
}
|
||||
final String line = rawLine.trim();
|
||||
|
||||
Token result = null;
|
||||
final Matcher foundNumbersInFront = DeckRecognizer.SEARCH_NUMBERS_IN_FRONT.matcher(line);
|
||||
// Matcher foundNumbersInBack = searchNumbersInBack.matcher(line);
|
||||
if (foundNumbersInFront.matches()) {
|
||||
final String cardName = foundNumbersInFront.group(2);
|
||||
final int amount = Integer.parseInt(foundNumbersInFront.group(1));
|
||||
result = recognizePossibleNameAndNumber(cardName, amount);
|
||||
} /*
|
||||
* else if (foundNumbersInBack.matches()) { String cardName =
|
||||
* foundNumbersInBack.group(1); int amount =
|
||||
* Integer.parseInt(foundNumbersInBack.group(2)); return new
|
||||
* Token(cardName, amount); }
|
||||
*/
|
||||
else {
|
||||
PaperCard pc = tryGetCard(line);
|
||||
if (null != pc) {
|
||||
return Token.knownCard(pc, 1);
|
||||
}
|
||||
result = DeckRecognizer.recognizeNonCard(line, 1);
|
||||
}
|
||||
return result != null ? result : new Token(TokenType.UnknownText, 0, line);
|
||||
}
|
||||
|
||||
private PaperCard tryGetCard(String text) {
|
||||
if(recognizeCardsPrintedBefore != null )
|
||||
return db.tryGetCardPrintedByDate(text, useLastSet, recognizeCardsPrintedBefore);
|
||||
return db.tryGetCard(text, useLastSet);
|
||||
}
|
||||
|
||||
private Token recognizePossibleNameAndNumber(final String name, final int n) {
|
||||
PaperCard pc = tryGetCard(name);
|
||||
if (null != pc) {
|
||||
return Token.knownCard(pc, n);
|
||||
}
|
||||
|
||||
// TODO: recognize format: http://topdeck.ru/forum/index.php?showtopic=12711
|
||||
//final Matcher foundEditionName = READ_SEPARATED_EDITION.matcher(name);
|
||||
|
||||
final Token known = DeckRecognizer.recognizeNonCard(name, n);
|
||||
return null == known ? Token.unknownCard(name, n) : known;
|
||||
}
|
||||
|
||||
private static Token recognizeNonCard(final String text, final int n) {
|
||||
if (DeckRecognizer.isDecoration(text)) {
|
||||
return new Token(TokenType.Comment, n, text);
|
||||
}
|
||||
if (DeckRecognizer.isSectionName(text)) {
|
||||
return new Token(TokenType.SectionName, n, text);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private static final String[] KNOWN_COMMENTS = new String[] { "land", "lands", "creatures", "creature", "spells",
|
||||
"enchancements", "other spells", "artifacts" };
|
||||
private static final String[] KNOWN_COMMENT_PARTS = new String[] { "card" };
|
||||
|
||||
private static boolean isDecoration(final String lineAsIs) {
|
||||
final String line = lineAsIs.toLowerCase();
|
||||
for (final String s : DeckRecognizer.KNOWN_COMMENT_PARTS) {
|
||||
if (line.contains(s)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
for (final String s : DeckRecognizer.KNOWN_COMMENTS) {
|
||||
if (line.equalsIgnoreCase(s)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private static boolean isSectionName(final String line) {
|
||||
if (line.toLowerCase().contains("side")) {
|
||||
return true;
|
||||
}
|
||||
if (line.toLowerCase().contains("main")) {
|
||||
return true;
|
||||
}
|
||||
if (line.toLowerCase().contains("commander")) {
|
||||
return true;
|
||||
}
|
||||
if (line.toLowerCase().contains("planes")) {
|
||||
return true;
|
||||
}
|
||||
if (line.toLowerCase().contains("schemes")) {
|
||||
return true;
|
||||
}
|
||||
if (line.toLowerCase().contains("vanguard")) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* TODO: Write javadoc for this method.
|
||||
* @param month
|
||||
* @param year
|
||||
*/
|
||||
public void setDateConstraint(int month, Integer year) {
|
||||
Calendar ca = Calendar.getInstance();
|
||||
ca.set(year, month, 1);
|
||||
recognizeCardsPrintedBefore = ca.getTime();
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,115 @@
|
||||
/*
|
||||
* 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.generation;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
||||
import org.apache.commons.lang3.tuple.ImmutablePair;
|
||||
import com.google.common.collect.Lists;
|
||||
|
||||
import forge.card.ColorSet;
|
||||
import forge.card.ICardDatabase;
|
||||
import forge.card.MagicColor;
|
||||
import forge.item.PaperCard;
|
||||
import forge.util.ItemPoolView;
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* Generate2ColorDeck class.
|
||||
* </p>
|
||||
*
|
||||
* @author Forge
|
||||
* @version $Id$
|
||||
*/
|
||||
public class DeckGenerator2Color extends DeckGeneratorBase {
|
||||
@Override protected final float getLandsPercentage() { return 0.39f; }
|
||||
@Override protected final float getCreatPercentage() { return 0.36f; }
|
||||
@Override protected final float getSpellPercentage() { return 0.25f; }
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
final List<ImmutablePair<FilterCMC, Integer>> cmcRelativeWeights = Lists.newArrayList(
|
||||
ImmutablePair.of(new FilterCMC(0, 2), 6),
|
||||
ImmutablePair.of(new FilterCMC(3, 4), 4),
|
||||
ImmutablePair.of(new FilterCMC(5, 6), 2),
|
||||
ImmutablePair.of(new FilterCMC(7, 20), 1)
|
||||
);
|
||||
|
||||
// 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>
|
||||
* Constructor for Generate2ColorDeck.
|
||||
* </p>
|
||||
*
|
||||
* @param clr1
|
||||
* a {@link java.lang.String} object.
|
||||
* @param clr2
|
||||
* a {@link java.lang.String} object.
|
||||
*/
|
||||
public DeckGenerator2Color(ICardDatabase cardDb, final String clr1, final String clr2) {
|
||||
super(cardDb);
|
||||
int c1 = MagicColor.fromName(clr1);
|
||||
int c2 = MagicColor.fromName(clr2);
|
||||
|
||||
if( c1 == 0 && c2 == 0) {
|
||||
int color1 = r.nextInt(5);
|
||||
int color2 = (color1 + 1 + r.nextInt(4)) % 5;
|
||||
colors = ColorSet.fromMask(MagicColor.WHITE << color1 | MagicColor.WHITE << color2);
|
||||
} else if ( c1 == 0 || c2 == 0 ) {
|
||||
byte knownColor = (byte) (c1 | c2);
|
||||
int color1 = Arrays.binarySearch(MagicColor.WUBRG, knownColor);
|
||||
int color2 = (color1 + 1 + r.nextInt(4)) % 5;
|
||||
colors = ColorSet.fromMask(MagicColor.WHITE << color1 | MagicColor.WHITE << color2);
|
||||
} else {
|
||||
colors = ColorSet.fromMask(c1 | c2);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public final ItemPoolView<PaperCard> getDeck(final int size, final boolean forAi) {
|
||||
addCreaturesAndSpells(size, cmcRelativeWeights, forAi);
|
||||
|
||||
// Add lands
|
||||
int numLands = Math.round(size * getLandsPercentage());
|
||||
adjustDeckSize(size - numLands);
|
||||
tmpDeck.append(String.format("Adjusted deck size to: %d, should add %d land(s)%n", size - numLands, numLands));
|
||||
|
||||
// Add dual lands
|
||||
List<String> duals = getDualLandList();
|
||||
for (String s : duals) {
|
||||
this.cardCounts.put(s, 0);
|
||||
}
|
||||
|
||||
int dblsAdded = addSomeStr((numLands / 6), duals);
|
||||
numLands -= dblsAdded;
|
||||
|
||||
addBasicLand(numLands);
|
||||
tmpDeck.append("DeckSize:").append(tDeck.countAll()).append("\n");
|
||||
|
||||
//System.out.println(tmpDeck.toString());
|
||||
|
||||
return tDeck;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,121 @@
|
||||
/*
|
||||
* 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.generation;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import org.apache.commons.lang3.tuple.ImmutablePair;
|
||||
|
||||
import com.google.common.collect.Lists;
|
||||
|
||||
import forge.card.ColorSet;
|
||||
import forge.card.ICardDatabase;
|
||||
import forge.card.MagicColor;
|
||||
import forge.item.PaperCard;
|
||||
import forge.util.ItemPoolView;
|
||||
import forge.util.MyRandom;
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* Generate3ColorDeck class.
|
||||
* </p>
|
||||
*
|
||||
* @author Forge
|
||||
* @version $Id$
|
||||
*/
|
||||
public class DeckGenerator3Color extends DeckGeneratorBase {
|
||||
@SuppressWarnings("unchecked")
|
||||
final List<ImmutablePair<FilterCMC, Integer>> cmcLevels = Lists.newArrayList(
|
||||
ImmutablePair.of(new FilterCMC(0, 2), 12),
|
||||
ImmutablePair.of(new FilterCMC(3, 5), 9),
|
||||
ImmutablePair.of(new FilterCMC(6, 20), 3)
|
||||
);
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* Constructor for Generate3ColorDeck.
|
||||
* </p>
|
||||
*
|
||||
* @param clr1
|
||||
* a {@link java.lang.String} object.
|
||||
* @param clr2
|
||||
* a {@link java.lang.String} object.
|
||||
* @param clr3
|
||||
* a {@link java.lang.String} object.
|
||||
*/
|
||||
public DeckGenerator3Color(ICardDatabase cardDb, final String clr1, final String clr2, final String clr3) {
|
||||
super(cardDb);
|
||||
int c1 = MagicColor.fromName(clr1);
|
||||
int c2 = MagicColor.fromName(clr2);
|
||||
int c3 = MagicColor.fromName(clr3);
|
||||
|
||||
int rc = 0;
|
||||
int combo = c1 | c2 | c3;
|
||||
|
||||
ColorSet param = ColorSet.fromMask(combo);
|
||||
switch(param.countColors()) {
|
||||
case 3:
|
||||
colors = param;
|
||||
return;
|
||||
|
||||
case 0:
|
||||
int color1 = r.nextInt(5);
|
||||
int color2 = (color1 + 1 + r.nextInt(4)) % 5;
|
||||
colors = ColorSet.fromMask(MagicColor.WHITE << color1 | MagicColor.WHITE << color2).inverse();
|
||||
return;
|
||||
|
||||
case 1:
|
||||
do {
|
||||
rc = MagicColor.WHITE << MyRandom.getRandom().nextInt(5);
|
||||
} while ( rc == combo );
|
||||
combo |= rc;
|
||||
// fall-through
|
||||
|
||||
case 2:
|
||||
do {
|
||||
rc = MagicColor.WHITE << MyRandom.getRandom().nextInt(5);
|
||||
} while ( (rc & combo) != 0 );
|
||||
combo |= rc;
|
||||
break;
|
||||
}
|
||||
colors = ColorSet.fromMask(combo);
|
||||
}
|
||||
|
||||
@Override
|
||||
public final ItemPoolView<PaperCard> getDeck(final int size, final boolean forAi) {
|
||||
addCreaturesAndSpells(size, cmcLevels, forAi);
|
||||
|
||||
// Add lands
|
||||
int numLands = Math.round(size * getLandsPercentage());
|
||||
adjustDeckSize(size - numLands);
|
||||
tmpDeck.append("numLands:").append(numLands).append("\n");
|
||||
|
||||
// Add dual lands
|
||||
List<String> duals = getDualLandList();
|
||||
for (String s : duals) {
|
||||
this.cardCounts.put(s, 0);
|
||||
}
|
||||
|
||||
int dblsAdded = addSomeStr((numLands / 4), duals);
|
||||
numLands -= dblsAdded;
|
||||
|
||||
addBasicLand(numLands);
|
||||
tmpDeck.append("DeckSize:").append(tDeck.countAll()).append("\n");
|
||||
return tDeck;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,84 @@
|
||||
/*
|
||||
* 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.generation;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import org.apache.commons.lang3.tuple.ImmutablePair;
|
||||
|
||||
import com.google.common.collect.Lists;
|
||||
|
||||
import forge.card.ColorSet;
|
||||
import forge.card.ICardDatabase;
|
||||
import forge.item.PaperCard;
|
||||
import forge.util.ItemPoolView;
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* Generate5ColorDeck class.
|
||||
* </p>
|
||||
*
|
||||
* @author Forge
|
||||
* @version $Id$
|
||||
*/
|
||||
public class DeckGenerator5Color extends DeckGeneratorBase {
|
||||
@SuppressWarnings("unchecked")
|
||||
final List<ImmutablePair<FilterCMC, Integer>> cmcLevels = Lists.newArrayList(
|
||||
ImmutablePair.of(new FilterCMC(0, 2), 3),
|
||||
ImmutablePair.of(new FilterCMC(3, 5), 2),
|
||||
ImmutablePair.of(new FilterCMC(6, 20), 1)
|
||||
);
|
||||
|
||||
// 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 DeckGenerator5Color(ICardDatabase cardDb) {
|
||||
super(cardDb);
|
||||
colors = ColorSet.fromMask(0).inverse();
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public final ItemPoolView<PaperCard> getDeck(final int size, final boolean forAi) {
|
||||
addCreaturesAndSpells(size, cmcLevels, forAi);
|
||||
|
||||
// Add lands
|
||||
int numLands = Math.round(size * getLandsPercentage());
|
||||
adjustDeckSize(size - numLands);
|
||||
tmpDeck.append("numLands:").append(numLands).append("\n");
|
||||
|
||||
// Add dual lands
|
||||
List<String> duals = getDualLandList();
|
||||
for (String s : duals) {
|
||||
this.cardCounts.put(s, 0);
|
||||
}
|
||||
|
||||
int dblsAdded = addSomeStr((numLands / 4), duals);
|
||||
numLands -= dblsAdded;
|
||||
|
||||
addBasicLand(numLands);
|
||||
tmpDeck.append("DeckSize:").append(tDeck.countAll()).append("\n");
|
||||
return tDeck;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,405 @@
|
||||
/*
|
||||
* 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.generation;
|
||||
|
||||
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 java.util.TreeMap;
|
||||
|
||||
import org.apache.commons.lang3.tuple.ImmutablePair;
|
||||
|
||||
import com.google.common.base.Predicate;
|
||||
import com.google.common.base.Predicates;
|
||||
import com.google.common.collect.Iterables;
|
||||
import com.google.common.collect.Lists;
|
||||
|
||||
import forge.card.CardRules;
|
||||
import forge.card.CardRulesPredicates;
|
||||
import forge.card.ColorSet;
|
||||
import forge.card.ICardDatabase;
|
||||
import forge.card.MagicColor;
|
||||
import forge.card.mana.ManaCost;
|
||||
import forge.item.PaperCard;
|
||||
import forge.util.Aggregates;
|
||||
import forge.util.ItemPool;
|
||||
import forge.util.ItemPoolView;
|
||||
import forge.util.MyRandom;
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* Generate2ColorDeck class.
|
||||
* </p>
|
||||
*
|
||||
* @author Forge
|
||||
* @version $Id: Generate2ColorDeck.java 14959 2012-03-28 14:03:43Z Chris H. $
|
||||
*/
|
||||
public abstract class DeckGeneratorBase {
|
||||
protected final Random r = MyRandom.getRandom();
|
||||
protected final Map<String, Integer> cardCounts = new HashMap<String, Integer>();
|
||||
protected int maxDuplicates = 4;
|
||||
protected boolean useArtifacts = true;
|
||||
|
||||
protected ColorSet colors;
|
||||
protected final ItemPool<PaperCard> tDeck = new ItemPool<PaperCard>(PaperCard.class);
|
||||
protected final ICardDatabase cardDb;
|
||||
|
||||
// 2-colored deck generator has its own constants. The rest works fine with these ones
|
||||
protected float getLandsPercentage() { return 0.44f; }
|
||||
protected float getCreatPercentage() { return 0.34f; }
|
||||
protected float getSpellPercentage() { return 0.22f; }
|
||||
|
||||
StringBuilder tmpDeck = new StringBuilder();
|
||||
|
||||
public DeckGeneratorBase(ICardDatabase cardDb) {
|
||||
this.cardDb = cardDb;
|
||||
}
|
||||
|
||||
public void setSingleton(boolean singleton){
|
||||
this.maxDuplicates = singleton ? 1 : 4;
|
||||
}
|
||||
public void setUseArtifacts(boolean value) {
|
||||
this.useArtifacts = value;
|
||||
}
|
||||
|
||||
protected void addCreaturesAndSpells(int size, List<ImmutablePair<FilterCMC, Integer>> cmcLevels, boolean forAi) {
|
||||
tmpDeck.append("Building deck of ").append(size).append("cards\n");
|
||||
|
||||
final Iterable<PaperCard> cards = selectCardsOfMatchingColorForPlayer(forAi);
|
||||
// build subsets based on type
|
||||
|
||||
final Iterable<PaperCard> creatures = Iterables.filter(cards, Predicates.compose(CardRulesPredicates.Presets.IS_CREATURE, PaperCard.FN_GET_RULES));
|
||||
final int creatCnt = (int) Math.ceil(getCreatPercentage() * size);
|
||||
tmpDeck.append("Creatures to add:").append(creatCnt).append("\n");
|
||||
addCmcAdjusted(creatures, creatCnt, cmcLevels);
|
||||
|
||||
Predicate<PaperCard> preSpells = Predicates.compose(CardRulesPredicates.Presets.IS_NONCREATURE_SPELL_FOR_GENERATOR, PaperCard.FN_GET_RULES);
|
||||
final Iterable<PaperCard> spells = Iterables.filter(cards, preSpells);
|
||||
final int spellCnt = (int) Math.ceil(getSpellPercentage() * size);
|
||||
tmpDeck.append("Spells to add:").append(spellCnt).append("\n");
|
||||
addCmcAdjusted(spells, spellCnt, cmcLevels);
|
||||
|
||||
tmpDeck.append(String.format("Current deck size: %d... should be %f%n", tDeck.countAll(), size * (getCreatPercentage() + getSpellPercentage())));
|
||||
}
|
||||
|
||||
public ItemPoolView<PaperCard> getDeck(final int size, final boolean forAi) {
|
||||
return null; // all but theme deck do override this method
|
||||
}
|
||||
|
||||
protected void addSome(int cnt, List<PaperCard> source) {
|
||||
for (int i = 0; i < cnt; i++) {
|
||||
PaperCard cp;
|
||||
int lc = 0;
|
||||
int srcLen = source.size();
|
||||
do {
|
||||
cp = source.get(this.r.nextInt(srcLen));
|
||||
lc++;
|
||||
} while (this.cardCounts.get(cp.getName()) > this.maxDuplicates - 1 && lc <= 100);
|
||||
|
||||
if (lc > 100) {
|
||||
throw new RuntimeException("Generate2ColorDeck : get2ColorDeck -- looped too much -- Cr12");
|
||||
}
|
||||
|
||||
tDeck.add(cp);
|
||||
final int n = this.cardCounts.get(cp.getName());
|
||||
this.cardCounts.put(cp.getName(), n + 1);
|
||||
if( n + 1 == this.maxDuplicates )
|
||||
source.remove(cp);
|
||||
tmpDeck.append(String.format("(%d) %s [%s]%n", cp.getRules().getManaCost().getCMC(), cp.getName(), cp.getRules().getManaCost()));
|
||||
}
|
||||
}
|
||||
|
||||
protected int addSomeStr(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) > 3) && (lc <= 20));
|
||||
// not an error if looped too much - could play singleton mode, with 6 slots for 3 non-basic lands.
|
||||
|
||||
tDeck.add(cardDb.getCard(s, false));
|
||||
|
||||
final int n = this.cardCounts.get(s);
|
||||
this.cardCounts.put(s, n + 1);
|
||||
tmpDeck.append(s + "\n");
|
||||
res++;
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
protected void addBasicLand(int cnt) {
|
||||
tmpDeck.append(cnt).append(" basic lands remain").append("\n");
|
||||
|
||||
// attempt to optimize basic land counts according to colors of picked cards
|
||||
final Map<String, Integer> clrCnts = countLands(tDeck);
|
||||
// total of all ClrCnts
|
||||
float totalColor = 0;
|
||||
for (Entry<String, Integer> c : clrCnts.entrySet()) {
|
||||
totalColor += c.getValue();
|
||||
tmpDeck.append(c.getKey()).append(":").append(c.getValue()).append("\n");
|
||||
}
|
||||
|
||||
tmpDeck.append("totalColor:").append(totalColor).append("\n");
|
||||
|
||||
int landsLeft = cnt;
|
||||
for (Entry<String, Integer> c : clrCnts.entrySet()) {
|
||||
String basicLandName = c.getKey();
|
||||
|
||||
|
||||
// calculate number of lands for each color
|
||||
final int nLand = Math.min(landsLeft, Math.round(cnt * c.getValue() / totalColor));
|
||||
tmpDeck.append("nLand-").append(basicLandName).append(":").append(nLand).append("\n");
|
||||
|
||||
// just to prevent a null exception by the deck size fixing code
|
||||
this.cardCounts.put(basicLandName, nLand);
|
||||
|
||||
PaperCard cp = cardDb.getCard(basicLandName);
|
||||
String basicLandSet = cp.getEdition();
|
||||
|
||||
tDeck.add(cardDb.getCard(cp.getName(), basicLandSet), nLand);
|
||||
landsLeft -= nLand;
|
||||
}
|
||||
}
|
||||
|
||||
protected void adjustDeckSize(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(diff, tDeck.toFlatList());
|
||||
} else if (actualSize > targetSize) {
|
||||
|
||||
Predicate<PaperCard> exceptBasicLand = Predicates.not(Predicates.compose(CardRulesPredicates.Presets.IS_BASIC_LAND, PaperCard.FN_GET_RULES));
|
||||
|
||||
for (int i = 0; i < 3 && actualSize > targetSize; i++) {
|
||||
Iterable<PaperCard> matchingCards = Iterables.filter(tDeck.toFlatList(), exceptBasicLand);
|
||||
List<PaperCard> toRemove = Aggregates.random(matchingCards, actualSize - targetSize);
|
||||
tDeck.removeAllFlat(toRemove);
|
||||
|
||||
for (PaperCard c : toRemove) {
|
||||
tmpDeck.append("Removed:").append(c.getName()).append("\n");
|
||||
}
|
||||
actualSize = tDeck.countAll();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected void addCmcAdjusted(Iterable<PaperCard> source, int cnt, List<ImmutablePair<FilterCMC, Integer>> cmcLevels) {
|
||||
int totalWeight = 0;
|
||||
for (ImmutablePair<FilterCMC, Integer> pair : cmcLevels) {
|
||||
totalWeight += pair.getRight();
|
||||
}
|
||||
|
||||
float variability = 0.6f; // if set to 1, you'll get minimum cards to choose from
|
||||
float desiredWeight = (float)cnt / ( maxDuplicates * variability );
|
||||
float desiredOverTotal = desiredWeight / totalWeight;
|
||||
float requestedOverTotal = (float)cnt / totalWeight;
|
||||
|
||||
for (ImmutablePair<FilterCMC, Integer> pair : cmcLevels) {
|
||||
Iterable<PaperCard> matchingCards = Iterables.filter(source, Predicates.compose(pair.getLeft(), PaperCard.FN_GET_RULES));
|
||||
int cmcCountForPool = (int) Math.ceil(pair.getRight().intValue() * desiredOverTotal);
|
||||
|
||||
int addOfThisCmc = Math.round(pair.getRight().intValue() * requestedOverTotal);
|
||||
tmpDeck.append(String.format("Adding %d cards for cmc range from a pool with %d cards:%n", addOfThisCmc, cmcCountForPool));
|
||||
|
||||
final List<PaperCard> curved = Aggregates.random(matchingCards, cmcCountForPool);
|
||||
final List<PaperCard> curvedRandomized = Lists.newArrayList();
|
||||
for (PaperCard c : curved) {
|
||||
this.cardCounts.put(c.getName(), 0);
|
||||
curvedRandomized.add(cardDb.getCard(c.getName(), false));
|
||||
}
|
||||
|
||||
addSome(addOfThisCmc, curvedRandomized);
|
||||
}
|
||||
}
|
||||
|
||||
protected Iterable<PaperCard> selectCardsOfMatchingColorForPlayer(boolean forAi) {
|
||||
|
||||
// start with all cards
|
||||
// remove cards that generated decks don't like
|
||||
Predicate<CardRules> canPlay = forAi ? AI_CAN_PLAY : HUMAN_CAN_PLAY;
|
||||
Predicate<CardRules> hasColor = new MatchColorIdentity(colors);
|
||||
|
||||
if (useArtifacts) {
|
||||
hasColor = Predicates.or(hasColor, COLORLESS_CARDS);
|
||||
}
|
||||
return Iterables.filter(cardDb.getAllCards(), Predicates.compose(Predicates.and(canPlay, hasColor), PaperCard.FN_GET_RULES));
|
||||
}
|
||||
|
||||
protected static Map<String, Integer> countLands(ItemPool<PaperCard> outList) {
|
||||
// attempt to optimize basic land counts according
|
||||
// to color representation
|
||||
|
||||
Map<String, Integer> res = new TreeMap<String, Integer>();
|
||||
// count each card color using mana costs
|
||||
// TODO: count hybrid mana differently?
|
||||
for (Entry<PaperCard, Integer> cpe : outList) {
|
||||
|
||||
int profile = cpe.getKey().getRules().getManaCost().getColorProfile();
|
||||
|
||||
if ((profile & MagicColor.WHITE) != 0) {
|
||||
increment(res, MagicColor.Constant.BASIC_LANDS.get(0), cpe.getValue());
|
||||
} else if ((profile & MagicColor.BLUE) != 0) {
|
||||
increment(res, MagicColor.Constant.BASIC_LANDS.get(1), cpe.getValue());
|
||||
} else if ((profile & MagicColor.BLACK) != 0) {
|
||||
increment(res, MagicColor.Constant.BASIC_LANDS.get(2), cpe.getValue());
|
||||
} else if ((profile & MagicColor.RED) != 0) {
|
||||
increment(res, MagicColor.Constant.BASIC_LANDS.get(3), cpe.getValue());
|
||||
} else if ((profile & MagicColor.GREEN) != 0) {
|
||||
increment(res, MagicColor.Constant.BASIC_LANDS.get(4), cpe.getValue());
|
||||
}
|
||||
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
protected static void increment(Map<String, Integer> map, String key, int delta)
|
||||
{
|
||||
final Integer boxed = map.get(key);
|
||||
map.put(key, boxed == null ? delta : boxed.intValue() + delta);
|
||||
}
|
||||
|
||||
public static final Predicate<CardRules> AI_CAN_PLAY = new Predicate<CardRules>() {
|
||||
@Override
|
||||
public boolean apply(CardRules c) {
|
||||
return !c.getAiHints().getRemAIDecks() && !c.getAiHints().getRemRandomDecks();
|
||||
}
|
||||
};
|
||||
|
||||
public static final Predicate<CardRules> HUMAN_CAN_PLAY = new Predicate<CardRules>() {
|
||||
@Override
|
||||
public boolean apply(CardRules c) {
|
||||
return !c.getAiHints().getRemRandomDecks();
|
||||
}
|
||||
};
|
||||
|
||||
public static final Predicate<CardRules> COLORLESS_CARDS = new Predicate<CardRules>() {
|
||||
@Override
|
||||
public boolean apply(CardRules c) {
|
||||
ManaCost mc = c.getManaCost();
|
||||
return c.getColorIdentity().isColorless() && !mc.isNoCost();
|
||||
}
|
||||
};
|
||||
|
||||
public static class MatchColorIdentity implements Predicate<CardRules> {
|
||||
private final ColorSet allowedColor;
|
||||
|
||||
public MatchColorIdentity(ColorSet color) {
|
||||
allowedColor = color;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean apply(CardRules subject) {
|
||||
ManaCost mc = subject.getManaCost();
|
||||
return !mc.isPureGeneric() && allowedColor.containsAllColorsFrom(subject.getColorIdentity().getColor());
|
||||
//return mc.canBePaidWithAvaliable(allowedColor);
|
||||
// return allowedColor.containsAllColorsFrom(mc.getColorProfile());
|
||||
}
|
||||
}
|
||||
|
||||
public static class FilterCMC implements Predicate<CardRules> {
|
||||
private final int min;
|
||||
private final int max;
|
||||
|
||||
public FilterCMC(int from, int to) {
|
||||
min = from;
|
||||
max = to;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean apply(CardRules c) {
|
||||
ManaCost mc = c.getManaCost();
|
||||
int cmc = mc.getCMC();
|
||||
return cmc >= min && cmc <= max && !mc.isNoCost();
|
||||
}
|
||||
}
|
||||
|
||||
private static Map<Integer, String[]> dualLands = new HashMap<Integer, String[]>();
|
||||
static {
|
||||
dualLands.put(MagicColor.WHITE | MagicColor.BLUE, new String[] { "Tundra", "Hallowed Fountain", "Flooded Strand" });
|
||||
dualLands.put(MagicColor.BLACK | MagicColor.BLUE, new String[] { "Underground Sea", "Watery Grave", "Polluted Delta" });
|
||||
dualLands.put(MagicColor.BLACK | MagicColor.RED, new String[] { "Badlands", "Blood Crypt", "Bloodstained Mire" });
|
||||
dualLands.put(MagicColor.GREEN | MagicColor.RED, new String[] { "Taiga", "Stomping Ground", "Wooded Foothills" });
|
||||
dualLands.put(MagicColor.GREEN | MagicColor.WHITE, new String[] { "Savannah", "Temple Garden", "Windswept Heath" });
|
||||
|
||||
dualLands.put(MagicColor.WHITE | MagicColor.BLACK, new String[] { "Scrubland", "Godless Shrine", "Marsh Flats" });
|
||||
dualLands.put(MagicColor.BLUE | MagicColor.RED, new String[] { "Volcanic Island", "Steam Vents", "Scalding Tarn" });
|
||||
dualLands.put(MagicColor.BLACK | MagicColor.GREEN, new String[] { "Bayou", "Overgrown Tomb", "Verdant Catacombs" });
|
||||
dualLands.put(MagicColor.WHITE | MagicColor.RED, new String[] { "Plateau", "Sacred Foundry", "Arid Mesa" });
|
||||
dualLands.put(MagicColor.GREEN | MagicColor.BLUE, new String[] { "Tropical Island", "Breeding Pool", "Misty Rainforest" });
|
||||
}
|
||||
|
||||
/**
|
||||
* Get list of dual lands for this color combo.
|
||||
*
|
||||
* @param color
|
||||
* the color
|
||||
* @return dual land names
|
||||
*/
|
||||
protected List<String> getDualLandList() {
|
||||
|
||||
final List<String> dLands = new ArrayList<String>();
|
||||
|
||||
if (colors.countColors() > 3) {
|
||||
dLands.add("Rupture Spire");
|
||||
dLands.add("Undiscovered Paradise");
|
||||
}
|
||||
|
||||
if (colors.countColors() > 2) {
|
||||
dLands.add("Evolving Wilds");
|
||||
dLands.add("Terramorphic Expanse");
|
||||
}
|
||||
for (Entry<Integer, String[]> dual : dualLands.entrySet()) {
|
||||
if (colors.hasAllColors(dual.getKey())) {
|
||||
for (String s : dual.getValue()) {
|
||||
dLands.add(s);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return dLands;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get all dual lands that do not match this color combo.
|
||||
*
|
||||
* @param color
|
||||
* the color
|
||||
* @return dual land names
|
||||
*/
|
||||
protected List<String> getInverseDualLandList() {
|
||||
|
||||
final List<String> dLands = new ArrayList<String>();
|
||||
|
||||
for (Entry<Integer, String[]> dual : dualLands.entrySet()) {
|
||||
if (!colors.hasAllColors(dual.getKey())) {
|
||||
for (String s : dual.getValue()) {
|
||||
dLands.add(s);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return dLands;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,98 @@
|
||||
/*
|
||||
* 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.generation;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import org.apache.commons.lang3.tuple.ImmutablePair;
|
||||
|
||||
import com.google.common.collect.Lists;
|
||||
|
||||
import forge.card.ColorSet;
|
||||
import forge.card.ICardDatabase;
|
||||
import forge.card.MagicColor;
|
||||
import forge.item.PaperCard;
|
||||
import forge.util.ItemPoolView;
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* Generate2ColorDeck class.
|
||||
* </p>
|
||||
*
|
||||
* @author Forge
|
||||
* @version $Id: Generate2ColorDeck.java 19765 2013-02-20 03:01:37Z myk $
|
||||
*/
|
||||
public class DeckGeneratorMonoColor extends DeckGeneratorBase {
|
||||
@Override protected final float getLandsPercentage() { return 0.39f; }
|
||||
@Override protected final float getCreatPercentage() { return 0.36f; }
|
||||
@Override protected final float getSpellPercentage() { return 0.25f; }
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
final List<ImmutablePair<FilterCMC, Integer>> cmcLevels = Lists.newArrayList(
|
||||
ImmutablePair.of(new FilterCMC(0, 2), 10),
|
||||
ImmutablePair.of(new FilterCMC(3, 4), 8),
|
||||
ImmutablePair.of(new FilterCMC(5, 6), 5),
|
||||
ImmutablePair.of(new FilterCMC(7, 20), 3)
|
||||
);
|
||||
|
||||
// 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>
|
||||
* Constructor for Generate2ColorDeck.
|
||||
* </p>
|
||||
*
|
||||
* @param clr1
|
||||
* a {@link java.lang.String} object.
|
||||
* @param clr2
|
||||
* a {@link java.lang.String} object.
|
||||
*/
|
||||
public DeckGeneratorMonoColor(ICardDatabase cardDb, final String clr1) {
|
||||
super(cardDb);
|
||||
if (MagicColor.fromName(clr1) == 0) {
|
||||
int color1 = r.nextInt(5);
|
||||
colors = ColorSet.fromMask(MagicColor.WHITE << color1);
|
||||
} else {
|
||||
colors = ColorSet.fromNames(clr1);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public final ItemPoolView<PaperCard> getDeck(final int size, final boolean forAi) {
|
||||
addCreaturesAndSpells(size, cmcLevels, forAi);
|
||||
|
||||
// Add lands
|
||||
int numLands = (int) (getLandsPercentage() * size);
|
||||
|
||||
tmpDeck.append("numLands:").append(numLands).append("\n");
|
||||
|
||||
addBasicLand(numLands);
|
||||
tmpDeck.append("DeckSize:").append(tDeck.countAll()).append("\n");
|
||||
|
||||
adjustDeckSize(size);
|
||||
tmpDeck.append("DeckSize:").append(tDeck.countAll()).append("\n");
|
||||
|
||||
return tDeck;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,3 @@
|
||||
/** Forge Card Game. */
|
||||
package forge.deck.generation;
|
||||
|
||||
Reference in New Issue
Block a user