diff --git a/Mage.Client/plugins/mage-player-ai-ma.jar b/Mage.Client/plugins/mage-player-ai-ma.jar index 0f416d0b87..c2468a1b93 100644 Binary files a/Mage.Client/plugins/mage-player-ai-ma.jar and b/Mage.Client/plugins/mage-player-ai-ma.jar differ diff --git a/Mage.Server.Plugins/Mage.Player.AI.MA/src/mage/player/ai/ComputerPlayer6.java b/Mage.Server.Plugins/Mage.Player.AI.MA/src/mage/player/ai/ComputerPlayer6.java index 7eed743e24..f63085f73d 100644 --- a/Mage.Server.Plugins/Mage.Player.AI.MA/src/mage/player/ai/ComputerPlayer6.java +++ b/Mage.Server.Plugins/Mage.Player.AI.MA/src/mage/player/ai/ComputerPlayer6.java @@ -40,20 +40,20 @@ import mage.abilities.costs.mana.ManaCosts; import mage.abilities.costs.mana.VariableManaCost; import mage.abilities.effects.Effect; import mage.abilities.effects.SearchEffect; -import mage.abilities.keyword.LevelUpAbility; import mage.cards.Card; import mage.cards.Cards; import mage.choices.Choice; -import mage.counters.CounterType; import mage.game.Game; import mage.game.combat.Combat; import mage.game.combat.CombatGroup; import mage.game.events.GameEvent; import mage.game.permanent.Permanent; -import mage.game.permanent.PermanentCard; import mage.game.stack.StackAbility; import mage.game.stack.StackObject; import mage.game.turn.*; +import mage.player.ai.ma.optimizers.TreeOptimizer; +import mage.player.ai.ma.optimizers.impl.EquipOptimizer; +import mage.player.ai.ma.optimizers.impl.LevelUpOptimizer; import mage.players.Player; import mage.target.Target; import mage.target.TargetCard; @@ -84,6 +84,13 @@ public class ComputerPlayer6 extends ComputerPlayer implements private static final String FILE_WITH_INSTRUCTIONS = "config/ai.please.cast.this.txt"; private List suggested = new ArrayList(); + private static final List optimizers = new ArrayList(); + + static { + optimizers.add(new LevelUpOptimizer()); + optimizers.add(new EquipOptimizer()); + } + public ComputerPlayer6(String name, RangeOfInfluence range, int skill) { super(name, range); maxDepth = skill * 2; @@ -582,26 +589,8 @@ public class ComputerPlayer6 extends ComputerPlayer implements * @param allActions */ protected void optimize(Game game, List allActions) { - List toRemove = null; - for (Ability ability : allActions) { - if (ability instanceof LevelUpAbility) { - Permanent permanent = game.getPermanent(ability.getSourceId()); - if (permanent != null && permanent instanceof PermanentCard) { - PermanentCard leveler = (PermanentCard) permanent; - // check already existing Level counters and compare to maximum that make sense - if (permanent.getCounters().getCount(CounterType.LEVEL) >= leveler.getMaxLevelCounters()) { - if (toRemove == null) { - toRemove = new ArrayList(); - } - toRemove.add(ability); - } - } - } - } - if (toRemove != null) { - for (Ability r : toRemove) { - allActions.remove(r); - } + for (TreeOptimizer optimizer : optimizers) { + optimizer.optimize(game, allActions); } } diff --git a/Mage.Server.Plugins/Mage.Player.AI.MA/src/mage/player/ai/ma/optimizers/TreeOptimizer.java b/Mage.Server.Plugins/Mage.Player.AI.MA/src/mage/player/ai/ma/optimizers/TreeOptimizer.java new file mode 100644 index 0000000000..fe12e8ab2a --- /dev/null +++ b/Mage.Server.Plugins/Mage.Player.AI.MA/src/mage/player/ai/ma/optimizers/TreeOptimizer.java @@ -0,0 +1,22 @@ +package mage.player.ai.ma.optimizers; + +import mage.abilities.Ability; +import mage.game.Game; + +import java.util.List; + +/** + * Interface for ai optimizer that cuts the tree of decision. + * + * @author ayratn + */ +public interface TreeOptimizer { + + /** + * Optimize provided actions removing those of them that are redundant or lead to combinatorial explosion. + * + * @param game + * @param actions + */ + void optimize(Game game, List actions); +} diff --git a/Mage.Server.Plugins/Mage.Player.AI.MA/src/mage/player/ai/ma/optimizers/impl/BaseTreeOptimizer.java b/Mage.Server.Plugins/Mage.Player.AI.MA/src/mage/player/ai/ma/optimizers/impl/BaseTreeOptimizer.java new file mode 100644 index 0000000000..3c450416ea --- /dev/null +++ b/Mage.Server.Plugins/Mage.Player.AI.MA/src/mage/player/ai/ma/optimizers/impl/BaseTreeOptimizer.java @@ -0,0 +1,61 @@ +package mage.player.ai.ma.optimizers.impl; + +import mage.abilities.Ability; +import mage.game.Game; +import mage.player.ai.ma.optimizers.TreeOptimizer; + +import java.util.ArrayList; +import java.util.List; + +/** + * Base class for tree optimizers. + * + * @author ayratn + */ +public abstract class BaseTreeOptimizer implements TreeOptimizer { + + /** + * List of abilities that should be removed because of optimization. + * + */ + protected List toRemove; + + /** + * Inner method for filtering actions. + * Should be implemented by classes. + * + * @param game + * @param actions + */ + abstract void filter(Game game, List actions); + + /** + * Template method for optimization. + * + * @param game + * @param actions + */ + @Override + public final void optimize(Game game, List actions) { + filter(game, actions); + + if (toRemove != null) { + for (Ability r : toRemove) { + actions.remove(r); + } + } + } + + /** + * Mark an ability to be removed + * Not thread-safe for performance reasons. + * + * @param ability + */ + protected void removeAbility(Ability ability) { + if (toRemove == null) { + toRemove = new ArrayList(); + } + toRemove.add(ability); + } +} diff --git a/Mage.Server.Plugins/Mage.Player.AI.MA/src/mage/player/ai/ma/optimizers/impl/EquipOptimizer.java b/Mage.Server.Plugins/Mage.Player.AI.MA/src/mage/player/ai/ma/optimizers/impl/EquipOptimizer.java new file mode 100644 index 0000000000..e01379cdd7 --- /dev/null +++ b/Mage.Server.Plugins/Mage.Player.AI.MA/src/mage/player/ai/ma/optimizers/impl/EquipOptimizer.java @@ -0,0 +1,31 @@ +package mage.player.ai.ma.optimizers.impl; + +import mage.abilities.Ability; +import mage.abilities.keyword.EquipAbility; +import mage.game.Game; +import mage.game.permanent.Permanent; + +import java.util.List; + +/** + * Make sure that AI won't equip the same creature equip already attached to. + * + * @author ayratn + */ +public class EquipOptimizer extends BaseTreeOptimizer { + + @Override + public void filter(Game game, List actions) { + for (Ability ability : actions) { + if (ability instanceof EquipAbility) { + Permanent permanent = game.getPermanent(ability.getFirstTarget()); + if (permanent != null) { + // check that equipment is not already attached to {this} + if (permanent.getAttachments().contains(ability.getSourceId())) { + removeAbility(ability); + } + } + } + } + } +} diff --git a/Mage.Server.Plugins/Mage.Player.AI.MA/src/mage/player/ai/ma/optimizers/impl/LevelUpOptimizer.java b/Mage.Server.Plugins/Mage.Player.AI.MA/src/mage/player/ai/ma/optimizers/impl/LevelUpOptimizer.java new file mode 100644 index 0000000000..3ee0ed62a5 --- /dev/null +++ b/Mage.Server.Plugins/Mage.Player.AI.MA/src/mage/player/ai/ma/optimizers/impl/LevelUpOptimizer.java @@ -0,0 +1,40 @@ +package mage.player.ai.ma.optimizers.impl; + +import mage.abilities.Ability; +import mage.abilities.keyword.LevelUpAbility; +import mage.counters.CounterType; +import mage.game.Game; +import mage.game.permanent.Permanent; +import mage.game.permanent.PermanentCard; + +import java.util.List; + +/** + * Make sure that AI won't level up whenever there are maximum possible level up counters. + * + * @author ayratn + */ +public class LevelUpOptimizer extends BaseTreeOptimizer { + + /** + * Check that ability is level up ability, then compare the current counters of Level type to maximum. + * + * @param game + * @param actions + */ + @Override + public void filter(Game game, List actions) { + for (Ability ability : actions) { + if (ability instanceof LevelUpAbility) { + Permanent permanent = game.getPermanent(ability.getSourceId()); + if (permanent != null && permanent instanceof PermanentCard) { + PermanentCard leveler = (PermanentCard) permanent; + // check already existing Level counters and compare to maximum that make sense + if (permanent.getCounters().getCount(CounterType.LEVEL) >= leveler.getMaxLevelCounters()) { + removeAbility(ability); + } + } + } + } + } +} diff --git a/Mage.Server/plugins/mage-player-ai-ma.jar b/Mage.Server/plugins/mage-player-ai-ma.jar index ea051d4d1d..c2468a1b93 100644 Binary files a/Mage.Server/plugins/mage-player-ai-ma.jar and b/Mage.Server/plugins/mage-player-ai-ma.jar differ diff --git a/Mage.Tests/plugins/mage-player-ai-ma.jar b/Mage.Tests/plugins/mage-player-ai-ma.jar index 0f416d0b87..c2468a1b93 100644 Binary files a/Mage.Tests/plugins/mage-player-ai-ma.jar and b/Mage.Tests/plugins/mage-player-ai-ma.jar differ