AI: improved performance on too many possible targets (fix game freezes and server crashes - see #9539, #9438, #9518, related to #11285, #5023);

This commit is contained in:
Oleg Agafonov 2025-08-10 02:16:18 +04:00
parent 384ce67cc3
commit 2833460e59
10 changed files with 397 additions and 234 deletions

View file

@ -6,7 +6,6 @@ import mage.constants.PhaseStep;
import mage.constants.Zone;
import mage.game.permanent.Permanent;
import org.junit.Assert;
import org.junit.Ignore;
import org.junit.Test;
import org.mage.test.serverside.base.CardTestPlayerBaseAI;
@ -21,7 +20,6 @@ import java.util.List;
* TODO: add tests and implement best choice selection on timeout
* (AI must make any good/bad choice on timeout with game log - not a skip)
* <p>
* TODO: AI do not support game simulations for target options in triggered
*
* @author JayDi85
*/
@ -106,28 +104,24 @@ public class SimulationPerformanceAITest extends CardTestPlayerBaseAI {
}
@Test
@Ignore // enable after triggered supported or need performance test
public void test_ManyTargetOptions_Triggered_Single() {
// 2 damage to bear and 3 damage to player B
runManyTargetOptionsInTrigger("1 target creature", 1, 1, false, 20 - 3);
}
@Test
@Ignore // enable after triggered supported or need performance test
public void test_ManyTargetOptions_Triggered_Few() {
// 4 damage to x2 bears and 1 damage to player B
runManyTargetOptionsInTrigger("2 target creatures", 2, 2, false, 20 - 1);
}
@Test
@Ignore // enable after triggered supported or need performance test
public void test_ManyTargetOptions_Triggered_Many() {
// 4 damage to x2 bears and 1 damage to player B
runManyTargetOptionsInTrigger("5 target creatures", 5, 2, false, 20 - 1);
}
@Test
@Ignore // enable after triggered supported or need performance test
public void test_ManyTargetOptions_Triggered_TooMuch() {
// warning, can be slow
@ -139,7 +133,6 @@ public class SimulationPerformanceAITest extends CardTestPlayerBaseAI {
}
@Test
@Ignore // enable after triggered supported or need performance test
public void test_ManyTargetOptions_Triggered_TargetGroups() {
// make sure targets optimization can find unique creatures, e.g. damaged
@ -213,4 +206,29 @@ public class SimulationPerformanceAITest extends CardTestPlayerBaseAI {
// 4 damage to x2 bears and 1 damage to damaged bear
runManyTargetOptionsInActivate("5 target creatures with one damaged", 5, 3, true, 20);
}
@Test
public void test_ElderDeepFiend_TooManyUpToChoices() {
// bug: game freeze with 100% CPU usage
// https://github.com/magefree/mage/issues/9518
int cardsCount = 2; // 2+ cards will generate too much target options for simulations
// Boulderfall deals 5 damage divided as you choose among any number of targets.
// Flash
// Emerge {5}{U}{U} (You may cast this spell by sacrificing a creature and paying the emerge cost reduced by that creature's mana value.)
// When you cast this spell, tap up to four target permanents.
addCard(Zone.HAND, playerA, "Elder Deep-Fiend", cardsCount); // {8}
addCard(Zone.BATTLEFIELD, playerA, "Island", 8 * cardsCount);
//
addCard(Zone.BATTLEFIELD, playerB, "Balduvian Bears", 2);
addCard(Zone.BATTLEFIELD, playerB, "Kitesail Corsair", 2);
addCard(Zone.BATTLEFIELD, playerB, "Alpha Tyrranax", 2);
addCard(Zone.BATTLEFIELD, playerB, "Abbey Griffin", 2);
setStrictChooseMode(true);
setStopAt(1, PhaseStep.END_TURN);
execute();
assertPermanentCount(playerA, "Elder Deep-Fiend", cardsCount); // ai must cast it
}
}

View file

@ -0,0 +1,84 @@
package org.mage.test.AI.basic;
import mage.constants.PhaseStep;
import mage.constants.Zone;
import mage.counters.CounterType;
import org.junit.Ignore;
import org.junit.Test;
import org.mage.test.serverside.base.CardTestPlayerBaseWithAIHelps;
/**
* Make sure AI can simulate priority with triggers resolve
*
* @author JayDi85
*/
public class SimulationTriggersAITest extends CardTestPlayerBaseWithAIHelps {
@Test
@Ignore
// TODO: trigger's target options supported on priority sim, but do not used for some reason
// see addTargetOptions, node.children, ComputerPlayer6->targets, etc
public void test_DeepglowSkate_MustBeSimulated() {
// make sure targets choosing on trigger use same game sims and best results
// When Deepglow Skate enters the battlefield, double the number of each kind of counter on any number
// of target permanents.
addCard(Zone.HAND, playerA, "Deepglow Skate", 1);
addCard(Zone.BATTLEFIELD, playerA, "Island", 5);
//
addCard(Zone.BATTLEFIELD, playerA, "Ajani, Adversary of Tyrants", 1); // x4 loyalty
addCard(Zone.BATTLEFIELD, playerA, "Ajani, Caller of the Pride", 1); // x4 loyalty
//
// This creature enters with a -1/-1 counter on it.
addCard(Zone.BATTLEFIELD, playerA, "Bloodied Ghost", 1); // 3/3
//
// Players can't activate planeswalkers' loyalty abilities.
addCard(Zone.BATTLEFIELD, playerA, "The Immortal Sun", 1); // disable planeswalkers usage by AI
// AI must cast boost and ignore doubling of -1/-1 counters on own creatures due bad score
aiPlayStep(1, PhaseStep.PRECOMBAT_MAIN, playerA);
setStrictChooseMode(true);
setStopAt(1, PhaseStep.END_TURN);
execute();
assertPermanentCount(playerA, "Deepglow Skate", 1);
assertCounterCount(playerA, "Ajani, Adversary of Tyrants", CounterType.LOYALTY, 4 * 2);
assertCounterCount(playerA, "Ajani, Caller of the Pride", CounterType.LOYALTY, 4 * 2);
assertCounterCount(playerA, "Bloodied Ghost", CounterType.M1M1, 1); // make sure AI will not double bad counters
}
@Test
public void test_DeepglowSkate_PerformanceOnTooManyChoices() {
// bug: game freeze with 100% CPU usage
// https://github.com/magefree/mage/issues/9438
int cardsCount = 2; // 2+ cards will generate too much target options for simulations
int boostMultiplier = (int) Math.pow(2, cardsCount);
// When Deepglow Skate enters the battlefield, double the number of each kind of counter on any number
// of target permanents.
addCard(Zone.HAND, playerA, "Deepglow Skate", cardsCount); // {4}{U}
addCard(Zone.BATTLEFIELD, playerA, "Island", 5 * cardsCount);
//
addCard(Zone.BATTLEFIELD, playerA, "Ajani, Adversary of Tyrants", 1); // x4 loyalty
addCard(Zone.BATTLEFIELD, playerA, "Ajani, Caller of the Pride", 1); // x4 loyalty
addCard(Zone.BATTLEFIELD, playerB, "Ajani Goldmane", 1); // x4 loyalty
addCard(Zone.BATTLEFIELD, playerB, "Ajani, Inspiring Leader", 1); // x5 loyalty
//
// Players can't activate planeswalkers' loyalty abilities.
addCard(Zone.BATTLEFIELD, playerA, "The Immortal Sun", 1); // disable planeswalkers usage by AI
// AI must cast multiple booster spells and double only own counters and only good
aiPlayStep(1, PhaseStep.PRECOMBAT_MAIN, playerA);
setStrictChooseMode(true);
setStopAt(1, PhaseStep.END_TURN);
execute();
assertPermanentCount(playerA, "Deepglow Skate", cardsCount);
assertCounterCount(playerA, "Ajani, Adversary of Tyrants", CounterType.LOYALTY, 4 * boostMultiplier);
assertCounterCount(playerA, "Ajani, Caller of the Pride", CounterType.LOYALTY, 4 * boostMultiplier);
assertCounterCount(playerB, "Ajani Goldmane", CounterType.LOYALTY, 4);
assertCounterCount(playerB, "Ajani, Inspiring Leader", CounterType.LOYALTY, 5);
}
}