Greatly simplified BoosterDraftAI to pick cards based on calculated card rating.

This commit is contained in:
Maxmtg
2012-12-23 22:45:49 +00:00
parent e7d108508a
commit c15f23f959
6 changed files with 82 additions and 280 deletions

View File

@@ -58,7 +58,7 @@ public final class ColorSet implements Comparable<ColorSet> {
}
public static ColorSet fromMask(final int mask) {
int mask32 = (mask & 0x3E) >> 1;
int mask32 = (mask & MagicColor.ALL_COLORS) >> 1;
if (allColors[mask32] == null) {
allColors[mask32] = new ColorSet((byte) mask);
}

View File

@@ -14,6 +14,8 @@ public class MagicColor {
public static final byte RED = 1 << 4;
public static final byte WHITE = 1 << 1;
public static final byte ALL_COLORS = BLACK | BLUE | WHITE | RED | GREEN;
public static final int NUMBER_OR_COLORS = 5;
public static byte fromName(String s) {

View File

@@ -115,13 +115,11 @@ public class AbilityManaPart implements java.io.Serializable {
for (final String c : produced.split(" ")) {
try {
int colorlessAmount = Integer.parseInt(c);
final String color = InputPayManaCostUtil.getLongColorString(c);
for (int i = 0; i < colorlessAmount; i++) {
this.lastProduced.add(new Mana(color, source, this));
this.lastProduced.add(new Mana(c, source, this));
}
} catch (NumberFormatException e) {
final String color = InputPayManaCostUtil.getLongColorString(c);
this.lastProduced.add(new Mana(color, source, this));
this.lastProduced.add(new Mana(c, source, this));
}
}

View File

@@ -19,23 +19,13 @@ package forge.game.limited;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Random;
import java.util.TreeMap;
import org.apache.commons.lang3.tuple.Pair;
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.Constant;
import forge.Constant.Preferences;
import forge.card.ColorSet;
import forge.card.CardRulesPredicates;
import forge.card.CardRules;
import forge.deck.Deck;
import forge.deck.generate.GenerateDeckUtil;
import forge.item.CardPrinted;
import forge.util.Aggregates;
/**
* <p>
@@ -79,141 +69,50 @@ public class BoosterDraftAI {
System.out.println("Player[" + player + "] pack: " + chooseFrom.toString());
}
CardPrinted pickedCard = null;
DeckColors deckCols = this.playerColors.get(player);
ColorSet currentChoice = deckCols.getChosenColors();
boolean canAddMoreColors = deckCols.canChoseMoreColors();
Predicate<CardPrinted> pred = Predicates.compose(CardRulesPredicates.IS_KEPT_IN_AI_DECKS, CardPrinted.FN_GET_RULES);
Iterable<CardPrinted> aiPlayablesView = Iterables.filter(chooseFrom, pred);
List<CardPrinted> aiPlayables = Lists.newArrayList(aiPlayablesView);
List<Pair<CardPrinted, Double>> rankedCards = rankCards(chooseFrom);
TreeMap<Double, CardPrinted> rankedCards = rankCards(chooseFrom);
for(Pair<CardPrinted, Double> p : rankedCards) {
// If a card is not ai playable, somewhat decreare its rating
if( p.getKey().getCard().getRemAIDecks() )
p.setValue(p.getValue() - TAKE_BEST_THRESHOLD);
if (this.playerColors.get(player).getColor1().equals("none")
&& this.playerColors.get(player).getColor2().equals("none")) {
// Generally the first pick of the draft, no colors selected yet.
// Sort playable cards by rank
TreeMap<Double, CardPrinted> rankedPlayableCards = rankCards(aiPlayables);
pickedCard = pickCard(rankedCards, rankedPlayableCards);
if (!pickedCard.getCard().getColor().isColorless() && aiPlayables.contains(pickedCard)) {
ColorSet color = pickedCard.getCard().getColor();
if (color.isMonoColor()) {
this.playerColors.get(player).setColor1(color.toString());
} else {
// Arbitrary ordering here...
if (color.hasWhite()) {
this.playerColors.get(player).setColor1(Constant.Color.WHITE);
}
if (color.hasBlue()) {
if (this.playerColors.get(player).getColor1().equals("none")) {
this.playerColors.get(player).setColor1(Constant.Color.BLUE);
} else {
this.playerColors.get(player).setColor2(Constant.Color.BLUE);
}
}
if (color.hasBlack()) {
if (this.playerColors.get(player).getColor1().equals("none")) {
this.playerColors.get(player).setColor1(Constant.Color.BLACK);
} else {
this.playerColors.get(player).setColor2(Constant.Color.BLACK);
}
}
if (color.hasRed()) {
if (this.playerColors.get(player).getColor1().equals("none")) {
this.playerColors.get(player).setColor1(Constant.Color.RED);
} else {
this.playerColors.get(player).setColor2(Constant.Color.RED);
}
}
if (color.hasGreen()) {
if (this.playerColors.get(player).getColor1().equals("none")) {
this.playerColors.get(player).setColor1(Constant.Color.GREEN);
} else {
this.playerColors.get(player).setColor2(Constant.Color.GREEN);
}
}
}
if (Preferences.DEV_MODE) {
System.out.println("Player[" + player + "] Color1: " + this.playerColors.get(player).getColor1());
if (!this.playerColors.get(player).getColor2().equals("none")) {
System.out.println("Player[" + player + "] Color2: "
+ this.playerColors.get(player).getColor2());
}
}
}
} else if (!this.playerColors.get(player).getColor1().equals("none")
&& this.playerColors.get(player).getColor2().equals("none")) {
// Has already picked one color, but not the second.
// Sort playable, on-color, or mono-colored, or colorless cards
TreeMap<Double, CardPrinted> rankedPlayableCards = new TreeMap<Double, CardPrinted>();
for (CardPrinted card : aiPlayables) {
ColorSet currentColor1 = ColorSet.fromNames(this.playerColors.get(player).getColor1());
ColorSet color = card.getCard().getColor();
if (color.isColorless() || color.sharesColorWith(currentColor1) || color.isMonoColor()) {
Double rkg = draftRankings.getRanking(card.getName(), card.getEdition());
if (rkg != null) {
rankedPlayableCards.put(rkg, card);
} else {
rankedPlayableCards.put(0.0, card);
}
}
}
pickedCard = pickCard(rankedCards, rankedPlayableCards);
ColorSet color = pickedCard.getCard().getColor();
if (!color.isColorless() && aiPlayables.contains(pickedCard)) {
ColorSet currentColor1 = ColorSet.fromNames(this.playerColors.get(player).getColor1());
if (color.isMonoColor()) {
if (!color.sharesColorWith(currentColor1)) {
this.playerColors.get(player).setColor2(color.toString());
}
} else {
// Arbitrary ordering...
if (color.hasWhite() && !currentColor1.isWhite()) {
this.playerColors.get(player).setColor2(Constant.Color.WHITE);
} else if (color.hasBlue() && !currentColor1.isBlue()) {
this.playerColors.get(player).setColor2(Constant.Color.BLUE);
} else if (color.hasBlack() && !currentColor1.isBlack()) {
this.playerColors.get(player).setColor2(Constant.Color.BLACK);
} else if (color.hasRed() && !currentColor1.isRed()) {
this.playerColors.get(player).setColor2(Constant.Color.RED);
} else if (color.hasGreen() && !currentColor1.isGreen()) {
this.playerColors.get(player).setColor2(Constant.Color.GREEN);
}
}
if (Preferences.DEV_MODE) {
System.out.println("Player[" + player + "] Color2: " + this.playerColors.get(player).getColor2());
}
}
} else {
// Has already picked both colors.
DeckColors dckColors = this.playerColors.get(player);
ColorSet colors = ColorSet.fromNames(dckColors.getColor1(), dckColors.getColor2());
Predicate<CardRules> hasColor = Predicates.or(new GenerateDeckUtil.CanBePaidWithColors(colors),
GenerateDeckUtil.COLORLESS_CARDS);
Iterable<CardPrinted> colorList = Iterables.filter(aiPlayables, Predicates.compose(hasColor, CardPrinted.FN_GET_RULES));
// Sort playable, on-color cards by rank
TreeMap<Double, CardPrinted> rankedPlayableCards = rankCards(colorList);
pickedCard = pickCard(rankedCards, rankedPlayableCards);
// if I cannot choose more colors, and the card cannot be played with chosen colors, decrease its rating.
if( !canAddMoreColors && !p.getKey().getCard().getManaCost().canBePaidWithAvaliable(currentChoice))
p.setValue(p.getValue() - 10);
}
if (pickedCard == null) {
final Random r = new Random();
pickedCard = chooseFrom.get(r.nextInt(chooseFrom.size()));
int cntBestCards = 0;
double bestRating = Double.NEGATIVE_INFINITY;
CardPrinted bestPick = null;
for(Pair<CardPrinted, Double> p : rankedCards) {
double rating = p.getValue();
if( rating > bestRating )
{
bestRating = rating;
bestPick = p.getKey();
cntBestCards = 1;
} else if ( rating == bestRating ) {
cntBestCards++;
}
}
if (pickedCard != null) {
chooseFrom.remove(pickedCard);
this.deck.get(player).add(pickedCard);
if (cntBestCards > 1) {
final List<CardPrinted> possiblePick = new ArrayList<CardPrinted>();
for(Pair<CardPrinted, Double> p : rankedCards) {
if ( p.getValue() == bestRating )
possiblePick.add(p.getKey());
}
bestPick = Aggregates.random(possiblePick);
}
return pickedCard;
if (canAddMoreColors)
deckCols.addColorsOf(bestPick);
return bestPick;
}
/**
@@ -225,69 +124,20 @@ public class BoosterDraftAI {
* List of cards
* @return map of rankings
*/
private TreeMap<Double, CardPrinted> rankCards(final Iterable<CardPrinted> chooseFrom) {
TreeMap<Double, CardPrinted> rankedCards = new TreeMap<Double, CardPrinted>();
private List<Pair<CardPrinted, Double>> rankCards(final Iterable<CardPrinted> chooseFrom) {
List<Pair<CardPrinted, Double>> rankedCards = new ArrayList<Pair<CardPrinted,Double>>();
for (CardPrinted card : chooseFrom) {
Double rkg = draftRankings.getRanking(card.getName(), card.getEdition());
if (rkg != null) {
rankedCards.put(rkg, card);
rankedCards.add(Pair.of(card, rkg));
} else {
System.out.println("Draft Rankings - Card Not Found: " + card.getName());
rankedCards.put(0.0, card);
rankedCards.add(Pair.of(card, 0.0));
}
}
return rankedCards;
}
/**
* Pick a card.
*
* @param rankedCards
* @param rankedPlayableCards
* @return CardPrinted
*/
private CardPrinted pickCard(TreeMap<Double, CardPrinted> rankedCards,
TreeMap<Double, CardPrinted> rankedPlayableCards) {
CardPrinted pickedCard = null;
Map.Entry<Double, CardPrinted> best = rankedCards.firstEntry();
if (best != null) {
if (rankedPlayableCards.containsValue(best.getValue())) {
// If best card is playable, pick it.
pickedCard = best.getValue();
System.out.println("Choose Best: " + "[" + best.getKey() + "] " + pickedCard.getName() + " ("
+ pickedCard.getCard().getManaCost() + ") " + pickedCard.getCard().getType().toString());
} else {
// If not, find the best card that is playable.
Map.Entry<Double, CardPrinted> bestPlayable = rankedPlayableCards.firstEntry();
if (bestPlayable == null) {
// Nothing is playable, so just take the best card.
pickedCard = best.getValue();
System.out.println("Nothing playable, choose Best: " + "[" + best.getKey() + "] "
+ pickedCard.getName() + " (" + pickedCard.getCard().getManaCost() + ") "
+ pickedCard.getCard().getType().toString());
} else {
// If the best card is far better than the best playable,
// take the best. Otherwise, take the one that is playable.
if (best.getKey() + TAKE_BEST_THRESHOLD < bestPlayable.getKey()) {
pickedCard = best.getValue();
System.out.println("Best is much better than playable; chose Best: " + "[" + best.getKey()
+ "] " + pickedCard.getName() + " (" + pickedCard.getCard().getManaCost() + ") "
+ pickedCard.getCard().getType().toString());
System.out.println("Playable was: " + "[" + bestPlayable.getKey() + "] "
+ bestPlayable.getValue().getName());
} else {
pickedCard = bestPlayable.getValue();
System.out.println("Chosen Playable: " + "[" + bestPlayable.getKey() + "] "
+ pickedCard.getName() + " (" + pickedCard.getCard().getManaCost() + ") "
+ pickedCard.getCard().getType().toString());
System.out.println("Best was: " + "[" + best.getKey() + "] " + best.getValue().getName());
}
}
}
}
return pickedCard;
}
/**
* <p>
* getDecks.

View File

@@ -17,7 +17,10 @@
*/
package forge.game.limited;
import forge.card.CardManaCost;
import forge.card.ColorSet;
import forge.card.MagicColor;
import forge.item.CardPrinted;
/**
* Created by IntelliJ IDEA. User: dhudson Date: 6/24/11 Time: 8:42 PM To change
@@ -25,96 +28,45 @@ import forge.card.ColorSet;
*/
class DeckColors {
/** The Color1. */
private String color1 = "none";
/** The Color2. */
private String color2 = "none";
private ColorSet chosen;
private int colorMask;
public final static int MAX_COLORS = 2;
// public String Splash = "none";
/**
* <p>
* Constructor for deckColors.
* </p>
*
* @param c1
* a {@link java.lang.String} object.
* @param c2
* a {@link java.lang.String} object.
* @param sp
* a {@link java.lang.String} object.
*/
public DeckColors(final String c1, final String c2, final String sp) {
this.setColor1(c1);
this.setColor2(c2);
// Splash = sp;
public ColorSet getChosenColors() {
if ( null == chosen )
chosen = ColorSet.fromMask(colorMask);
return chosen;
}
/**
* <p>
* Constructor for DeckColors.
* </p>
* TODO: Write javadoc for this method.
* @param pickedCard
*/
public DeckColors() {
public void addColorsOf(CardPrinted pickedCard) {
CardManaCost colorsInCard = pickedCard.getCard().getManaCost();
int colorsCanAdd = MagicColor.ALL_COLORS & ~getChosenColors().getColor();
int colorsWantAdd = colorsInCard.getColorProfile() & colorsCanAdd;
ColorSet toAdd = ColorSet.fromMask(colorsWantAdd);
int cntColorsAssigned = getChosenColors().countColors();
boolean haveSpace = cntColorsAssigned < MAX_COLORS;
if( !haveSpace || toAdd.isColorless() )
return;
for(int i = 0; i < MagicColor.NUMBER_OR_COLORS && cntColorsAssigned < MAX_COLORS; i++ )
if (( colorsWantAdd & MagicColor.WHITE << i ) > 0) {
colorMask |= MagicColor.WHITE << i;
chosen = null; // invalidate color set
cntColorsAssigned++;
}
}
/**
* Gets the color1.
*
* @return the color1
*/
public String getColor1() {
return this.color1;
}
/**
* Sets the color1.
*
* @param color1in
* the color1 to set
*/
public void setColor1(final String color1in) {
this.color1 = color1in;
}
/**
* Gets the color2.
*
* @return the color2
*/
public String getColor2() {
return this.color2;
}
/**
* Sets the color2.
*
* @param color2in
* the color2 to set
*/
public void setColor2(final String color2in) {
this.color2 = color2in;
}
/**
* Convert this to CardColor.
*
* @return equivalent CardColor
*/
public ColorSet getCardColors() {
return ColorSet.fromNames(color1, color2);
}
/**
* toString.
*
* @return description.
*/
@Override
public String toString() {
return color1 + '/' + color2;
public boolean canChoseMoreColors() {
return getChosenColors().countColors() < MAX_COLORS;
}
}

View File

@@ -66,7 +66,7 @@ public class LimitedDeck {
public LimitedDeck(List<CardPrinted> dList, DeckColors pClrs) {
this.availableList = dList;
this.deckColors = pClrs;
this.colors = pClrs.getCardColors();
this.colors = pClrs.getChosenColors();
// removeUnplayables();
Iterable<CardPrinted> playables = Iterables.filter(availableList,