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 dde4e4f219..4a945e05f0 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 @@ -34,6 +34,10 @@ import mage.Constants.RangeOfInfluence; import mage.abilities.Ability; import mage.abilities.ActivatedAbility; import mage.abilities.common.PassAbility; +import mage.abilities.costs.mana.GenericManaCost; +import mage.abilities.costs.mana.ManaCost; +import mage.abilities.costs.mana.ManaCosts; +import mage.abilities.costs.mana.VariableManaCost; import mage.abilities.effects.Effect; import mage.abilities.effects.SearchEffect; import mage.cards.Card; @@ -59,8 +63,6 @@ import java.util.LinkedList; import java.util.List; import java.util.UUID; import java.util.concurrent.*; -import java.util.logging.Level; -import java.util.logging.Logger; /** * @@ -68,7 +70,7 @@ import java.util.logging.Logger; */ public class ComputerPlayer6 extends ComputerPlayer implements Player { - private static final transient Logger logger = Logging.getLogger(ComputerPlayer6.class.getName()); + private static final transient org.apache.log4j.Logger logger = org.apache.log4j.Logger.getLogger(ComputerPlayer6.class); private static final ExecutorService pool = Executors.newFixedThreadPool(1); protected int maxDepth; @@ -122,6 +124,7 @@ public class ComputerPlayer6 extends ComputerPlayer implements case POSTCOMBAT_MAIN: if (game.getActivePlayerId().equals(playerId)) { printOutState(game, playerId); + printOutState(game, game.getOpponents(playerId).iterator().next()); if (actions.size() == 0) { calculateActions(game); } @@ -143,7 +146,7 @@ public class ComputerPlayer6 extends ComputerPlayer implements calculateActions(game); } act(game); - printOutState(game, playerId); + //printOutState(game, playerId); } else { pass(); } @@ -205,13 +208,13 @@ public class ComputerPlayer6 extends ComputerPlayer implements } protected void calculateActions(Game game) { - currentScore = GameStateEvaluator2.evaluate(playerId, 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(new FilterAbility()); if (root.children.size() > 0) { root = root.children.get(0); @@ -333,7 +336,7 @@ public class ComputerPlayer6 extends ComputerPlayer implements SimulationNode2 newNode = new SimulationNode2(node, sim, depth, ability.getControllerId()); node.children.add(newNode); newNode.getTargets().add(targetId); - logger.fine("simulating search -- node#: " + SimulationNode2.getCount() + "for player: " + sim.getPlayer(ability.getControllerId()).getName()); + logger.debug("simulating search -- node#: " + SimulationNode2.getCount() + "for player: " + sim.getPlayer(ability.getControllerId()).getName()); } return; } @@ -355,7 +358,7 @@ public class ComputerPlayer6 extends ComputerPlayer implements }); pool.execute(task); try { - return task.get(Config2.maxThinkSeconds, TimeUnit.MINUTES); + return task.get(Config2.maxThinkSeconds, TimeUnit.SECONDS); } catch (TimeoutException e) { logger.info("simulating - timed out"); task.cancel(true); @@ -374,28 +377,29 @@ public class ComputerPlayer6 extends ComputerPlayer implements } protected int addActions(SimulationNode2 node, FilterAbility filter, int depth, int alpha, int beta) { - logger.fine("addActions: " + depth + ", alpha=" + alpha + ", beta=" + beta); + logger.debug("addActions: " + depth + ", alpha=" + alpha + ", beta=" + beta); Game game = node.getGame(); int val; if (Thread.interrupted()) { Thread.currentThread().interrupt(); - logger.info("interrupted"); val = GameStateEvaluator2.evaluate(playerId, game); + logger.info("interrupted - " + val); return val; } if (depth <= 0 || SimulationNode2.nodeCount > maxNodes || game.isGameOver()) { - logger.fine("simulating -- reached end state, node count=" + SimulationNode2.nodeCount + ", depth=" + depth); + logger.debug("simulating -- 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().size() > 0) { - logger.fine("simulating -- somthing added children:" + node.getChildren().size()); + logger.debug("simulating -- somthing added children:" + node.getChildren().size()); val = minimaxAB(node, filter, depth-1, alpha, beta); return val; } else { - if (logger.isLoggable(Level.FINE)) - logger.fine("simulating -- alpha: " + alpha + " beta: " + beta + " depth:" + depth + " step:" + game.getTurn().getStepType() + " for player:" + (node.getPlayerId().equals(playerId) ? "yes" : "no")); + logger.debug("simulating -- 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); @@ -408,10 +412,9 @@ public class ComputerPlayer6 extends ComputerPlayer implements if (game.isGameOver()) { val = GameStateEvaluator2.evaluate(playerId, game); - } - else if (node.getChildren().size() > 0) { + } else if (node.getChildren().size() > 0) { //declared attackers or blockers or triggered abilities - logger.fine("simulating -- attack/block/trigger added children:" + node.getChildren().size()); + logger.debug("simulating -- attack/block/trigger added children:" + node.getChildren().size()); val = minimaxAB(node, filter, depth-1, alpha, beta); } else { @@ -419,8 +422,7 @@ public class ComputerPlayer6 extends ComputerPlayer implements } } - if (logger.isLoggable(Level.FINE)) - logger.fine("returning -- score: " + val + " depth:" + depth + " step:" + game.getTurn().getStepType() + " for player:" + game.getPlayer(node.getPlayerId()).getName()); + logger.debug("returning -- score: " + val + " depth:" + depth + " step:" + game.getTurn().getStepType() + " for player:" + game.getPlayer(node.getPlayerId()).getName()); return val; } @@ -436,8 +438,7 @@ public class ComputerPlayer6 extends ComputerPlayer implements //logger.info("simulating -- player " + currentPlayer.getName()); SimulationNode2 bestNode = null; List allActions = currentPlayer.simulatePriority(game, filter); - if (logger.isLoggable(Level.FINE)) - logger.fine("simulating -- adding " + allActions.size() + " children:" + allActions); + logger.debug("simulating -- adding " + allActions.size() + " children:" + allActions); for (Ability action: allActions) { Game sim = game.copy(); if (sim.getPlayer(currentPlayer.getId()).activateAbility((ActivatedAbility) action.copy(), sim)) { @@ -450,10 +451,15 @@ public class ComputerPlayer6 extends ComputerPlayer implements sim.getPlayerList().getNext(); } SimulationNode2 newNode = new SimulationNode2(node, sim, action, depth, currentPlayer.getId()); - if (logger.isLoggable(Level.FINE)) - logger.fine("simulating -- node #:" + SimulationNode2.getCount() + " actions:" + action); + logger.debug("simulating -- node #:" + SimulationNode2.getCount() + " actions:" + action); sim.checkStateAndTriggered(); + if (depth == 20) { + logger.info("*** Action *** " + action.toString()); + } int val = addActions(newNode, filter, depth-1, alpha, beta); + if (depth == 20) { + logger.info("*** Value *** " + val); + } if (!currentPlayer.getId().equals(playerId)) { if (val < beta) { beta = val; @@ -472,6 +478,18 @@ public class ComputerPlayer6 extends ComputerPlayer implements targets = node.getTargets(); if (node.getChoices().size() > 0) choices = node.getChoices(); + if (depth == 20) { + logger.info("saved"); + node.children.clear(); + node.children.add(bestNode); + node.setScore(bestNode.getScore()); + } + } + + // no need to check other actions + if (val == GameStateEvaluator2.WIN_GAME_SCORE) { + logger.info("win - break"); + break; } } if (alpha >= beta) { @@ -479,7 +497,7 @@ public class ComputerPlayer6 extends ComputerPlayer implements break; } if (SimulationNode2.nodeCount > maxNodes) { - logger.fine("simulating -- reached end-state"); + logger.debug("simulating -- reached end-state"); break; } } @@ -558,6 +576,20 @@ public class ComputerPlayer6 extends ComputerPlayer implements return true; } + @Override + public boolean playXMana(VariableManaCost cost, ManaCosts costs, Game game) { + //SimulatedPlayer.simulateVariableCosts method adds a generic mana cost for each option + for (ManaCost manaCost: costs) { + if (manaCost instanceof GenericManaCost) { + cost.setPayment(manaCost.getPayment()); + logger.debug("using X = " + cost.getPayment().count()); + break; + } + } + cost.setPaid(); + return true; + } + public void playNext(Game game, UUID activePlayerId, SimulationNode2 node) { boolean skip = false; while (true) { @@ -628,7 +660,7 @@ public class ComputerPlayer6 extends ComputerPlayer implements } sim.fireEvent(GameEvent.getEvent(GameEvent.EventType.DECLARED_ATTACKERS, playerId, playerId)); SimulationNode2 newNode = new SimulationNode2(node, sim, node.getDepth()-1, activePlayerId); - logger.info("simulating -- node #:" + SimulationNode2.getCount() + " declare attakers"); + logger.debug("simulating -- node #:" + SimulationNode2.getCount() + " declare attakers"); newNode.setCombat(sim.getCombat()); node.children.add(newNode); } @@ -652,7 +684,7 @@ public class ComputerPlayer6 extends ComputerPlayer implements } sim.fireEvent(GameEvent.getEvent(GameEvent.EventType.DECLARED_BLOCKERS, playerId, playerId)); SimulationNode2 newNode = new SimulationNode2(node, sim, node.getDepth()-1, defenderId); - logger.info("simulating -- node #:" + SimulationNode2.getCount() + " declare blockers"); + logger.debug("simulating -- node #:" + SimulationNode2.getCount() + " declare blockers"); newNode.setCombat(sim.getCombat()); node.children.add(newNode); } @@ -675,11 +707,11 @@ public class ComputerPlayer6 extends ComputerPlayer implements @Override public void selectAttackers(Game game) { - logger.info("selectAttackers"); + logger.debug("selectAttackers"); if (combat != null) { UUID opponentId = game.getCombat().getDefenders().iterator().next(); for (UUID attackerId: combat.getAttackers()) { - logger.info("declare attacker: " + game.getCard(attackerId).getName()); + logger.debug("declare attacker: " + game.getCard(attackerId).getName()); this.declareAttacker(attackerId, opponentId, game); } } @@ -687,7 +719,7 @@ public class ComputerPlayer6 extends ComputerPlayer implements @Override public void selectBlockers(Game game) { - logger.info("selectBlockers"); + logger.debug("selectBlockers"); if (combat != null && combat.getGroups().size() > 0) { List groups = game.getCombat().getGroups(); for (int i = 0; i < groups.size(); i++) { 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 45eb92cb77..52e107a148 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 @@ -35,11 +35,13 @@ import java.util.List; import java.util.Map; import java.util.UUID; import java.util.concurrent.ConcurrentLinkedQueue; -import java.util.logging.Level; -import java.util.logging.Logger; import mage.abilities.Ability; import mage.abilities.TriggeredAbility; import mage.abilities.common.PassAbility; +import mage.abilities.costs.mana.GenericManaCost; +import mage.abilities.costs.mana.ManaCost; +import mage.abilities.costs.mana.ManaCosts; +import mage.abilities.costs.mana.VariableManaCost; import mage.abilities.mana.ManaOptions; import mage.choices.Choice; import mage.filter.FilterAbility; @@ -50,6 +52,7 @@ import mage.game.permanent.Permanent; import mage.game.stack.StackAbility; import mage.target.Target; import mage.util.Logging; +import org.apache.log4j.Logger; /** * @@ -57,7 +60,7 @@ import mage.util.Logging; */ public class SimulatedPlayer2 extends ComputerPlayer { - private final static transient Logger logger = Logging.getLogger(SimulatedPlayer2.class.getName()); + private final static transient Logger logger = Logger.getLogger(SimulatedPlayer2.class); private boolean isSimulatedPlayer; private FilterAbility filter; private transient ConcurrentLinkedQueue allActions; @@ -101,13 +104,23 @@ public class SimulatedPlayer2 extends ComputerPlayer { for (Ability ability: playables) { List options = game.getPlayer(playerId).getPlayableOptions(ability, game); if (options.size() == 0) { - allActions.add(ability); + if (ability.getManaCosts().getVariableCosts().size() > 0) { + simulateVariableCosts(ability, game); + } + else { + allActions.add(ability); + } // simulateAction(game, previousActions, ability); } else { // ExecutorService simulationExecutor = Executors.newFixedThreadPool(4); for (Ability option: options) { - allActions.add(option); + if (ability.getManaCosts().getVariableCosts().size() > 0) { + simulateVariableCosts(option, game); + } + else { + allActions.add(option); + } // SimulationWorker worker = new SimulationWorker(game, this, previousActions, option); // simulationExecutor.submit(worker); } @@ -128,6 +141,31 @@ public class SimulatedPlayer2 extends ComputerPlayer { // } // } + //add a generic mana cost for each amount possible + protected void simulateVariableCosts(Ability ability, Game game) { + int numAvailable = getAvailableManaProducers(game).size(); + // Start with X = {1} + for (int i = 1; i < numAvailable; i++) { + Ability newAbility = ability.copy(); + newAbility.addManaCost(new GenericManaCost(i)); + allActions.add(newAbility); + } + } + + @Override + public boolean playXMana(VariableManaCost cost, ManaCosts costs, Game game) { + //simulateVariableCosts method adds a generic mana cost for each option + for (ManaCost manaCost: costs) { + if (manaCost instanceof GenericManaCost) { + cost.setPayment(manaCost.getPayment()); + logger.debug("simulating -- X = " + cost.getPayment().count()); + break; + } + } + cost.setPaid(); + return true; + } + public List addAttackers(Game game) { Map engagements = new HashMap(); //useful only for two player games - will only attack first opponent @@ -148,10 +186,10 @@ public class SimulatedPlayer2 extends ComputerPlayer { sim.getCombat().declareAttacker(attackersList.get(j).getId(), defenderId, sim); } if (engagements.put(sim.getCombat().getValue(sim), sim.getCombat()) != null) { - logger.fine("simulating -- found redundant attack combination"); + logger.debug("simulating -- found redundant attack combination"); } - else if (logger.isLoggable(Level.FINE)) { - logger.fine("simulating -- attack:" + sim.getCombat().getGroups().size()); + else { + logger.debug("simulating -- attack:" + sim.getCombat().getGroups().size()); } } return new ArrayList(engagements.values()); @@ -179,15 +217,14 @@ public class SimulatedPlayer2 extends ComputerPlayer { int numGroups = game.getCombat().getGroups().size(); //try to block each attacker with each potential blocker Permanent blocker = blockers.get(0); - if (logger.isLoggable(Level.FINE)) - logger.fine("simulating -- block:" + blocker); + logger.debug("simulating -- block:" + blocker); List remaining = remove(blockers, blocker); for (int i = 0; i < numGroups; i++) { if (game.getCombat().getGroups().get(i).canBlock(blocker, game)) { Game sim = game.copy(); sim.getCombat().getGroups().get(i).addBlocker(blocker.getId(), playerId, sim); if (engagements.put(sim.getCombat().getValue(sim), sim.getCombat()) != null) - logger.fine("simulating -- found redundant block combination"); + logger.debug("simulating -- found redundant block combination"); addBlocker(sim, remaining, engagements); // and recurse minus the used blocker } } @@ -199,8 +236,7 @@ public class SimulatedPlayer2 extends ComputerPlayer { Ability ability = source.copy(); List options = getPlayableOptions(ability, game); if (options.size() == 0) { - if (logger.isLoggable(Level.FINE)) - logger.fine("simulating -- triggered ability:" + ability); + logger.debug("simulating -- triggered ability:" + ability); game.getStack().push(new StackAbility(ability, playerId)); ability.activate(game, false); game.applyEffects(); @@ -210,7 +246,7 @@ public class SimulatedPlayer2 extends ComputerPlayer { SimulationNode2 parent = (SimulationNode2) game.getCustomData(); int depth = parent.getDepth() - 1; if (depth == 0) return true; - logger.fine("simulating -- triggered ability - adding children:" + options.size()); + logger.debug("simulating -- triggered ability - adding children:" + options.size()); for (Ability option: options) { addAbilityNode(parent, option, depth, game); } @@ -224,7 +260,7 @@ public class SimulatedPlayer2 extends ComputerPlayer { ability.activate(sim, false); sim.applyEffects(); SimulationNode2 newNode = new SimulationNode2(parent, sim, depth, playerId); - logger.fine("simulating -- node #:" + SimulationNode2.getCount() + " triggered ability option"); + logger.debug("simulating -- node #:" + SimulationNode2.getCount() + " triggered ability option"); for (Target target: ability.getTargets()) { for (UUID targetId: target.getTargets()) { newNode.getTargets().add(targetId); diff --git a/Mage.Server/plugins/mage-player-ai-ma.jar b/Mage.Server/plugins/mage-player-ai-ma.jar index 69ae3994e2..457fe25f12 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 9800e002e0..61b204cfa6 100644 Binary files a/Mage.Tests/plugins/mage-player-ai-ma.jar and b/Mage.Tests/plugins/mage-player-ai-ma.jar differ diff --git a/Mage.Tests/plugins/mage-player-aiminimax.jar b/Mage.Tests/plugins/mage-player-aiminimax.jar index a436a53d19..d37d42fcc6 100644 Binary files a/Mage.Tests/plugins/mage-player-aiminimax.jar and b/Mage.Tests/plugins/mage-player-aiminimax.jar differ diff --git a/Mage.Tests/scenario5.txt b/Mage.Tests/scenario5.txt index e00fa18214..9572b2336f 100644 --- a/Mage.Tests/scenario5.txt +++ b/Mage.Tests/scenario5.txt @@ -3,9 +3,9 @@ ### ComputerA ### # Battlefield battlefield:ComputerA:Island:2 -battlefield:ComputerA:Mountain:1 +battlefield:ComputerA:Mountain:3 battlefield:ComputerA:Dragonskull Summit:1 -battlefield:ComputerA:Lavaclaw Reaches:1 +battlefield:ComputerA:Lavaclaw Reaches:0 # Hand hand:ComputerA:Mountain:0 hand:ComputerA:Earthquake:1 diff --git a/Mage.Tests/src/test/java/org/mage/test/serverside/PlayGameTest.java b/Mage.Tests/src/test/java/org/mage/test/serverside/PlayGameTest.java index d9918778a9..7cc3a5d15c 100644 --- a/Mage.Tests/src/test/java/org/mage/test/serverside/PlayGameTest.java +++ b/Mage.Tests/src/test/java/org/mage/test/serverside/PlayGameTest.java @@ -43,31 +43,35 @@ public class PlayGameTest extends MageTestBase { Deck deck = Deck.load(Sets.loadDeck("RB Aggro.dck")); if (deck.getCards().size() < 40) { - throw new IllegalArgumentException("Couldn't load deck, deck side=" + deck.getCards().size()); + throw new IllegalArgumentException("Couldn't load deck, deck size=" + deck.getCards().size()); } game.addPlayer(computerA, deck); game.loadCards(deck.getCards(), computerA.getId()); - Player computerB = createPlayer("ComputerB", "Computer - mad"); + Player computerB = createPlayer("ComputerB", "Computer - minimax hybrid"); Deck deck2 = Deck.load(Sets.loadDeck("RB Aggro.dck")); if (deck2.getCards().size() < 40) { - throw new IllegalArgumentException("Couldn't load deck, deck side=" + deck2.getCards().size()); + throw new IllegalArgumentException("Couldn't load deck, deck size=" + deck2.getCards().size()); } game.addPlayer(computerB, deck2); game.loadCards(deck2.getCards(), computerB.getId()); - parseScenario("scenario5.txt"); + /*parseScenario("scenario7.txt"); game.cheat(computerA.getId(), commandsA); game.cheat(computerA.getId(), libraryCardsA, handCardsA, battlefieldCardsA, graveyardCardsA); game.cheat(computerB.getId(), commandsB); game.cheat(computerB.getId(), libraryCardsB, handCardsB, battlefieldCardsB, graveyardCardsB); + */ long t1 = System.nanoTime(); - game.start(computerA.getId(), true); + game.start(computerA.getId(), false); long t2 = System.nanoTime(); logger.info("Winner: " + game.getWinner()); logger.info("Time: " + (t2 - t1) / 1000000 + " ms"); + /*if (!game.getWinner().equals("Player ComputerA is the winner")) { + throw new RuntimeException("Lost :("); + }*/ } private void addCard(List cards, String name, int count) {