From ae7623e118b0a629065111b0461788586ec0cb18 Mon Sep 17 00:00:00 2001 From: Oleg Agafonov Date: Fri, 12 Jul 2019 18:36:32 +0400 Subject: [PATCH] AI: fixed that AI never use alpha strike to kill opponent (doesn't use "all in" attack, #4486); --- .../src/mage/player/ai/util/CombatUtil.java | 12 +- .../test/AI/basic/AttackAndBlockByAITest.java | 207 ++++++++++++++++++ .../continuous/TroveOfTemptationTest.java | 27 --- 3 files changed, 213 insertions(+), 33 deletions(-) create mode 100644 Mage.Tests/src/test/java/org/mage/test/AI/basic/AttackAndBlockByAITest.java delete mode 100644 Mage.Tests/src/test/java/org/mage/test/cards/continuous/TroveOfTemptationTest.java 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 5fab2bcc822..3d0fe4e6bf7 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 @@ -32,7 +32,7 @@ public final class CombatUtil { public static List canKillOpponent(Game game, List attackersList, List blockersList, Player defender) { - List blockableAttackers = new ArrayList<>(blockersList); + List blockableAttackers = new ArrayList<>(attackersList); List unblockableAttackers = new ArrayList<>(); for (Permanent attacker : attackersList) { if (!canBeBlocked(game, attacker, blockersList)) { @@ -292,7 +292,7 @@ public final class CombatUtil { } return canBlock; } - + public static CombatInfo blockWithGoodTrade2(Game game, List attackers, List blockers) { UUID attackerId = game.getCombat().getAttackingPlayerId(); @@ -319,7 +319,7 @@ public final class CombatUtil { return combatInfo; } - + private static List getBlockersThatWillSurvive2(Game game, UUID attackerId, UUID defenderId, Permanent attacker, List possibleBlockers) { List blockers = new ArrayList<>(); for (Permanent blocker : possibleBlockers) { @@ -335,9 +335,9 @@ public final class CombatUtil { } return blockers; } - + public static SurviveInfo willItSurvive2(Game game, UUID attackingPlayerId, UUID defendingPlayerId, Permanent attacker, Permanent blocker) { - + Game sim = game.copy(); Combat combat = sim.getCombat(); @@ -347,7 +347,7 @@ public final class CombatUtil { if (blocker == null || attacker == null || sim.getPlayer(defendingPlayerId) == null) { return null; } - + if (attacker.getPower().getValue() >= blocker.getToughness().getValue()) { sim.getBattlefield().removePermanent(blocker.getId()); } diff --git a/Mage.Tests/src/test/java/org/mage/test/AI/basic/AttackAndBlockByAITest.java b/Mage.Tests/src/test/java/org/mage/test/AI/basic/AttackAndBlockByAITest.java new file mode 100644 index 00000000000..720846e5a62 --- /dev/null +++ b/Mage.Tests/src/test/java/org/mage/test/AI/basic/AttackAndBlockByAITest.java @@ -0,0 +1,207 @@ +package org.mage.test.AI.basic; + +import mage.constants.PhaseStep; +import mage.constants.Zone; +import org.junit.Ignore; +import org.junit.Test; +import org.mage.test.serverside.base.CardTestPlayerBaseAI; + +/** + * @author JayDi85 + */ +public class AttackAndBlockByAITest extends CardTestPlayerBaseAI { + + // only PlayerA is AI controlled + + // Trove of Temptation + // Each opponent must attack you or a planeswalker you control with at least one creature each combat if able. + + @Test + public void test_Attack_2_big_vs_0() { + // 2 x 2/2 vs 0 - can't lose any attackers + addCard(Zone.BATTLEFIELD, playerA, "Balduvian Bears", 2); // 2/2 + + setStopAt(1, PhaseStep.END_TURN); + setStrictChooseMode(true); + execute(); + assertAllCommandsUsed(); + + assertLife(playerA, 20); + assertLife(playerB, 20 - 2 - 2); + } + + @Test + public void test_Attack_2_big_vs_1_small() { + // 2 x 2/2 vs 1 x 1/1 - can't lose any attackers + addCard(Zone.BATTLEFIELD, playerA, "Balduvian Bears", 2); // 2/2 + addCard(Zone.BATTLEFIELD, playerB, "Arbor Elf", 1); // 1/1 + + setStopAt(1, PhaseStep.END_TURN); + setStrictChooseMode(true); + execute(); + assertAllCommandsUsed(); + + assertLife(playerA, 20); + assertLife(playerB, 20 - 2 - 2); + } + + @Test + public void test_Attack_1_big_vs_2_small() { + // 1 x 2/2 vs 2 x 1/1 - can lose 1 attacker, but will kill more opponents + addCard(Zone.BATTLEFIELD, playerA, "Balduvian Bears", 1); // 2/2 + addCard(Zone.BATTLEFIELD, playerB, "Arbor Elf", 2); // 1/1 + + setStopAt(1, PhaseStep.END_TURN); + setStrictChooseMode(true); + execute(); + assertAllCommandsUsed(); + + assertLife(playerA, 20); + assertLife(playerB, 20 - 2); + } + + @Test + public void test_Attack_2_big_vs_2_small() { + // 2 x 2/2 vs 2 x 1/1 - can lose 1 attacker, but will kill more opponents + addCard(Zone.BATTLEFIELD, playerA, "Balduvian Bears", 2); // 2/2 + addCard(Zone.BATTLEFIELD, playerB, "Arbor Elf", 2); // 1/1 + + setStopAt(1, PhaseStep.END_TURN); + setStrictChooseMode(true); + execute(); + assertAllCommandsUsed(); + + assertLife(playerA, 20); + assertLife(playerB, 20 - 2 - 2); + } + + @Test + public void test_Attack_1_small_vs_0() { + addCard(Zone.BATTLEFIELD, playerA, "Arbor Elf", 1); // 1/1 + + setStopAt(1, PhaseStep.END_TURN); + setStrictChooseMode(true); + execute(); + assertAllCommandsUsed(); + + assertLife(playerA, 20); + assertLife(playerB, 20 - 1); + } + + @Test + public void test_Attack_1_small_vs_1_big() { + addCard(Zone.BATTLEFIELD, playerA, "Arbor Elf", 1); // 1/1 + addCard(Zone.BATTLEFIELD, playerB, "Balduvian Bears", 1); // 2/2 + + setStopAt(1, PhaseStep.END_TURN); + setStrictChooseMode(true); + execute(); + assertAllCommandsUsed(); + + assertLife(playerA, 20); + assertLife(playerB, 20); // no attacks + } + + @Test + public void test_Attack_2_small_vs_1_big() { + addCard(Zone.BATTLEFIELD, playerA, "Arbor Elf", 2); // 1/1 + addCard(Zone.BATTLEFIELD, playerB, "Balduvian Bears", 1); // 2/2 + + setStopAt(1, PhaseStep.END_TURN); + setStrictChooseMode(true); + execute(); + assertAllCommandsUsed(); + + assertLife(playerA, 20); + assertLife(playerB, 20); // no attacks + } + + @Test + public void test_Attack_15_small_vs_1_big_kill_stike() { + addCard(Zone.BATTLEFIELD, playerA, "Balduvian Bears", 15); // 2/2 + addCard(Zone.BATTLEFIELD, playerB, "Ancient Brontodon", 1); // 9/9 + + block(1, playerB, "Ancient Brontodon", "Balduvian Bears"); + + setStopAt(1, PhaseStep.END_TURN); + setStrictChooseMode(true); + execute(); + assertAllCommandsUsed(); + + assertLife(playerA, 20); + assertLife(playerB, 20 - ((15 - 1) * 2)); // one will be blocked + } + + @Test + @Ignore // TODO: add massive attack vs small amount of blockers + public void test_Attack_10_small_vs_1_big_massive_strike() { + addCard(Zone.BATTLEFIELD, playerA, "Balduvian Bears", 10); // 2/2 + addCard(Zone.BATTLEFIELD, playerB, "Ancient Brontodon", 1); // 9/9 + + block(1, playerB, "Ancient Brontodon", "Balduvian Bears"); + + setStopAt(1, PhaseStep.END_TURN); + setStrictChooseMode(true); + execute(); + assertAllCommandsUsed(); + + assertLife(playerA, 20); + assertLife(playerB, 20 - ((10 - 1) * 2)); // one will be blocked + } + + @Test + public void test_ForceAttack_1_small_vs_1_big_a() { + addCard(Zone.BATTLEFIELD, playerA, "Goblin Brigand", 1); // 1/1, force to attack + addCard(Zone.BATTLEFIELD, playerB, "Ancient Brontodon", 1); // 9/9 + + block(1, playerB, "Ancient Brontodon", "Goblin Brigand"); + + setStopAt(1, PhaseStep.END_TURN); + setStrictChooseMode(true); + execute(); + assertAllCommandsUsed(); + + assertGraveyardCount(playerA, "Goblin Brigand", 1); + assertLife(playerA, 20); + assertLife(playerB, 20); + } + + @Test + public void test_ForceAttack_2_small_vs_2_big() { + addCard(Zone.BATTLEFIELD, playerA, "Goblin Brigand", 2); // 1/1, force to attack + addCard(Zone.BATTLEFIELD, playerB, "Ancient Brontodon", 2); // 9/9 + + block(1, playerB, "Ancient Brontodon:0", "Goblin Brigand:0"); + block(1, playerB, "Ancient Brontodon:1", "Goblin Brigand:1"); + + setStopAt(1, PhaseStep.END_TURN); + setStrictChooseMode(true); + execute(); + assertAllCommandsUsed(); + + assertGraveyardCount(playerA, "Goblin Brigand", 2); + assertLife(playerA, 20); + assertLife(playerB, 20); + } + + @Test + @Ignore // TODO: need to fix Trove of Temptation effect (player must attack by one creature) + public void test_ForceAttack_1_small_vs_1_big_b() { + addCard(Zone.BATTLEFIELD, playerA, "Arbor Elf", 1); // 1/1 + addCard(Zone.BATTLEFIELD, playerB, "Ancient Brontodon", 1); // 9/9 + // Trove of Temptation + // Each opponent must attack you or a planeswalker you control with at least one creature each combat if able. + addCard(Zone.BATTLEFIELD, playerB, "Trove of Temptation", 1); // 9/9 + + block(1, playerB, "Ancient Brontodon", "Arbor Elf"); + + setStopAt(1, PhaseStep.END_TURN); + setStrictChooseMode(true); + execute(); + assertAllCommandsUsed(); + + assertGraveyardCount(playerA, "Arbor Elf", 1); + assertLife(playerA, 20); + assertLife(playerB, 20); + } +} diff --git a/Mage.Tests/src/test/java/org/mage/test/cards/continuous/TroveOfTemptationTest.java b/Mage.Tests/src/test/java/org/mage/test/cards/continuous/TroveOfTemptationTest.java deleted file mode 100644 index a980bbd46e2..00000000000 --- a/Mage.Tests/src/test/java/org/mage/test/cards/continuous/TroveOfTemptationTest.java +++ /dev/null @@ -1,27 +0,0 @@ -package org.mage.test.cards.continuous; - -import mage.constants.PhaseStep; -import mage.constants.Zone; -import org.junit.Ignore; -import org.junit.Test; -import org.mage.test.serverside.base.CardTestPlayerBase; - -/** - * @author JayDi85 - */ -public class TroveOfTemptationTest extends CardTestPlayerBase { - - @Test - @Ignore // TODO: 2019-04-28 - improve and uncomment test after computer player can process playerMustBeAttackedIfAble restriction - public void test_SingleOpponentMustAttack() { - // Each opponent must attack you or a planeswalker you control with at least one creature each combat if able. - addCard(Zone.BATTLEFIELD, playerA, "Trove of Temptation"); - addCard(Zone.BATTLEFIELD, playerB, "Balduvian Bears", 1); // 2/2 - addCard(Zone.BATTLEFIELD, playerB, "Ashcoat Bear", 1); // 2/2 - - setStopAt(2, PhaseStep.END_TURN); - setStrictChooseMode(true); - execute(); - assertAllCommandsUsed(); - } -}