Simulated AI: Fix multi-target spell simulation. (#2181)

* Simulated AI: Fix multi-target spell simulation.

Removes an incorrect check that was comparing two semantically different things (number of possible to choose from vs. number of targets chosen). Adds a test using Incremental Growth, where number of possible targets is 5, but the spell requires only 3 to be chosen.

* Fix the root issue and eliminate incorrect simulations.

* Fix infinite loop with invalid targets.

* Fix logic.
This commit is contained in:
asvitkine
2023-01-12 06:38:27 -05:00
committed by GitHub
parent 876668c370
commit c207a2def9
4 changed files with 150 additions and 70 deletions

View File

@@ -137,4 +137,10 @@ public class SimulationTest {
protected Card addCard(String name, Player p) {
return addCardToZone(name, p, ZoneType.Battlefield);
}
protected void addCards(String name, int count, Player p) {
for (int i = 0; i < count; i++) {
addCardToZone(name, p, ZoneType.Battlefield);
}
}
}

View File

@@ -95,11 +95,8 @@ public class SpellAbilityPickerSimulationTest extends SimulationTest {
Game game = initAndCreateGame();
Player p = game.getPlayers().get(1);
addCard("Island", p);
addCard("Island", p);
addCard("Forest", p);
addCard("Forest", p);
addCard("Forest", p);
addCards("Island", 2, p);
addCards("Forest", 3, p);
Card tatyova = addCardToZone("Tatyova, Benthic Druid", p, ZoneType.Hand);
addCardToZone("Forest", p, ZoneType.Hand);
@@ -169,10 +166,7 @@ public class SpellAbilityPickerSimulationTest extends SimulationTest {
Game game = initAndCreateGame();
Player p = game.getPlayers().get(1);
addCard("Mountain", p);
addCard("Mountain", p);
addCard("Mountain", p);
addCard("Mountain", p);
addCards("Mountain", 4, p);
Card spell = addCardToZone("Fiery Confluence", p, ZoneType.Hand);
Player opponent = game.getPlayers().get(0);
@@ -198,10 +192,7 @@ public class SpellAbilityPickerSimulationTest extends SimulationTest {
Game game = initAndCreateGame();
Player p = game.getPlayers().get(1);
addCard("Mountain", p);
addCard("Mountain", p);
addCard("Mountain", p);
addCard("Mountain", p);
addCards("Mountain", 4, p);
Card spell = addCardToZone("Fiery Confluence", p, ZoneType.Hand);
Player opponent = game.getPlayers().get(0);
@@ -226,8 +217,7 @@ public class SpellAbilityPickerSimulationTest extends SimulationTest {
Game game = initAndCreateGame();
Player p = game.getPlayers().get(1);
addCard("Mountain", p);
addCard("Mountain", p);
addCards("Mountain", 2, p);
Card spell = addCardToZone("Arc Trail", p, ZoneType.Hand);
Player opponent = game.getPlayers().get(0);
@@ -289,8 +279,7 @@ public class SpellAbilityPickerSimulationTest extends SimulationTest {
Game game = initAndCreateGame();
Player p = game.getPlayers().get(1);
addCard("Mountain", p);
addCard("Mountain", p);
addCards("Mountain", 2, p);
Card abbot = addCardToZone("Abbot of Keral Keep", p, ZoneType.Hand);
addCardToZone("Lightning Bolt", p, ZoneType.Hand);
// Note: This assumes the top of library is revealed. If the AI is made
@@ -321,9 +310,7 @@ public class SpellAbilityPickerSimulationTest extends SimulationTest {
Game game = initAndCreateGame();
Player p = game.getPlayers().get(1);
addCard("Mountain", p);
addCard("Mountain", p);
addCard("Mountain", p);
addCards("Mountain", 3, p);
Card abbot = addCardToZone("Abbot of Keral Keep", p, ZoneType.Hand);
// Note: This assumes the top of library is revealed. If the AI is made
// smarter to not assume that, then this test can be updated to have
@@ -426,8 +413,7 @@ public class SpellAbilityPickerSimulationTest extends SimulationTest {
Card blocker = addCard("Fugitive Wizard", opponent);
Card attacker1 = addCard("Dwarven Trader", p);
attacker1.setSickness(false);
addCard("Swamp", p);
addCard("Swamp", p);
addCards("Swamp", 2, p);
addCardToZone("Doom Blade", p, ZoneType.Hand);
game.getPhaseHandler().devModeSet(PhaseType.MAIN1, p);
@@ -455,9 +441,7 @@ public class SpellAbilityPickerSimulationTest extends SimulationTest {
Player opponent = game.getPlayers().get(0);
addCardToZone("Chaos Warp", p, ZoneType.Hand);
addCard("Mountain", p);
addCard("Mountain", p);
addCard("Mountain", p);
addCards("Mountain", 3, p);
addCard("Plains", opponent);
addCard("Mountain", opponent);
@@ -489,8 +473,7 @@ public class SpellAbilityPickerSimulationTest extends SimulationTest {
Game game = initAndCreateGame();
Player p = game.getPlayers().get(1);
addCard("Island", p);
addCard("Island", p);
addCards("Forest", 2, p);
addCardToZone("Counterspell", p, ZoneType.Hand);
addCardToZone("Unsummon", p, ZoneType.Hand);
@@ -605,4 +588,74 @@ public class SpellAbilityPickerSimulationTest extends SimulationTest {
// Still, this test case exercises the code path and ensures we don't crash in this case.
AssertJUnit.assertEquals(1, picker.getNumSimulations());
}
@Test
public void threeDistinctTargetSpell() {
Game game = initAndCreateGame();
Player p = game.getPlayers().get(1);
Player opponent = game.getPlayers().get(0);
addCardToZone("Incremental Growth", p, ZoneType.Hand);
addCards("Forest", 5, p);
addCard("Forest Bear", p);
addCard("Flying Men", opponent);
addCard("Runeclaw Bear", p);
addCard("Water Elemental", opponent);
addCard("Grizzly Bears", p);
game.getPhaseHandler().devModeSet(PhaseType.MAIN2, p);
game.getAction().checkStateEffects(true);
SpellAbilityPicker picker = new SpellAbilityPicker(game, p);
SpellAbility sa = picker.chooseSpellAbilityToPlay(null);
AssertJUnit.assertNotNull(sa);
MultiTargetSelector.Targets targets = picker.getPlan().getSelectedDecision().targets;
AssertJUnit.assertEquals(3, targets.size());
AssertJUnit.assertTrue(targets.toString().contains("Forest Bear"));
AssertJUnit.assertTrue(targets.toString().contains("Runeclaw Bear"));
AssertJUnit.assertTrue(targets.toString().contains("Grizzly Bear"));
// Expected 5*4*3=60 iterations (5 choices for first target, 4 for next, 3 for last.)
AssertJUnit.assertEquals(60, picker.getNumSimulations());
}
@Test
public void threeDistinctTargetSpellCantBeCast() {
Game game = initAndCreateGame();
Player p = game.getPlayers().get(1);
Player opponent = game.getPlayers().get(0);
addCardToZone("Incremental Growth", p, ZoneType.Hand);
addCards("Forest", 5, p);
addCard("Forest Bear", p);
addCard("Flying Men", opponent);
game.getPhaseHandler().devModeSet(PhaseType.MAIN2, p);
game.getAction().checkStateEffects(true);
SpellAbilityPicker picker = new SpellAbilityPicker(game, p);
SpellAbility sa = picker.chooseSpellAbilityToPlay(null);
AssertJUnit.assertNull(sa);
}
@Test
public void correctTargetChoicesWithTwoTargetSpell() {
Game game = initAndCreateGame();
Player p = game.getPlayers().get(1);
Player opponent = game.getPlayers().get(0);
addCardToZone("Rites of Reaping", p, ZoneType.Hand);
addCard("Swamp", p);
addCards("Forest", 5, p);
addCard("Flying Men", opponent);
addCard("Forest Bear", p);
addCard("Water Elemental", opponent);
game.getPhaseHandler().devModeSet(PhaseType.MAIN2, p);
game.getAction().checkStateEffects(true);
SpellAbilityPicker picker = new SpellAbilityPicker(game, p);
SpellAbility sa = picker.chooseSpellAbilityToPlay(null);
AssertJUnit.assertNotNull(sa);
MultiTargetSelector.Targets targets = picker.getPlan().getSelectedDecision().targets;
AssertJUnit.assertEquals(2, targets.size());
AssertJUnit.assertTrue(targets.toString().contains("Forest Bear"));
AssertJUnit.assertTrue(targets.toString().contains("Flying Men"));
}
}