- Moved common AI functions from AbilityFactories to ComputerUtil.

This commit is contained in:
Sloth
2012-10-21 11:54:11 +00:00
parent 9ec90fabee
commit f76638a227
9 changed files with 82 additions and 53 deletions

View File

@@ -1503,24 +1503,6 @@ public class AbilityFactory {
&& Singletons.getModel().getGame().getPhaseHandler().isNextTurn(PlayerType.COMPUTER)); && Singletons.getModel().getGame().getPhaseHandler().isNextTurn(PlayerType.COMPUTER));
} }
// returns true if it's better to wait until blockers are declared
/**
* <p>
* waitForBlocking.
* </p>
*
* @param sa
* a {@link forge.card.spellability.SpellAbility} object.
* @return a boolean.
*/
public static boolean waitForBlocking(final SpellAbility sa) {
return (sa.getSourceCard().isCreature()
&& sa.getPayCosts().getTap()
&& (Singletons.getModel().getGame().getPhaseHandler().getPhase().isBefore(PhaseType.COMBAT_DECLARE_BLOCKERS_INSTANT_ABILITY)
|| Singletons.getModel().getGame().getPhaseHandler().isNextTurn(PlayerType.HUMAN)));
}
/** /**
* <p> * <p>
* isSorcerySpeed. * isSorcerySpeed.

View File

@@ -361,7 +361,7 @@ public class AbilityFactoryAlterLife {
} }
// Don't tap creatures that may be able to block // Don't tap creatures that may be able to block
if (AbilityFactory.waitForBlocking(sa)) { if (ComputerUtil.waitForBlocking(sa)) {
return false; return false;
} }
@@ -777,6 +777,10 @@ public class AbilityFactoryAlterLife {
return false; return false;
} }
if (ComputerUtil.preventRunAwayActivations(sa)) {
return false;
}
if (amount >= opp.getLife()) { if (amount >= opp.getLife()) {
priority = true; // killing the human should be done asap priority = true; // killing the human should be done asap
} }
@@ -788,13 +792,10 @@ public class AbilityFactoryAlterLife {
} }
// Don't tap creatures that may be able to block // Don't tap creatures that may be able to block
if (AbilityFactory.waitForBlocking(sa) && !priority) { if (ComputerUtil.waitForBlocking(sa) && !priority) {
return false; return false;
} }
// prevent run-away activations - first time will always return true
final boolean chance = r.nextFloat() <= Math.pow(.6667, sa.getActivationsThisTurn());
final Target tgt = sa.getTarget(); final Target tgt = sa.getTarget();
if (sa.getTarget() != null) { if (sa.getTarget() != null) {
@@ -811,7 +812,7 @@ public class AbilityFactoryAlterLife {
randomReturn = true; randomReturn = true;
} }
return (randomReturn && chance); return (randomReturn);
} }
/** /**
@@ -1270,7 +1271,7 @@ public class AbilityFactoryAlterLife {
} }
// Don't tap creatures that may be able to block // Don't tap creatures that may be able to block
if (AbilityFactory.waitForBlocking(sa)) { if (ComputerUtil.waitForBlocking(sa)) {
return false; return false;
} }

View File

@@ -1532,7 +1532,7 @@ public final class AbilityFactoryChoose {
if (params.containsKey("AILogic")) { if (params.containsKey("AILogic")) {
// Don't tap creatures that may be able to block // Don't tap creatures that may be able to block
if (AbilityFactory.waitForBlocking(sa)) { if (ComputerUtil.waitForBlocking(sa)) {
return false; return false;
} }

View File

@@ -310,9 +310,12 @@ public class AbilityFactoryCounters {
Card choice = null; Card choice = null;
final String type = params.get("CounterType"); final String type = params.get("CounterType");
final String amountStr = params.get("CounterNum"); final String amountStr = params.get("CounterNum");
final Player player = af.isCurse() ? ai.getOpponent() : ai; final Player player = af.isCurse() ? ai.getOpponent() : ai;
if (ComputerUtil.preventRunAwayActivations(sa)) {
return false;
}
list = player.getCardsIn(ZoneType.Battlefield); list = player.getCardsIn(ZoneType.Battlefield);
list = CardLists.filter(list, new Predicate<Card>() { list = CardLists.filter(list, new Predicate<Card>() {
@Override @Override
@@ -367,9 +370,6 @@ public class AbilityFactoryCounters {
return false; return false;
} }
// prevent run-away activations - first time will always return true
boolean chance = r.nextFloat() <= Math.pow(.6667, sa.getActivationsThisTurn());
// Targeting // Targeting
if (abTgt != null) { if (abTgt != null) {
abTgt.resetTargets(); abTgt.resetTargets();
@@ -430,16 +430,16 @@ public class AbilityFactoryCounters {
return false; return false;
} }
if (AbilityFactory.waitForBlocking(sa)) { if (ComputerUtil.waitForBlocking(sa)) {
return false; return false;
} }
final AbilitySub subAb = sa.getSubAbility(); final AbilitySub subAb = sa.getSubAbility();
if (subAb != null) { if (subAb != null && !subAb.chkAIDrawback()) {
chance &= subAb.chkAIDrawback(); return false;
} }
return chance; return true;
} // putCanPlayAI } // putCanPlayAI
/** /**

View File

@@ -845,8 +845,9 @@ public class AbilityFactoryPump {
return false; return false;
} }
} }
if (ComputerUtil.preventRunAwayActivations(sa)) {
final SpellAbilityRestriction restrict = sa.getRestrictions(); return false;
}
// Phase Restrictions // Phase Restrictions
if ((Singletons.getModel().getGame().getStack().size() == 0) && ph.getPhase().isBefore(PhaseType.COMBAT_BEGIN)) { if ((Singletons.getModel().getGame().getStack().size() == 0) && ph.getPhase().isBefore(PhaseType.COMBAT_BEGIN)) {
@@ -861,6 +862,7 @@ public class AbilityFactoryPump {
} }
} }
final SpellAbilityRestriction restrict = sa.getRestrictions();
final int activations = restrict.getNumberTurnActivations(); final int activations = restrict.getNumberTurnActivations();
final int sacActivations = restrict.getActivationNumberSacrifice(); final int sacActivations = restrict.getActivationNumberSacrifice();
// don't risk sacrificing a creature just to pump it // don't risk sacrificing a creature just to pump it
@@ -915,7 +917,6 @@ public class AbilityFactoryPump {
if (cards.size() == 0) { if (cards.size() == 0) {
return false; return false;
} }
final Random r = MyRandom.getRandom();
// when this happens we need to expand AI to consider if its ok for // when this happens we need to expand AI to consider if its ok for
// everything? // everything?
@@ -929,10 +930,10 @@ public class AbilityFactoryPump {
continue; continue;
} }
return r.nextFloat() <= Math.pow(.9, activations); return true;
} }
if (shouldPumpCard(ai, sa, card)) { if (shouldPumpCard(ai, sa, card)) {
return r.nextFloat() <= Math.pow(.9, activations); return true;
} }
} }
return false; return false;
@@ -1714,15 +1715,15 @@ public class AbilityFactoryPump {
*/ */
private boolean pumpAllCanPlayAI(final Player ai, final SpellAbility sa) { private boolean pumpAllCanPlayAI(final Player ai, final SpellAbility sa) {
String valid = ""; String valid = "";
final Random r = MyRandom.getRandom();
final Card source = sa.getSourceCard(); final Card source = sa.getSourceCard();
this.params = this.abilityFactory.getMapParams(); this.params = this.abilityFactory.getMapParams();
final int power = this.getNumAttack(sa); final int power = this.getNumAttack(sa);
final int defense = this.getNumDefense(sa); final int defense = this.getNumDefense(sa);
final PhaseType phase = Singletons.getModel().getGame().getPhaseHandler().getPhase(); final PhaseType phase = Singletons.getModel().getGame().getPhaseHandler().getPhase();
// prevent runaway activations if (ComputerUtil.preventRunAwayActivations(sa)) {
final boolean chance = r.nextFloat() <= Math.pow(.6667, sa.getActivationsThisTurn()); // to return false;
}
if (this.params.containsKey("ValidCards")) { if (this.params.containsKey("ValidCards")) {
valid = this.params.get("ValidCards"); valid = this.params.get("ValidCards");
@@ -1794,7 +1795,7 @@ public class AbilityFactoryPump {
if ((CardFactoryUtil.evaluateCreatureList(comp) + 200) >= CardFactoryUtil.evaluateCreatureList(human)) { if ((CardFactoryUtil.evaluateCreatureList(comp) + 200) >= CardFactoryUtil.evaluateCreatureList(human)) {
return false; return false;
} }
return chance; return true;
} // end Curse } // end Curse
// don't use non curse PumpAll after Combat_Begin until AI is improved // don't use non curse PumpAll after Combat_Begin until AI is improved
@@ -1823,7 +1824,7 @@ public class AbilityFactoryPump {
return false; return false;
} }
return chance; return true;
} // pumpAllCanPlayAI() } // pumpAllCanPlayAI()
/** /**

View File

@@ -246,7 +246,7 @@ public class AbilityFactoryStoreSVar {
//Tree of Redemption //Tree of Redemption
final Player ai = sa.getActivatingPlayer(); final Player ai = sa.getActivatingPlayer();
final Card source = sa.getSourceCard(); final Card source = sa.getSourceCard();
if (AbilityFactory.waitForBlocking(sa) || ai.getLife() + 1 >= source.getNetDefense() if (ComputerUtil.waitForBlocking(sa) || ai.getLife() + 1 >= source.getNetDefense()
|| (ai.getLife() > 5 && !CombatUtil.lifeInSeriousDanger(ai, Singletons.getModel().getGame().getCombat()))) { || (ai.getLife() > 5 && !CombatUtil.lifeInSeriousDanger(ai, Singletons.getModel().getGame().getCombat()))) {
return false; return false;
} }

View File

@@ -295,6 +295,10 @@ public class AbilityFactoryToken extends AbilityFactory {
final AbilityFactory af = sa.getAbilityFactory(); final AbilityFactory af = sa.getAbilityFactory();
final HashMap<String, String> mapParams = af.getMapParams(); final HashMap<String, String> mapParams = af.getMapParams();
if (ComputerUtil.preventRunAwayActivations(sa)) {
return false;
}
Player opp = ai.getOpponent(); Player opp = ai.getOpponent();
for (final String type : this.tokenTypes) { for (final String type : this.tokenTypes) {
if (type.equals("Legendary")) { if (type.equals("Legendary")) {
@@ -340,7 +344,6 @@ public class AbilityFactoryToken extends AbilityFactory {
// prevent run-away activations - first time will always return true // prevent run-away activations - first time will always return true
final Random r = MyRandom.getRandom(); final Random r = MyRandom.getRandom();
final Card source = sa.getSourceCard(); final Card source = sa.getSourceCard();
final boolean chance = r.nextFloat() <= Math.pow(.9, sa.getActivationsThisTurn());
final Target tgt = sa.getTarget(); final Target tgt = sa.getTarget();
if (tgt != null) { if (tgt != null) {
@@ -383,17 +386,17 @@ public class AbilityFactoryToken extends AbilityFactory {
} }
if (AbilityFactory.playReusable(sa)) { if (AbilityFactory.playReusable(sa)) {
return chance; return true;
} }
if (Singletons.getModel().getGame().getPhaseHandler().is(PhaseType.COMBAT_DECLARE_ATTACKERS_INSTANT_ABILITY)) { if (Singletons.getModel().getGame().getPhaseHandler().is(PhaseType.COMBAT_DECLARE_ATTACKERS_INSTANT_ABILITY)) {
return ((r.nextFloat() < .95) && chance); return true;
} }
if (sa.isAbility()) { if (sa.isAbility()) {
return ((r.nextFloat() < .9) && chance); return (r.nextFloat() < .9);
} }
return ((r.nextFloat() < .8) && chance); return (r.nextFloat() < .8);
} }
/** /**

View File

@@ -351,7 +351,7 @@ public class AbilityFactoryZoneAffecting {
} }
// Don't tap creatures that may be able to block // Don't tap creatures that may be able to block
if (AbilityFactory.waitForBlocking(sa)) { if (ComputerUtil.waitForBlocking(sa)) {
return false; return false;
} }
@@ -906,7 +906,7 @@ public class AbilityFactoryZoneAffecting {
} }
// Don't tap creatures that may be able to block // Don't tap creatures that may be able to block
if (AbilityFactory.waitForBlocking(sa)) { if (ComputerUtil.waitForBlocking(sa)) {
return false; return false;
} }
@@ -1688,7 +1688,7 @@ public class AbilityFactoryZoneAffecting {
} }
// Don't tap creatures that may be able to block // Don't tap creatures that may be able to block
if (AbilityFactory.waitForBlocking(sa) && !params.containsKey("ActivationPhases")) { if (ComputerUtil.waitForBlocking(sa) && !params.containsKey("ActivationPhases")) {
return false; return false;
} }

View File

@@ -22,6 +22,7 @@ import java.util.Collections;
import java.util.Comparator; import java.util.Comparator;
import java.util.HashMap; import java.util.HashMap;
import java.util.List; import java.util.List;
import java.util.Random;
import com.google.common.base.Predicate; import com.google.common.base.Predicate;
import com.google.common.base.Predicates; import com.google.common.base.Predicates;
@@ -54,10 +55,12 @@ import forge.control.input.InputPayManaCostUtil;
import forge.error.ErrorViewer; import forge.error.ErrorViewer;
import forge.game.phase.Combat; import forge.game.phase.Combat;
import forge.game.phase.CombatUtil; import forge.game.phase.CombatUtil;
import forge.game.phase.PhaseHandler;
import forge.game.phase.PhaseType; import forge.game.phase.PhaseType;
import forge.game.zone.ZoneType; import forge.game.zone.ZoneType;
import forge.gui.GuiChoose; import forge.gui.GuiChoose;
import forge.util.Aggregates; import forge.util.Aggregates;
import forge.util.MyRandom;
/** /**
@@ -2179,4 +2182,43 @@ public class ComputerUtil {
sa.setTargetPlayer(human); sa.setTargetPlayer(human);
return true; return true;
} }
// returns true if it's better to wait until blockers are declared
/**
* <p>
* waitForBlocking.
* </p>
*
* @param sa
* a {@link forge.card.spellability.SpellAbility} object.
* @return a boolean (returns true if it's better to wait until blockers are declared).
*/
public static boolean waitForBlocking(final SpellAbility sa) {
final PhaseHandler ph = Singletons.getModel().getGame().getPhaseHandler();
return (sa.getSourceCard().isCreature()
&& sa.getPayCosts().getTap()
&& (ph.getPhase().isBefore(PhaseType.COMBAT_DECLARE_BLOCKERS_INSTANT_ABILITY)
|| !ph.getNextTurn().equals(sa.getActivatingPlayer())));
}
// returns true if the AI should stop using the ability
/**
* <p>
* preventRunAwayActivations.
* </p>
*
* @param sa
* a {@link forge.card.spellability.SpellAbility} object.
* @return a boolean (returns true if the AI should stop using the ability).
*/
public static boolean preventRunAwayActivations(final SpellAbility sa) {
final int activations = sa.getRestrictions().getNumberTurnActivations();
if (activations < 10) { //10 activations per turn should still be acceptable
return false;
}
final Random r = MyRandom.getRandom();
return r.nextFloat() <= Math.pow(.95, activations);
}
} }