mirror of
https://github.com/correl/mage.git
synced 2024-11-25 03:00:11 +00:00
Tree optimizers. Fixed Issue 420.
This commit is contained in:
parent
a71ce5c405
commit
eb0bc89597
8 changed files with 166 additions and 23 deletions
Binary file not shown.
|
@ -40,20 +40,20 @@ import mage.abilities.costs.mana.ManaCosts;
|
||||||
import mage.abilities.costs.mana.VariableManaCost;
|
import mage.abilities.costs.mana.VariableManaCost;
|
||||||
import mage.abilities.effects.Effect;
|
import mage.abilities.effects.Effect;
|
||||||
import mage.abilities.effects.SearchEffect;
|
import mage.abilities.effects.SearchEffect;
|
||||||
import mage.abilities.keyword.LevelUpAbility;
|
|
||||||
import mage.cards.Card;
|
import mage.cards.Card;
|
||||||
import mage.cards.Cards;
|
import mage.cards.Cards;
|
||||||
import mage.choices.Choice;
|
import mage.choices.Choice;
|
||||||
import mage.counters.CounterType;
|
|
||||||
import mage.game.Game;
|
import mage.game.Game;
|
||||||
import mage.game.combat.Combat;
|
import mage.game.combat.Combat;
|
||||||
import mage.game.combat.CombatGroup;
|
import mage.game.combat.CombatGroup;
|
||||||
import mage.game.events.GameEvent;
|
import mage.game.events.GameEvent;
|
||||||
import mage.game.permanent.Permanent;
|
import mage.game.permanent.Permanent;
|
||||||
import mage.game.permanent.PermanentCard;
|
|
||||||
import mage.game.stack.StackAbility;
|
import mage.game.stack.StackAbility;
|
||||||
import mage.game.stack.StackObject;
|
import mage.game.stack.StackObject;
|
||||||
import mage.game.turn.*;
|
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.players.Player;
|
||||||
import mage.target.Target;
|
import mage.target.Target;
|
||||||
import mage.target.TargetCard;
|
import mage.target.TargetCard;
|
||||||
|
@ -84,6 +84,13 @@ public class ComputerPlayer6 extends ComputerPlayer<ComputerPlayer6> implements
|
||||||
private static final String FILE_WITH_INSTRUCTIONS = "config/ai.please.cast.this.txt";
|
private static final String FILE_WITH_INSTRUCTIONS = "config/ai.please.cast.this.txt";
|
||||||
private List<String> suggested = new ArrayList<String>();
|
private List<String> suggested = new ArrayList<String>();
|
||||||
|
|
||||||
|
private static final List<TreeOptimizer> optimizers = new ArrayList<TreeOptimizer>();
|
||||||
|
|
||||||
|
static {
|
||||||
|
optimizers.add(new LevelUpOptimizer());
|
||||||
|
optimizers.add(new EquipOptimizer());
|
||||||
|
}
|
||||||
|
|
||||||
public ComputerPlayer6(String name, RangeOfInfluence range, int skill) {
|
public ComputerPlayer6(String name, RangeOfInfluence range, int skill) {
|
||||||
super(name, range);
|
super(name, range);
|
||||||
maxDepth = skill * 2;
|
maxDepth = skill * 2;
|
||||||
|
@ -582,26 +589,8 @@ public class ComputerPlayer6 extends ComputerPlayer<ComputerPlayer6> implements
|
||||||
* @param allActions
|
* @param allActions
|
||||||
*/
|
*/
|
||||||
protected void optimize(Game game, List<Ability> allActions) {
|
protected void optimize(Game game, List<Ability> allActions) {
|
||||||
List<Ability> toRemove = null;
|
for (TreeOptimizer optimizer : optimizers) {
|
||||||
for (Ability ability : allActions) {
|
optimizer.optimize(game, 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<Ability>();
|
|
||||||
}
|
|
||||||
toRemove.add(ability);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (toRemove != null) {
|
|
||||||
for (Ability r : toRemove) {
|
|
||||||
allActions.remove(r);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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<Ability> actions);
|
||||||
|
}
|
|
@ -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<Ability> toRemove;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Inner method for filtering actions.
|
||||||
|
* Should be implemented by classes.
|
||||||
|
*
|
||||||
|
* @param game
|
||||||
|
* @param actions
|
||||||
|
*/
|
||||||
|
abstract void filter(Game game, List<Ability> actions);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Template method for optimization.
|
||||||
|
*
|
||||||
|
* @param game
|
||||||
|
* @param actions
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public final void optimize(Game game, List<Ability> 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<Ability>();
|
||||||
|
}
|
||||||
|
toRemove.add(ability);
|
||||||
|
}
|
||||||
|
}
|
|
@ -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<Ability> 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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -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<Ability> 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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
Binary file not shown.
Binary file not shown.
Loading…
Reference in a new issue