diff --git a/Mage.Server.Plugins/Mage.Player.AI.MA/src/mage/player/ai/ComputerPlayer4.java b/Mage.Server.Plugins/Mage.Player.AI.MA/src/mage/player/ai/ComputerPlayer4.java deleted file mode 100644 index 52b80e504f..0000000000 --- a/Mage.Server.Plugins/Mage.Player.AI.MA/src/mage/player/ai/ComputerPlayer4.java +++ /dev/null @@ -1,679 +0,0 @@ -/* - * Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without modification, are - * permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, this list of - * conditions and the following disclaimer. - * - * 2. Redistributions in binary form must reproduce the above copyright notice, this list - * of conditions and the following disclaimer in the documentation and/or other materials - * provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED - * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND - * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR - * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR - * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON - * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING - * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF - * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * - * The views and conclusions contained in the software and documentation are those of the - * authors and should not be interpreted as representing official policies, either expressed - * or implied, of BetaSteward_at_googlemail.com. - */ - -package mage.player.ai; - -import java.util.ArrayList; -import java.util.LinkedList; -import java.util.List; -import java.util.UUID; -import java.util.concurrent.Callable; -import java.util.concurrent.ExecutionException; -import java.util.concurrent.ExecutorService; -import java.util.concurrent.Executors; -import java.util.concurrent.FutureTask; -import java.util.concurrent.TimeUnit; -import java.util.concurrent.TimeoutException; -import java.util.logging.Level; -import java.util.logging.Logger; -import mage.Constants.Outcome; -import mage.Constants.PhaseStep; -import mage.Constants.RangeOfInfluence; -import mage.abilities.Ability; -import mage.abilities.ActivatedAbility; -import mage.abilities.effects.Effect; -import mage.abilities.effects.SearchEffect; -import mage.cards.Card; -import mage.cards.Cards; -import mage.choices.Choice; -import mage.filter.FilterAbility; -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.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.players.Player; -import mage.target.Target; -import mage.target.TargetCard; -import mage.util.Logging; - -/** - * - * @author BetaSteward_at_googlemail.com - */ -public class ComputerPlayer4 extends ComputerPlayer implements Player { - - private static final transient Logger logger = Logging.getLogger(ComputerPlayer4.class.getName()); - private static final ExecutorService pool = Executors.newFixedThreadPool(1); - - protected int maxDepth; - protected int maxNodes; - protected LinkedList actions = new LinkedList(); - protected List targets = new ArrayList(); - protected List choices = new ArrayList(); - protected Combat combat; - protected int currentScore; - protected SimulationNode2 root; - - public ComputerPlayer4(String name, RangeOfInfluence range) { - super(name, range); - maxDepth = Config2.maxDepth; - maxNodes = Config2.maxNodes; - } - - public ComputerPlayer4(final ComputerPlayer4 player) { - super(player); - this.maxDepth = player.maxDepth; - this.currentScore = player.currentScore; - if (player.combat != null) - this.combat = player.combat.copy(); - for (Ability ability: player.actions) { - actions.add(ability); - } - for (UUID targetId: player.targets) { - targets.add(targetId); - } - for (String choice: player.choices) { - choices.add(choice); - } - } - - @Override - public ComputerPlayer4 copy() { - return new ComputerPlayer4(this); - } - - @Override - public void priority(Game game) { - logState(game); - game.firePriorityEvent(playerId); - switch (game.getTurn().getStepType()) { - case UPKEEP: - case DRAW: - pass(); - break; - case PRECOMBAT_MAIN: - case POSTCOMBAT_MAIN: - if (game.getActivePlayerId().equals(playerId)) { - Player player = game.getPlayer(playerId); - System.out.println("Turn::"+game.getTurnNum()); - System.out.println("[" + game.getPlayer(playerId).getName() + "] " + game.getTurn().getStepType().name() +", life=" + player.getLife()); - String s = "["; - for (Card card : player.getHand().getCards(game)) { - s += card.getName() + ";"; - } - s += "]"; - System.out.println("Hand: " + s); - s = "["; - for (Permanent permanent : game.getBattlefield().getAllPermanents()) { - if (permanent.getOwnerId().equals(player.getId())) { - s += permanent.getName() + ";"; - } - } - s += "]"; - System.out.println("Permanents: " + s); - } - if (actions.size() == 0) { - calculateActions(game); - } - act(game); - break; - case BEGIN_COMBAT: - case DECLARE_ATTACKERS: - case DECLARE_BLOCKERS: - case COMBAT_DAMAGE: - case END_COMBAT: - case END_TURN: - pass(); - break; - case CLEANUP: - pass(); - break; - } - } - - protected void act(Game game) { - if (actions == null || actions.size() == 0) - pass(); - else { - boolean usedStack = false; - while (actions.peek() != null) { - Ability ability = actions.poll(); - System.out.println("[" + game.getPlayer(playerId).getName() + "] Action: " + ability.toString()); - this.activateAbility((ActivatedAbility) ability, game); - if (ability.isUsesStack()) - usedStack = true; - } - if (usedStack) - pass(); - } - } - - protected void calculateActions(Game game) { - currentScore = GameStateEvaluator2.evaluate(playerId, game); - if (!getNextAction(game)) { - Game sim = createSimulation(game); - SimulationNode2.resetCount(); - root = new SimulationNode2(sim, maxDepth, playerId); - logger.info("simulating actions"); - addActionsTimed(new FilterAbility()); - if (root.children.size() > 0) { - root = root.children.get(0); - int bestScore = GameStateEvaluator2.evaluate(playerId, root.getGame()); - if (bestScore > currentScore) { - actions = new LinkedList(root.abilities); - combat = root.combat; - } - } - } - } - - protected boolean getNextAction(Game game) { - if (root != null && root.children.size() > 0) { - SimulationNode2 test = root; - root = root.children.get(0); - while (root.children.size() > 0 && !root.playerId.equals(playerId)) { - test = root; - root = root.children.get(0); - } - logger.info("simlating -- game value:" + game.getState().getValue() + " test value:" + test.gameValue); - if (root.playerId.equals(playerId) && root.abilities != null && game.getState().getValue() == test.gameValue) { - logger.info("simulating -- continuing previous action chain"); - actions = new LinkedList(root.abilities); - combat = root.combat; - return true; - } - else { - return false; - } - } - return false; - } - - protected int minimaxAB(SimulationNode2 node, FilterAbility filter, int depth, int alpha, int beta) { - UUID currentPlayerId = node.getGame().getPlayerList().get(); - SimulationNode2 bestChild = null; - for (SimulationNode2 child: node.getChildren()) { - 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, filter, depth-1, alpha, beta); - if (!currentPlayerId.equals(playerId)) { - if (val < beta) { - beta = val; - bestChild = child; - if (node.getCombat() == null) - node.setCombat(child.getCombat()); - } - } - else { - if (val > alpha) { - alpha = val; - bestChild = child; - if (node.getCombat() == null) - node.setCombat(child.getCombat()); - } - } - } - node.children.clear(); - if (bestChild != null) - 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; - } - } - - protected SearchEffect getSearchEffect(StackAbility ability) { - for (Effect effect: ability.getEffects()) { - if (effect instanceof SearchEffect) { - return (SearchEffect) effect; - } - } - return null; - } - - protected void resolve(SimulationNode2 node, int depth, Game game) { - StackObject ability = game.getStack().pop(); - if (ability instanceof StackAbility) { - SearchEffect effect = getSearchEffect((StackAbility) ability); - if (effect != null && ability.getControllerId().equals(playerId)) { - Target target = effect.getTarget(); - if (!target.doneChosing()) { - for (UUID targetId: target.possibleTargets(ability.getSourceId(), ability.getControllerId(), game)) { - Game sim = game.copy(); - StackAbility newAbility = (StackAbility) ability.copy(); - SearchEffect newEffect = getSearchEffect((StackAbility) newAbility); - newEffect.getTarget().addTarget(targetId, newAbility, sim); - sim.getStack().push(newAbility); - SimulationNode2 newNode = new SimulationNode2(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()); - } - return; - } - } - } - //logger.info("simulating resolve "); - ability.resolve(game); - game.applyEffects(); - game.getPlayers().resetPassed(); - game.getPlayerList().setCurrent(game.getActivePlayerId()); - } - - protected void addActionsTimed(final FilterAbility filter) { - FutureTask task = new FutureTask(new Callable() { - public Integer call() throws Exception - { - return addActions(root, filter, maxDepth, Integer.MIN_VALUE, Integer.MAX_VALUE); - } - }); - pool.execute(task); - try { - task.get(Config2.maxThinkSeconds, TimeUnit.MINUTES); - } catch (TimeoutException e) { - logger.info("simulating - timed out"); - task.cancel(true); - } catch (ExecutionException e) { - e.printStackTrace(); - } catch (InterruptedException e) { - e.printStackTrace(); - } - } - - protected int addActions(SimulationNode2 node, FilterAbility filter, int depth, int alpha, int beta) { - logger.fine("addActions: " + depth + ", alpha=" + alpha + ", beta=" + beta); - Game game = node.getGame(); - int val; - if (Thread.interrupted()) { - Thread.currentThread().interrupt(); - logger.info("interrupted"); - return GameStateEvaluator2.evaluate(playerId, game); - } - if (depth <= 0 || SimulationNode2.nodeCount > maxNodes || game.isGameOver()) { - logger.fine("simulating -- reached end state, node count="+ SimulationNode2.nodeCount + ", depth="+depth); - val = GameStateEvaluator2.evaluate(playerId, game); - } - else if (node.getChildren().size() > 0) { - logger.fine("simulating -- somthing added children:" + node.getChildren().size()); - val = minimaxAB(node, filter, depth-1, alpha, beta); - } - 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")); - if (allPassed(game)) { - if (!game.getStack().isEmpty()) { - resolve(node, depth, game); - } - else { -// int testScore = GameStateEvaluator.evaluate(playerId, game); -// if (testScore < currentScore) { -// // if score at end of step is worse than original score don't check any further -// logger.info("simulating -- abandoning current check, no immediate benefit"); -// return testScore; -// } - game.getPlayers().resetPassed(); - playNext(game, game.getActivePlayerId(), node); - } - } - - if (game.isGameOver()) { - val = GameStateEvaluator2.evaluate(playerId, game); - } - else if (node.getChildren().size() > 0) { - //declared attackers or blockers or triggered abilities - logger.fine("simulating -- attack/block/trigger added children:" + node.getChildren().size()); - val = minimaxAB(node, filter, depth-1, alpha, beta); - } - else { - val = simulatePriority(node, game, filter, depth, alpha, beta); - } - } - - if (logger.isLoggable(Level.FINE)) - logger.fine("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, FilterAbility filter, int depth, int alpha, int beta) { - if (Thread.interrupted()) { - Thread.currentThread().interrupt(); - logger.info("interrupted"); - return GameStateEvaluator2.evaluate(playerId, game); - } - node.setGameValue(game.getState().getValue()); - SimulatedPlayer2 currentPlayer = (SimulatedPlayer2) game.getPlayer(game.getPlayerList().get()); - //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); - for (Ability action: allActions) { - Game sim = game.copy(); - if (sim.getPlayer(currentPlayer.getId()).activateAbility((ActivatedAbility) action.copy(), sim)) { - sim.applyEffects(); - if (!sim.isGameOver() && action.isUsesStack()) { - // only pass if the last action uses the stack - sim.getPlayer(currentPlayer.getId()).pass(); - sim.getPlayerList().getNext(); - } - SimulationNode2 newNode = new SimulationNode2(sim, action, depth, currentPlayer.getId()); - if (logger.isLoggable(Level.FINE)) - logger.fine("simulating -- node #:" + SimulationNode2.getCount() + " actions:" + action); - sim.checkStateAndTriggered(); - int val = addActions(newNode, filter, depth-1, alpha, beta); - if (!currentPlayer.getId().equals(playerId)) { - if (val < beta) { - beta = val; - bestNode = newNode; - node.setCombat(newNode.getCombat()); - } - } - else { - if (val > alpha) { - alpha = val; - bestNode = newNode; - node.setCombat(newNode.getCombat()); - if (node.getTargets().size() > 0) - targets = node.getTargets(); - if (node.getChoices().size() > 0) - choices = node.getChoices(); - } - } - if (alpha >= beta) { - //logger.info("simulating -- pruning"); - break; - } - if (SimulationNode2.nodeCount > maxNodes) { - logger.fine("simulating -- reached end-state"); - break; - } - } - } - if (bestNode != null) { - node.children.clear(); - node.children.add(bestNode); - } - if (!currentPlayer.getId().equals(playerId)) { - //logger.info("returning priority beta: " + beta); - return beta; - } - else { - //logger.info("returning priority alpha: " + alpha); - return alpha; - } - } - - protected boolean allPassed(Game game) { - for (Player player: game.getPlayers().values()) { - if (!player.isPassed() && !player.hasLost() && !player.hasLeft()) - return false; - } - return true; - } - - @Override - public boolean choose(Outcome outcome, Choice choice, Game game) { - if (choices.size() == 0) - return super.choose(outcome, choice, game); - if (!choice.isChosen()) { - for (String achoice: choices) { - choice.setChoice(achoice); - if (choice.isChosen()) { - choices.clear(); - return true; - } - } - return false; - } - return true; - } - - @Override - public boolean chooseTarget(Cards cards, TargetCard target, Ability source, Game game) { - if (targets.size() == 0) - return super.chooseTarget(cards, target, source, game); - if (!target.doneChosing()) { - for (UUID targetId: targets) { - target.addTarget(targetId, source, game); - if (target.doneChosing()) { - targets.clear(); - return true; - } - } - return false; - } - return true; - } - - @Override - public boolean choose(Cards cards, TargetCard target, Game game) { - if (targets.size() == 0) - return super.choose(cards, target, game); - if (!target.doneChosing()) { - for (UUID targetId: targets) { - target.add(targetId, game); - if (target.doneChosing()) { - targets.clear(); - return true; - } - } - return false; - } - 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 CombatDamageStep(true)); - break; - case COMBAT_DAMAGE: - if (((CombatDamageStep)currentPhase.getStep()).getFirst()) - game.getPhase().setStep(new CombatDamageStep(false)); - else - 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.isGameOver()) { - 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) { - 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); - } - } - sim.fireEvent(GameEvent.getEvent(GameEvent.EventType.DECLARED_ATTACKERS, playerId, playerId)); - SimulationNode2 newNode = new SimulationNode2(sim, node.getDepth()-1, activePlayerId); - logger.info("simulating -- node #:" + SimulationNode2.getCount() + " declare attakers"); - newNode.setCombat(sim.getCombat()); - node.children.add(newNode); - } - } - } - else if (game.getTurn().getStepType() == PhaseStep.DECLARE_BLOCKERS) { - 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()) { - for (UUID blockerId: group.getBlockers()) { - group.addBlocker(blockerId, defenderId, sim); - } - } - sim.fireEvent(GameEvent.getEvent(GameEvent.EventType.DECLARED_BLOCKERS, playerId, playerId)); - SimulationNode2 newNode = new SimulationNode2(sim, node.getDepth()-1, defenderId); - logger.info("simulating -- node #:" + SimulationNode2.getCount() + " declare blockers"); - newNode.setCombat(sim.getCombat()); - node.children.add(newNode); - } - } - } - } - } - else { - game.getStep().beginStep(game, activePlayerId); - } - if (game.getStep().getHasPriority()) - break; - } - else { - skip = true; - } - } - game.checkStateAndTriggered(); - } - - @Override - public void selectAttackers(Game game) { - logger.info("selectAttackers"); - if (combat != null) { - UUID opponentId = game.getCombat().getDefenders().iterator().next(); - for (UUID attackerId: combat.getAttackers()) { - logger.info("declare attacker: " + game.getCard(attackerId).getName()); - this.declareAttacker(attackerId, opponentId, game); - } - } - } - - @Override - public void selectBlockers(Game game) { - logger.info("selectBlockers"); - 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()) { - this.declareBlocker(blockerId, groups.get(i).getAttackers().get(0), game); - } - } - } - } - } - - /** - * Copies game and replaces all players in copy with simulated players - * - * @param game - * @return a new game object with simulated players - */ - protected Game createSimulation(Game game) { - Game sim = game.copy(); - - for (Player copyPlayer: sim.getState().getPlayers().values()) { - Player origPlayer = game.getState().getPlayers().get(copyPlayer.getId()); - SimulatedPlayer2 newPlayer = new SimulatedPlayer2(copyPlayer.getId(), copyPlayer.getId().equals(playerId)); - newPlayer.restore(origPlayer); - sim.getState().getPlayers().put(copyPlayer.getId(), newPlayer); - } - return sim; - } - -} diff --git a/Mage.Server.Plugins/Mage.Player.AI.MA/src/mage/player/ai/ComputerPlayer5.java b/Mage.Server.Plugins/Mage.Player.AI.MA/src/mage/player/ai/ComputerPlayer5.java deleted file mode 100644 index f320a1da3d..0000000000 --- a/Mage.Server.Plugins/Mage.Player.AI.MA/src/mage/player/ai/ComputerPlayer5.java +++ /dev/null @@ -1,564 +0,0 @@ -/* - * Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without modification, are - * permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, this list of - * conditions and the following disclaimer. - * - * 2. Redistributions in binary form must reproduce the above copyright notice, this list - * of conditions and the following disclaimer in the documentation and/or other materials - * provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED - * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND - * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR - * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR - * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON - * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING - * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF - * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * - * The views and conclusions contained in the software and documentation are those of the - * authors and should not be interpreted as representing official policies, either expressed - * or implied, of BetaSteward_at_googlemail.com. - */ - -package mage.player.ai; - -import java.util.LinkedList; -import java.util.UUID; -import java.util.logging.Level; -import java.util.logging.Logger; -import mage.Constants.AbilityType; -import mage.Constants.PhaseStep; -import mage.Constants.RangeOfInfluence; -import mage.Constants.Zone; -import mage.abilities.Ability; -import mage.cards.Card; -import mage.filter.FilterAbility; -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.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.PostCombatMainPhase; -import mage.game.turn.PostCombatMainStep; -import mage.game.turn.Step; -import mage.game.turn.UntapStep; -import mage.game.turn.UpkeepStep; -import mage.players.Player; -import mage.util.Logging; - -/** - * - * @author BetaSteward_at_googlemail.com - */ -public class ComputerPlayer5 extends ComputerPlayer4 implements Player { - - private static final transient Logger logger = Logging.getLogger(ComputerPlayer5.class.getName()); - - private static FilterAbility filterLand = new FilterAbility(); - private static FilterAbility filterNotLand = new FilterAbility(); - - static { - filterLand.getTypes().add(AbilityType.PLAY_LAND); - filterLand.setZone(Zone.HAND); - - filterNotLand.getTypes().add(AbilityType.PLAY_LAND); - filterNotLand.setZone(Zone.HAND); - filterNotLand.setNotFilter(true); - - logger.setLevel(Level.ALL); - } - - public ComputerPlayer5(String name, RangeOfInfluence range) { - super(name, range); - maxDepth = Config2.maxDepth; - maxNodes = Config2.maxNodes; - } - - public ComputerPlayer5(final ComputerPlayer5 player) { - super(player); - } - - @Override - public ComputerPlayer5 copy() { - return new ComputerPlayer5(this); - } - - @Override - public void priority(Game game) { - logState(game); - game.firePriorityEvent(playerId); - switch (game.getTurn().getStepType()) { - case UPKEEP: - case DRAW: - pass(); - break; - case PRECOMBAT_MAIN: - if (game.getActivePlayerId().equals(playerId)) { - Player player = game.getPlayer(playerId); - System.out.println("Turn:"+game.getTurnNum()); - System.out.println("[" + game.getPlayer(playerId).getName() + "] Precombat Main, life=" + player.getLife()); - String s = "["; - for (Card card : player.getHand().getCards(game)) { - s += card.getName() + ";"; - } - s += "]"; - System.out.println("Hand: " + s); - s = "["; - for (Permanent permanent : game.getBattlefield().getAllPermanents()) { - if (permanent.getOwnerId().equals(player.getId())) { - s += permanent.getName() + ";"; - } - } - s += "]"; - System.out.println("Permanents: " + s); - if (actions.size() == 0) { - calculatePreCombatActions(game); - } - act(game); - } - else - pass(); - break; - case BEGIN_COMBAT: - pass(); - break; - case DECLARE_ATTACKERS: - if (!game.getActivePlayerId().equals(playerId)) { - if (actions.size() == 0) { - calculatePreCombatActions(game); - } - act(game); - } - else - pass(); - break; - case DECLARE_BLOCKERS: - case COMBAT_DAMAGE: - case END_COMBAT: - pass(); - break; - case POSTCOMBAT_MAIN: - if (game.getActivePlayerId().equals(playerId)) { - if (actions.size() == 0) { - calculatePostCombatActions(game); - } - act(game); - } - else - pass(); - break; - case END_TURN: - case CLEANUP: - pass(); - break; - } - } - - protected void calculatePreCombatActions(Game game) { - //if (!getNextAction(game)) { - currentScore = GameStateEvaluator2.evaluate(playerId, game); - Game sim = createSimulation(game); - SimulationNode2.resetCount(); - root = new SimulationNode2(sim, maxDepth, playerId); - logger.fine("simulating pre combat actions -----------------------------------------------------------------------------------------"); - - addActionsTimed(new FilterAbility()); - if (root.children.size() > 0) { - root = root.children.get(0); - int bestScore = GameStateEvaluator2.evaluate(playerId, root.getGame()); - if (bestScore > currentScore) { - actions = new LinkedList(root.abilities); - combat = root.combat; - } - } - //} - } - - protected void calculatePostCombatActions(Game game) { - if (!getNextAction(game)) { - currentScore = GameStateEvaluator2.evaluate(playerId, game); - Game sim = createSimulation(game); - SimulationNode2.resetCount(); - root = new SimulationNode2(sim, maxDepth, playerId); - logger.fine("simulating post combat actions ----------------------------------------------------------------------------------------"); - addActionsTimed(new FilterAbility()); - if (root.children.size() > 0) { - root = root.children.get(0); - int bestScore = GameStateEvaluator2.evaluate(playerId, root.getGame()); - if (bestScore > currentScore) { - actions = new LinkedList(root.abilities); - combat = root.combat; - } - } - } - } - - @Override - protected int addActions(SimulationNode2 node, FilterAbility filter, int depth, int alpha, int beta) { - boolean stepFinished = false; - int val; - Game game = node.getGame(); - if (Thread.interrupted()) { - Thread.currentThread().interrupt(); - logger.fine("interrupted"); - return GameStateEvaluator2.evaluate(playerId, game); - } - if (depth <= 0 || SimulationNode2.nodeCount > maxNodes || game.isGameOver()) { - logger.fine("simulating -- reached end state"); - val = GameStateEvaluator2.evaluate(playerId, game); - } - else if (node.getChildren().size() > 0) { - logger.fine("simulating -- somthing added children:" + node.getChildren().size()); - val = minimaxAB(node, filter, depth-1, alpha, beta); - } - else { - if (logger.isLoggable(Level.FINE)) - logger.fine("simulating -- 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.isGameOver()) { - val = GameStateEvaluator2.evaluate(playerId, game); - } - else if (stepFinished) { - logger.fine("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.fine("simulating -- 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; - } - } - } - else { - 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().size() > 0) { - logger.fine("simulating -- trigger added children:" + node.getChildren().size()); - val = minimaxAB(node, filter, depth, alpha, beta); - } - else { - val = simulatePriority(node, game, filter, depth, alpha, beta); - } - } - - if (logger.isLoggable(Level.FINE)) - logger.fine("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 (Thread.interrupted()) { - Thread.currentThread().interrupt(); - logger.fine("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 = GameStateEvaluator2.evaluate(playerId, game); -// val = simulateCounterAttack(game, node, depth, alpha, beta); - } - } - if (val == null) - val = GameStateEvaluator2.evaluate(playerId, game); - if (logger.isLoggable(Level.FINE)) - logger.fine("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 (Thread.interrupted()) { - Thread.currentThread().interrupt(); - logger.fine("interrupted"); - return GameStateEvaluator2.evaluate(playerId, game); - } - Integer val = null; - SimulationNode2 bestNode = null; - SimulatedPlayer2 attacker = (SimulatedPlayer2) game.getPlayer(attackerId); - - for (Combat engagement: attacker.addAttackers(game)) { - if (alpha >= beta) { - //logger.fine("simulating -- pruning attackers"); - break; - } - Game sim = game.copy(); - UUID defenderId = game.getOpponents(playerId).iterator().next(); - for (CombatGroup group: engagement.getGroups()) { - for (UUID attackId: group.getAttackers()) { - sim.getPlayer(attackerId).declareAttacker(attackId, defenderId, sim); - } - } - sim.fireEvent(GameEvent.getEvent(GameEvent.EventType.DECLARED_ATTACKERS, playerId, playerId)); - SimulationNode2 newNode = new SimulationNode2(sim, depth, game.getActivePlayerId()); - if (logger.isLoggable(Level.FINE)) - logger.fine("simulating attack -- node#: " + SimulationNode2.getCount()); - sim.checkStateAndTriggered(); - while (!sim.getStack().isEmpty()) { - sim.getStack().resolve(sim); - logger.fine("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; - node.setCombat(simCombat); - } - } - else { - if (val > alpha) { - alpha = val; - bestNode = newNode; - node.setCombat(simCombat); - } - } - } - if (val == null) - val = GameStateEvaluator2.evaluate(playerId, game); - if (bestNode != null) { - node.children.clear(); - node.children.add(bestNode); - } - if (logger.isLoggable(Level.FINE)) - logger.fine("returning -- combat attacker 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 (Thread.interrupted()) { - Thread.currentThread().interrupt(); - logger.fine("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); - for (Combat engagement: defender.addBlockers(game)) { - if (alpha >= beta) { - logger.fine("simulating -- pruning blockers"); - break; - } - Game sim = game.copy(); - for (CombatGroup group : engagement.getGroups()) { - if (group.getAttackers().size() > 0) { - UUID attackerId = group.getAttackers().get(0); - for (UUID blockerId : group.getBlockers()) { - sim.getPlayer(defenderId).declareBlocker(blockerId, attackerId, sim); - } - } - - } - sim.fireEvent(GameEvent.getEvent(GameEvent.EventType.DECLARED_BLOCKERS, playerId, playerId)); - SimulationNode2 newNode = new SimulationNode2(sim, depth, defenderId); - if (logger.isLoggable(Level.FINE)) - logger.fine("simulating block -- node#: " + SimulationNode2.getCount()); - sim.checkStateAndTriggered(); - while (!sim.getStack().isEmpty()) { - sim.getStack().resolve(sim); - logger.fine("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.isGameOver()) { - 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; - node.setCombat(simCombat); - } - } - else { - if (val > alpha) { - alpha = val; - bestNode = newNode; - node.setCombat(simCombat); - } - } - } - } - if (val == null) - val = GameStateEvaluator2.evaluate(playerId, game); - if (bestNode != null) { - node.children.clear(); - node.children.add(bestNode); - } - if (logger.isLoggable(Level.FINE)) - logger.fine("returning -- combat blocker 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 (Thread.interrupted()) { - Thread.currentThread().interrupt(); - logger.fine("interrupted"); - return GameStateEvaluator2.evaluate(playerId, game); - } - Integer val = null; - if (!game.isGameOver()) { - logger.fine("simulating -- counter attack"); - simulateToEnd(game); - game.getState().setActivePlayerId(game.getState().getPlayerList(game.getActivePlayerId()).getNext()); - 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.isLoggable(Level.FINE)) - logger.fine("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 (Thread.interrupted()) { - Thread.currentThread().interrupt(); - logger.fine("interrupted"); - return; - } - if (!game.isGameOver()) { - 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 (Thread.interrupted()) { - Thread.currentThread().interrupt(); - logger.fine("interrupted"); - return; - } - simulateStep(game, new CombatDamageStep(true)); - simulateStep(game, new CombatDamageStep(false)); - simulateStep(game, new EndOfCombatStep()); - } - - protected int simulatePostCombatMain(Game game, SimulationNode2 node, int depth, int alpha, int beta) { - if (Thread.interrupted()) { - Thread.currentThread().interrupt(); - logger.fine("interrupted"); - return GameStateEvaluator2.evaluate(playerId, game); - } - logger.fine("simulating -- 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, new FilterAbility(), depth, alpha, beta); - } - return simulateCounterAttack(game, node, depth, alpha, beta); - } - - protected void simulateToEnd(Game game) { - if (Thread.interrupted()) { - Thread.currentThread().interrupt(); - logger.fine("interrupted"); - return; - } - if (!game.isGameOver()) { - 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()); - } - } - } - -} 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 272de90b47..f26b622914 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 @@ -33,12 +33,14 @@ import mage.Constants.PhaseStep; import mage.Constants.RangeOfInfluence; import mage.abilities.Ability; import mage.abilities.ActivatedAbility; +import mage.abilities.common.PassAbility; import mage.abilities.effects.Effect; import mage.abilities.effects.SearchEffect; import mage.cards.Card; import mage.cards.Cards; import mage.choices.Choice; import mage.filter.FilterAbility; +import mage.filter.common.FilterCreatureForAttack; import mage.game.Game; import mage.game.combat.Combat; import mage.game.combat.CombatGroup; @@ -116,35 +118,35 @@ public class ComputerPlayer6 extends ComputerPlayer implements pass(); break; case PRECOMBAT_MAIN: - case BEGIN_COMBAT: - case DECLARE_ATTACKERS: case DECLARE_BLOCKERS: - case COMBAT_DAMAGE: - case END_COMBAT: case POSTCOMBAT_MAIN: if (game.getActivePlayerId().equals(playerId)) { - Player player = game.getPlayer(playerId); - System.out.println("Turn::"+game.getTurnNum()); - System.out.println("[" + game.getPlayer(playerId).getName() + "] " + game.getTurn().getStepType().name() +", life=" + player.getLife()); - String s = "["; - for (Card card : player.getHand().getCards(game)) { - s += card.getName() + ";"; + printOutState(game, playerId); + if (actions.size() == 0) { + calculateActions(game); } - s += "]"; - System.out.println("Hand: " + s); - s = "["; - for (Permanent permanent : game.getBattlefield().getAllPermanents()) { - if (permanent.getOwnerId().equals(player.getId())) { - s += permanent.getName() + ";"; - } + act(game); + } else { + pass(); + } + break; + case BEGIN_COMBAT: + case COMBAT_DAMAGE: + case END_COMBAT: + pass(); + break; + case DECLARE_ATTACKERS: + if (!game.getActivePlayerId().equals(playerId)) { + printOutState(game, playerId); + printOutState(game, game.getOpponents(playerId).iterator().next()); + if (actions.size() == 0) { + calculateActions(game); } - s += "]"; - System.out.println("Permanents: " + s); + act(game); + printOutState(game, playerId); + } else { + pass(); } - if (actions.size() == 0) { - calculateActions(game); - } - act(game); break; case END_TURN: pass(); @@ -155,6 +157,36 @@ public class ComputerPlayer6 extends ComputerPlayer implements } } + private void printOutState(Game game, UUID playerId) { + Player player = game.getPlayer(playerId); + System.out.println("Turn::"+game.getTurnNum()); + System.out.println("[" + game.getPlayer(playerId).getName() + "] " + game.getTurn().getStepType().name() +", life=" + player.getLife()); + Player opponent = game.getPlayer(game.getOpponents(playerId).iterator().next()); + System.out.println("[Opponent] life=" + opponent.getLife()); + + String s = "["; + for (Card card : player.getHand().getCards(game)) { + s += card.getName() + ";"; + } + s += "]"; + System.out.println("Hand: " + s); + s = "["; + for (Permanent permanent : game.getBattlefield().getAllPermanents()) { + if (permanent.getOwnerId().equals(player.getId())) { + s += permanent.getName(); + if (permanent.isTapped()) { + s+="(tapped)"; + } + if (permanent.isAttacking()) { + s+="(attacking)"; + } + s+=";"; + } + } + s += "]"; + System.out.println("Permanents: " + s); + } + protected void act(Game game) { if (actions == null || actions.size() == 0) pass(); @@ -177,7 +209,7 @@ public class ComputerPlayer6 extends ComputerPlayer implements if (!getNextAction(game)) { Game sim = createSimulation(game); SimulationNode2.resetCount(); - root = new SimulationNode2(sim, maxDepth, playerId); + root = new SimulationNode2(null, sim, maxDepth, playerId); logger.info("simulating actions"); //int bestScore = addActionsTimed(new FilterAbility()); addActionsTimed(new FilterAbility()); @@ -203,6 +235,19 @@ public class ComputerPlayer6 extends ComputerPlayer implements } logger.info("simlating -- game value:" + game.getState().getValue() + " test value:" + test.gameValue); if (root.playerId.equals(playerId) && root.abilities != null && game.getState().getValue() == test.gameValue) { + + // Try to fix horizon effect + if (root.combat == null || root.combat.getAttackers().size() == 0) { + 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; + } + } + logger.info("simulating -- continuing previous action chain"); actions = new LinkedList(root.abilities); combat = root.combat; @@ -219,6 +264,7 @@ public class ComputerPlayer6 extends ComputerPlayer implements UUID currentPlayerId = node.getGame().getPlayerList().get(); SimulationNode2 bestChild = null; for (SimulationNode2 child: node.getChildren()) { + Combat _combat = child.getCombat(); if (alpha >= beta) { logger.info("alpha beta pruning"); break; @@ -232,16 +278,20 @@ public class ComputerPlayer6 extends ComputerPlayer implements if (val < beta) { beta = val; bestChild = child; - if (node.getCombat() == null) - node.setCombat(child.getCombat()); + if (node.getCombat() == null) { + node.setCombat(_combat); + bestChild.setCombat(_combat); + } } } else { if (val > alpha) { alpha = val; bestChild = child; - if (node.getCombat() == null) - node.setCombat(child.getCombat()); + if (node.getCombat() == null) { + node.setCombat(_combat); + bestChild.setCombat(_combat); + } } } } @@ -280,7 +330,7 @@ public class ComputerPlayer6 extends ComputerPlayer implements SearchEffect newEffect = getSearchEffect((StackAbility) newAbility); newEffect.getTarget().addTarget(targetId, newAbility, sim); sim.getStack().push(newAbility); - SimulationNode2 newNode = new SimulationNode2(sim, depth, ability.getControllerId()); + 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()); @@ -315,6 +365,9 @@ public class ComputerPlayer6 extends ComputerPlayer implements } catch (InterruptedException e) { e.printStackTrace(); task.cancel(true); + } catch (Exception e) { + e.printStackTrace(); + task.cancel(true); } //TODO: timeout handling return 0; @@ -389,12 +442,14 @@ public class ComputerPlayer6 extends ComputerPlayer implements Game sim = game.copy(); if (sim.getPlayer(currentPlayer.getId()).activateAbility((ActivatedAbility) action.copy(), sim)) { sim.applyEffects(); + if (checkForRepeatedAction(sim, node, action, currentPlayer.getId())) + continue; if (!sim.isGameOver() && action.isUsesStack()) { // only pass if the last action uses the stack sim.getPlayer(currentPlayer.getId()).pass(); sim.getPlayerList().getNext(); } - SimulationNode2 newNode = new SimulationNode2(sim, action, depth, currentPlayer.getId()); + SimulationNode2 newNode = new SimulationNode2(node, sim, action, depth, currentPlayer.getId()); if (logger.isLoggable(Level.FINE)) logger.fine("simulating -- node #:" + SimulationNode2.getCount() + " actions:" + action); sim.checkStateAndTriggered(); @@ -572,7 +627,7 @@ public class ComputerPlayer6 extends ComputerPlayer implements } } sim.fireEvent(GameEvent.getEvent(GameEvent.EventType.DECLARED_ATTACKERS, playerId, playerId)); - SimulationNode2 newNode = new SimulationNode2(sim, node.getDepth()-1, activePlayerId); + SimulationNode2 newNode = new SimulationNode2(node, sim, node.getDepth()-1, activePlayerId); logger.info("simulating -- node #:" + SimulationNode2.getCount() + " declare attakers"); newNode.setCombat(sim.getCombat()); node.children.add(newNode); @@ -593,7 +648,7 @@ public class ComputerPlayer6 extends ComputerPlayer implements } } sim.fireEvent(GameEvent.getEvent(GameEvent.EventType.DECLARED_BLOCKERS, playerId, playerId)); - SimulationNode2 newNode = new SimulationNode2(sim, node.getDepth()-1, defenderId); + SimulationNode2 newNode = new SimulationNode2(node, sim, node.getDepth()-1, defenderId); logger.info("simulating -- node #:" + SimulationNode2.getCount() + " declare blockers"); newNode.setCombat(sim.getCombat()); node.children.add(newNode); @@ -660,4 +715,19 @@ public class ComputerPlayer6 extends ComputerPlayer implements return sim; } + private boolean checkForRepeatedAction(Game sim, SimulationNode2 node, Ability action, UUID playerId) { + if (action instanceof PassAbility) + return false; + int val = GameStateEvaluator2.evaluate(playerId, sim); + SimulationNode2 test = node.getParent(); + while (test != null && !test.getPlayerId().equals(playerId)) { + test = test.getParent(); + } + if (test != null && test.getAbilities() != null && test.getAbilities().size() == 1) { + if (action.toString().equals(test.getAbilities().get(0).toString()) && GameStateEvaluator2.evaluate(playerId, sim) == val) { + return true; + } + } + return false; + } } 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 210ac15ba9..3aa0a88949 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 @@ -44,9 +44,9 @@ public class GameStateEvaluator2 { Player opponent = game.getPlayer(game.getOpponents(playerId).iterator().next()); if (game.isGameOver()) { if (player.hasLost() || opponent.hasWon()) - return Integer.MIN_VALUE; + return LOSE_GAME_SCORE; if (opponent.hasLost() || player.hasWon()) - return Integer.MAX_VALUE; + return WIN_GAME_SCORE; } //int lifeScore = (player.getLife() - opponent.getLife()) * LIFE_FACTOR; @@ -73,12 +73,11 @@ public class GameStateEvaluator2 { } //permanentScore *= PERMANENT_FACTOR; - /*int handScore = 0; - handScore = 7 - opponent.getHand().size(); - handScore += Math.min(7, player.getHand().size()); - handScore *= HAND_FACTOR;*/ + int handScore = 0; + handScore = player.getHand().size() - opponent.getHand().size(); + handScore *= 5; - int score = lifeScore + permanentScore /*+ handScore*/; + int score = lifeScore + permanentScore + handScore; //if (logger.isLoggable(Level.FINE)) logger.fine("game state evaluated to- lifeScore:" + lifeScore + " permanentScore:" + permanentScore /*+ " handScore:" + handScore*/ + "total:" + score); return score; diff --git a/Mage.Server.Plugins/Mage.Player.AI.MA/src/mage/player/ai/SimulateBlockWorker2.java b/Mage.Server.Plugins/Mage.Player.AI.MA/src/mage/player/ai/SimulateBlockWorker2.java deleted file mode 100644 index d779c311e7..0000000000 --- a/Mage.Server.Plugins/Mage.Player.AI.MA/src/mage/player/ai/SimulateBlockWorker2.java +++ /dev/null @@ -1,62 +0,0 @@ -/* - * Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without modification, are - * permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, this list of - * conditions and the following disclaimer. - * - * 2. Redistributions in binary form must reproduce the above copyright notice, this list - * of conditions and the following disclaimer in the documentation and/or other materials - * provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED - * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND - * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR - * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR - * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON - * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING - * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF - * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * - * The views and conclusions contained in the software and documentation are those of the - * authors and should not be interpreted as representing official policies, either expressed - * or implied, of BetaSteward_at_googlemail.com. - */ - -package mage.player.ai; - -import java.util.concurrent.Callable; -import java.util.logging.Level; -import java.util.logging.Logger; - -import mage.util.Logging; - -/** - * - * @author BetaSteward_at_googlemail.com - */ -public class SimulateBlockWorker2 implements Callable { - - private final static Logger logger = Logging.getLogger(SimulationWorker2.class.getName()); - - private SimulationNode2 node; - private ComputerPlayer5 player; - - public SimulateBlockWorker2(ComputerPlayer5 player, SimulationNode2 node) { - this.player = player; - this.node = node; - } - - @Override - public Object call() { - try { -// player.simulateBlock(node); - } catch (Exception ex) { - logger.log(Level.SEVERE, null, ex); - } - return null; - } -} 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 48e494ddbf..45eb92cb77 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 @@ -223,7 +223,7 @@ public class SimulatedPlayer2 extends ComputerPlayer { sim.getStack().push(new StackAbility(ability, playerId)); ability.activate(sim, false); sim.applyEffects(); - SimulationNode2 newNode = new SimulationNode2(sim, depth, playerId); + SimulationNode2 newNode = new SimulationNode2(parent, sim, depth, playerId); logger.fine("simulating -- node #:" + SimulationNode2.getCount() + " triggered ability option"); for (Target target: ability.getTargets()) { for (UUID targetId: target.getTargets()) { diff --git a/Mage.Server.Plugins/Mage.Player.AI.MA/src/mage/player/ai/SimulationNode2.java b/Mage.Server.Plugins/Mage.Player.AI.MA/src/mage/player/ai/SimulationNode2.java index 7e86c59ce5..6ac1fc3f09 100644 --- a/Mage.Server.Plugins/Mage.Player.AI.MA/src/mage/player/ai/SimulationNode2.java +++ b/Mage.Server.Plugins/Mage.Player.AI.MA/src/mage/player/ai/SimulationNode2.java @@ -50,12 +50,14 @@ public class SimulationNode2 implements Serializable { protected List abilities; protected int depth; protected List children = new ArrayList(); + protected SimulationNode2 parent; protected List targets = new ArrayList(); protected List choices = new ArrayList(); protected UUID playerId; protected Combat combat; - public SimulationNode2(Game game, int depth, UUID playerId) { + public SimulationNode2(SimulationNode2 parent, Game game, int depth, UUID playerId) { + this.parent = parent; this.game = game; this.depth = depth; this.playerId = playerId; @@ -63,13 +65,13 @@ public class SimulationNode2 implements Serializable { nodeCount++; } - public SimulationNode2(Game game, List abilities, int depth, UUID playerId) { - this(game, depth, playerId); + public SimulationNode2(SimulationNode2 parent, Game game, List abilities, int depth, UUID playerId) { + this(parent, game, depth, playerId); this.abilities = abilities; } - public SimulationNode2(Game game, Ability ability, int depth, UUID playerId) { - this(game, depth, playerId); + public SimulationNode2(SimulationNode2 parent, Game game, Ability ability, int depth, UUID playerId) { + this(parent, game, depth, playerId); this.abilities = new ArrayList(); abilities.add(ability); } @@ -98,6 +100,10 @@ public class SimulationNode2 implements Serializable { return this.abilities; } + public SimulationNode2 getParent() { + return this.parent; + } + public List getChildren() { return this.children; } 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 f9237e902a..850465316f 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 @@ -225,6 +225,7 @@ public class ComputerPlayer> extends PlayerImpl i return true; } } + return false; } if (target instanceof TargetDiscard) { findPlayables(game); @@ -242,6 +243,7 @@ public class ComputerPlayer> extends PlayerImpl i return true; } } + return false; } if (target instanceof TargetControlledPermanent) { List targets; @@ -269,6 +271,7 @@ public class ComputerPlayer> extends PlayerImpl i return true; } } + return false; } if (target instanceof TargetCreatureOrPlayer) { List targets; @@ -297,8 +300,9 @@ public class ComputerPlayer> extends PlayerImpl i return true; } } + return false; } - return false; + throw new IllegalStateException("Target wasn't handled. class:" + target.getClass().toString()); } @Override diff --git a/Mage.Server/plugins/mage-player-ai-ma.jar b/Mage.Server/plugins/mage-player-ai-ma.jar index a2e07914e7..1b61670148 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/AIMinimax.properties b/Mage.Tests/plugins/AIMinimax.properties index 96b5480294..0dbf3860df 100644 --- a/Mage.Tests/plugins/AIMinimax.properties +++ b/Mage.Tests/plugins/AIMinimax.properties @@ -1,4 +1,4 @@ -maxDepth=10 +maxDepth=20 maxNodes=5000 evaluatorLifeFactor=2 evaluatorPermanentFactor=1 diff --git a/Mage.Tests/plugins/mage-player-ai-ma.jar b/Mage.Tests/plugins/mage-player-ai-ma.jar index a2e07914e7..1b61670148 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 9ddd1b6941..bcc39cedd2 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/scenario1.txt b/Mage.Tests/scenario1.txt index 4c8bae0af9..479785f2c9 100644 --- a/Mage.Tests/scenario1.txt +++ b/Mage.Tests/scenario1.txt @@ -1,14 +1,14 @@ ### ComputerA ### # Battlefield battlefield:ComputerA:Island:1 -battlefield:ComputerA:Goblin Guide:1 +#battlefield:ComputerA:Goblin Guide:1 # Hand hand:ComputerA:Mountain:2 -hand:ComputerA:Lightning Bolt:5 +hand:ComputerA:Hellspark Elemental:5 # Library # from down to top library:ComputerA:clear:0 -library:ComputerA:Lightning Bolt:10 +library:ComputerA:Hellspark Elemental:10 ### ComputerB ### # Battlefield diff --git a/Mage.Tests/scenario2.txt b/Mage.Tests/scenario2.txt new file mode 100644 index 0000000000..7776ff7002 --- /dev/null +++ b/Mage.Tests/scenario2.txt @@ -0,0 +1,22 @@ +### ComputerA ### +# Battlefield +battlefield:ComputerA:Island:2 +battlefield:ComputerA:Mountain:2 +# Hand +hand:ComputerA:Mountain:0 +hand:ComputerA:Hellspark Elemental:5 +# Library +# from down to top +library:ComputerA:clear:0 +library:ComputerA:Hellspark Elemental:10 + +### ComputerB ### +# Battlefield +battlefield:ComputerB:Plains:1 +# Hand +hand:ComputerB:Plains:2 +# Library +# from down to top +library:ComputerB:clear:0 +library:ComputerB:Plains:10 + diff --git a/Mage.Tests/scenario3.txt b/Mage.Tests/scenario3.txt new file mode 100644 index 0000000000..6b62aaa618 --- /dev/null +++ b/Mage.Tests/scenario3.txt @@ -0,0 +1,24 @@ +### ComputerA ### +# Battlefield +battlefield:ComputerA:Island:2 +battlefield:ComputerA:Mountain:2 +# Hand +hand:ComputerA:Mountain:0 +hand:ComputerA:Hellspark Elemental:5 +# Library +# from down to top +library:ComputerA:clear:0 +library:ComputerA:Hellspark Elemental:10 + +### ComputerB ### +# Battlefield +battlefield:ComputerB:Plains:1 +# Hand +hand:ComputerB:Plains:2 +# Library +# from down to top +library:ComputerB:clear:0 +library:ComputerB:Plains:10 +# Life +player:ComputerB:life:2 + diff --git a/Mage.Tests/scenario4.txt b/Mage.Tests/scenario4.txt new file mode 100644 index 0000000000..c0832cd0c6 --- /dev/null +++ b/Mage.Tests/scenario4.txt @@ -0,0 +1,21 @@ +### ComputerA ### +# Battlefield +battlefield:ComputerA:Swamp:1 +battlefield:ComputerA:Mountain:2 +# Hand +hand:ComputerA:Blightning:5 +# Library +# from down to top +library:ComputerA:clear:0 +library:ComputerA:Blightning:15 + +### ComputerB ### +# Battlefield +battlefield:ComputerB:Plains:1 +# Hand +hand:ComputerB:Plains:2 +# Library +# from down to top +library:ComputerB:clear:0 +library:ComputerB:Plains:10 + 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 31fc551dd7..5bfdf57689 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 @@ -56,7 +56,7 @@ public class PlayGameTest extends MageTestBase { game.addPlayer(computerB, deck2); game.loadCards(deck2.getCards(), computerB.getId()); - //parseScenario("scenario1.txt"); + //parseScenario("scenario4.txt"); game.cheat(computerA.getId(), commandsA); game.cheat(computerA.getId(), libraryCardsA, handCardsA, battlefieldCardsA, graveyardCardsA); game.cheat(computerB.getId(), commandsB); @@ -108,6 +108,16 @@ public class PlayGameTest extends MageTestBase { } else if ("library".equalsIgnoreCase(zone)) { gameZone = Constants.Zone.LIBRARY; cards = nickname.equals("ComputerA") ? libraryCardsA : libraryCardsB; + } else if ("player".equalsIgnoreCase(zone)) { + String command = m.group(3); + if ("life".equals(command)) { + if (nickname.equals("ComputerA")) { + commandsA.put(Constants.Zone.OUTSIDE, "life:" + m.group(4)); + } else { + commandsB.put(Constants.Zone.OUTSIDE, "life:" + m.group(4)); + } + } + continue; } else { continue; // go parse next line } diff --git a/Mage/src/mage/game/GameImpl.java b/Mage/src/mage/game/GameImpl.java index 09a801fe5c..5833e957d9 100644 --- a/Mage/src/mage/game/GameImpl.java +++ b/Mage/src/mage/game/GameImpl.java @@ -357,7 +357,9 @@ public abstract class GameImpl> implements Game, Serializa //20091005 - 103.3 for (UUID playerId: state.getPlayerList(startingPlayerId)) { Player player = getPlayer(playerId); - player.setLife(this.getLife(), this); + if (!testMode || player.getLife() == 0) { + player.setLife(this.getLife(), this); + } if (!testMode) { player.drawCards(7, this); } @@ -949,6 +951,22 @@ public abstract class GameImpl> implements Game, Serializa gameCards.remove(card); } player.getLibrary().clear(); + } + break; + case OUTSIDE: + if (command.getValue().contains("life:")) { + String[] s = command.getValue().split(":"); + if (s.length == 2) { + try { + Integer amount = Integer.parseInt(s[1]); + player.setLife(amount, this); + logger.info("Setting player's life: "); + } catch (NumberFormatException e) { + e.printStackTrace(); + } + } + + } break; }