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 b90e7be7bbd..868bb030b73 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 @@ -54,6 +54,7 @@ import mage.game.turn.*; import mage.player.ai.ma.optimizers.TreeOptimizer; import mage.player.ai.ma.optimizers.impl.EquipOptimizer; import mage.player.ai.ma.optimizers.impl.LevelUpOptimizer; +import mage.player.ai.util.CombatInfo; import mage.player.ai.util.CombatUtil; import mage.players.Player; import mage.target.Target; @@ -150,7 +151,6 @@ public class ComputerPlayer6 extends ComputerPlayer implements if (game.getActivePlayerId().equals(playerId)) { declareAttackers(game, playerId); pass(); - return true; } else { pass(); } @@ -159,7 +159,6 @@ public class ComputerPlayer6 extends ComputerPlayer implements if (!game.getActivePlayerId().equals(playerId)) { declareBlockers(game, playerId); pass(); - return true; } else { pass(); } @@ -770,22 +769,24 @@ public class ComputerPlayer6 extends ComputerPlayer implements CombatUtil.sortByPower(attackers, false); - //TODO: - + CombatInfo combatInfo = CombatUtil.blockWithGoodTrade(game, attackers, possibleBlockers); Player player = game.getPlayer(this.playerId); - Map> map = new HashMap>(); - for (Map.Entry> entry : map.entrySet()) { + boolean blocked = false; + for (Map.Entry> entry : combatInfo.getCombat().entrySet()) { UUID attackerId = entry.getKey().getId(); List blockers = entry.getValue(); if (blockers != null) { for (Permanent blocker : blockers) { - player.declareAttacker(attackerId, blocker.getId(), game); + player.declareBlocker(blocker.getId(), attackerId, game); + blocked = true; } } - } + if (blocked) { + game.getPlayers().resetPassed(); + } } } @@ -887,7 +888,7 @@ public class ComputerPlayer6 extends ComputerPlayer implements CombatUtil.handleExalted(); - int aggressionRate = 5; + int aggressionRate = 0; for (Permanent attacker : attackersList) { if (aggressionRate == 5) { attackingPlayer.declareAttacker(attacker.getId(), defenderId, game); 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 e58e904a03c..64259e82312 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,17 +28,23 @@ package mage.player.ai; +import mage.Constants; import mage.Constants.AbilityType; import mage.Constants.RangeOfInfluence; import mage.Constants.Zone; import mage.abilities.Ability; 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.turn.*; import mage.players.Player; import org.apache.log4j.Logger; import java.util.LinkedList; +import java.util.List; +import java.util.UUID; /** * @@ -275,14 +281,14 @@ public class ComputerPlayer7 extends ComputerPlayer6 implements Player { } - /*protected int simulateCombat(Game game, SimulationNode2 node, int depth, int alpha, int beta, boolean counter) { + 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.debug("interrupted"); return GameStateEvaluator2.evaluate(playerId, game); } - if (game.getTurn().getStepType() != PhaseStep.DECLARE_BLOCKERS) { + if (game.getTurn().getStepType() != Constants.PhaseStep.DECLARE_BLOCKERS) { game.getTurn().setPhase(new CombatPhase()); if (game.getPhase().beginPhase(game, game.getActivePlayerId())) { simulateStep(game, new BeginCombatStep()); @@ -317,10 +323,10 @@ public class ComputerPlayer7 extends ComputerPlayer6 implements Player { 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) { + protected int simulateAttackers(Game game, SimulationNode2 node, UUID attackerId, int depth, int alpha, int beta, boolean counter) { if (Thread.interrupted()) { Thread.currentThread().interrupt(); logger.debug("interrupted"); @@ -392,9 +398,9 @@ public class ComputerPlayer7 extends ComputerPlayer6 implements Player { if (logger.isDebugEnabled()) logger.debug("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) { + protected int simulateBlockers(Game game, SimulationNode2 node, UUID defenderId, int depth, int alpha, int beta, boolean counter) { if (Thread.interrupted()) { Thread.currentThread().interrupt(); logger.debug("interrupted"); @@ -471,7 +477,7 @@ public class ComputerPlayer7 extends ComputerPlayer6 implements Player { if (logger.isDebugEnabled()) logger.debug("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()) { @@ -520,7 +526,7 @@ public class ComputerPlayer7 extends ComputerPlayer6 implements Player { } } - /*protected void finishCombat(Game game) { + protected void finishCombat(Game game) { if (Thread.interrupted()) { Thread.currentThread().interrupt(); logger.debug("interrupted"); @@ -529,7 +535,7 @@ public class ComputerPlayer7 extends ComputerPlayer6 implements Player { 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 (Thread.interrupted()) { diff --git a/Mage.Server.Plugins/Mage.Player.AI.MA/src/mage/player/ai/util/Combat.java b/Mage.Server.Plugins/Mage.Player.AI.MA/src/mage/player/ai/util/Combat.java deleted file mode 100644 index f36f9074ceb..00000000000 --- a/Mage.Server.Plugins/Mage.Player.AI.MA/src/mage/player/ai/util/Combat.java +++ /dev/null @@ -1,7 +0,0 @@ -package mage.player.ai.util; - -/** - * @author noxx - */ -public class Combat { -} diff --git a/Mage.Server.Plugins/Mage.Player.AI.MA/src/mage/player/ai/util/CombatInfo.java b/Mage.Server.Plugins/Mage.Player.AI.MA/src/mage/player/ai/util/CombatInfo.java new file mode 100644 index 00000000000..0a0377ce266 --- /dev/null +++ b/Mage.Server.Plugins/Mage.Player.AI.MA/src/mage/player/ai/util/CombatInfo.java @@ -0,0 +1,29 @@ +package mage.player.ai.util; + +import mage.game.permanent.Permanent; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +/** + * @author noxx + */ +public class CombatInfo { + + private Map> combat = new HashMap>(); + + public void addPair(Permanent attacker, Permanent blocker) { + List blockers = combat.get(attacker); + if (blockers == null) { + blockers = new ArrayList(); + combat.put(attacker, blockers); + } + blockers.add(blocker); + } + + public Map> getCombat() { + return combat; + } +} diff --git a/Mage.Server.Plugins/Mage.Player.AI.MA/src/mage/player/ai/util/CombatUtil.java b/Mage.Server.Plugins/Mage.Player.AI.MA/src/mage/player/ai/util/CombatUtil.java index 43b11cf1ea9..6a485018e89 100644 --- a/Mage.Server.Plugins/Mage.Player.AI.MA/src/mage/player/ai/util/CombatUtil.java +++ b/Mage.Server.Plugins/Mage.Player.AI.MA/src/mage/player/ai/util/CombatUtil.java @@ -4,13 +4,16 @@ import mage.abilities.keyword.DoubleStrikeAbility; import mage.abilities.keyword.InfectAbility; import mage.counters.CounterType; import mage.game.Game; +import mage.game.combat.Combat; +import mage.game.events.GameEvent; import mage.game.permanent.Permanent; +import mage.game.turn.CombatDamageStep; +import mage.game.turn.EndOfCombatStep; +import mage.game.turn.FirstCombatDamageStep; +import mage.game.turn.Step; import mage.players.Player; -import java.util.ArrayList; -import java.util.Collections; -import java.util.Comparator; -import java.util.List; +import java.util.*; /** * Base helper methods for combat. @@ -21,6 +24,8 @@ public class CombatUtil { private static final List emptyList = new ArrayList(); + private static final transient org.apache.log4j.Logger log = org.apache.log4j.Logger.getLogger(CombatUtil.class); + private CombatUtil() { } @@ -90,6 +95,19 @@ public class CombatUtil { }); } + public static Permanent getWorstCreature(List creatures) { + if (creatures.isEmpty()) { + return null; + } + Collections.sort(creatures, new Comparator() { + @Override + public int compare(Permanent o1, Permanent o2) { + return o2.getPower().getValue() - o1.getPower().getValue(); + } + }); + return creatures.get(0); + } + private static int sumDamage(List attackersThatWontBeBlocked, Player defender) { int damage = 0; for (Permanent attacker : attackersThatWontBeBlocked) { @@ -137,11 +155,84 @@ public class CombatUtil { return canBlock; } - public void blockWithGoodTrade(Game game, List attackers, List possibleBlockers) { + public static CombatInfo blockWithGoodTrade(Game game, List attackers, List blockers) { + + UUID attackerId = game.getCombat().getAttackerId(); + UUID defenderId = game.getCombat().getDefenders().iterator().next(); + if (attackerId == null || defenderId == null) { + log.warn("Couldn't find attacker or defender: " + attackerId + " " + defenderId); + return new CombatInfo(); + } + + CombatInfo combatInfo = new CombatInfo(); for (Permanent attacker : attackers) { //TODO: handle attackers with "can't be blocked except" - List blockers = getPossibleBlockers(game, attacker, possibleBlockers); - + List possibleBlockers = getPossibleBlockers(game, attacker, blockers); + List survivedBlockers = getBlockersThatWillSurvive(game, attackerId, defenderId, attacker, possibleBlockers); + if (!survivedBlockers.isEmpty()) { + Permanent blocker = getWorstCreature(survivedBlockers); + combatInfo.addPair(attacker, blocker); + blockers.remove(blocker); + } + if (blockers.isEmpty()) { + break; + } } + + return combatInfo; } + + private static List getBlockersThatWillSurvive(Game game, UUID attackerId, UUID defenderId, Permanent attacker, List possibleBlockers) { + List blockers = new ArrayList(); + for (Permanent blocker : possibleBlockers) { + SurviveInfo info = willItSurvive(game, attackerId, defenderId, attacker, blocker); + if (info.isAttackerDied() && !info.isBlockerDied()) { + blockers.add(blocker); + } + } + return blockers; + } + + private static SurviveInfo willItSurvive(Game game, UUID attackingPlayerId, UUID defendingPlayerId, Permanent attacker, Permanent blocker) { + Game sim = game.copy(); + + Combat combat = sim.getCombat(); + combat.setAttacker(attackingPlayerId); + combat.setDefenders(sim); + + sim.getPlayer(defendingPlayerId).declareBlocker(blocker.getId(), attacker.getId(), sim); + sim.fireEvent(GameEvent.getEvent(GameEvent.EventType.DECLARED_BLOCKERS, defendingPlayerId, defendingPlayerId)); + + sim.checkStateAndTriggered(); + while (!sim.getStack().isEmpty()) { + sim.getStack().resolve(sim); + sim.applyEffects(); + } + sim.fireEvent(GameEvent.getEvent(GameEvent.EventType.DECLARE_BLOCKERS_STEP_POST, sim.getActivePlayerId(), sim.getActivePlayerId())); + + simulateStep(sim, new FirstCombatDamageStep()); + simulateStep(sim, new CombatDamageStep()); + simulateStep(sim, new EndOfCombatStep()); + + sim.checkStateAndTriggered(); + while (!sim.getStack().isEmpty()) { + sim.getStack().resolve(sim); + sim.applyEffects(); + } + + return new SurviveInfo(!sim.getBattlefield().containsPermanent(attacker.getId()), !sim.getBattlefield().containsPermanent(blocker.getId())); + } + + protected static void simulateStep(Game game, Step step) { + 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()); + } + } } diff --git a/Mage.Server.Plugins/Mage.Player.AI.MA/src/mage/player/ai/util/SurviveInfo.java b/Mage.Server.Plugins/Mage.Player.AI.MA/src/mage/player/ai/util/SurviveInfo.java new file mode 100644 index 00000000000..5e2deb58b23 --- /dev/null +++ b/Mage.Server.Plugins/Mage.Player.AI.MA/src/mage/player/ai/util/SurviveInfo.java @@ -0,0 +1,30 @@ +package mage.player.ai.util; + +/** + * @author noxx + */ +public class SurviveInfo { + private boolean attackerDied; + private boolean blockerDied; + + public SurviveInfo(boolean attackerDied, boolean blockerDied) { + this.attackerDied = attackerDied; + this.blockerDied = blockerDied; + } + + public boolean isAttackerDied() { + return attackerDied; + } + + public void setAttackerDied(boolean attackerDied) { + this.attackerDied = attackerDied; + } + + public boolean isBlockerDied() { + return blockerDied; + } + + public void setBlockerDied(boolean blockerDied) { + this.blockerDied = blockerDied; + } +} diff --git a/Mage.Server/plugins/mage-player-ai-ma.jar b/Mage.Server/plugins/mage-player-ai-ma.jar index 05dc334ce2e..a878f31c038 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.Server/plugins/mage-player-ai.jar b/Mage.Server/plugins/mage-player-ai.jar index 3dbe4404426..b3aa1833235 100644 Binary files a/Mage.Server/plugins/mage-player-ai.jar and b/Mage.Server/plugins/mage-player-ai.jar differ diff --git a/Mage.Server/plugins/mage-player-aimcts.jar b/Mage.Server/plugins/mage-player-aimcts.jar index d08891b73ff..e2ce1797b25 100644 Binary files a/Mage.Server/plugins/mage-player-aimcts.jar and b/Mage.Server/plugins/mage-player-aimcts.jar differ diff --git a/Mage.Server/plugins/mage-player-aiminimax.jar b/Mage.Server/plugins/mage-player-aiminimax.jar index cf0f8c1d4d4..d19f3b26f2e 100644 Binary files a/Mage.Server/plugins/mage-player-aiminimax.jar and b/Mage.Server/plugins/mage-player-aiminimax.jar differ diff --git a/Mage.Server/plugins/mage-player-human.jar b/Mage.Server/plugins/mage-player-human.jar index debc252881b..b99a89ad70c 100644 Binary files a/Mage.Server/plugins/mage-player-human.jar and b/Mage.Server/plugins/mage-player-human.jar differ diff --git a/Mage/src/mage/game/combat/Combat.java b/Mage/src/mage/game/combat/Combat.java index 8bbd339ecf2..c105716e74f 100644 --- a/Mage/src/mage/game/combat/Combat.java +++ b/Mage/src/mage/game/combat/Combat.java @@ -438,8 +438,12 @@ public class Combat implements Serializable, Copyable { if (creature != null) creature.setBlocking(0); } - - @Override + + public UUID getAttackerId() { + return attackerId; + } + + @Override public Combat copy() { return new Combat(this); }