LandEvaluator for AI

This commit is contained in:
Anthony Calosa
2023-02-21 21:21:39 +08:00
committed by tool4ever
parent b38a6edbbb
commit c02447ece2
2 changed files with 236 additions and 209 deletions

View File

@@ -108,6 +108,7 @@ public class AiController {
public boolean usesSimulation() { public boolean usesSimulation() {
return this.useSimulation; return this.useSimulation;
} }
public void setUseSimulation(boolean value) { public void setUseSimulation(boolean value) {
this.useSimulation = value; this.useSimulation = value;
} }
@@ -217,6 +218,7 @@ public class AiController {
card.setCastSA(null); card.setCastSA(null);
return result; return result;
} }
private boolean checkETBEffectsPreparedCard(final Card card, final SpellAbility sa, final ApiType api) { private boolean checkETBEffectsPreparedCard(final Card card, final SpellAbility sa, final ApiType api) {
final Player activator = sa.getActivatingPlayer(); final Player activator = sa.getActivatingPlayer();
@@ -476,6 +478,8 @@ public class AiController {
// If nothing is done here, proceeds to the default land picking strategy // If nothing is done here, proceeds to the default land picking strategy
} }
return ComputerUtilCard.getBestLandToPlayAI(landList);
/*
//Skip reflected lands. //Skip reflected lands.
CardCollection unreflectedLands = new CardCollection(landList); CardCollection unreflectedLands = new CardCollection(landList);
for (Card l : landList) { for (Card l : landList) {
@@ -574,7 +578,7 @@ public class AiController {
landList = CardLists.filter(landList, Predicates.not(CardPredicates.Presets.BASIC_LANDS)); landList = CardLists.filter(landList, Predicates.not(CardPredicates.Presets.BASIC_LANDS));
} }
} }
return landList.get(0); return landList.get(0);*/
} }
// if return true, go to next phase // if return true, go to next phase
@@ -617,6 +621,7 @@ public class AiController {
public SpellAbility predictSpellToCastInMain2(ApiType exceptSA) { public SpellAbility predictSpellToCastInMain2(ApiType exceptSA) {
return predictSpellToCastInMain2(exceptSA, true); return predictSpellToCastInMain2(exceptSA, true);
} }
private SpellAbility predictSpellToCastInMain2(ApiType exceptSA, boolean handOnly) { private SpellAbility predictSpellToCastInMain2(ApiType exceptSA, boolean handOnly) {
if (!getBooleanProperty(AiProps.PREDICT_SPELLS_FOR_MAIN2)) { if (!getBooleanProperty(AiProps.PREDICT_SPELLS_FOR_MAIN2)) {
return null; return null;
@@ -629,8 +634,7 @@ public class AiController {
try { try {
Collections.sort(all, saComparator); // put best spells first Collections.sort(all, saComparator); // put best spells first
} } catch (IllegalArgumentException ex) {
catch (IllegalArgumentException ex) {
System.err.println(ex.getMessage()); System.err.println(ex.getMessage());
String assertex = ComparatorUtil.verifyTransitivity(saComparator, all); String assertex = ComparatorUtil.verifyTransitivity(saComparator, all);
Sentry.captureMessage(ex.getMessage() + "\nAssertionError [verifyTransitivity]: " + assertex); Sentry.captureMessage(ex.getMessage() + "\nAssertionError [verifyTransitivity]: " + assertex);
@@ -657,12 +661,15 @@ public class AiController {
public boolean reserveManaSourcesForNextSpell(SpellAbility sa, SpellAbility exceptForSa) { public boolean reserveManaSourcesForNextSpell(SpellAbility sa, SpellAbility exceptForSa) {
return reserveManaSources(sa, null, false, true, exceptForSa); return reserveManaSources(sa, null, false, true, exceptForSa);
} }
public boolean reserveManaSources(SpellAbility sa) { public boolean reserveManaSources(SpellAbility sa) {
return reserveManaSources(sa, PhaseType.MAIN2, false, false, null); return reserveManaSources(sa, PhaseType.MAIN2, false, false, null);
} }
public boolean reserveManaSources(SpellAbility sa, PhaseType phaseType, boolean enemy) { public boolean reserveManaSources(SpellAbility sa, PhaseType phaseType, boolean enemy) {
return reserveManaSources(sa, phaseType, enemy, true, null); return reserveManaSources(sa, phaseType, enemy, true, null);
} }
public boolean reserveManaSources(SpellAbility sa, PhaseType phaseType, boolean enemy, boolean forNextSpell, SpellAbility exceptForThisSa) { public boolean reserveManaSources(SpellAbility sa, PhaseType phaseType, boolean enemy, boolean forNextSpell, SpellAbility exceptForThisSa) {
ManaCostBeingPaid cost = ComputerUtilMana.calculateManaCost(sa, true, 0); ManaCostBeingPaid cost = ComputerUtilMana.calculateManaCost(sa, true, 0);
CardCollection manaSources = ComputerUtilMana.getManaSourcesToPayCost(cost, sa, player); CardCollection manaSources = ComputerUtilMana.getManaSourcesToPayCost(cost, sa, player);
@@ -784,8 +791,9 @@ public class AiController {
return AiPlayDecision.CantAfford; return AiPlayDecision.CantAfford;
} }
} }
SpellAbilityAi topAI = new SpellAbilityAi() {}; SpellAbilityAi topAI = new SpellAbilityAi() {
if (!topAI.willPayCosts(player, sa , wardCost, host)) { };
if (!topAI.willPayCosts(player, sa, wardCost, host)) {
return AiPlayDecision.CostNotAcceptable; return AiPlayDecision.CostNotAcceptable;
} }
} }
@@ -899,7 +907,7 @@ public class AiController {
return AiPlayDecision.AnotherTime; return AiPlayDecision.AnotherTime;
} }
if (sa instanceof SpellPermanent) { if (sa instanceof SpellPermanent) {
return canPlayFromEffectAI((SpellPermanent)sa, false, true); return canPlayFromEffectAI((SpellPermanent) sa, false, true);
} }
if (sa.usesTargeting()) { if (sa.usesTargeting()) {
if (!sa.isTargetNumberValid() && sa.getTargetRestrictions().getNumCandidates(sa, true) == 0) { if (!sa.isTargetNumberValid() && sa.getTargetRestrictions().getNumCandidates(sa, true) == 0) {
@@ -1142,6 +1150,7 @@ public class AiController {
public CardCollection getCardsToDiscard(final int numDiscard, final String[] uTypes, final SpellAbility sa) { public CardCollection getCardsToDiscard(final int numDiscard, final String[] uTypes, final SpellAbility sa) {
return getCardsToDiscard(numDiscard, uTypes, sa, CardCollection.EMPTY); return getCardsToDiscard(numDiscard, uTypes, sa, CardCollection.EMPTY);
} }
public CardCollection getCardsToDiscard(final int numDiscard, final String[] uTypes, final SpellAbility sa, final CardCollectionView exclude) { public CardCollection getCardsToDiscard(final int numDiscard, final String[] uTypes, final SpellAbility sa, final CardCollectionView exclude) {
boolean noFiltering = sa != null && "DiscardCMCX".equals(sa.getParam("AILogic")); // list AI logic for which filtering is taken care of elsewhere boolean noFiltering = sa != null && "DiscardCMCX".equals(sa.getParam("AILogic")); // list AI logic for which filtering is taken care of elsewhere
CardCollection hand = new CardCollection(player.getCardsIn(ZoneType.Hand)); CardCollection hand = new CardCollection(player.getCardsIn(ZoneType.Hand));
@@ -1193,7 +1202,9 @@ public class AiController {
} }
} }
for (Card c : inHand) { for (Card c : inHand) {
if (c.hasSVar("DoNotDiscardIfAble") || c.hasSVar("IsReanimatorCard")) { continue; } if (c.hasSVar("DoNotDiscardIfAble") || c.hasSVar("IsReanimatorCard")) {
continue;
}
if (c.isCreature() && !ComputerUtilMana.hasEnoughManaSourcesToCast(c.getSpellPermanent(), player)) { if (c.isCreature() && !ComputerUtilMana.hasEnoughManaSourcesToCast(c.getSpellPermanent(), player)) {
discards.add(c); discards.add(c);
} }
@@ -1232,8 +1243,7 @@ public class AiController {
discardList.add(prefCard); discardList.add(prefCard);
validCards.remove(prefCard); validCards.remove(prefCard);
count++; count++;
} } else {
else {
break; break;
} }
} }
@@ -1256,8 +1266,7 @@ public class AiController {
if (canDiscardLands) { if (canDiscardLands) {
discardList.add(landsInHand.get(0)); discardList.add(landsInHand.get(0));
validCards.remove(landsInHand.get(0)); validCards.remove(landsInHand.get(0));
} } else { // Discard other stuff
else { // Discard other stuff
CardLists.sortByCmcDesc(validCards); CardLists.sortByCmcDesc(validCards);
int numLandsAvailable = numLandsInPlay; int numLandsAvailable = numLandsInPlay;
if (numLandsInHand > 0) { if (numLandsInHand > 0) {
@@ -1448,7 +1457,9 @@ public class AiController {
} }
private List<SpellAbility> singleSpellAbilityList(SpellAbility sa) { private List<SpellAbility> singleSpellAbilityList(SpellAbility sa) {
if (sa == null) { return null; } if (sa == null) {
return null;
}
final List<SpellAbility> abilities = Lists.newArrayList(); final List<SpellAbility> abilities = Lists.newArrayList();
abilities.add(sa); abilities.add(sa);
@@ -1705,8 +1716,7 @@ public class AiController {
try { try {
Collections.sort(all, saComparator); // put best spells first Collections.sort(all, saComparator); // put best spells first
} } catch (IllegalArgumentException ex) {
catch (IllegalArgumentException ex) {
System.err.println(ex.getMessage()); System.err.println(ex.getMessage());
String assertex = ComparatorUtil.verifyTransitivity(saComparator, all); String assertex = ComparatorUtil.verifyTransitivity(saComparator, all);
Sentry.captureMessage(ex.getMessage() + "\nAssertionError [verifyTransitivity]: " + assertex); Sentry.captureMessage(ex.getMessage() + "\nAssertionError [verifyTransitivity]: " + assertex);
@@ -1783,7 +1793,7 @@ public class AiController {
public boolean doTrigger(SpellAbility spell, boolean mandatory) { public boolean doTrigger(SpellAbility spell, boolean mandatory) {
if (spell instanceof WrappedAbility) if (spell instanceof WrappedAbility)
return doTrigger(((WrappedAbility)spell).getWrappedAbility(), mandatory); return doTrigger(((WrappedAbility) spell).getWrappedAbility(), mandatory);
if (spell.getApi() != null) if (spell.getApi() != null)
return SpellApiToAi.Converter.get(spell.getApi()).doTriggerAI(player, spell, mandatory); return SpellApiToAi.Converter.get(spell.getApi()).doTriggerAI(player, spell, mandatory);
if (spell.getPayCosts() == Cost.Zero && !spell.usesTargeting()) { if (spell.getPayCosts() == Cost.Zero && !spell.usesTargeting()) {
@@ -1929,7 +1939,7 @@ public class AiController {
} else if ("LowestLoseLife".equals(logic)) { } else if ("LowestLoseLife".equals(logic)) {
return MyRandom.getRandom().nextInt(Math.min(player.getLife() / 3, player.getWeakestOpponent().getLife())) + 1; return MyRandom.getRandom().nextInt(Math.min(player.getLife() / 3, player.getWeakestOpponent().getLife())) + 1;
} else if ("HighestLoseLife".equals(logic)) { } else if ("HighestLoseLife".equals(logic)) {
return Math.min(player.getLife() -1,MyRandom.getRandom().nextInt(Math.max(player.getLife() / 3, player.getWeakestOpponent().getLife())) + 1); return Math.min(player.getLife() - 1, MyRandom.getRandom().nextInt(Math.max(player.getLife() / 3, player.getWeakestOpponent().getLife())) + 1);
} else if ("HighestGetCounter".equals(logic)) { } else if ("HighestGetCounter".equals(logic)) {
return MyRandom.getRandom().nextInt(3); return MyRandom.getRandom().nextInt(3);
} else if (sa.hasSVar("EnergyToPay")) { } else if (sa.hasSVar("EnergyToPay")) {
@@ -1949,8 +1959,7 @@ public class AiController {
} }
public int chooseNumber(SpellAbility sa, String title, List<Integer> options, Player relatedPlayer) { public int chooseNumber(SpellAbility sa, String title, List<Integer> options, Player relatedPlayer) {
switch(sa.getApi()) switch (sa.getApi()) {
{
case SetLife: // Reverse the Sands case SetLife: // Reverse the Sands
if (relatedPlayer.equals(sa.getHostCard().getController())) { if (relatedPlayer.equals(sa.getHostCard().getController())) {
return Collections.max(options); return Collections.max(options);
@@ -2082,8 +2091,7 @@ public class AiController {
* smoothComputerManaCurve. * smoothComputerManaCurve.
* </p> * </p>
* *
* @param in * @param in an array of {@link forge.game.card.Card} objects.
* an array of {@link forge.game.card.Card} objects.
* @return an array of {@link forge.game.card.Card} objects. * @return an array of {@link forge.game.card.Card} objects.
*/ */
public CardCollectionView cheatShuffle(CardCollectionView in) { public CardCollectionView cheatShuffle(CardCollectionView in) {

View File

@@ -9,6 +9,8 @@ import java.util.Map;
import java.util.Map.Entry; import java.util.Map.Entry;
import java.util.Set; import java.util.Set;
import com.google.common.base.Function;
import forge.ai.simulation.GameStateEvaluator;
import forge.card.mana.ManaCost; import forge.card.mana.ManaCost;
import org.apache.commons.lang3.StringUtils; import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.tuple.MutablePair; import org.apache.commons.lang3.tuple.MutablePair;
@@ -92,6 +94,7 @@ public class ComputerUtilCard {
} }
// The AI doesn't really pick the best artifact, just the most expensive. // The AI doesn't really pick the best artifact, just the most expensive.
/** /**
* <p> * <p>
* getBestArtifactAI. * getBestArtifactAI.
@@ -111,6 +114,7 @@ public class ComputerUtilCard {
/** /**
* Returns the best Planeswalker from a given list * Returns the best Planeswalker from a given list
*
* @param list list of cards to evaluate * @param list list of cards to evaluate
* @return best Planeswalker * @return best Planeswalker
*/ */
@@ -125,6 +129,7 @@ public class ComputerUtilCard {
/** /**
* Returns the worst Planeswalker from a given list * Returns the worst Planeswalker from a given list
*
* @param list list of cards to evaluate * @param list list of cards to evaluate
* @return best Planeswalker * @return best Planeswalker
*/ */
@@ -188,16 +193,15 @@ public class ComputerUtilCard {
} }
// The AI doesn't really pick the best enchantment, just the most expensive. // The AI doesn't really pick the best enchantment, just the most expensive.
/** /**
* <p> * <p>
* getBestEnchantmentAI. * getBestEnchantmentAI.
* </p> * </p>
* *
* @param list * @param list
* @param spell * @param spell a {@link forge.game.card.Card} object.
* a {@link forge.game.card.Card} object. * @param targeted a boolean.
* @param targeted
* a boolean.
* @return a {@link forge.game.card.Card} object. * @return a {@link forge.game.card.Card} object.
*/ */
public static Card getBestEnchantmentAI(final List<Card> list, final SpellAbility spell, final boolean targeted) { public static Card getBestEnchantmentAI(final List<Card> list, final SpellAbility spell, final boolean targeted) {
@@ -326,10 +330,8 @@ public class ComputerUtilCard {
* </p> * </p>
* *
* @param all * @param all
* @param spell * @param spell a {@link forge.game.card.Card} object.
* a {@link forge.game.card.Card} object. * @param targeted a boolean.
* @param targeted
* a boolean.
* @return a {@link forge.game.card.Card} object. * @return a {@link forge.game.card.Card} object.
*/ */
public static Card getCheapestPermanentAI(Iterable<Card> all, final SpellAbility spell, final boolean targeted) { public static Card getCheapestPermanentAI(Iterable<Card> all, final SpellAbility spell, final boolean targeted) {
@@ -358,6 +360,7 @@ public class ComputerUtilCard {
} }
// returns null if list.size() == 0 // returns null if list.size() == 0
/** /**
* <p> * <p>
* getBestAI. * getBestAI.
@@ -381,8 +384,7 @@ public class ComputerUtilCard {
/** /**
* getBestCreatureAI. * getBestCreatureAI.
* *
* @param list * @param list the list
* the list
* @return the card * @return the card
*/ */
public static Card getBestCreatureAI(final Iterable<Card> list) { public static Card getBestCreatureAI(final Iterable<Card> list) {
@@ -392,6 +394,19 @@ public class ComputerUtilCard {
return Aggregates.itemWithMax(Iterables.filter(list, CardPredicates.Presets.CREATURES), ComputerUtilCard.creatureEvaluator); return Aggregates.itemWithMax(Iterables.filter(list, CardPredicates.Presets.CREATURES), ComputerUtilCard.creatureEvaluator);
} }
/**
* getBestLandToPlayAI.
*
* @param list the list
* @return the card
*/
public static Card getBestLandToPlayAI(final Iterable<Card> list) {
if (Iterables.size(list) == 1) {
return Iterables.get(list, 0);
}
return Aggregates.itemWithMax(Iterables.filter(list, CardPredicates.Presets.LANDS), ComputerUtilCard.landEvaluator);
}
/** /**
* <p> * <p>
* getWorstCreatureAI. * getWorstCreatureAI.
@@ -408,6 +423,7 @@ public class ComputerUtilCard {
} }
// This selection rates tokens higher // This selection rates tokens higher
/** /**
* <p> * <p>
* getBestCreatureToBounceAI. * getBestCreatureToBounceAI.
@@ -438,7 +454,7 @@ public class ComputerUtilCard {
// For ability of Oracle en-Vec, return the first card that are going to attack next turn // For ability of Oracle en-Vec, return the first card that are going to attack next turn
public static Card getBestCreatureToAttackNextTurnAI(final Player aiPlayer, final Iterable<Card> list) { public static Card getBestCreatureToAttackNextTurnAI(final Player aiPlayer, final Iterable<Card> list) {
AiController aic = ((PlayerControllerAi)aiPlayer.getController()).getAi(); AiController aic = ((PlayerControllerAi) aiPlayer.getController()).getAi();
for (final Card card : list) { for (final Card card : list) {
if (aic.getPredictedCombatNextTurn().isAttacking(card)) { if (aic.getPredictedCombatNextTurn().isAttacking(card)) {
return card; return card;
@@ -465,14 +481,10 @@ public class ComputerUtilCard {
* </p> * </p>
* *
* @param list * @param list
* @param biasEnch * @param biasEnch a boolean.
* a boolean. * @param biasLand a boolean.
* @param biasLand * @param biasArt a boolean.
* a boolean. * @param biasCreature a boolean.
* @param biasArt
* a boolean.
* @param biasCreature
* a boolean.
* @return a {@link forge.game.card.Card} object. * @return a {@link forge.game.card.Card} object.
*/ */
public static Card getWorstPermanentAI(final Iterable<Card> list, final boolean biasEnch, final boolean biasLand, public static Card getWorstPermanentAI(final Iterable<Card> list, final boolean biasEnch, final boolean biasLand,
@@ -557,14 +569,14 @@ public class ComputerUtilCard {
}; };
private static final CreatureEvaluator creatureEvaluator = new CreatureEvaluator(); private static final CreatureEvaluator creatureEvaluator = new CreatureEvaluator();
private static final LandEvaluator landEvaluator = new LandEvaluator();
/** /**
* <p> * <p>
* evaluateCreature. * evaluateCreature.
* </p> * </p>
* *
* @param c * @param c a {@link forge.game.card.Card} object.
* a {@link forge.game.card.Card} object.
* @return a int. * @return a int.
*/ */
public static int evaluateCreature(final Card c) { public static int evaluateCreature(final Card c) {
@@ -603,13 +615,14 @@ public class ComputerUtilCard {
} }
public static boolean doesCreatureAttackAI(final Player aiPlayer, final Card card) { public static boolean doesCreatureAttackAI(final Player aiPlayer, final Card card) {
AiController aic = ((PlayerControllerAi)aiPlayer.getController()).getAi(); AiController aic = ((PlayerControllerAi) aiPlayer.getController()).getAi();
return aic.getPredictedCombat().isAttacking(card); return aic.getPredictedCombat().isAttacking(card);
} }
/** /**
* Extension of doesCreatureAttackAI() for "virtual" creatures that do not actually exist on the battlefield yet * Extension of doesCreatureAttackAI() for "virtual" creatures that do not actually exist on the battlefield yet
* such as unanimated manlands. * such as unanimated manlands.
*
* @param ai controller of creature * @param ai controller of creature
* @param card creature to be evaluated * @param card creature to be evaluated
* @return creature will be attack * @return creature will be attack
@@ -623,6 +636,7 @@ public class ComputerUtilCard {
/** /**
* Create a mock combat where ai is being attacked and returns the list of likely blockers. * Create a mock combat where ai is being attacked and returns the list of likely blockers.
*
* @param ai blocking player * @param ai blocking player
* @param blockers list of additional blockers to be considered * @param blockers list of additional blockers to be considered
* @return list of creatures assigned to block in the simulation * @return list of creatures assigned to block in the simulation
@@ -654,6 +668,7 @@ public class ComputerUtilCard {
/** /**
* Decide if a creature is going to be used as a blocker. * Decide if a creature is going to be used as a blocker.
*
* @param ai controller of creature * @param ai controller of creature
* @param blocker creature to be evaluated * @param blocker creature to be evaluated
* @return creature will be a blocker * @return creature will be a blocker
@@ -664,6 +679,7 @@ public class ComputerUtilCard {
/** /**
* Check if an attacker can be blocked profitably (ie. kill attacker) * Check if an attacker can be blocked profitably (ie. kill attacker)
*
* @param ai controller of attacking creature * @param ai controller of attacking creature
* @param attacker attacking creature to evaluate * @param attacker attacking creature to evaluate
* @return attacker will die * @return attacker will die
@@ -709,8 +725,7 @@ public class ComputerUtilCard {
/** /**
* getMostExpensivePermanentAI. * getMostExpensivePermanentAI.
* *
* @param all * @param all the all
* the all
* @return the card * @return the card
*/ */
public static Card getMostExpensivePermanentAI(final Iterable<Card> all) { public static Card getMostExpensivePermanentAI(final Iterable<Card> all) {
@@ -926,22 +941,23 @@ public class ComputerUtilCard {
public static List<String> getColorByProminence(final List<Card> list) { public static List<String> getColorByProminence(final List<Card> list) {
int cntColors = MagicColor.WUBRG.length; int cntColors = MagicColor.WUBRG.length;
final List<Pair<Byte,Integer>> map = new ArrayList<>(); final List<Pair<Byte, Integer>> map = new ArrayList<>();
for (int i = 0; i < cntColors; i++) { for (int i = 0; i < cntColors; i++) {
map.add(MutablePair.of(MagicColor.WUBRG[i], 0)); map.add(MutablePair.of(MagicColor.WUBRG[i], 0));
} }
for (final Card crd : list) { for (final Card crd : list) {
ColorSet color = crd.getColor(); ColorSet color = crd.getColor();
if (color.hasWhite()) map.get(0).setValue(Integer.valueOf(map.get(0).getValue()+1)); if (color.hasWhite()) map.get(0).setValue(Integer.valueOf(map.get(0).getValue() + 1));
if (color.hasBlue()) map.get(1).setValue(Integer.valueOf(map.get(1).getValue()+1)); if (color.hasBlue()) map.get(1).setValue(Integer.valueOf(map.get(1).getValue() + 1));
if (color.hasBlack()) map.get(2).setValue(Integer.valueOf(map.get(2).getValue()+1)); if (color.hasBlack()) map.get(2).setValue(Integer.valueOf(map.get(2).getValue() + 1));
if (color.hasRed()) map.get(3).setValue(Integer.valueOf(map.get(3).getValue()+1)); if (color.hasRed()) map.get(3).setValue(Integer.valueOf(map.get(3).getValue() + 1));
if (color.hasGreen()) map.get(4).setValue(Integer.valueOf(map.get(4).getValue()+1)); if (color.hasGreen()) map.get(4).setValue(Integer.valueOf(map.get(4).getValue() + 1));
} }
Collections.sort(map, new Comparator<Pair<Byte,Integer>>() { Collections.sort(map, new Comparator<Pair<Byte, Integer>>() {
@Override public int compare(Pair<Byte, Integer> o1, Pair<Byte, Integer> o2) { @Override
public int compare(Pair<Byte, Integer> o1, Pair<Byte, Integer> o2) {
return o2.getValue() - o1.getValue(); return o2.getValue() - o1.getValue();
} }
}); });
@@ -978,49 +994,38 @@ public class ComputerUtilCard {
if (logic.equals("MostProminentInHumanDeck")) { if (logic.equals("MostProminentInHumanDeck")) {
chosen.add(getMostProminentColor(CardLists.filterControlledBy(game.getCardsInGame(), opp), colorChoices)); chosen.add(getMostProminentColor(CardLists.filterControlledBy(game.getCardsInGame(), opp), colorChoices));
} } else if (logic.equals("MostProminentInComputerDeck")) {
else if (logic.equals("MostProminentInComputerDeck")) {
chosen.add(getMostProminentColor(CardLists.filterControlledBy(game.getCardsInGame(), ai), colorChoices)); chosen.add(getMostProminentColor(CardLists.filterControlledBy(game.getCardsInGame(), ai), colorChoices));
} } else if (logic.equals("MostProminentDualInComputerDeck")) {
else if (logic.equals("MostProminentDualInComputerDeck")) {
List<String> prominence = getColorByProminence(CardLists.filterControlledBy(game.getCardsInGame(), ai)); List<String> prominence = getColorByProminence(CardLists.filterControlledBy(game.getCardsInGame(), ai));
chosen.add(prominence.get(0)); chosen.add(prominence.get(0));
chosen.add(prominence.get(1)); chosen.add(prominence.get(1));
} } else if (logic.equals("MostProminentInGame")) {
else if (logic.equals("MostProminentInGame")) {
chosen.add(getMostProminentColor(game.getCardsInGame(), colorChoices)); chosen.add(getMostProminentColor(game.getCardsInGame(), colorChoices));
} } else if (logic.equals("MostProminentHumanCreatures")) {
else if (logic.equals("MostProminentHumanCreatures")) {
CardCollectionView list = opp.getCreaturesInPlay(); CardCollectionView list = opp.getCreaturesInPlay();
if (list.isEmpty()) { if (list.isEmpty()) {
list = CardLists.filter(CardLists.filterControlledBy(game.getCardsInGame(), opp), CardPredicates.Presets.CREATURES); list = CardLists.filter(CardLists.filterControlledBy(game.getCardsInGame(), opp), CardPredicates.Presets.CREATURES);
} }
chosen.add(getMostProminentColor(list, colorChoices)); chosen.add(getMostProminentColor(list, colorChoices));
} } else if (logic.equals("MostProminentComputerControls")) {
else if (logic.equals("MostProminentComputerControls")) {
chosen.add(getMostProminentColor(ai.getCardsIn(ZoneType.Battlefield), colorChoices)); chosen.add(getMostProminentColor(ai.getCardsIn(ZoneType.Battlefield), colorChoices));
} } else if (logic.equals("MostProminentHumanControls")) {
else if (logic.equals("MostProminentHumanControls")) {
chosen.add(getMostProminentColor(opp.getCardsIn(ZoneType.Battlefield), colorChoices)); chosen.add(getMostProminentColor(opp.getCardsIn(ZoneType.Battlefield), colorChoices));
} } else if (logic.equals("MostProminentPermanent")) {
else if (logic.equals("MostProminentPermanent")) {
chosen.add(getMostProminentColor(game.getCardsIn(ZoneType.Battlefield), colorChoices)); chosen.add(getMostProminentColor(game.getCardsIn(ZoneType.Battlefield), colorChoices));
} } else if (logic.equals("MostProminentAttackers") && game.getPhaseHandler().inCombat()) {
else if (logic.equals("MostProminentAttackers") && game.getPhaseHandler().inCombat()) {
chosen.add(getMostProminentColor(game.getCombat().getAttackers(), colorChoices)); chosen.add(getMostProminentColor(game.getCombat().getAttackers(), colorChoices));
} } else if (logic.equals("MostProminentInActivePlayerHand")) {
else if (logic.equals("MostProminentInActivePlayerHand")) {
chosen.add(getMostProminentColor(game.getPhaseHandler().getPlayerTurn().getCardsIn(ZoneType.Hand), colorChoices)); chosen.add(getMostProminentColor(game.getPhaseHandler().getPlayerTurn().getCardsIn(ZoneType.Hand), colorChoices));
} } else if (logic.equals("MostProminentInComputerDeckButGreen")) {
else if (logic.equals("MostProminentInComputerDeckButGreen")) {
List<String> prominence = getColorByProminence(CardLists.filterControlledBy(game.getCardsInGame(), ai)); List<String> prominence = getColorByProminence(CardLists.filterControlledBy(game.getCardsInGame(), ai));
if (prominence.get(0).equals(MagicColor.Constant.GREEN)) { if (prominence.get(0).equals(MagicColor.Constant.GREEN)) {
chosen.add(prominence.get(1)); chosen.add(prominence.get(1));
} else { } else {
chosen.add(prominence.get(0)); chosen.add(prominence.get(0));
} }
} } else if (logic.equals("MostExcessOpponentControls")) {
else if (logic.equals("MostExcessOpponentControls")) {
int maxExcess = 0; int maxExcess = 0;
String bestColor = Constant.GREEN; String bestColor = Constant.GREEN;
for (byte color : MagicColor.WUBRG) { for (byte color : MagicColor.WUBRG) {
@@ -1034,8 +1039,7 @@ public class ComputerUtilCard {
} }
} }
chosen.add(bestColor); chosen.add(bestColor);
} } else if (logic.equals("MostProminentKeywordInComputerDeck")) {
else if (logic.equals("MostProminentKeywordInComputerDeck")) {
CardCollectionView list = ai.getAllCards(); CardCollectionView list = ai.getAllCards();
int m1 = 0; int m1 = 0;
String chosenColor = MagicColor.Constant.WHITE; String chosenColor = MagicColor.Constant.WHITE;
@@ -1048,8 +1052,7 @@ public class ComputerUtilCard {
} }
} }
chosen.add(chosenColor); chosen.add(chosenColor);
} } else if (logic.equals("HighestDevotionToColor")) {
else if (logic.equals("HighestDevotionToColor")) {
int curDevotion = 0; int curDevotion = 0;
String chosenColor = MagicColor.Constant.WHITE; String chosenColor = MagicColor.Constant.WHITE;
CardCollectionView hand = ai.getCardsIn(ZoneType.Hand); CardCollectionView hand = ai.getCardsIn(ZoneType.Hand);
@@ -1075,7 +1078,7 @@ public class ComputerUtilCard {
public static boolean useRemovalNow(final SpellAbility sa, final Card c, final int dmg, ZoneType destination) { public static boolean useRemovalNow(final SpellAbility sa, final Card c, final int dmg, ZoneType destination) {
final Player ai = sa.getActivatingPlayer(); final Player ai = sa.getActivatingPlayer();
final AiController aic = ((PlayerControllerAi)ai.getController()).getAi(); final AiController aic = ((PlayerControllerAi) ai.getController()).getAi();
final Game game = ai.getGame(); final Game game = ai.getGame();
final PhaseHandler ph = game.getPhaseHandler(); final PhaseHandler ph = game.getPhaseHandler();
final PhaseType phaseType = ph.getPhase(); final PhaseType phaseType = ph.getPhase();
@@ -1296,6 +1299,7 @@ public class ComputerUtilCard {
/** /**
* Decides if the "pump" is worthwhile * Decides if the "pump" is worthwhile
*
* @param ai casting player * @param ai casting player
* @param sa Pump* or CounterPut* * @param sa Pump* or CounterPut*
* @param c target of sa * @param c target of sa
@@ -1308,6 +1312,7 @@ public class ComputerUtilCard {
final int power, final List<String> keywords) { final int power, final List<String> keywords) {
return shouldPumpCard(ai, sa, c, toughness, power, keywords, false); return shouldPumpCard(ai, sa, c, toughness, power, keywords, false);
} }
public static boolean shouldPumpCard(final Player ai, final SpellAbility sa, final Card c, final int toughness, public static boolean shouldPumpCard(final Player ai, final SpellAbility sa, final Card c, final int toughness,
final int power, final List<String> keywords, boolean immediately) { final int power, final List<String> keywords, boolean immediately) {
final Game game = ai.getGame(); final Game game = ai.getGame();
@@ -1452,7 +1457,9 @@ public class ComputerUtilCard {
boolean pumpedWillDie = false; boolean pumpedWillDie = false;
final boolean isAttacking = combat.isAttacking(c); final boolean isAttacking = combat.isAttacking(c);
if ((isBerserk && isAttacking) || loseCardAtEOT) { pumpedWillDie = true; } if ((isBerserk && isAttacking) || loseCardAtEOT) {
pumpedWillDie = true;
}
if (isAttacking) { if (isAttacking) {
pumpedCombat.addAttacker(pumped, opp); pumpedCombat.addAttacker(pumped, opp);
@@ -1615,7 +1622,7 @@ public class ComputerUtilCard {
// if we got here, Berserk will result in the pumped creature dying at EOT and the opponent will not lose // if we got here, Berserk will result in the pumped creature dying at EOT and the opponent will not lose
// (other similar cards with AILogic$ Berserk that do not die only when attacking are excluded from consideration) // (other similar cards with AILogic$ Berserk that do not die only when attacking are excluded from consideration)
if (ai.getController() instanceof PlayerControllerAi) { if (ai.getController() instanceof PlayerControllerAi) {
boolean aggr = ((PlayerControllerAi)ai.getController()).getAi().getBooleanProperty(AiProps.USE_BERSERK_AGGRESSIVELY) boolean aggr = ((PlayerControllerAi) ai.getController()).getAi().getBooleanProperty(AiProps.USE_BERSERK_AGGRESSIVELY)
|| sa.hasParam("AtEOT"); || sa.hasParam("AtEOT");
if (!aggr) { if (!aggr) {
return false; return false;
@@ -1663,6 +1670,7 @@ public class ComputerUtilCard {
/** /**
* Apply "pump" ability and return modified creature * Apply "pump" ability and return modified creature
*
* @param ai casting player * @param ai casting player
* @param sa Pump* or CounterPut* * @param sa Pump* or CounterPut*
* @param c target of sa * @param c target of sa
@@ -1740,6 +1748,7 @@ public class ComputerUtilCard {
/** /**
* Applies static continuous Power/Toughness effects to a (virtual) creature. * Applies static continuous Power/Toughness effects to a (virtual) creature.
*
* @param game game instance to work with * @param game game instance to work with
* @param vCard creature to work with * @param vCard creature to work with
* @param exclude list of cards to exclude when considering ability sources, accepts null * @param exclude list of cards to exclude when considering ability sources, accepts null
@@ -1787,6 +1796,7 @@ public class ComputerUtilCard {
/** /**
* Evaluate if the ability can save a target against removal * Evaluate if the ability can save a target against removal
*
* @param ai casting player * @param ai casting player
* @param sa Pump* or CounterPut* * @param sa Pump* or CounterPut*
* @return * @return
@@ -1889,7 +1899,7 @@ public class ComputerUtilCard {
int priorityRemovalThreshold = 0; int priorityRemovalThreshold = 0;
int lifeInDanger = 5; int lifeInDanger = 5;
if (ai.getController().isAI()) { if (ai.getController().isAI()) {
AiController aic = ((PlayerControllerAi)ai.getController()).getAi(); AiController aic = ((PlayerControllerAi) ai.getController()).getAi();
enablePriorityRemoval = aic.getBooleanProperty(AiProps.ACTIVELY_DESTROY_IMMEDIATELY_UNBLOCKABLE); enablePriorityRemoval = aic.getBooleanProperty(AiProps.ACTIVELY_DESTROY_IMMEDIATELY_UNBLOCKABLE);
priorityRemovalThreshold = aic.getIntProperty(AiProps.DESTROY_IMMEDIATELY_UNBLOCKABLE_THRESHOLD); priorityRemovalThreshold = aic.getIntProperty(AiProps.DESTROY_IMMEDIATELY_UNBLOCKABLE_THRESHOLD);
priorityRemovalOnlyInDanger = aic.getBooleanProperty(AiProps.DESTROY_IMMEDIATELY_UNBLOCKABLE_ONLY_IN_DNGR); priorityRemovalOnlyInDanger = aic.getBooleanProperty(AiProps.DESTROY_IMMEDIATELY_UNBLOCKABLE_ONLY_IN_DNGR);
@@ -2083,10 +2093,19 @@ public class ComputerUtilCard {
public static boolean isCardRemAIDeck(final Card card) { public static boolean isCardRemAIDeck(final Card card) {
return card.getRules() != null && card.getRules().getAiHints().getRemAIDecks(); return card.getRules() != null && card.getRules().getAiHints().getRemAIDecks();
} }
public static boolean isCardRemRandomDeck(final Card card) { public static boolean isCardRemRandomDeck(final Card card) {
return card.getRules() != null && card.getRules().getAiHints().getRemRandomDecks(); return card.getRules() != null && card.getRules().getAiHints().getRemRandomDecks();
} }
public static boolean isCardRemNonCommanderDeck(final Card card) { public static boolean isCardRemNonCommanderDeck(final Card card) {
return card.getRules() != null && card.getRules().getAiHints().getRemNonCommanderDecks(); return card.getRules() != null && card.getRules().getAiHints().getRemNonCommanderDecks();
} }
static class LandEvaluator implements Function<Card, Integer> {
@Override
public Integer apply(Card card) {
return GameStateEvaluator.evaluateLand(card);
}
}
} }