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 abb13ee7740..da899f41f40 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 @@ -63,6 +63,7 @@ import mage.target.Targets; import java.io.File; import java.util.*; import java.util.concurrent.*; +import mage.constants.AbilityType; /** * @@ -86,7 +87,8 @@ public class ComputerPlayer6 extends ComputerPlayer /*implements Player*/ { protected Set actionCache; private static final List optimizers = new ArrayList<>(); protected int lastLoggedTurn = 0; - + Random random = new Random(); + protected static final String BLANKS = "..............................................."; static { optimizers.add(new LevelUpOptimizer()); optimizers.add(new EquipOptimizer()); @@ -436,8 +438,12 @@ public class ComputerPlayer6 extends ComputerPlayer /*implements Player*/ { }); pool.execute(task); try { - logger.debug("maxThink: " + maxThink + " seconds"); - return task.get(maxThink, TimeUnit.SECONDS); + int maxSeconds = maxThink; + if (!ALLOW_INTERRUPT) { + maxSeconds = 3600; + } + logger.debug("maxThink: " + maxSeconds + " seconds "); + return task.get(maxSeconds, TimeUnit.SECONDS); } catch (TimeoutException e) { logger.info("simulating - timed out"); task.cancel(true); @@ -461,7 +467,7 @@ public class ComputerPlayer6 extends ComputerPlayer /*implements Player*/ { } Game game = node.getGame(); int val; - if (Thread.interrupted()) { + if (ALLOW_INTERRUPT && Thread.interrupted()) { Thread.currentThread().interrupt(); val = GameStateEvaluator2.evaluate(playerId, game); logger.trace("interrupted - " + val); @@ -505,7 +511,7 @@ public class ComputerPlayer6 extends ComputerPlayer /*implements Player*/ { } protected int simulatePriority(SimulationNode2 node, Game game, int depth, int alpha, int beta) { - if (Thread.interrupted()) { + if (ALLOW_INTERRUPT && Thread.interrupted()) { Thread.currentThread().interrupt(); logger.info("interrupted"); return GameStateEvaluator2.evaluate(playerId, game); @@ -522,7 +528,7 @@ public class ComputerPlayer6 extends ComputerPlayer /*implements Player*/ { int counter = 0; for (Ability action : allActions) { counter++; - if (Thread.interrupted()) { + if (ALLOW_INTERRUPT && Thread.interrupted()) { Thread.currentThread().interrupt(); logger.info("Sim Prio [" + depth + "] -- interrupted"); break; @@ -537,16 +543,24 @@ public class ComputerPlayer6 extends ComputerPlayer /*implements Player*/ { } if (!sim.gameOver(null) && action.isUsesStack()) { // only pass if the last action uses the stack - sim.getPlayer(currentPlayer.getId()).pass(game); - sim.getPlayerList().getNext(); + UUID nextPlayerId = sim.getPlayerList().get(); + do { + sim.getPlayer(nextPlayerId).pass(game); + nextPlayerId = sim.getPlayerList().getNext(); + } while (nextPlayerId != this.getId()); } SimulationNode2 newNode = new SimulationNode2(node, sim, action, depth, currentPlayer.getId()); - logger.trace(new StringBuilder("Sim Prio [").append(depth).append("]#").append(counter).append(" -- newNode (").append(action.toString()).append(") ").append(newNode.hashCode()).append(" parent node ").append(node.hashCode())); - // int testVal = GameStateEvaluator2.evaluate(currentPlayer.getId(), sim); - sim.checkStateAndTriggered(); - int val = addActions(newNode, depth - 1, alpha, beta); - + int val; + if (action instanceof PassAbility) { + // Stop to simulate deeper if PassAbility + val = GameStateEvaluator2.evaluate(this.getId(), sim); +// logger.info("evaluate = " + val ); + } else { + val = addActions(newNode, depth - 1, alpha, beta); +// logger.info("addAction = " + val ); + } + logger.debug("Sim Prio " + BLANKS.substring(0, 2 + (maxDepth-depth) * 3)+ "["+depth+"]#"+counter+" <" + val +"> - ("+action.toString()+") "+newNode.hashCode()+" parent node "+node.hashCode()); if (logger.isInfoEnabled() && depth == maxDepth) { StringBuilder sb = new StringBuilder("Sim Prio [").append(depth).append("] #").append(counter) .append(" <").append(val).append("> (").append(action) @@ -564,10 +578,10 @@ public class ComputerPlayer6 extends ComputerPlayer /*implements Player*/ { } if (currentPlayer.getId().equals(playerId)) { - if (action instanceof PassAbility) { - val = val -15; // passivity penalty + if (depth == maxDepth && action instanceof PassAbility) { + val = val - PASSIVITY_PENALTY; // passivity penalty } - if (val > alpha) { + if (val > alpha || (depth == maxDepth && val == alpha && random.nextBoolean())) { // Adding random for equal value to get change sometimes alpha = val; bestNode = newNode; bestNode.setScore(val); @@ -1311,7 +1325,7 @@ public class ComputerPlayer6 extends ComputerPlayer /*implements Player*/ { private boolean checkForRepeatedAction(Game sim, SimulationNode2 node, Ability action, UUID playerId) { // pass or casting two times a spell multiple times on hand is ok - if (action instanceof PassAbility || action instanceof SpellAbility) { + if (action instanceof PassAbility || action instanceof SpellAbility || action.getAbilityType().equals(AbilityType.MANA)) { return false; } int newVal = GameStateEvaluator2.evaluate(playerId, sim); diff --git a/Mage.Server.Plugins/Mage.Player.AI.MA/src/mage/player/ai/ComputerPlayer7.java b/Mage.Server.Plugins/Mage.Player.AI.MA/src/mage/player/ai/ComputerPlayer7.java index 4b443351f06..6c28193b776 100644 --- a/Mage.Server.Plugins/Mage.Player.AI.MA/src/mage/player/ai/ComputerPlayer7.java +++ b/Mage.Server.Plugins/Mage.Player.AI.MA/src/mage/player/ai/ComputerPlayer7.java @@ -244,7 +244,7 @@ public class ComputerPlayer7 extends ComputerPlayer6 { logger.trace("Add Action [" + depth + "] " + node.getAbilities().toString() + " a: " + alpha + " b: " + beta); } Game game = node.getGame(); - if (Thread.interrupted()) { + if (ALLOW_INTERRUPT && Thread.interrupted()) { Thread.currentThread().interrupt(); logger.debug("interrupted"); return GameStateEvaluator2.evaluate(playerId, game); @@ -349,7 +349,7 @@ public class ComputerPlayer7 extends ComputerPlayer6 { protected int simulateCombat(Game game, SimulationNode2 node, int depth, int alpha, int beta, boolean counter) { Integer val = null; - if (Thread.interrupted()) { + if (ALLOW_INTERRUPT && Thread.interrupted()) { Thread.currentThread().interrupt(); logger.debug("interrupted"); return GameStateEvaluator2.evaluate(playerId, game); @@ -395,7 +395,7 @@ public class ComputerPlayer7 extends ComputerPlayer6 { protected int simulateAttackers(Game game, SimulationNode2 node, UUID attackerId, int depth, int alpha, int beta, boolean counter) { - if (Thread.interrupted()) { + if (ALLOW_INTERRUPT && Thread.interrupted()) { Thread.currentThread().interrupt(); logger.debug("interrupted"); return GameStateEvaluator2.evaluate(playerId, game); @@ -472,7 +472,7 @@ public class ComputerPlayer7 extends ComputerPlayer6 { } protected int simulateBlockers(Game game, SimulationNode2 node, UUID defenderId, int depth, int alpha, int beta, boolean counter) { - if (Thread.interrupted()) { + if (ALLOW_INTERRUPT && Thread.interrupted()) { Thread.currentThread().interrupt(); logger.debug("interrupted"); return GameStateEvaluator2.evaluate(playerId, game); @@ -556,7 +556,7 @@ public class ComputerPlayer7 extends ComputerPlayer6 { } /*protected int simulateCounterAttack(Game game, SimulationNode2 node, int depth, int alpha, int beta) { - if (Thread.interrupted()) { + if (ALLOW_INTERRUP && Thread.interrupted()) { Thread.currentThread().interrupt(); logger.debug("interrupted"); return GameStateEvaluator2.evaluate(playerId, game); @@ -583,7 +583,7 @@ public class ComputerPlayer7 extends ComputerPlayer6 { }*/ protected void simulateStep(Game game, Step step) { - if (Thread.interrupted()) { + if (ALLOW_INTERRUPT && Thread.interrupted()) { Thread.currentThread().interrupt(); logger.debug("interrupted"); return; @@ -603,7 +603,7 @@ public class ComputerPlayer7 extends ComputerPlayer6 { } protected void finishCombat(Game game) { - if (Thread.interrupted()) { + if (ALLOW_INTERRUPT && Thread.interrupted()) { Thread.currentThread().interrupt(); logger.debug("interrupted"); return; @@ -614,7 +614,7 @@ public class ComputerPlayer7 extends ComputerPlayer6 { } protected int simulatePostCombatMain(Game game, SimulationNode2 node, int depth, int alpha, int beta) { - if (Thread.interrupted()) { + if (ALLOW_INTERRUPT && Thread.interrupted()) { Thread.currentThread().interrupt(); logger.debug("interrupted"); return GameStateEvaluator2.evaluate(playerId, game); @@ -632,7 +632,7 @@ public class ComputerPlayer7 extends ComputerPlayer6 { } protected void simulateToEnd(Game game) { - if (Thread.interrupted()) { + if (ALLOW_INTERRUPT && Thread.interrupted()) { Thread.currentThread().interrupt(); logger.debug("interrupted"); return; diff --git a/Mage.Server.Plugins/Mage.Player.AI.MA/src/mage/player/ai/SimulatedPlayer2.java b/Mage.Server.Plugins/Mage.Player.AI.MA/src/mage/player/ai/SimulatedPlayer2.java index d58a47dbaa0..40e947230c6 100644 --- a/Mage.Server.Plugins/Mage.Player.AI.MA/src/mage/player/ai/SimulatedPlayer2.java +++ b/Mage.Server.Plugins/Mage.Player.AI.MA/src/mage/player/ai/SimulatedPlayer2.java @@ -46,6 +46,7 @@ import mage.abilities.costs.mana.VariableManaCost; import mage.abilities.effects.Effect; import mage.cards.Card; import mage.choices.Choice; +import mage.constants.AbilityType; import mage.game.Game; import mage.game.combat.Combat; import mage.game.events.GameEvent; @@ -124,6 +125,9 @@ public class SimulatedPlayer2 extends ComputerPlayer { List playables = game.getPlayer(playerId).getPlayable(game, isSimulatedPlayer); playables = filterAbilities(game, playables, suggested); for (Ability ability: playables) { + if (ability.getAbilityType().equals(AbilityType.MANA)) { + continue; + } List options = game.getPlayer(playerId).getPlayableOptions(ability, game); options = filterOptions(game, options, ability, suggested); options = optimizeOptions(game, options, ability); diff --git a/Mage.Server.Plugins/Mage.Player.AI.MA/src/mage/player/ai/ma/ArtificialScoringSystem.java b/Mage.Server.Plugins/Mage.Player.AI.MA/src/mage/player/ai/ma/ArtificialScoringSystem.java index 5e5f1542bc5..4c008d09ff8 100644 --- a/Mage.Server.Plugins/Mage.Player.AI.MA/src/mage/player/ai/ma/ArtificialScoringSystem.java +++ b/Mage.Server.Plugins/Mage.Player.AI.MA/src/mage/player/ai/ma/ArtificialScoringSystem.java @@ -129,7 +129,7 @@ public class ArtificialScoringSystem { if (permanent.getCardType().contains(CardType.CREATURE)) { return -100; } else if (permanent.getCardType().contains(CardType.LAND)) { - return -1; + return -20; // means probably no mana available (should be greater than passivity penalty } else { return -2; } diff --git a/Mage.Server.Plugins/Mage.Player.AI/src/main/java/mage/player/ai/ComputerPlayer.java b/Mage.Server.Plugins/Mage.Player.AI/src/main/java/mage/player/ai/ComputerPlayer.java index df0f14580ba..2208d111554 100644 --- a/Mage.Server.Plugins/Mage.Player.AI/src/main/java/mage/player/ai/ComputerPlayer.java +++ b/Mage.Server.Plugins/Mage.Player.AI/src/main/java/mage/player/ai/ComputerPlayer.java @@ -160,6 +160,10 @@ import org.apache.log4j.Logger; public class ComputerPlayer extends PlayerImpl implements Player { private transient final static Logger log = Logger.getLogger(ComputerPlayer.class); + + protected int PASSIVITY_PENALTY = 5; // Penalty value for doing nothing if some actions are availble + protected boolean ALLOW_INTERRUPT = true; // change this for test purposes to switch off interrupts while debugging + private transient Map unplayable = new TreeMap<>(); private transient List playableNonInstant = new ArrayList<>(); private transient List playableInstant = new ArrayList<>();