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 d453f2418d0..38358cda3bb 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 @@ -81,6 +81,7 @@ public class ComputerPlayer extends PlayerImpl { // * 5 for good performance on average computer // * use your's CPU cores for best performance // TODO: add server config to control max AI threads (with CPU cores by default) + // TODO: rework AI implementation to use multiple sims calculation instead one by one final static int COMPUTER_MAX_THREADS_FOR_SIMULATIONS = 5; private final transient Map unplayable = new TreeMap<>(); diff --git a/Mage.Tests/src/test/java/org/mage/test/AI/basic/SimulationPerformanceAITest.java b/Mage.Tests/src/test/java/org/mage/test/AI/basic/SimulationPerformanceAITest.java index 45db260750a..2bdd36e9bf0 100644 --- a/Mage.Tests/src/test/java/org/mage/test/AI/basic/SimulationPerformanceAITest.java +++ b/Mage.Tests/src/test/java/org/mage/test/AI/basic/SimulationPerformanceAITest.java @@ -3,6 +3,7 @@ package org.mage.test.AI.basic; import mage.constants.PhaseStep; import mage.constants.Zone; import org.junit.Assert; +import org.junit.Ignore; import org.junit.Test; import org.mage.test.serverside.base.CardTestPlayerBaseAI; @@ -61,4 +62,52 @@ public class SimulationPerformanceAITest extends CardTestPlayerBaseAI { Assert.assertTrue("One of player must won a game before turn " + maxTurn + ", but it ends on " + currentGame, currentGame.hasEnded()); } + + private void runManyTargetOptionsTest(String info, int totalCreatures, int needDiedCreatures, int needPlayerLife) { + // When Bogardan Hellkite enters, it deals 5 damage divided as you choose among any number of targets. + addCard(Zone.HAND, playerA, "Bogardan Hellkite", 1); // {6}{R}{R} + addCard(Zone.BATTLEFIELD, playerA, "Mountain", 8); + // + addCard(Zone.BATTLEFIELD, playerB, "Balduvian Bears", totalCreatures); + + setStrictChooseMode(true); + setStopAt(1, PhaseStep.BEGIN_COMBAT); + execute(); + + assertPermanentCount(playerA, "Bogardan Hellkite", 1); // if fail then AI stops before all sims ends + assertGraveyardCount(playerB, "Balduvian Bears", needDiedCreatures); + assertLife(playerB, needPlayerLife); + } + + @Test + public void test_AIvsAI_ManyTargetOptions_Simple() { + // 2 damage to bear and 3 damage to player B + runManyTargetOptionsTest("1 target creature", 1, 1, 20 - 3); + } + + @Test + public void test_AIvsAI_ManyTargetOptions_Few() { + // 4 damage to x2 bears and 1 damage to player B + runManyTargetOptionsTest("2 target creatures", 2, 2, 20 - 1); + } + + @Test + public void test_AIvsAI_ManyTargetOptions_Many() { + // 4 damage to x2 bears and 1 damage to player B + runManyTargetOptionsTest("5 target creatures", 2, 2, 20 - 1); + } + + @Test + @Ignore // AI code must be improved + // TODO: need memory optimization + // TODO: need sims/options amount optimization (example: target name + score as unique param to reduce possible options) + // TODO: need best choice selection on timeout (AI must make any good/bad choice on timeout with game log - not a skip) + public void test_AIvsAI_ManyTargetOptions_TooMuch() { + // possible problems: + // - big memory consumption on sims prepare (memory overflow) + // - too many sims to calculate (AI fail on time out and do nothing) + + // 4 damage to x2 bears and 1 damage to player B + runManyTargetOptionsTest("50 target creatures", 50, 2, 20 - 1); + } }