From a1a7390d800c8f945a9287551818a23cf1463fe1 Mon Sep 17 00:00:00 2001 From: Agetian Date: Fri, 20 Apr 2018 07:13:25 +0300 Subject: [PATCH] - Fixed the AI hanging the game when trying to choose a source in absence of a creature in combat on the opponent's battlefield. --- .../java/forge/ai/ability/ChooseSourceAi.java | 44 ++++++++++++++++--- .../java/forge/game/card/CardPredicates.java | 2 +- 2 files changed, 40 insertions(+), 6 deletions(-) diff --git a/forge-ai/src/main/java/forge/ai/ability/ChooseSourceAi.java b/forge-ai/src/main/java/forge/ai/ability/ChooseSourceAi.java index 4132118283d..7f740adb8dc 100644 --- a/forge-ai/src/main/java/forge/ai/ability/ChooseSourceAi.java +++ b/forge-ai/src/main/java/forge/ai/ability/ChooseSourceAi.java @@ -3,6 +3,8 @@ package forge.ai.ability; import java.util.List; 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.ComputerUtil; @@ -17,6 +19,7 @@ import forge.game.ability.ApiType; import forge.game.card.Card; import forge.game.card.CardCollectionView; import forge.game.card.CardLists; +import forge.game.card.CardPredicates; import forge.game.combat.Combat; import forge.game.cost.Cost; import forge.game.phase.PhaseType; @@ -25,6 +28,7 @@ import forge.game.spellability.SpellAbility; import forge.game.spellability.SpellAbilityStackInstance; import forge.game.spellability.TargetRestrictions; import forge.game.zone.ZoneType; +import forge.util.Aggregates; public class ChooseSourceAi extends SpellAbilityAi { @@ -133,9 +137,9 @@ public class ChooseSourceAi extends SpellAbilityAi { final Player ai = sa.getActivatingPlayer(); final Game game = ai.getGame(); if (!game.getStack().isEmpty()) { - Card choseCard = chooseCardOnStack(sa, ai, game); - if (choseCard != null) { - return choseCard; + Card chosenCard = chooseCardOnStack(sa, ai, game); + if (chosenCard != null) { + return chosenCard; } } @@ -151,8 +155,38 @@ public class ChooseSourceAi extends SpellAbilityAi { return ComputerUtilCombat.damageIfUnblocked(c, ai, combat, true) > 0; } }); - return ComputerUtilCard.getBestCreatureAI(permanentSources); - + + // Try to choose the best creature for damage prevention. + Card bestCreature = ComputerUtilCard.getBestCreatureAI(permanentSources); + if (bestCreature != null) { + return bestCreature; + } else { + // No optimal creature was found above, so try to broaden the choice. + if (!Iterables.isEmpty(options)) { + List oppCreatures = CardLists.filter(options, Predicates.and(CardPredicates.Presets.CREATURES, + Predicates.not(CardPredicates.isOwner(aiChoser)))); + List aiNonCreatures = CardLists.filter(options, Predicates.and(Predicates.not(CardPredicates.Presets.CREATURES), + CardPredicates.Presets.PERMANENTS, CardPredicates.isOwner(aiChoser))); + + if (!oppCreatures.isEmpty()) { + return ComputerUtilCard.getBestCreatureAI(oppCreatures); + } else if (!aiNonCreatures.isEmpty()) { + return Aggregates.random(aiNonCreatures); + } else { + return Aggregates.random(options); + } + } else if (!game.getStack().isEmpty()) { + // No permanent for the AI to choose. Should normally not happen unless using dev mode or something, + // but when it does happen, choose the top card on stack if possible (generally it'll be the SA + // source) in order to choose at least something, or the game will hang. + return game.getStack().peekAbility().getHostCard(); + } + } + + // Should never get here + System.err.println("Unexpected behavior: The AI was unable to choose anything for AF ChooseSource in " + + sa.getHostCard() + ", the game will likely hang."); + return null; } else { return ComputerUtilCard.getBestAI(options); } diff --git a/forge-game/src/main/java/forge/game/card/CardPredicates.java b/forge-game/src/main/java/forge/game/card/CardPredicates.java index ec22b7d74d0..d462bddcabb 100644 --- a/forge-game/src/main/java/forge/game/card/CardPredicates.java +++ b/forge-game/src/main/java/forge/game/card/CardPredicates.java @@ -61,7 +61,7 @@ public final class CardPredicates { return new Predicate() { @Override public boolean apply(final Card c) { - return c.getOwner().equals(p); + return p.equals(c.getOwner()); } }; }