- Simple AI support for Explore (feel free to expand).

git-svn-id: http://svn.slightlymagic.net/forge/trunk@35759 269b9781-a132-4a9b-9d4e-f004f1b56b58
This commit is contained in:
Agetian 2017-09-25 08:02:08 +00:00
parent 443f0f5ee2
commit d35831d328
9 changed files with 105 additions and 17 deletions

View File

@ -25,6 +25,7 @@ import com.google.common.collect.Iterables;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import forge.ai.ability.ChangeZoneAi;
import forge.ai.ability.ExploreAi;
import forge.ai.simulation.SpellAbilityPicker;
import forge.card.MagicColor;
import forge.card.mana.ManaCost;
@ -1749,8 +1750,12 @@ public class AiController {
if (useSimulation) {
return simPicker.chooseCardToHiddenOriginChangeZone(destination, origin, sa, fetchList, player2, decider);
}
if (sa.getApi() == ApiType.Explore) {
return ExploreAi.shouldPutInGraveyard(fetchList, decider);
} else {
return ChangeZoneAi.chooseCardToHiddenOriginChangeZone(destination, origin, sa, fetchList, player2, decider);
}
}
public List<SpellAbility> orderPlaySa(List<SpellAbility> activePlayerSAs) {
// list is only one or empty, no need to filter

View File

@ -94,8 +94,10 @@ public enum AiProps { /** */
BOUNCE_ALL_TO_HAND_CREAT_EVAL_DIFF ("200"), /** */
BOUNCE_ALL_ELSEWHERE_CREAT_EVAL_DIFF ("200"), /** */
BOUNCE_ALL_TO_HAND_NONCREAT_EVAL_DIFF ("3"), /** */
BOUNCE_ALL_ELSEWHERE_NONCREAT_EVAL_DIFF ("3"),
INTUITION_ALTERNATIVE_LOGIC ("false"); /** */
BOUNCE_ALL_ELSEWHERE_NONCREAT_EVAL_DIFF ("3"), /** */
INTUITION_ALTERNATIVE_LOGIC ("false"), /** */
EXPLORE_MAX_CMC_DIFF_TO_PUT_IN_GRAVEYARD ("2"),
EXPLORE_NUM_LANDS_TO_STILL_NEED_MORE ("2"); /** */
// Experimental features, must be removed after extensive testing and, ideally, defaulting
// <-- There are no experimental options here -->

View File

@ -1,14 +1,13 @@
package forge.ai;
import java.util.Map;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.Maps;
import forge.ai.ability.*;
import forge.game.ability.ApiType;
import forge.util.ReflectionUtil;
import java.util.Map;
public enum SpellApiToAi {
Converter;
@ -72,7 +71,7 @@ public enum SpellApiToAi {
.put(ApiType.ExchangeControlVariant, CannotPlayAi.class)
.put(ApiType.ExchangePower, PowerExchangeAi.class)
.put(ApiType.ExchangeZone, ZoneExchangeAi.class)
.put(ApiType.Explore, AlwaysPlayAi.class)
.put(ApiType.Explore, ExploreAi.class)
.put(ApiType.Fight, FightAi.class)
.put(ApiType.FlipACoin, FlipACoinAi.class)
.put(ApiType.Fog, FogAi.class)

View File

@ -0,0 +1,52 @@
package forge.ai.ability;
import forge.ai.*;
import forge.game.card.*;
import forge.game.player.Player;
import forge.game.spellability.SpellAbility;
import forge.game.zone.ZoneType;
public class ExploreAi extends SpellAbilityAi {
/* (non-Javadoc)
* @see forge.card.abilityfactory.SpellAiLogic#canPlayAI(forge.game.player.Player, java.util.Map, forge.card.spellability.SpellAbility)
*/
@Override
protected boolean canPlayAI(Player aiPlayer, SpellAbility sa) {
return true;
}
public static Card shouldPutInGraveyard(CardCollection top, Player ai) {
int predictedMana = ComputerUtilMana.getAvailableManaSources(ai, false).size();
CardCollectionView cardsOTB = ai.getCardsIn(ZoneType.Battlefield);
CardCollectionView cardsInHand = ai.getCardsIn(ZoneType.Hand);
CardCollection landsOTB = CardLists.filter(cardsOTB, CardPredicates.Presets.LANDS_PRODUCING_MANA);
CardCollection landsInHand = CardLists.filter(cardsInHand, CardPredicates.Presets.LANDS_PRODUCING_MANA);
int maxCMCDiff = 1;
int numLandsToStillNeedMore = 2;
if (ai.getController().isAI()) {
AiController aic = ((PlayerControllerAi)ai.getController()).getAi();
maxCMCDiff = aic.getIntProperty(AiProps.EXPLORE_MAX_CMC_DIFF_TO_PUT_IN_GRAVEYARD);
numLandsToStillNeedMore = aic.getIntProperty(AiProps.EXPLORE_NUM_LANDS_TO_STILL_NEED_MORE);
}
if (!top.isEmpty()) {
Card topCard = top.getFirst();
if (landsInHand.isEmpty() && landsOTB.size() <= numLandsToStillNeedMore) {
// We need more lands to improve our mana base, explore away the non-lands
return topCard;
}
if (topCard.getCMC() - maxCMCDiff >= predictedMana) {
// We're not casting this in foreseeable future, put it in the graveyard
return topCard;
}
}
// Put on top of the library (do not mark the card for placement in the graveyard)
return null;
}
}

View File

@ -1,22 +1,16 @@
package forge.ai.simulation;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import forge.ai.AiPlayDecision;
import forge.ai.ComputerUtil;
import forge.ai.ComputerUtilAbility;
import forge.ai.ComputerUtilCost;
import forge.ai.ability.ChangeZoneAi;
import forge.ai.ability.ExploreAi;
import forge.ai.simulation.GameStateEvaluator.Score;
import forge.game.Game;
import forge.game.ability.ApiType;
import forge.game.ability.effects.CharmEffect;
import forge.game.card.Card;
import forge.game.card.CardCollection;
import forge.game.card.CardCollectionView;
import forge.game.card.CardLists;
import forge.game.card.CardPredicates;
import forge.game.card.*;
import forge.game.cost.Cost;
import forge.game.phase.PhaseType;
import forge.game.player.Player;
@ -27,6 +21,10 @@ import forge.game.spellability.SpellAbilityCondition;
import forge.game.zone.ZoneType;
import forge.util.TextUtil;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
public class SpellAbilityPicker {
private Game game;
private Player player;
@ -432,8 +430,12 @@ public class SpellAbilityPicker {
return card;
}
}
if (sa.getApi() == ApiType.Explore) {
return ExploreAi.shouldPutInGraveyard(fetchList, decider);
} else {
return ChangeZoneAi.chooseCardToHiddenOriginChangeZone(destination, origin, sa, fetchList, player2, decider);
}
}
public CardCollectionView chooseSacrificeType(String type, SpellAbility ability, int amount) {
if (amount == 1) {

View File

@ -170,3 +170,10 @@ BOUNCE_ALL_ELSEWHERE_NONCREAT_EVAL_DIFF=3
# combo deck more appropriately. In Reanimator decks, this logic will make the AI pick the fattest threats in the
# library to put some into the graveyard.
INTUITION_ALTERNATIVE_LOGIC=true
# How big of a difference is allowed between the revealed card CMC and the currently castable CMC to still put the
# card on top of the library
EXPLORE_MAX_CMC_DIFF_TO_PUT_IN_GRAVEYARD=2
# The number of lands on the battlefield when the AI would use Explore to put non-land cards in graveyard if it
# doesn't have a land in hand
EXPLORE_NUM_LANDS_TO_STILL_NEED_MORE=2

View File

@ -170,3 +170,10 @@ BOUNCE_ALL_ELSEWHERE_NONCREAT_EVAL_DIFF=3
# combo deck more appropriately. In Reanimator decks, this logic will make the AI pick the fattest threats in the
# library to put some into the graveyard.
INTUITION_ALTERNATIVE_LOGIC=true
# How big of a difference is allowed between the revealed card CMC and the currently castable CMC to still put the
# card on top of the library
EXPLORE_MAX_CMC_DIFF_TO_PUT_IN_GRAVEYARD=2
# The number of lands on the battlefield when the AI would use Explore to put non-land cards in graveyard if it
# doesn't have a land in hand
EXPLORE_NUM_LANDS_TO_STILL_NEED_MORE=2

View File

@ -171,6 +171,13 @@ BOUNCE_ALL_ELSEWHERE_NONCREAT_EVAL_DIFF=5
# library to put some into the graveyard.
INTUITION_ALTERNATIVE_LOGIC=true
# How big of a difference is allowed between the revealed card CMC and the currently castable CMC to still put the
# card on top of the library
EXPLORE_MAX_CMC_DIFF_TO_PUT_IN_GRAVEYARD=2
# The number of lands on the battlefield when the AI would use Explore to put non-land cards in graveyard if it
# doesn't have a land in hand
EXPLORE_NUM_LANDS_TO_STILL_NEED_MORE=3
# -- Experimental feature toggles which only exist until the testing procedure for the relevant --
# -- features is over. These toggles will be removed later, or may be reintroduced under a --
# -- different name if necessary --

View File

@ -170,3 +170,10 @@ BOUNCE_ALL_ELSEWHERE_NONCREAT_EVAL_DIFF=3
# combo deck more appropriately. In Reanimator decks, this logic will make the AI pick the fattest threats in the
# library to put some into the graveyard.
INTUITION_ALTERNATIVE_LOGIC=true
# How big of a difference is allowed between the revealed card CMC and the currently castable CMC to still put the
# card on top of the library
EXPLORE_MAX_CMC_DIFF_TO_PUT_IN_GRAVEYARD=1
# The number of lands on the battlefield when the AI would use Explore to put non-land cards in graveyard if it
# doesn't have a land in hand
EXPLORE_NUM_LANDS_TO_STILL_NEED_MORE=2