mirror of
https://github.com/Relintai/mtg-forge-ios.git
synced 2024-12-21 07:16:52 +01:00
- 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:
parent
443f0f5ee2
commit
d35831d328
@ -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
|
||||
|
@ -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 -->
|
||||
|
||||
|
@ -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)
|
||||
|
52
forge-ai/src/main/java/forge/ai/ability/ExploreAi.java
Normal file
52
forge-ai/src/main/java/forge/ai/ability/ExploreAi.java
Normal 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;
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -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) {
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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 --
|
||||
|
@ -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
|
||||
|
Loading…
Reference in New Issue
Block a user