From 9cd3c010fd65d54788639cc0d30f5bb3a950b10b Mon Sep 17 00:00:00 2001 From: Jeff Date: Fri, 19 Jan 2018 16:37:09 -0600 Subject: [PATCH] - Cleanup of AI classes. --- .../src/mage/player/ai/ComputerPlayer6.java | 751 +++--------------- .../src/mage/player/ai/ComputerPlayer7.java | 455 +---------- .../mage/player/ai/GameStateEvaluator2.java | 49 +- .../java/mage/player/ai/ComputerPlayer.java | 23 +- 4 files changed, 162 insertions(+), 1116 deletions(-) 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 1776806eed0..e313d6b7633 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 @@ -64,34 +64,13 @@ import mage.cards.Cards; import mage.choices.Choice; import mage.constants.AbilityType; import mage.constants.Outcome; -import mage.constants.PhaseStep; import mage.constants.RangeOfInfluence; 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.stack.StackAbility; import mage.game.stack.StackObject; -import mage.game.turn.BeginCombatStep; -import mage.game.turn.BeginningPhase; -import mage.game.turn.CleanupStep; -import mage.game.turn.CombatDamageStep; -import mage.game.turn.CombatPhase; -import mage.game.turn.DeclareAttackersStep; -import mage.game.turn.DeclareBlockersStep; -import mage.game.turn.DrawStep; -import mage.game.turn.EndOfCombatStep; -import mage.game.turn.EndPhase; -import mage.game.turn.EndStep; -import mage.game.turn.FirstCombatDamageStep; -import mage.game.turn.Phase; -import mage.game.turn.PostCombatMainPhase; -import mage.game.turn.PostCombatMainStep; -import mage.game.turn.PreCombatMainPhase; -import mage.game.turn.PreCombatMainStep; -import mage.game.turn.UntapStep; -import mage.game.turn.UpkeepStep; import mage.player.ai.ma.optimizers.TreeOptimizer; import mage.player.ai.ma.optimizers.impl.DiscardCardOptimizer; import mage.player.ai.ma.optimizers.impl.EquipOptimizer; @@ -168,63 +147,6 @@ public class ComputerPlayer6 extends ComputerPlayer /*implements Player*/ { return new ComputerPlayer6(this); } - @Override - public boolean priority(Game game) { - logState(game); - game.getState().setPriorityPlayerId(playerId); - game.firePriorityEvent(playerId); - switch (game.getTurn().getStepType()) { - case UPKEEP: - case DRAW: - pass(game); - return false; - case PRECOMBAT_MAIN: - case POSTCOMBAT_MAIN: - if (game.getActivePlayerId().equals(playerId)) { - if (logger.isInfoEnabled()) { - printOutState(game); - } - if (actions.isEmpty()) { - calculateActions(game); - } - act(game); - return true; - } else { - pass(game); - } - return false; - case BEGIN_COMBAT: - case FIRST_COMBAT_DAMAGE: - case COMBAT_DAMAGE: - case END_COMBAT: - pass(game); - return false; - case DECLARE_ATTACKERS: - if (game.getActivePlayerId().equals(playerId)) { - //declareAttackers(game, playerId); - pass(game); - } else { - pass(game); - } - return false; - case DECLARE_BLOCKERS: - if (!game.getActivePlayerId().equals(playerId)) { - declareBlockers(game, playerId); - pass(game); - } else { - pass(game); - } - return false; - case END_TURN: - pass(game); - return false; - case CLEANUP: - pass(game); - return false; - } - return false; - } - protected void printOutState(Game game) { if (logger.isInfoEnabled()) { printOutState(game, playerId); @@ -265,7 +187,8 @@ public class ComputerPlayer6 extends ComputerPlayer /*implements Player*/ { } protected void act(Game game) { - if (actions == null || actions.isEmpty()) { + if (actions == null + || actions.isEmpty()) { pass(game); } else { boolean usedStack = false; @@ -309,36 +232,105 @@ public class ComputerPlayer6 extends ComputerPlayer /*implements Player*/ { } } - protected void calculateActions(Game game) { - if (!getNextAction(game)) { - Game sim = createSimulation(game); - SimulationNode2.resetCount(); - root = new SimulationNode2(null, sim, maxDepth, playerId); - logger.info("simulating actions"); - //int bestScore = addActionsTimed(new FilterAbility()); - currentScore = GameStateEvaluator2.evaluate(playerId, game); - addActionsTimed(); - if (!root.children.isEmpty()) { - root = root.children.get(0); - //GameStateEvaluator2.evaluate(playerId, root.getGame()); - int bestScore = root.getScore(); - //if (bestScore > currentScore) { - actions = new LinkedList<>(root.abilities); - combat = root.combat; - //} else { - //System.out.println("[" + game.getPlayer(playerId).getName() + "] Action: not better score"); - //} + protected int addActions(SimulationNode2 node, int depth, int alpha, int beta) { + boolean stepFinished = false; + int val; + if (logger.isTraceEnabled() + && node != null + && node.getAbilities() != null + && !node.getAbilities().toString().equals("[Pass]")) { + logger.trace("Add Action [" + depth + "] " + node.getAbilities().toString() + " a: " + alpha + " b: " + beta); + } + Game game = node.getGame(); + if (ALLOW_INTERRUPT + && Thread.interrupted()) { + Thread.currentThread().interrupt(); + logger.debug("interrupted"); + return GameStateEvaluator2.evaluate(playerId, game); + } + // Condition to stop deeper simulation + if (depth <= 0 + || SimulationNode2.nodeCount > maxNodes + || game.checkIfGameIsOver()) { + val = GameStateEvaluator2.evaluate(playerId, game); + if (logger.isTraceEnabled()) { + StringBuilder sb = new StringBuilder("Add Actions -- reached end state <").append(val).append('>'); + SimulationNode2 logNode = node; + do { + sb.append(new StringBuilder(" <- [" + logNode.getDepth() + ']' + (logNode.getAbilities() != null ? logNode.getAbilities().toString() : "[empty]"))); + logNode = logNode.getParent(); + } while ((logNode.getParent() != null)); + logger.trace(sb); + } + } else if (!node.getChildren().isEmpty()) { + if (logger.isDebugEnabled()) { + StringBuilder sb = new StringBuilder("Add Action [").append(depth) + .append("] -- something added children ") + .append(node.getAbilities() != null ? node.getAbilities().toString() : "null") + .append(" added children: ").append(node.getChildren().size()).append(" ("); + for (SimulationNode2 logNode : node.getChildren()) { + sb.append(logNode.getAbilities() != null ? logNode.getAbilities().toString() : "null").append(", "); + } + sb.append(')'); + logger.debug(sb); + } + val = minimaxAB(node, depth - 1, alpha, beta); + } else { + logger.trace("Add Action -- alpha: " + alpha + " beta: " + beta + " depth:" + depth + " step:" + game.getTurn().getStepType() + " for player:" + game.getPlayer(game.getPlayerList().get()).getName()); + if (allPassed(game)) { + if (!game.getStack().isEmpty()) { + resolve(node, depth, game); + } else { + stepFinished = true; + } + } + + if (game.checkIfGameIsOver()) { + val = GameStateEvaluator2.evaluate(playerId, game); + } else if (stepFinished) { + logger.debug("Step finished"); + int testScore = GameStateEvaluator2.evaluate(playerId, game); + if (game.getActivePlayerId().equals(playerId)) { + if (testScore < currentScore) { + // if score at end of step is worse than original score don't check further + //logger.debug("Add Action -- abandoning check, no immediate benefit"); + val = testScore; + } else { + val = GameStateEvaluator2.evaluate(playerId, game); + } + } else { + val = GameStateEvaluator2.evaluate(playerId, game); + } + } else if (!node.getChildren().isEmpty()) { + if (logger.isDebugEnabled()) { + StringBuilder sb = new StringBuilder("Add Action [").append(depth) + .append("] -- trigger ") + .append(node.getAbilities() != null ? node.getAbilities().toString() : "null") + .append(" added children: ").append(node.getChildren().size()).append(" ("); + for (SimulationNode2 logNode : node.getChildren()) { + sb.append(logNode.getAbilities() != null ? logNode.getAbilities().toString() : "null").append(", "); + } + sb.append(')'); + logger.debug(sb); + } + val = minimaxAB(node, depth - 1, alpha, beta); } else { - logger.info('[' + game.getPlayer(playerId).getName() + "] Action: skip Root.score = " + root.getScore() + " currentScore = " + currentScore); + val = simulatePriority(node, game, depth, alpha, beta); } } + node.setScore(val); + logger.trace("returning -- score: " + val + " depth:" + depth + " step:" + game.getTurn().getStepType() + " for player:" + game.getPlayer(node.getPlayerId()).getName()); + return val; + } protected boolean getNextAction(Game game) { - if (root != null && !root.children.isEmpty()) { + if (root != null + && !root.children.isEmpty()) { SimulationNode2 test = root; root = root.children.get(0); - while (!root.children.isEmpty() && !root.playerId.equals(playerId)) { + while (!root.children.isEmpty() + && !root.playerId.equals(playerId)) { test = root; root = root.children.get(0); } @@ -346,20 +338,9 @@ public class ComputerPlayer6 extends ComputerPlayer /*implements Player*/ { if (!suggested.isEmpty()) { return false; } - if (root.playerId.equals(playerId) && root.abilities != null && game.getState().getValue(true).hashCode() == test.gameValue) { - - /* - * // Try to fix horizon effect if (root.combat == null || - * root.combat.getAttackers().isEmpty()) { - * FilterCreatureForAttack attackFilter = new - * FilterCreatureForAttack(); - * attackFilter.getControllerId().add(playerId); List - * attackers = - * game.getBattlefield().getAllActivePermanents(attackFilter); - * if (attackers.size() > 0) { // we have attackers but don't - * attack with any of them // let's try once again to avoid - * possible horizon effect return false; } } - */ + if (root.playerId.equals(playerId) + && root.abilities != null + && game.getState().getValue(true).hashCode() == test.gameValue) { logger.info("simulating -- continuing previous action chain"); actions = new LinkedList<>(root.abilities); combat = root.combat; @@ -378,11 +359,9 @@ public class ComputerPlayer6 extends ComputerPlayer /*implements Player*/ { for (SimulationNode2 child : node.getChildren()) { Combat _combat = child.getCombat(); if (alpha >= beta) { - //logger.info("alpha beta pruning"); break; } if (SimulationNode2.nodeCount > maxNodes) { - //logger.info("simulating -- reached end-state, count=" + SimulationNode2.nodeCount); break; } int val = addActions(child, depth - 1, alpha, beta); @@ -421,10 +400,8 @@ public class ComputerPlayer6 extends ComputerPlayer /*implements Player*/ { node.children.add(bestChild); } if (!currentPlayerId.equals(playerId)) { - //logger.info("returning minimax beta: " + beta); return beta; } else { - //logger.info("returning minimax alpha: " + alpha); return alpha; } } @@ -442,7 +419,8 @@ public class ComputerPlayer6 extends ComputerPlayer /*implements Player*/ { StackObject stackObject = game.getStack().getFirst(); if (stackObject instanceof StackAbility) { SearchEffect effect = getSearchEffect((StackAbility) stackObject); - if (effect != null && stackObject.getControllerId().equals(playerId)) { + if (effect != null + && stackObject.getControllerId().equals(playerId)) { Target target = effect.getTarget(); if (!target.doneChosing()) { for (UUID targetId : target.possibleTargets(stackObject.getSourceId(), stackObject.getControllerId(), game)) { @@ -460,7 +438,6 @@ public class ComputerPlayer6 extends ComputerPlayer /*implements Player*/ { } } } - //logger.info("simulating resolve "); stackObject.resolve(game); if (stackObject instanceof StackAbility) { game.getStack().remove(stackObject); @@ -509,75 +486,29 @@ public class ComputerPlayer6 extends ComputerPlayer /*implements Player*/ { return 0; } - protected int addActions(SimulationNode2 node, int depth, int alpha, int beta) { - if (logger.isInfoEnabled() && node != null && node.getAbilities() != null && !node.getAbilities().toString().equals("[Pass]")) { - logger.info("Add actions [" + depth + "] " + (node.getAbilities().toString() + " -- a: " + alpha + " b: " + beta)); - } - Game game = node.getGame(); - int val; - if (ALLOW_INTERRUPT && Thread.interrupted()) { - Thread.currentThread().interrupt(); - val = GameStateEvaluator2.evaluate(playerId, game); - logger.trace("interrupted - " + val); - return val; - } - if (depth <= 0 || SimulationNode2.nodeCount > maxNodes || game.checkIfGameIsOver()) { - logger.trace("Add actions -- reached end state, node count=" + SimulationNode2.nodeCount + ", depth=" + depth); - val = GameStateEvaluator2.evaluate(playerId, game); - UUID currentPlayerId = node.getGame().getPlayerList().get(); - //logger.info("reached - " + val + ", playerId=" + playerId + ", node.pid="+currentPlayerId); - return val; - } else if (!node.getChildren().isEmpty()) { - logger.trace("Add actions -- something added children:" + node.getChildren().size()); - val = minimaxAB(node, depth - 1, alpha, beta); - return val; - } else { - logger.trace("Add actions -- alpha: " + alpha + " beta: " + beta + " depth:" + depth + " step:" + game.getTurn().getStepType() + " for player:" + (node.getPlayerId().equals(playerId) ? "yes" : "no")); - if (allPassed(game)) { - if (!game.getStack().isEmpty()) { - resolve(node, depth, game); - } else { - game.getPlayers().resetPassed(); - playNext(game, game.getActivePlayerId(), node); - } - } - - if (game.checkIfGameIsOver()) { - val = GameStateEvaluator2.evaluate(playerId, game); - } else if (!node.getChildren().isEmpty()) { - //declared attackers or blockers or triggered abilities - logger.debug("Add actions -- attack/block/trigger added children:" + node.getChildren().size()); - val = minimaxAB(node, depth - 1, alpha, beta); - } else { - val = simulatePriority(node, game, depth, alpha, beta); - } - } - - logger.trace("returning -- score: " + val + " depth:" + depth + " step:" + game.getTurn().getStepType() + " for player:" + game.getPlayer(node.getPlayerId()).getName()); - return val; - - } - protected int simulatePriority(SimulationNode2 node, Game game, int depth, int alpha, int beta) { - if (ALLOW_INTERRUPT && Thread.interrupted()) { + if (ALLOW_INTERRUPT + && Thread.interrupted()) { Thread.currentThread().interrupt(); logger.info("interrupted"); return GameStateEvaluator2.evaluate(playerId, game); } node.setGameValue(game.getState().getValue(true).hashCode()); SimulatedPlayer2 currentPlayer = (SimulatedPlayer2) game.getPlayer(game.getPlayerList().get()); - //logger.info("Sim Prio -- player " + currentPlayer.getName()); SimulationNode2 bestNode = null; List allActions = currentPlayer.simulatePriority(game); optimize(game, allActions); - if (logger.isInfoEnabled() && !allActions.isEmpty() && depth == maxDepth) { + if (logger.isInfoEnabled() + && !allActions.isEmpty() + && depth == maxDepth) { logger.info("ADDED ACTIONS (" + allActions.size() + ") " + ' ' + allActions); } int counter = 0; int bestValSubNodes = Integer.MIN_VALUE; for (Ability action : allActions) { counter++; - if (ALLOW_INTERRUPT && Thread.interrupted()) { + if (ALLOW_INTERRUPT + && Thread.interrupted()) { Thread.currentThread().interrupt(); logger.info("Sim Prio [" + depth + "] -- interrupted"); break; @@ -590,7 +521,8 @@ public class ComputerPlayer6 extends ComputerPlayer /*implements Player*/ { logger.debug("Sim Prio [" + depth + "] -- repeated action: " + action.toString()); continue; } - if (!sim.checkIfGameIsOver() && action.isUsesStack()) { + if (!sim.checkIfGameIsOver() + && action.isUsesStack()) { // only pass if the last action uses the stack UUID nextPlayerId = sim.getPlayerList().get(); do { @@ -604,21 +536,23 @@ public class ComputerPlayer6 extends ComputerPlayer /*implements Player*/ { 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.debug("Sim Prio " + BLANKS.substring(0, 2 + (maxDepth - depth) * 3) + '[' + depth + "]#" + counter + " <" + val + "> - (" + action.toString() + ") "); - if (logger.isInfoEnabled() && depth >= maxDepth) { + if (logger.isInfoEnabled() + && depth >= maxDepth) { StringBuilder sb = new StringBuilder("Sim Prio [").append(depth).append("] #").append(counter) .append(" <").append(val).append("> (").append(action) .append(action.isModal() ? " Mode = " + action.getModes().getMode().toString() : "") .append(listTargets(game, action.getTargets())).append(')') .append(logger.isTraceEnabled() ? " #" + newNode.hashCode() : ""); SimulationNode2 logNode = newNode; - while (logNode.getChildren() != null && !logNode.getChildren().isEmpty()) { + while (logNode.getChildren() != null + && !logNode.getChildren().isEmpty()) { logNode = logNode.getChildren().get(0); - if (logNode.getAbilities() != null && !logNode.getAbilities().isEmpty()) { + if (logNode.getAbilities() != null + && !logNode.getAbilities().isEmpty()) { sb.append(" -> [").append(logNode.getDepth()).append(']').append(logNode.getAbilities().toString()).append('<').append(logNode.getScore()).append('>'); } } @@ -629,21 +563,20 @@ public class ComputerPlayer6 extends ComputerPlayer /*implements Player*/ { if (val > bestValSubNodes) { bestValSubNodes = val; } - if (depth == maxDepth && action instanceof PassAbility) { + if (depth == maxDepth + && action instanceof PassAbility) { val = val - PASSIVITY_PENALTY; // passivity penalty } - if (val > alpha || (depth == maxDepth && val == alpha && RandomUtil.nextBoolean())) { // Adding random for equal value to get change sometimes + if (val > alpha + || (depth == maxDepth + && val == alpha + && RandomUtil.nextBoolean())) { // Adding random for equal value to get change sometimes alpha = val; bestNode = newNode; bestNode.setScore(val); if (!newNode.getChildren().isEmpty()) { bestNode.setCombat(newNode.getChildren().get(0).getCombat()); } - /* - * if (node.getTargets().size() > 0) targets = - * node.getTargets(); if (node.getChoices().size() > 0) - * choices = node.getChoices(); - */ if (depth == maxDepth) { logger.info("Sim Prio [" + depth + "] -- Saved best node yet <" + bestNode.getScore() + "> " + bestNode.getAbilities().toString()); node.children.clear(); @@ -674,7 +607,6 @@ public class ComputerPlayer6 extends ComputerPlayer /*implements Player*/ { } } if (alpha >= beta) { - //logger.info("Sim Prio -- pruning"); break; } if (SimulationNode2.nodeCount > maxNodes) { @@ -683,6 +615,7 @@ public class ComputerPlayer6 extends ComputerPlayer /*implements Player*/ { } } } // end of for (allActions) + if (depth == maxDepth) { logger.info(new StringBuilder("Sim Prio [").append(depth).append("] -- End for Max Depth -- Nodes calculated: ").append(SimulationNode2.nodeCount)); } @@ -690,26 +623,15 @@ public class ComputerPlayer6 extends ComputerPlayer /*implements Player*/ { node.children.clear(); node.children.add(bestNode); node.setScore(bestNode.getScore()); - if (logger.isTraceEnabled() && !bestNode.getAbilities().toString().equals("[Pass]")) { + if (logger.isTraceEnabled() + && !bestNode.getAbilities().toString().equals("[Pass]")) { logger.trace(new StringBuilder("Sim Prio [").append(depth).append("] -- Set after (depth=").append(depth).append(") <").append(bestNode.getScore()).append("> ").append(bestNode.getAbilities().toString()).toString()); } } if (currentPlayer.getId().equals(playerId)) { - /* - * if (alpha == Integer.MIN_VALUE) { int val = - * GameStateEvaluator2.evaluate(playerId, game); - * logger.info("returning priority beta: " + val); return val; - } - */ - //logger.info("returning priority alpha: " + alpha); return bestValSubNodes; } else { -// if (beta == Integer.MAX_VALUE) { -// int val = GameStateEvaluator2.evaluate(playerId, game); -// logger.info("returning priority beta: " + val); -// return val; -// } return beta; } } @@ -754,7 +676,9 @@ public class ComputerPlayer6 extends ComputerPlayer /*implements Player*/ { protected boolean allPassed(Game game) { for (Player player : game.getPlayers().values()) { - if (!player.isPassed() && !player.hasLost() && !player.hasLeft()) { + if (!player.isPassed() + && !player.hasLost() + && !player.hasLeft()) { return false; } } @@ -767,7 +691,7 @@ public class ComputerPlayer6 extends ComputerPlayer /*implements Player*/ { return super.choose(outcome, choice, game); } if (!choice.isChosen()) { - if(!choice.setChoiceByAnswers(choices, true)){ + if (!choice.setChoiceByAnswers(choices, true)) { choice.setRandomChoice(); } } @@ -810,81 +734,6 @@ public class ComputerPlayer6 extends ComputerPlayer /*implements Player*/ { return true; } - public void playNext(Game game, UUID activePlayerId, SimulationNode2 node) { - boolean skip = false; - while (true) { - Phase currentPhase = game.getPhase(); - if (!skip) { - currentPhase.getStep().endStep(game, activePlayerId); - } - game.applyEffects(); - switch (currentPhase.getStep().getType()) { - case UNTAP: - game.getPhase().setStep(new UpkeepStep()); - break; - case UPKEEP: - game.getPhase().setStep(new DrawStep()); - break; - case DRAW: - game.getTurn().setPhase(new PreCombatMainPhase()); - game.getPhase().setStep(new PreCombatMainStep()); - break; - case PRECOMBAT_MAIN: - game.getTurn().setPhase(new CombatPhase()); - game.getPhase().setStep(new BeginCombatStep()); - break; - case BEGIN_COMBAT: - game.getPhase().setStep(new DeclareAttackersStep()); - break; - case DECLARE_ATTACKERS: - game.getPhase().setStep(new DeclareBlockersStep()); - break; - case DECLARE_BLOCKERS: - game.getPhase().setStep(new FirstCombatDamageStep()); - break; - case FIRST_COMBAT_DAMAGE: - game.getPhase().setStep(new CombatDamageStep()); - break; - case COMBAT_DAMAGE: - game.getPhase().setStep(new EndOfCombatStep()); - break; - case END_COMBAT: - game.getTurn().setPhase(new PostCombatMainPhase()); - game.getPhase().setStep(new PostCombatMainStep()); - break; - case POSTCOMBAT_MAIN: - game.getTurn().setPhase(new EndPhase()); - game.getPhase().setStep(new EndStep()); - break; - case END_TURN: - game.getPhase().setStep(new CleanupStep()); - break; - case CLEANUP: - game.getPhase().getStep().beginStep(game, activePlayerId); - if (!game.checkStateAndTriggered() && !game.checkIfGameIsOver()) { - game.getState().setActivePlayerId(game.getState().getPlayerList(game.getActivePlayerId()).getNext()); - game.getTurn().setPhase(new BeginningPhase()); - game.getPhase().setStep(new UntapStep()); - } - } - if (!game.getStep().skipStep(game, game.getActivePlayerId())) { - if (game.getTurn().getStepType() == PhaseStep.DECLARE_ATTACKERS) { - declareAttackers(game, activePlayerId, node); - } else if (game.getTurn().getStepType() == PhaseStep.DECLARE_BLOCKERS) { - declareBlockers(game, activePlayerId, node); - } else { - game.getStep().beginStep(game, activePlayerId); - } - if (game.getStep().getHasPriority()) { - break; - } - } else { - skip = true; - } - } - game.checkStateAndTriggered(); - } - private void declareBlockers(Game game, UUID activePlayerId) { game.fireEvent(new GameEvent(GameEvent.EventType.DECLARE_BLOCKERS_STEP_PRE, null, null, activePlayerId)); if (!game.replaceEvent(GameEvent.getEvent(GameEvent.EventType.DECLARING_BLOCKERS, activePlayerId, activePlayerId))) { @@ -906,9 +755,8 @@ public class ComputerPlayer6 extends ComputerPlayer /*implements Player*/ { CombatUtil.sortByPower(attackers, false); - //this is where my code goes CombatInfo combatInfo = CombatUtil.blockWithGoodTrade2(game, attackers, possibleBlockers); - Player player = game.getPlayer(this.playerId); + Player player = game.getPlayer(playerId); boolean blocked = false; for (Map.Entry> entry : combatInfo.getCombat().entrySet()) { @@ -921,11 +769,9 @@ public class ComputerPlayer6 extends ComputerPlayer /*implements Player*/ { } } } - if (blocked) { game.getPlayers().resetPassed(); } - } } @@ -966,31 +812,6 @@ public class ComputerPlayer6 extends ComputerPlayer /*implements Player*/ { return attackers; } - private void declareBlockers(Game game, UUID activePlayerId, SimulationNode2 node) { - game.fireEvent(new GameEvent(GameEvent.EventType.DECLARE_BLOCKERS_STEP_PRE, null, null, activePlayerId)); - if (!game.replaceEvent(GameEvent.getEvent(GameEvent.EventType.DECLARING_BLOCKERS, activePlayerId, activePlayerId))) { - /* - * for (UUID defenderId: game.getCombat().getDefenders()) { //check - * if defender is being attacked if - * (game.getCombat().isAttacked(defenderId, game)) { for (Combat - * engagement: - * ((SimulatedPlayer2)game.getPlayer(defenderId)).addBlockers(game)) - * { Game sim = game.copy(); for (CombatGroup group: - * engagement.getGroups()) { List blockers = new - * ArrayList(); blockers.addAll(group.getBlockers()); for - * (UUID blockerId: blockers) { group.addBlocker(blockerId, - * defenderId, sim); } blockers = null; } - * sim.fireEvent(GameEvent.getEvent(GameEvent.EventType.DECLARED_BLOCKERS, - * playerId, playerId)); SimulationNode2 newNode = new - * SimulationNode2(node, sim, node.getDepth()-1, defenderId); - * logger.debug("simulating -- node #:" + SimulationNode2.getCount() - * + " declare blockers"); newNode.setCombat(sim.getCombat()); - * node.children.add(newNode); } } - } - */ - } - } - /** * Choose attackers based on static information. That means that AI won't * look to the future as it was before, but just choose attackers based on @@ -1015,22 +836,8 @@ public class ComputerPlayer6 extends ComputerPlayer /*implements Player*/ { return; } - logger.debug("Declare Attackers: Number of potential attackers " + attackersList.size()); - for (Permanent attacker : attackersList) { - logger.debug(" Potential attacker: " + attacker.getName()); - } - - if (attackersList.isEmpty()) { - return; - } - List possibleBlockers = defender.getAvailableBlockers(game); - logger.debug("Possible Blockers: Number of blockers " + possibleBlockers.size()); - for (Permanent blocker : possibleBlockers) { - logger.debug(" Blocker: " + blocker.getName()); - } - List killers = CombatUtil.canKillOpponent(game, attackersList, possibleBlockers, defender); if (!killers.isEmpty()) { for (Permanent attacker : killers) { @@ -1039,118 +846,6 @@ public class ComputerPlayer6 extends ComputerPlayer /*implements Player*/ { return; } - //CombatUtil.handleExalted(); - //TODO: refactor -- extract to method - //List counterAttackList = new ArrayList(); - //int counterAttackDamage = 0; - //int defenderForces = 0; - //int defenderForcesForBlock = 0; -/* - * FilterCreatureForCombat filter = new FilterCreatureForCombat(); - * for (Permanent possibleAttacker : - * game.getBattlefield().getAllActivePermanents(filter, - * defender.getId(), game)) { //TODO: it can be improved with next - * turn emulation if - * (!possibleAttacker.getAbilities().contains(DefenderAbility.getInstance())) - * { counterAttackList.add(possibleAttacker); if - * (possibleAttacker.getPower().getValue() > 0) { // TODO: DB and - * infect counterAttackDamage += - * possibleAttacker.getPower().getValue(); defenderForces++; } if - * (CombatUtil.canBlock(game, possibleAttacker)) { - * defenderForcesForBlock++; } } } - * - * double oppScore = 1000000; if (counterAttackDamage > 0) { - * oppScore = (double) attackingPlayer.getLife() / - * counterAttackDamage; } - * - * List possibleAttackersList = new - * ArrayList(); int possibleAttackersDamage = 0; int - * ourForces = 0; - * - * for (Permanent possibleAttacker : - * game.getBattlefield().getAllActivePermanents(filter, playerId, - * game)) { //TODO: it can be improved with next turn emulation if - * (!possibleAttacker.getAbilities().contains(DefenderAbility.getInstance())) - * { possibleAttackersList.add(possibleAttacker); - * - * if (possibleAttacker.getPower().getValue() > 0) { // TODO: DB and - * infect possibleAttackersDamage += - * possibleAttacker.getPower().getValue(); ourForces++; } } } - * - * double ourScore = 1000000; if (possibleAttackersDamage > 0) { - * ourScore = (double) defender.getLife() / possibleAttackersDamage; - * } - * - * int outNumber = ourForces - defenderForces; - * - * double score = ourScore - oppScore; - * - * boolean doAttack = false; - * - * //attackersList CombatUtil.sortByPower(attackersList, false); int - * opponentLife = defender.getLife(); - * - * List notBlockedAttackers = new ArrayList(); - * for (int i = 0; i < (attackersList.size() - defenderForces); i++) - * { notBlockedAttackers.add(attackersList.get(i)); } - * - * int attackRound = 1; while (notBlockedAttackers.size() > 0 && - * opponentLife > 0 && attackRound < 99) { int damageThisRound = 0; - * for (Permanent attacker : notBlockedAttackers) { damageThisRound - * += attacker.getPower().getValue(); } opponentLife -= - * damageThisRound; for (int i = 0; i < defenderForcesForBlock && - * !notBlockedAttackers.isEmpty(); i++) { - * notBlockedAttackers.remove(notBlockedAttackers.size() - 1); } - * attackRound++; if (opponentLife <= 0) { doAttack = true; } } - * - * double unblockableDamage = 0; double turnsUntilDeathByUnblockable - * = 0; boolean doUnblockableAttack = false; for (Permanent attacker - * : attackersList) { boolean isUnblockableCreature = true; for - * (Permanent blocker : possibleBlockers) { if - * (blocker.canBlock(attacker.getId(), game)) { - * isUnblockableCreature = false; } } if (isUnblockableCreature) { - * unblockableDamage += attacker.getPower().getValue(); } } if - * (unblockableDamage > 0) { turnsUntilDeathByUnblockable = - * defender.getLife() / unblockableDamage; } if (unblockableDamage > - * defender.getLife()) { doUnblockableAttack = true; } - * - * int aggressionRate = 5; //aggressionRate = - * getAggressionRate(oppScore, ourScore, outNumber, score, doAttack, - * turnsUntilDeathByUnblockable, doUnblockableAttack, - * aggressionRate); System.out.println("AI aggression = " + - * String.valueOf(aggressionRate)); - * - * - * System.out.println("AI attackers size: " + attackersList.size()); - * - * List finalAttackers = new ArrayList(); for - * (int i = 0; i < attackersList.size(); i++) { Permanent attacker = - * attackersList.get(i); int totalFirstStrikeBlockPower = 0; - * - * if - * (!attacker.getAbilities().contains(FirstStrikeAbility.getInstance()) - * && - * !attacker.getAbilities().contains(DoubleStrikeAbility.getInstance())) - * { for (Permanent blockerWithFSorDB : - * game.getBattlefield().getAllActivePermanents(filter, playerId, - * game)) { if - * (blockerWithFSorDB.getAbilities().contains(DoubleStrikeAbility.getInstance())) - * { totalFirstStrikeBlockPower += 2 * - * blockerWithFSorDB.getPower().getValue(); } else if - * (blockerWithFSorDB.getAbilities().contains(FirstStrikeAbility.getInstance())) - * { totalFirstStrikeBlockPower += - * blockerWithFSorDB.getPower().getValue(); } } - * - * } - * - * boolean shouldAttack = shouldAttack(game, - * attackingPlayer.getId(), defenderId, attacker, possibleBlockers, - * aggressionRate); - * - * if (aggressionRate == 5 || shouldAttack && - * (totalFirstStrikeBlockPower < attacker.getToughness().getValue()) - * ) { finalAttackers.add(attacker); } } - */ // The AI will now attack more sanely. Simple, but good enough for now. // The sim minmax does not work at the moment. boolean safeToAttack; @@ -1200,150 +895,16 @@ public class ComputerPlayer6 extends ComputerPlayer /*implements Player*/ { } } - /* - * private boolean shouldAttack(Game game, UUID attackingPlayerId, UUID - * defenderId, Permanent attacker, List blockers, int - * aggressionRate) { boolean canBeKilledByOne = false; boolean canKillAll = - * true; boolean canKillAllDangerous = true; - * - * boolean isWorthLessThanAllKillers = true; boolean canBeBlocked = false; - * int numberOfPossibleBlockers = 0; - * - * //int life = game.getPlayer(defenderId).getLife(); //int poison = - * game.getPlayer(defenderId).getCounters().getCount(CounterType.POISON); - * - * if (!isEffectiveAttacker(game, attackingPlayerId, defenderId, attacker, - * life, poison)) { System.out.println("Ahh, this is why it is not - * attacking"); return false; } - * - * for (Permanent defender : blockers) { System.out.println("The blocker is - * " + defender.getName()); if (defender.canBlock(attacker.getId(), game)) { - * System.out.println("The blocker can block the attacker" + - * defender.getName() + attacker.getName()); numberOfPossibleBlockers += 1; - * System.out.println("The number of possible blockers is " + - * numberOfPossibleBlockers); SurviveInfo info = - * CombatUtil.willItSurvive(game, attackingPlayerId, defenderId, attacker, - * defender); System.out.println("Did the attacker die? " + - * info.isAttackerDied()); if (info.isAttackerDied()) { boolean - * canBeReallyKilled = true; for (Ability ability : attacker.getAbilities()) - * { if (ability instanceof UndyingAbility) { if - * (attacker.getCounters().getCount(CounterType.P1P1) == 0) { - * canBeReallyKilled = false; } } } - * - * if (canBeReallyKilled) { canBeKilledByOne = true; if - * (GameStateEvaluator2.evaluateCreature(defender, game) <= - * GameStateEvaluator2.evaluateCreature(attacker, game)) { - * isWorthLessThanAllKillers = false; } } } // see if this attacking - * creature can destroy this defender, if // not record that it can't kill - * everything if (info.isBlockerDied()) { canKillAll = false; if - * (defender.getAbilities().contains(WitherAbility.getInstance()) || - * defender.getAbilities().contains(InfectAbility.getInstance())) { - * canKillAllDangerous = false; } } } } - * - * if (canKillAll && !CombatUtil.canBlock(game, attacker) && - * isWorthLessThanAllKillers) { System.out.println(attacker.getName() + " = - * attacking because they can't block, expecting to kill or damage player"); - * return true; } - * - * if (numberOfPossibleBlockers >= 1) { canBeBlocked = true; } - * - * // This is how I know this does quite work. Something is wrong with the - * sim part. System.out.println("canKillAll, canKillAllDangerous, - * canbeKilledByOne, canBeBlocked " + canKillAll + canKillAllDangerous + - * canBeKilledByOne + canBeBlocked); - * - * switch (aggressionRate) { case 4: if (canKillAll || (canKillAllDangerous - * && !canBeKilledByOne) || !canBeBlocked) { - * System.out.println(attacker.getName() + " = attacking expecting to at - * least trade with something"); return true; } case 3: if ((canKillAll && - * isWorthLessThanAllKillers) || (canKillAllDangerous && !canBeKilledByOne) - * || !canBeBlocked) { System.out.println(attacker.getName() + " = attacking - * expecting to kill creature or cause damage, or is unblockable"); return - * true; } case 2: if ((canKillAll && !canBeKilledByOne) || !canBeBlocked) { - * System.out.println(attacker.getName() + " = attacking expecting to - * survive or attract group block"); return true; } case 1: if - * (!canBeBlocked) { System.out.println(attacker.getName() + " = attacking - * expecting not to be blocked"); return true; } default: break; } - * - * return false; } - * - * private boolean isEffectiveAttacker(Game game, UUID attackingPlayerId, - * UUID defenderId, Permanent attacker, int life, int poison) { try { - * SurviveInfo info = CombatUtil.getCombatInfo(game, attackingPlayerId, - * defenderId, attacker); if (info.isAttackerDied()) { return false; } - * - * if (info.getDefender().getLife() < life) { return true; } - * - * if (info.getDefender().getCounters().getCount(CounterType.POISON) > - * poison && poison < 10) { return true; } - * - * if (info.isTriggered()) { return true; } } catch (Exception e) { // - * swallow exception and return false logger.error(e); return false; } - * - * return false; } - * - * private int getAggressionRate(double oppScore, double ourScore, int - * outNumber, double score, boolean doAttack, double - * turnsUntilDeathByUnblockable, boolean doUnblockableAttack, int - * aggressionRate) { if (score > 0 && doAttack) { aggressionRate = 5; } else - * if (((ourScore < 2) && score >= 0) || (score > 3) || (score > 0 && - * outNumber > 0)) { aggressionRate = 3; } else if (score >= 0 || (score + - * outNumber >= -1)) { aggressionRate = 2; } else if (score < 0 && oppScore - * > 1) { aggressionRate = 2; } else if (doUnblockableAttack || score * -1 < - * turnsUntilDeathByUnblockable) { aggressionRate = 2; } else if (score < 0) - * { aggressionRate = 1; } return aggressionRate; } - */ - - private void declareAttackers(Game game, UUID activePlayerId, SimulationNode2 node) { - game.fireEvent(new GameEvent(GameEvent.EventType.DECLARE_ATTACKERS_STEP_PRE, null, null, activePlayerId)); - if (!game.replaceEvent(GameEvent.getEvent(GameEvent.EventType.DECLARING_ATTACKERS, activePlayerId, activePlayerId))) { - for (Combat engagement : ((SimulatedPlayer2) game.getPlayer(activePlayerId)).addAttackers(game)) { - Game sim = game.copy(); - UUID defenderId = game.getOpponents(playerId).iterator().next(); - for (CombatGroup group : engagement.getGroups()) { - for (UUID attackerId : group.getAttackers()) { - sim.getPlayer(activePlayerId).declareAttacker(attackerId, defenderId, sim, false); - } - } - sim.fireEvent(GameEvent.getEvent(GameEvent.EventType.DECLARED_ATTACKERS, playerId, playerId)); - SimulationNode2 newNode = new SimulationNode2(node, sim, node.getDepth() - 1, activePlayerId); - logger.debug("simulating -- node #:" + SimulationNode2.getCount() + " declare attakers"); - newNode.setCombat(sim.getCombat()); - node.children.add(newNode); - } - } - } - @Override public void selectAttackers(Game game, UUID attackingPlayerId) { logger.debug("selectAttackers"); declareAttackers(game, playerId); - /* - * if (combat != null) { UUID opponentId = - * game.getCombat().getDefenders().iterator().next(); String attackers = - * ""; for (UUID attackerId: combat.getAttackers()) { Permanent attacker - * = game.getPermanent(attackerId); if (attacker != null) { attackers = - * "[" + attacker.getName() + "]"; this.declareAttacker(attackerId, - * opponentId, game); } } logger.info("declare attackers: " + - * (attackers.isEmpty() ? "none" : attackers)); - } - */ - } @Override public void selectBlockers(Game game, UUID defendingPlayerId) { logger.debug("selectBlockers"); declareBlockers(game, playerId); - /* - * if (combat != null && combat.getGroups().size() > 0) { - * List groups = game.getCombat().getGroups(); for (int i = - * 0; i < groups.size(); i++) { if (i < combat.getGroups().size()) { for - * (UUID blockerId: combat.getGroups().get(i).getBlockers()) { - * logger.info("select blocker: " + blockerId + " vs " + - * groups.get(i).getAttackers().get(0)); this.declareBlocker(blockerId, - * groups.get(i).getAttackers().get(0), game); } } } } - */ } /** @@ -1402,7 +963,8 @@ public class ComputerPlayer6 extends ComputerPlayer /*implements Player*/ { Scanner scanner = new Scanner(file); while (scanner.hasNextLine()) { String line = scanner.nextLine(); - if (line.startsWith("cast:") || line.startsWith("play:")) { + if (line.startsWith("cast:") + || line.startsWith("play:")) { suggested.add(line.substring(5, line.length())); } } @@ -1419,8 +981,9 @@ public class ComputerPlayer6 extends ComputerPlayer /*implements Player*/ { @Override public void addAction(String action) { - System.out.println("adding to suggested actions: " + action); - if (action != null && (action.startsWith("cast:") || action.startsWith("play:"))) { + if (action != null + && (action.startsWith("cast:") + || action.startsWith("play:"))) { suggested.add(action.substring(5, action.length())); } } @@ -1449,54 +1012,4 @@ public class ComputerPlayer6 extends ComputerPlayer /*implements Player*/ { super.cleanUpOnMatchEnd(); } - @Override - public UUID chooseBlockerOrder(List blockers, CombatGroup combatGroup, List blockerOrder, Game game) { - if (combatGroup.getAttackers().size() == 1) { - Permanent attacker = game.getPermanent(combatGroup.getAttackers().get(0)); - boolean attackerDeathtouch = attacker.getAbilities().containsKey(DeathtouchAbility.getInstance().getId()); - // boolean attackerFirstStrike = attacker.getAbilities().containsKey(FirstStrikeAbility.getInstance().getId()); - List blockerAlreadySet = getAlreadyBlockingPermanents(blockerOrder, game); - int powerAlreadyNeeded = getPowerAlreadyNeeded(blockerAlreadySet, attackerDeathtouch); - int powerLeftToKill = attacker.getPower().getValue() - powerAlreadyNeeded; - // no possible damage left, order doesn't matter - if (powerLeftToKill <= 0) { - return blockers.iterator().next().getId(); - } - for (Permanent blocker : blockers) { - if (attackerDeathtouch || powerLeftToKill >= blocker.getToughness().getValue()) { - if (!blocker.getAbilities().containsKey(IndestructibleAbility.getInstance().getId())) { - return blocker.getId(); - } - } - } - // Can't kill a blocker so it doesn't matter - return blockers.iterator().next().getId(); - } else { // multiple attackers (like banding) - //TODO: improve this - return blockers.iterator().next().getId(); - } - } - - private List getAlreadyBlockingPermanents(List blockerOrder, Game game) { - List blockerAlreadySet = new ArrayList<>(); - for (UUID uuid : blockerOrder) { - Permanent permanent = game.getPermanent(uuid); - if (permanent != null) { - blockerAlreadySet.add(permanent); - } - } - return blockerAlreadySet; - } - - private int getPowerAlreadyNeeded(List blockerAlreadySet, boolean attackerDeathtouch) { - int toughnessAlreadyNeeded = 0; - if (attackerDeathtouch) { - return blockerAlreadySet.size(); - } - for (Permanent creature : blockerAlreadySet) { - toughnessAlreadyNeeded += creature.getToughness().getValue(); - } - return toughnessAlreadyNeeded; - } - } 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 28cd4879ae7..71c7da0196f 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 @@ -28,28 +28,9 @@ package mage.player.ai; import java.util.LinkedList; -import java.util.List; -import java.util.UUID; import mage.abilities.Ability; -import mage.constants.PhaseStep; import mage.constants.RangeOfInfluence; import mage.game.Game; -import mage.game.combat.Combat; -import mage.game.combat.CombatGroup; -import mage.game.events.GameEvent; -import mage.game.turn.BeginCombatStep; -import mage.game.turn.CleanupStep; -import mage.game.turn.CombatDamageStep; -import mage.game.turn.CombatPhase; -import mage.game.turn.DeclareAttackersStep; -import mage.game.turn.DeclareBlockersStep; -import mage.game.turn.EndOfCombatStep; -import mage.game.turn.EndPhase; -import mage.game.turn.EndStep; -import mage.game.turn.FirstCombatDamageStep; -import mage.game.turn.PostCombatMainPhase; -import mage.game.turn.PostCombatMainStep; -import mage.game.turn.Step; import org.apache.log4j.Logger; /** @@ -103,7 +84,7 @@ public class ComputerPlayer7 extends ComputerPlayer6 { printOutState(game); if (actions.isEmpty()) { logger.info("Sim Calculate pre combat actions ----------------------------------------------------- "); - calculatePreCombatActions(game); + calculateActions(game); } act(game); return true; @@ -119,7 +100,7 @@ public class ComputerPlayer7 extends ComputerPlayer6 { printOutState(game); if (actions.isEmpty()) { logger.info("Sim Calculate declare attackers actions ----------------------------------------------------- "); - calculatePreCombatActions(game); + calculateActions(game); } act(game); return true; @@ -134,18 +115,12 @@ public class ComputerPlayer7 extends ComputerPlayer6 { pass(game); return false; case POSTCOMBAT_MAIN: -// if (game.getActivePlayerId().equals(playerId)) { printOutState(game); if (actions.isEmpty()) { - calculatePostCombatActions(game); + calculateActions(game); } act(game); return true; -// } -// else { -// pass(game); -// } -// return false; case END_TURN: case CLEANUP: actionCache.clear(); @@ -155,24 +130,23 @@ public class ComputerPlayer7 extends ComputerPlayer6 { return false; } - protected void calculatePreCombatActions(Game game) { + protected void calculateActions(Game game) { if (!getNextAction(game)) { currentScore = GameStateEvaluator2.evaluate(playerId, game); Game sim = createSimulation(game); SimulationNode2.resetCount(); root = new SimulationNode2(null, sim, maxDepth, playerId); addActionsTimed(); - if (root.children != null && !root.children.isEmpty()) { + if (root.children != null + && !root.children.isEmpty()) { logger.trace("After add actions timed: root.children.size = " + root.children.size()); root = root.children.get(0); - // int bestScore = root.getScore(); - // if (bestScore > currentScore || allowBadMoves) { - // prevent repeating always the same action with no cost boolean doThis = true; if (root.abilities.size() == 1) { for (Ability ability : root.abilities) { - if (ability.getManaCosts().convertedManaCost() == 0 && ability.getCosts().isEmpty()) { + if (ability.getManaCosts().convertedManaCost() == 0 + && ability.getCosts().isEmpty()) { if (actionCache.contains(ability.getRule() + '_' + ability.getSourceId())) { doThis = false; // don't do it again } @@ -194,419 +168,6 @@ public class ComputerPlayer7 extends ComputerPlayer6 { } } - protected void calculatePostCombatActions(Game game) { - if (!getNextAction(game)) { - currentScore = GameStateEvaluator2.evaluate(playerId, game); - Game sim = createSimulation(game); - SimulationNode2.resetCount(); - root = new SimulationNode2(null, sim, maxDepth, playerId); - logger.debug("Sim Calculate post combat actions ----------------------------------------------------------------------------------------"); - - addActionsTimed(); - if (root != null && !root.children.isEmpty()) { - root = root.children.get(0); - int bestScore = root.getScore(); - if (bestScore > currentScore || allowBadMoves) { - actions = new LinkedList<>(root.abilities); - combat = root.combat; - } else { - logger.debug('[' + game.getPlayer(playerId).getName() + "] no better score current: " + currentScore + " bestScore: " + bestScore); - } - } else { - logger.debug('[' + game.getPlayer(playerId).getName() + "][post] Action: skip"); - } - } - } - - @Override - protected int addActions(SimulationNode2 node, int depth, int alpha, int beta) { - boolean stepFinished = false; - int val; - if (logger.isTraceEnabled() && node != null && node.getAbilities() != null && !node.getAbilities().toString().equals("[Pass]")) { - logger.trace("Add Action [" + depth + "] " + node.getAbilities().toString() + " a: " + alpha + " b: " + beta); - } - Game game = node.getGame(); - if (ALLOW_INTERRUPT && Thread.interrupted()) { - Thread.currentThread().interrupt(); - logger.debug("interrupted"); - return GameStateEvaluator2.evaluate(playerId, game); - } - // Condition to stop deeper simulation - if (depth <= 0 || SimulationNode2.nodeCount > maxNodes || game.checkIfGameIsOver()) { - val = GameStateEvaluator2.evaluate(playerId, game); - if (logger.isTraceEnabled()) { - StringBuilder sb = new StringBuilder("Add Actions -- reached end state <").append(val).append('>'); - SimulationNode2 logNode = node; - do { - sb.append(new StringBuilder(" <- [" + logNode.getDepth() + ']' + (logNode.getAbilities() != null ? logNode.getAbilities().toString() : "[empty]"))); - logNode = logNode.getParent(); - } while ((logNode.getParent() != null)); - logger.trace(sb); - } - } else if (!node.getChildren().isEmpty()) { - if (logger.isDebugEnabled()) { - StringBuilder sb = new StringBuilder("Add Action [").append(depth) - .append("] -- something added children ") - .append(node.getAbilities() != null ? node.getAbilities().toString() : "null") - .append(" added children: ").append(node.getChildren().size()).append(" ("); - for (SimulationNode2 logNode : node.getChildren()) { - sb.append(logNode.getAbilities() != null ? logNode.getAbilities().toString() : "null").append(", "); - } - sb.append(')'); - logger.debug(sb); - } - val = minimaxAB(node, depth - 1, alpha, beta); - } else { - logger.trace("Add Action -- alpha: " + alpha + " beta: " + beta + " depth:" + depth + " step:" + game.getTurn().getStepType() + " for player:" + game.getPlayer(game.getPlayerList().get()).getName()); - if (allPassed(game)) { - if (!game.getStack().isEmpty()) { - resolve(node, depth, game); - } else { - stepFinished = true; - } - } - - if (game.checkIfGameIsOver()) { - val = GameStateEvaluator2.evaluate(playerId, game); - } else if (stepFinished) { - logger.debug("Step finished"); - int testScore = GameStateEvaluator2.evaluate(playerId, game); - if (game.getActivePlayerId().equals(playerId)) { - if (testScore < currentScore) { - // if score at end of step is worse than original score don't check further - //logger.debug("Add Action -- abandoning check, no immediate benefit"); - val = testScore; - } else { - /*switch (game.getTurn().getStepType()) { - case PRECOMBAT_MAIN: - val = simulateCombat(game, node, depth-1, alpha, beta, false); - break; - case POSTCOMBAT_MAIN: - val = simulateCounterAttack(game, node, depth-1, alpha, beta); - break; - default: - val = GameStateEvaluator2.evaluate(playerId, game); - break; - }*/ - val = GameStateEvaluator2.evaluate(playerId, game); - } - } else { - val = GameStateEvaluator2.evaluate(playerId, game); - /*if (game.getTurn().getStepType() == PhaseStep.DECLARE_ATTACKERS) - val = simulateBlockers(game, node, playerId, depth-1, alpha, beta, true); - else - val = GameStateEvaluator2.evaluate(playerId, game); - */ - } - } else if (!node.getChildren().isEmpty()) { - if (logger.isDebugEnabled()) { - StringBuilder sb = new StringBuilder("Add Action [").append(depth) - .append("] -- trigger ") - .append(node.getAbilities() != null ? node.getAbilities().toString() : "null") - .append(" added children: ").append(node.getChildren().size()).append(" ("); - for (SimulationNode2 logNode : node.getChildren()) { - sb.append(logNode.getAbilities() != null ? logNode.getAbilities().toString() : "null").append(", "); - } - sb.append(')'); - logger.debug(sb); - } - - val = minimaxAB(node, depth, alpha, beta); - } else { - val = simulatePriority(node, game, depth, alpha, beta); - } - } - node.setScore(val); // test - logger.trace("returning -- score: " + val + " depth:" + depth + " step:" + game.getTurn().getStepType() + " for player:" + game.getPlayer(node.getPlayerId()).getName()); - return val; - - } - - protected int simulateCombat(Game game, SimulationNode2 node, int depth, int alpha, int beta, boolean counter) { - Integer val = null; - if (ALLOW_INTERRUPT && Thread.interrupted()) { - Thread.currentThread().interrupt(); - logger.debug("interrupted"); - return GameStateEvaluator2.evaluate(playerId, game); - } - if (game.getTurn().getStepType() != PhaseStep.DECLARE_BLOCKERS) { - game.getTurn().setPhase(new CombatPhase()); - if (game.getPhase().beginPhase(game, game.getActivePlayerId())) { - simulateStep(game, new BeginCombatStep()); - game.getPhase().setStep(new DeclareAttackersStep()); - if (!game.getStep().skipStep(game, game.getActivePlayerId())) { - game.fireEvent(new GameEvent(GameEvent.EventType.DECLARE_ATTACKERS_STEP_PRE, null, null, game.getActivePlayerId())); - if (!game.replaceEvent(GameEvent.getEvent(GameEvent.EventType.DECLARING_ATTACKERS, game.getActivePlayerId(), game.getActivePlayerId()))) { - val = simulateAttackers(game, node, game.getActivePlayerId(), depth, alpha, beta, counter); - } - } else if (!counter) { - simulateToEnd(game); - val = simulatePostCombatMain(game, node, depth, alpha, beta); - } - } - } else if (!game.getStep().skipStep(game, game.getActivePlayerId())) { - game.fireEvent(new GameEvent(GameEvent.EventType.DECLARE_BLOCKERS_STEP_PRE, null, null, game.getActivePlayerId())); - if (!game.replaceEvent(GameEvent.getEvent(GameEvent.EventType.DECLARING_BLOCKERS, game.getActivePlayerId(), game.getActivePlayerId()))) { - //only suitable for two player games - only simulates blocks for 1st defender - val = simulateBlockers(game, node, game.getCombat().getDefenders().iterator().next(), depth, alpha, beta, counter); - } - } else if (!counter) { - finishCombat(game); - ///val = simulateCounterAttack(game, node, depth, alpha, beta); - } - if (val == null) { - val = GameStateEvaluator2.evaluate(playerId, game); - } - if (logger.isDebugEnabled()) { - logger.debug("returning -- combat score: " + val + " depth:" + depth + " for player:" + game.getPlayer(node.getPlayerId()).getName()); - } - return val; - } - - protected int simulateAttackers(Game game, SimulationNode2 node, UUID attackerId, int depth, int alpha, int beta, boolean counter) { - if (ALLOW_INTERRUPT && Thread.interrupted()) { - Thread.currentThread().interrupt(); - logger.debug("interrupted"); - return GameStateEvaluator2.evaluate(playerId, game); - } - Integer val = null; - SimulationNode2 bestNode = null; - SimulatedPlayer2 attacker = (SimulatedPlayer2) game.getPlayer(attackerId); - UUID defenderId = game.getOpponents(attackerId).iterator().next(); - if (logger.isDebugEnabled()) { - logger.debug(attacker.getName() + "'s possible attackers: " + attacker.getAvailableAttackers(defenderId, game)); - } - for (Combat engagement : attacker.addAttackers(game)) { - if (logger.isDebugEnabled()) { - logger.debug("Sim Attackers: " + engagement.getAttackers() + ", blockers: " + engagement.getBlockers()); - } - if (alpha >= beta) { - logger.debug("Sim Attackers -- pruning attackers"); - break; - } - Game sim = game.copy(); - for (CombatGroup group : engagement.getGroups()) { - for (UUID attackId : group.getAttackers()) { - sim.getPlayer(attackerId).declareAttacker(attackId, defenderId, sim, false); - } - } - sim.fireEvent(GameEvent.getEvent(GameEvent.EventType.DECLARED_ATTACKERS, attackerId, attackerId)); - SimulationNode2 newNode = new SimulationNode2(node, sim, depth, attackerId); - if (logger.isDebugEnabled()) { - logger.debug("Sim attack for player:" + game.getPlayer(attackerId).getName()); - } - sim.checkStateAndTriggered(); - while (!sim.getStack().isEmpty()) { - sim.getStack().resolve(sim); - logger.debug("Sim attack: resolving triggered abilities"); - sim.applyEffects(); - } - sim.fireEvent(GameEvent.getEvent(GameEvent.EventType.DECLARE_ATTACKERS_STEP_POST, sim.getActivePlayerId(), sim.getActivePlayerId())); - Combat simCombat = sim.getCombat().copy(); - sim.getPhase().setStep(new DeclareBlockersStep()); - val = simulateCombat(sim, newNode, depth - 1, alpha, beta, counter); - if (!attackerId.equals(playerId)) { - if (val < beta) { - beta = val; - bestNode = newNode; - bestNode.setScore(val); - if (!newNode.getChildren().isEmpty()) { - bestNode.setCombat(newNode.getChildren().get(0).getCombat()); - } - } - } else if (val > alpha) { - alpha = val; - bestNode = newNode; - bestNode.setScore(val); - if (!newNode.getChildren().isEmpty()) { - bestNode.setCombat(newNode.getChildren().get(0).getCombat()); - } - } - } - if (val == null) { - val = GameStateEvaluator2.evaluate(playerId, game); - } - if (bestNode != null) { - node.children.clear(); - node.children.add(bestNode); - node.setScore(bestNode.getScore()); - } - if (logger.isDebugEnabled()) { - logger.debug("Sim attackers: returning score: " + val + " depth:" + depth + " for player:" + game.getPlayer(node.getPlayerId()).getName()); - } - return val; - } - - protected int simulateBlockers(Game game, SimulationNode2 node, UUID defenderId, int depth, int alpha, int beta, boolean counter) { - if (ALLOW_INTERRUPT && Thread.interrupted()) { - Thread.currentThread().interrupt(); - logger.debug("interrupted"); - return GameStateEvaluator2.evaluate(playerId, game); - } - Integer val = null; - SimulationNode2 bestNode = null; - //check if defender is being attacked - if (game.getCombat().isAttacked(defenderId, game)) { - SimulatedPlayer2 defender = (SimulatedPlayer2) game.getPlayer(defenderId); - if (logger.isDebugEnabled()) { - logger.debug(defender.getName() + "'s possible blockers: " + defender.getAvailableBlockers(game)); - } - List combats = defender.addBlockers(game); - for (Combat engagement : combats) { - if (alpha >= beta) { - logger.debug("Sim blockers -- pruning blockers"); - break; - } - Game sim = game.copy(); - for (CombatGroup group : engagement.getGroups()) { - if (!group.getAttackers().isEmpty()) { - UUID attackerId = group.getAttackers().get(0); - for (UUID blockerId : group.getBlockers()) { - sim.getPlayer(defenderId).declareBlocker(defenderId, blockerId, attackerId, sim); - } - } - } - sim.fireEvent(GameEvent.getEvent(GameEvent.EventType.DECLARED_BLOCKERS, defenderId, defenderId)); - SimulationNode2 newNode = new SimulationNode2(node, sim, depth, defenderId); - if (logger.isDebugEnabled()) { - logger.debug("Sim block for player:" + game.getPlayer(defenderId).getName()); - } - sim.checkStateAndTriggered(); - while (!sim.getStack().isEmpty()) { - sim.getStack().resolve(sim); - logger.debug("Sim blockers: resolving triggered abilities"); - sim.applyEffects(); - } - sim.fireEvent(GameEvent.getEvent(GameEvent.EventType.DECLARE_BLOCKERS_STEP_POST, sim.getActivePlayerId(), sim.getActivePlayerId())); - Combat simCombat = sim.getCombat().copy(); - finishCombat(sim); - if (sim.checkIfGameIsOver()) { - val = GameStateEvaluator2.evaluate(playerId, sim); - } else if (!counter) { - val = simulatePostCombatMain(sim, newNode, depth - 1, alpha, beta); - } else { - val = GameStateEvaluator2.evaluate(playerId, sim); - } - if (!defenderId.equals(playerId)) { - if (val < beta) { - beta = val; - bestNode = newNode; - bestNode.setScore(val); - bestNode.setCombat(simCombat); - } - } else if (val > alpha) { - alpha = val; - bestNode = newNode; - bestNode.setScore(val); - bestNode.setCombat(simCombat); - } - } - } - if (val == null) { - val = GameStateEvaluator2.evaluate(playerId, game); - } - if (bestNode != null) { - node.children.clear(); - node.children.add(bestNode); - node.setScore(bestNode.getScore()); - } - if (logger.isDebugEnabled()) { - logger.debug("Sim blockers: returning score: " + val + " depth:" + depth + " for player:" + game.getPlayer(node.getPlayerId()).getName()); - } - return val; - } - - /*protected int simulateCounterAttack(Game game, SimulationNode2 node, int depth, int alpha, int beta) { - if (ALLOW_INTERRUP && Thread.interrupted()) { - Thread.currentThread().interrupt(); - logger.debug("interrupted"); - return GameStateEvaluator2.evaluate(playerId, game); - } - Integer val = null; - if (!game.isGameOver()) { - simulateToEnd(game); - game.getState().setActivePlayerId(game.getState().getPlayerList(game.getActivePlayerId()).getNext()); - logger.debug("simulating -- counter attack for player " + game.getPlayer(game.getActivePlayerId()).getName()); - game.getTurn().setPhase(new BeginningPhase()); - if (game.getPhase().beginPhase(game, game.getActivePlayerId())) { - simulateStep(game, new UntapStep()); - simulateStep(game, new UpkeepStep()); - simulateStep(game, new DrawStep()); - game.getPhase().endPhase(game, game.getActivePlayerId()); - } - val = simulateCombat(game, node, depth-1, alpha, beta, true); - if (logger.isDebugEnabled()) - logger.debug("returning -- counter attack score: " + val + " depth:" + depth + " for player:" + game.getPlayer(node.getPlayerId()).getName()); - } - if (val == null) - val = GameStateEvaluator2.evaluate(playerId, game); - return val; - }*/ - protected void simulateStep(Game game, Step step) { - if (ALLOW_INTERRUPT && Thread.interrupted()) { - Thread.currentThread().interrupt(); - logger.debug("interrupted"); - return; - } - if (!game.checkIfGameIsOver()) { - game.getPhase().setStep(step); - if (!step.skipStep(game, game.getActivePlayerId())) { - step.beginStep(game, game.getActivePlayerId()); - game.checkStateAndTriggered(); - while (!game.getStack().isEmpty()) { - game.getStack().resolve(game); - game.applyEffects(); - } - step.endStep(game, game.getActivePlayerId()); - } - } - } - - protected void finishCombat(Game game) { - if (ALLOW_INTERRUPT && Thread.interrupted()) { - Thread.currentThread().interrupt(); - logger.debug("interrupted"); - return; - } - simulateStep(game, new FirstCombatDamageStep()); - simulateStep(game, new CombatDamageStep()); - simulateStep(game, new EndOfCombatStep()); - } - - protected int simulatePostCombatMain(Game game, SimulationNode2 node, int depth, int alpha, int beta) { - if (ALLOW_INTERRUPT && Thread.interrupted()) { - Thread.currentThread().interrupt(); - logger.debug("interrupted"); - return GameStateEvaluator2.evaluate(playerId, game); - } - logger.debug("Sim [" + depth + "] -- post combat main"); - game.getTurn().setPhase(new PostCombatMainPhase()); - if (game.getPhase().beginPhase(game, game.getActivePlayerId())) { - game.getPhase().setStep(new PostCombatMainStep()); - game.getStep().beginStep(game, playerId); - game.getPlayers().resetPassed(); - return addActions(node, depth, alpha, beta); - } - //return simulateCounterAttack(game, node, depth, alpha, beta); - return GameStateEvaluator2.evaluate(playerId, game); - } - - protected void simulateToEnd(Game game) { - if (ALLOW_INTERRUPT && Thread.interrupted()) { - Thread.currentThread().interrupt(); - logger.debug("interrupted"); - return; - } - if (!game.checkIfGameIsOver()) { - game.getTurn().getPhase().endPhase(game, game.getActivePlayerId()); - game.getTurn().setPhase(new EndPhase()); - if (game.getTurn().getPhase().beginPhase(game, game.getActivePlayerId())) { - simulateStep(game, new EndStep()); - simulateStep(game, new CleanupStep()); - } - } - } - @Override public void setAllowBadMoves(boolean allowBadMoves) { this.allowBadMoves = allowBadMoves; diff --git a/Mage.Server.Plugins/Mage.Player.AI.MA/src/mage/player/ai/GameStateEvaluator2.java b/Mage.Server.Plugins/Mage.Player.AI.MA/src/mage/player/ai/GameStateEvaluator2.java index 580f47ba324..77a07050014 100644 --- a/Mage.Server.Plugins/Mage.Player.AI.MA/src/mage/player/ai/GameStateEvaluator2.java +++ b/Mage.Server.Plugins/Mage.Player.AI.MA/src/mage/player/ai/GameStateEvaluator2.java @@ -15,7 +15,7 @@ import org.apache.log4j.Logger; * * @author nantuko * - * this evaluator is only good for two player games + * This evaluator is only good for two player games * */ public final class GameStateEvaluator2 { @@ -25,25 +25,19 @@ public final class GameStateEvaluator2 { public static final int WIN_GAME_SCORE = 100000000; public static final int LOSE_GAME_SCORE = -WIN_GAME_SCORE; - private static final int LIFE_FACTOR = Config2.evaluatorLifeFactor; - private static final int PERMANENT_FACTOR = Config2.evaluatorPermanentFactor; - private static final int CREATURE_FACTOR = Config2.evaluatorCreatureFactor; - private static final int HAND_FACTOR = Config2.evaluatorHandFactor; - public static int evaluate(UUID playerId, Game game) { Player player = game.getPlayer(playerId); Player opponent = game.getPlayer(game.getOpponents(playerId).iterator().next()); if (game.checkIfGameIsOver()) { - if (player.hasLost() || opponent.hasWon()) { + if (player.hasLost() + || opponent.hasWon()) { return LOSE_GAME_SCORE; } - if (opponent.hasLost() || player.hasWon()) { + if (opponent.hasLost() + || player.hasWon()) { return WIN_GAME_SCORE; } } - //int lifeScore = (player.getLife() - opponent.getLife()) * LIFE_FACTOR; - - //int lifeScore = (ArtificialScoringSystem.getLifeScore(player.getLife()) - opponent.getLife()) * LIFE_FACTOR; int lifeScore = 0; if (player.getLife() <= 0) { // we don't want a tie lifeScore = ArtificialScoringSystem.LOSE_GAME_SCORE; @@ -52,7 +46,6 @@ public final class GameStateEvaluator2 { } else { lifeScore = ArtificialScoringSystem.getLifeScore(player.getLife()) - ArtificialScoringSystem.getLifeScore(opponent.getLife()); } - int permanentScore = 0; int playerScore = 0; int opponentScore = 0; @@ -90,56 +83,24 @@ public final class GameStateEvaluator2 { permanentScore = playerScore - opponentScore; } catch (Throwable t) { } - //permanentScore *= PERMANENT_FACTOR; - int handScore; handScore = player.getHand().size() - opponent.getHand().size(); handScore *= 5; int score = lifeScore + permanentScore + handScore; logger.debug(score + " total Score (life:" + lifeScore + " permanents:" + permanentScore + " hand:" + handScore + ')'); - return score; } public static int evaluatePermanent(Permanent permanent, Game game) { - /*int value = permanent.isTapped()?4:5; - if (permanent.getCardType().contains(CardType.CREATURE)) { - value += evaluateCreature(permanent, game) * CREATURE_FACTOR; - } - value += permanent.getAbilities().getManaAbilities(Zone.BATTLEFIELD).size(); - for (ActivatedAbility ability: permanent.getAbilities().getActivatedAbilities(Zone.BATTLEFIELD)) { - if (!(ability instanceof ManaAbility) && ability.canActivate(ability.getControllerId(), game)) - value += ability.getEffects().size(); - } - value += permanent.getAbilities().getStaticAbilities(Zone.BATTLEFIELD).size(); - value += permanent.getAbilities().getTriggeredAbilities(Zone.BATTLEFIELD).size(); - value += permanent.getManaCost().convertedManaCost(); - */ - int value = ArtificialScoringSystem.getFixedPermanentScore(game, permanent) + ArtificialScoringSystem.getVariablePermanentScore(game, permanent); - - //TODO: add a difficulty to calculation to ManaCost - sort permanents by difficulty for casting when evaluating game states return value; } public static int evaluateCreature(Permanent creature, Game game) { int value = ArtificialScoringSystem.getFixedPermanentScore(game, creature) + ArtificialScoringSystem.getVariablePermanentScore(game, creature); - - /*int value = 0; - value += creature.getPower().getValue(); - value += creature.getToughness().getValue(); - // if (creature.canAttack(game)) - // value += creature.getPower().getValue(); - // if (!creature.isTapped()) - // value += 2; - value += creature.getAbilities().getEvasionAbilities().size(); - value += creature.getAbilities().getProtectionAbilities().size(); - value += creature.getAbilities().containsKey(FirstStrikeAbility.getInstance().getId())?1:0; - value += creature.getAbilities().containsKey(DoubleStrikeAbility.getInstance().getId())?2:0; - value += creature.getAbilities().containsKey(TrampleAbility.getInstance().getId())?1:0;*/ return value; } 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 08bb65641c3..f8b1bc543aa 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 @@ -126,11 +126,14 @@ public class ComputerPlayer extends PlayerImpl implements Player { @Override public boolean chooseMulligan(Game game) { log.debug("chooseMulligan"); - if (hand.size() < 6 || isTestMode() || game.getClass().getName().contains("Momir")) { + if (hand.size() < 6 + || isTestMode() + || game.getClass().getName().contains("Momir")) { return false; } Set lands = hand.getCards(new FilterLandCard(), game); - return lands.size() < 2 || lands.size() > hand.size() - 2; + return lands.size() < 2 + || lands.size() > hand.size() - 2; } @Override @@ -140,12 +143,14 @@ public class ComputerPlayer extends PlayerImpl implements Player { @Override public boolean choose(Outcome outcome, Target target, UUID sourceId, Game game, Map options) { + System.out.println("choose in ComputerPlayer"); if (log.isDebugEnabled()) { log.debug("chooseTarget: " + outcome.toString() + ':' + target.toString()); } // sometimes a target selection can be made from a player that does not control the ability UUID abilityControllerId = playerId; - if (target.getTargetController() != null && target.getAbilityController() != null) { + if (target.getTargetController() != null + && target.getAbilityController() != null) { abilityControllerId = target.getAbilityController(); } UUID randomOpponentId = getRandomOpponent(abilityControllerId, game); @@ -388,10 +393,11 @@ public class ComputerPlayer extends PlayerImpl implements Player { } throw new IllegalStateException("Target wasn't handled. class:" + target.getClass().toString()); - } + } //end of choose method @Override public boolean chooseTarget(Outcome outcome, Target target, Ability source, Game game) { + System.out.println("chooseTarget in ComputerPlayer"); if (log.isDebugEnabled()) { log.debug("chooseTarget: " + outcome.toString() + ':' + target.toString()); } @@ -747,9 +753,10 @@ public class ComputerPlayer extends PlayerImpl implements Player { return target.isChosen(); } throw new IllegalStateException("Target wasn't handled. class:" + target.getClass().toString()); - } + } //end of chooseTarget method protected Card pickTarget(List cards, Outcome outcome, Target target, Ability source, Game game) { + System.out.println("pickTarget in ComputerPlayer"); Card card; while (!cards.isEmpty()) { if (outcome.isGood()) { @@ -771,6 +778,7 @@ public class ComputerPlayer extends PlayerImpl implements Player { @Override public boolean chooseTargetAmount(Outcome outcome, TargetAmount target, Ability source, Game game) { + System.out.println("chooseTargetAmount in ComputerPlayer"); if (log.isDebugEnabled()) { log.debug("chooseTarget: " + outcome.toString() + ':' + target.toString()); } @@ -811,6 +819,7 @@ public class ComputerPlayer extends PlayerImpl implements Player { @Override public boolean priority(Game game) { + System.out.println("priority in ComputerPlayer"); game.resumeTimer(getTurnControlledBy()); log.debug("priority"); boolean result = priorityPlay(game); @@ -819,6 +828,7 @@ public class ComputerPlayer extends PlayerImpl implements Player { } private boolean priorityPlay(Game game) { + System.out.println("priorityPlay in ComputerPlayer"); UUID opponentId = game.getOpponents(playerId).iterator().next(); if (game.getActivePlayerId().equals(playerId)) { if (game.isMainPhase() && game.getStack().isEmpty()) { @@ -906,7 +916,7 @@ public class ComputerPlayer extends PlayerImpl implements Player { } pass(game); return true; - } + } // end priorityPlay method @Override public boolean activateAbility(ActivatedAbility ability, Game game) { @@ -975,6 +985,7 @@ public class ComputerPlayer extends PlayerImpl implements Player { } protected void findPlayables(Game game) { + System.out.println("Here in findPlayables"); playableInstant.clear(); playableNonInstant.clear(); unplayable.clear();