Update Gideon Blackblade AI logic (#1630)

* - Update Gideon Blackblade AI logic.

* - Update imports.

* - Update imports.

* - Modify the method name to make more sense in the updated context.
This commit is contained in:
Agetian
2022-10-02 19:56:35 +03:00
committed by GitHub
parent 2f08524bf5
commit 614e067bc9
4 changed files with 33 additions and 47 deletions

View File

@@ -943,6 +943,12 @@ public class PlayerControllerAi extends PlayerController {
@Override
public String chooseKeywordForPump(final List<String> options, final SpellAbility sa, final String prompt) {
final String aiLogic = sa.getParamOrDefault("AILogic", "");
if (aiLogic.equals("GideonBlackblade")) {
return SpecialCardAi.GideonBlackblade.chooseKeyword(player, sa, options);
}
return Iterables.getFirst(options, null);
}

View File

@@ -17,33 +17,20 @@
*/
package forge.ai;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import forge.game.GameEntity;
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.ai.ability.AnimateAi;
import forge.card.ColorSet;
import forge.card.MagicColor;
import forge.card.mana.ManaCost;
import forge.game.Game;
import forge.game.GameEntity;
import forge.game.GameType;
import forge.game.ability.AbilityUtils;
import forge.game.ability.ApiType;
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.CardUtil;
import forge.game.card.CounterEnumType;
import forge.game.card.*;
import forge.game.combat.Combat;
import forge.game.combat.CombatUtil;
import forge.game.cost.CostPart;
@@ -64,6 +51,11 @@ import forge.util.MyRandom;
import forge.util.TextUtil;
import forge.util.maps.LinkedHashMapToAmount;
import forge.util.maps.MapToAmount;
import org.apache.commons.lang3.tuple.Pair;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
/**
* Special logic for individual cards
@@ -610,35 +602,31 @@ public class SpecialCardAi {
return true;
}
public static SpellAbility chooseSpellAbility(final Player ai, final SpellAbility sa, final List<SpellAbility> spells) {
public static String chooseKeyword(final Player ai, final SpellAbility sa, final List<String> options) {
// TODO: generalize and improve this so that it acts in a more reasonable way and can potentially be used for other cards too
List<SpellAbility> best = Lists.newArrayList();
List<SpellAbility> possible = Lists.newArrayList();
List<String> possible = Lists.newArrayList();
Card tgtCard = sa.getTargetCard();
if (tgtCard != null) {
for (SpellAbility sp : spells) {
if (SpellApiToAi.Converter.get(sp.getApi()).canPlayAIWithSubs(ai, sp)) {
best.add(sp); // these SAs are prioritized since the AI sees a reason to play them now
}
final List<String> keywords = sp.hasParam("KW") ? Arrays.asList(sp.getParam("KW").split(" & "))
: Lists.newArrayList();
for (String kw : keywords) {
if (!tgtCard.hasKeyword(kw)) {
if ("Indestructible".equals(kw) && ai.getOpponents().getCreaturesInPlay().isEmpty()) {
CardCollection oppUntappedCreatures = CardLists.filter(ai.getOpponents().getCreaturesInPlay(), CardPredicates.Presets.UNTAPPED);
for (String kw : options) {
if (!tgtCard.hasKeyword(kw)) {
if ("Indestructible".equals(kw)) {
if (oppUntappedCreatures.isEmpty()) {
continue; // nothing to damage or kill the creature with
} else {
possible.clear();
possible.add(kw); // prefer Indestructible above all else
break;
}
possible.add(sp); // these SAs at least don't duplicate a keyword on the card
break;
}
possible.add(kw); // these SAs at least don't duplicate a keyword on the card
}
}
}
if (!best.isEmpty()) {
return Aggregates.random(best);
} else if (!possible.isEmpty()) {
if (!possible.isEmpty()) {
return Aggregates.random(possible);
} else {
return Aggregates.random(spells); // if worst comes to worst, it's a PW +1 ability, so do at least something
return Aggregates.random(options); // if worst comes to worst, it's a PW +1 ability, so do at least something
}
}
}

View File

@@ -1,25 +1,16 @@
package forge.ai.ability;
import java.util.List;
import java.util.Map;
import com.google.common.base.Predicate;
import com.google.common.collect.Iterables;
import com.google.common.collect.Lists;
import com.google.common.collect.Sets;
import forge.ai.ComputerUtilAbility;
import forge.ai.ComputerUtilCost;
import forge.ai.SpecialCardAi;
import forge.ai.SpellAbilityAi;
import forge.ai.SpellApiToAi;
import forge.card.MagicColor;
import forge.game.Game;
import forge.game.card.Card;
import forge.game.card.CardCollection;
import forge.game.card.CardCollectionView;
import forge.game.card.CardUtil;
import forge.game.card.CounterEnumType;
import forge.game.card.*;
import forge.game.combat.Combat;
import forge.game.cost.Cost;
import forge.game.keyword.Keyword;
@@ -32,6 +23,9 @@ import forge.game.zone.ZoneType;
import forge.util.Aggregates;
import forge.util.collect.FCollection;
import java.util.List;
import java.util.Map;
public class ChooseGenericEffectAi extends SpellAbilityAi {
@@ -47,8 +41,6 @@ public class ChooseGenericEffectAi extends SpellAbilityAi {
return true;
}
}
} else if ("GideonBlackblade".equals(aiLogic)) {
return SpecialCardAi.GideonBlackblade.consider(ai, sa);
} else if ("AtOppEOT".equals(aiLogic)) {
PhaseHandler ph = ai.getGame().getPhaseHandler();
return ph.is(PhaseType.END_OF_TURN) && ph.getNextTurn() == ai;
@@ -99,8 +91,6 @@ public class ChooseGenericEffectAi extends SpellAbilityAi {
return spells.get(0);
} else if ("Random".equals(logic)) {
return Aggregates.random(spells);
} else if ("GideonBlackblade".equals(logic)) {
return SpecialCardAi.GideonBlackblade.chooseSpellAbility(player, sa, spells);
} else if ("Phasing".equals(logic)) { // Teferi's Realm : keep aggressive
List<SpellAbility> filtered = Lists.newArrayList(Iterables.filter(spells, new Predicate<SpellAbility>() {
@Override

View File

@@ -143,6 +143,8 @@ public class PumpAi extends PumpAiBase {
return SpecialCardAi.ElectrostaticPummeler.consider(ai, sa);
} else if (aiLogic.startsWith("AristocratCounters")) {
return true; // the preconditions to this are already tested in checkAiLogic
} else if ("GideonBlackblade".equals(aiLogic)) {
return SpecialCardAi.GideonBlackblade.consider(ai, sa);
} else if ("MoveCounter".equals(aiLogic)) {
final SpellAbility moveSA = sa.findSubAbilityByType(ApiType.MoveCounter);