Refactor logic for continuing simulation to SimulationController class.

This commit is contained in:
Myrd
2015-03-08 17:13:43 +00:00
parent aed4b5cdfa
commit 219eae0a00
6 changed files with 78 additions and 49 deletions

1
.gitattributes vendored
View File

@@ -154,6 +154,7 @@ forge-ai/src/main/java/forge/ai/simulation/GameCopier.java -text
forge-ai/src/main/java/forge/ai/simulation/GameSimulator.java -text forge-ai/src/main/java/forge/ai/simulation/GameSimulator.java -text
forge-ai/src/main/java/forge/ai/simulation/GameStateEvaluator.java -text forge-ai/src/main/java/forge/ai/simulation/GameStateEvaluator.java -text
forge-ai/src/main/java/forge/ai/simulation/PossibleTargetSelector.java -text forge-ai/src/main/java/forge/ai/simulation/PossibleTargetSelector.java -text
forge-ai/src/main/java/forge/ai/simulation/SimulationController.java -text
forge-ai/src/main/java/forge/ai/simulation/SpellAbilityPicker.java -text forge-ai/src/main/java/forge/ai/simulation/SpellAbilityPicker.java -text
forge-ai/src/main/java/forge/ai/simulation/TODO.txt -text forge-ai/src/main/java/forge/ai/simulation/TODO.txt -text
forge-core/.classpath -text forge-core/.classpath -text

View File

@@ -1173,7 +1173,7 @@ public class AiController {
return null; return null;
if (useSimulation) { if (useSimulation) {
return simPicker.chooseSpellAbilityToPlay(all, skipCounter); return simPicker.chooseSpellAbilityToPlay(null, all, skipCounter);
} }
Collections.sort(all, saComparator); // put best spells first Collections.sort(all, saComparator); // put best spells first

View File

@@ -21,18 +21,17 @@ import forge.game.spellability.TargetChoices;
import forge.game.spellability.TargetRestrictions; import forge.game.spellability.TargetRestrictions;
public class GameSimulator { public class GameSimulator {
private static int MAX_DEPTH = 5;
public static boolean COPY_STACK = false; public static boolean COPY_STACK = false;
final private SimulationController controller;
private GameCopier copier; private GameCopier copier;
private Game simGame; private Game simGame;
private Player aiPlayer; private Player aiPlayer;
private GameStateEvaluator eval; private GameStateEvaluator eval;
private int recursionDepth;
private ArrayList<String> origLines; private ArrayList<String> origLines;
private Score origScore; private Score origScore;
public GameSimulator(final Game origGame, final Player origAiPlayer) { public GameSimulator(final SimulationController controller, final Game origGame, final Player origAiPlayer) {
this.controller = controller;
copier = new GameCopier(origGame); copier = new GameCopier(origGame);
simGame = copier.makeCopy(); simGame = copier.makeCopy();
@@ -76,10 +75,6 @@ public class GameSimulator {
debugLines = null; debugLines = null;
} }
public void setRecursionDepth(int depth) {
this.recursionDepth = depth;
}
private void printDiff(List<String> lines1, List<String> lines2) { private void printDiff(List<String> lines1, List<String> lines2) {
int i = 0; int i = 0;
int j = 0; int j = 0;
@@ -191,21 +186,17 @@ public class GameSimulator {
debugPrint = true; debugPrint = true;
printDiff(origLines, simLines); printDiff(origLines, simLines);
} }
for (int i = 0; i < recursionDepth; i++) controller.printState(score, origSa);
System.err.print(" "); if (controller.shouldRecurse() && !simGame.isGameOver()) {
System.err.println(recursionDepth + ": [" + score.value + "] " + SpellAbilityPicker.abilityToString(origSa)); controller.push(sa);
if (recursionDepth < MAX_DEPTH && !simGame.isGameOver()) {
debugPrint("Recursing DEPTH=" + recursionDepth);
debugPrint(" With: " + sa);
SpellAbilityPicker sim = new SpellAbilityPicker(simGame, aiPlayer); SpellAbilityPicker sim = new SpellAbilityPicker(simGame, aiPlayer);
sim.setRecursionDepth(recursionDepth + 1);
CardCollection cards = ComputerUtilAbility.getAvailableCards(simGame, aiPlayer); CardCollection cards = ComputerUtilAbility.getAvailableCards(simGame, aiPlayer);
ArrayList<SpellAbility> all = ComputerUtilAbility.getSpellAbilities(cards, aiPlayer); ArrayList<SpellAbility> all = ComputerUtilAbility.getSpellAbilities(cards, aiPlayer);
SpellAbility nextSa = sim.chooseSpellAbilityToPlay(all, true); SpellAbility nextSa = sim.chooseSpellAbilityToPlay(controller, all, true);
if (nextSa != null) { if (nextSa != null) {
score = sim.getScoreForChosenAbility(); score = sim.getScoreForChosenAbility();
} }
debugPrint("DEPTH"+recursionDepth+" best score " + score + " " + nextSa); controller.pop(score, nextSa);
} }
return score; return score;

View File

@@ -0,0 +1,34 @@
package forge.ai.simulation;
import forge.ai.simulation.GameStateEvaluator.Score;
import forge.game.spellability.SpellAbility;
public class SimulationController {
private static int MAX_DEPTH = 5;
private int recursionDepth;
public SimulationController() {
}
public boolean shouldRecurse() {
return recursionDepth < MAX_DEPTH;
}
public void push(SpellAbility sa) {
GameSimulator.debugPrint("Recursing DEPTH=" + recursionDepth);
GameSimulator.debugPrint(" With: " + sa);
recursionDepth++;
}
public void pop(Score score, SpellAbility nextSa) {
recursionDepth--;
GameSimulator.debugPrint("DEPTH"+recursionDepth+" best score " + score + " " + nextSa);
}
public void printState(Score score, SpellAbility origSa) {
for (int i = 0; i < recursionDepth; i++)
System.err.print(" ");
System.err.println(recursionDepth + ": [" + score.value + "] " + SpellAbilityPicker.abilityToString(origSa));
}
}

View File

@@ -18,25 +18,26 @@ import forge.game.spellability.TargetChoices;
public class SpellAbilityPicker { public class SpellAbilityPicker {
private Game game; private Game game;
private Player player; private Player player;
private int recursionDepth;
private Score bestScore; private Score bestScore;
private boolean printOutput;
public SpellAbilityPicker(Game game, Player player) { public SpellAbilityPicker(Game game, Player player) {
this.game = game; this.game = game;
this.player = player; this.player = player;
} }
public void setRecursionDepth(int depth) {
recursionDepth = depth;
}
private void print(String str) { private void print(String str) {
if (recursionDepth == 0) { if (printOutput) {
System.out.println(str); System.out.println(str);
} }
} }
public SpellAbility chooseSpellAbilityToPlay(final ArrayList<SpellAbility> all, boolean skipCounter) { public SpellAbility chooseSpellAbilityToPlay(SimulationController controller, final ArrayList<SpellAbility> all, boolean skipCounter) {
printOutput = false;
if (controller == null) {
controller = new SimulationController();
printOutput = true;
}
print("---- choose ability (phase = " + game.getPhaseHandler().getPhase() + ")"); print("---- choose ability (phase = " + game.getPhaseHandler().getPhase() + ")");
ArrayList<SpellAbility> candidateSAs = new ArrayList<>(); ArrayList<SpellAbility> candidateSAs = new ArrayList<>();
@@ -64,13 +65,13 @@ public class SpellAbilityPicker {
} }
SpellAbility bestSa = null; SpellAbility bestSa = null;
print("Evaluating..."); print("Evaluating...");
GameSimulator simulator = new GameSimulator(game, player); GameSimulator simulator = new GameSimulator(controller, game, player);
// FIXME: This is wasteful, we should re-use the same simulator... // FIXME: This is wasteful, we should re-use the same simulator...
Score origGameScore = simulator.getScoreForOrigGame(); Score origGameScore = simulator.getScoreForOrigGame();
Score bestSaValue = origGameScore; Score bestSaValue = origGameScore;
for (final SpellAbility sa : candidateSAs) { for (final SpellAbility sa : candidateSAs) {
print(abilityToString(sa));; print(abilityToString(sa));;
Score value = evaluateSa(sa); Score value = evaluateSa(controller, sa);
if (value.value > bestSaValue.value) { if (value.value > bestSaValue.value) {
bestSaValue = value; bestSaValue = value;
bestSa = sa; bestSa = sa;
@@ -148,11 +149,10 @@ public class SpellAbilityPicker {
return AiPlayDecision.WillPlay; return AiPlayDecision.WillPlay;
} }
private Score evaluateSa(SpellAbility sa) { private Score evaluateSa(SimulationController controller, SpellAbility sa) {
GameSimulator.debugPrint("Evaluate SA: " + sa); GameSimulator.debugPrint("Evaluate SA: " + sa);
if (!sa.usesTargeting()) { if (!sa.usesTargeting()) {
GameSimulator simulator = new GameSimulator(game, player); GameSimulator simulator = new GameSimulator(controller, game, player);
simulator.setRecursionDepth(recursionDepth);
return simulator.simulateSpellAbility(sa); return simulator.simulateSpellAbility(sa);
} }
GameSimulator.debugPrint("Checking out targets"); GameSimulator.debugPrint("Checking out targets");
@@ -161,8 +161,7 @@ public class SpellAbilityPicker {
TargetChoices tgt = null; TargetChoices tgt = null;
while (selector.selectNextTargets()) { while (selector.selectNextTargets()) {
GameSimulator.debugPrint("Trying targets: " + sa.getTargets().getTargetedString()); GameSimulator.debugPrint("Trying targets: " + sa.getTargets().getTargetedString());
GameSimulator simulator = new GameSimulator(game, player); GameSimulator simulator = new GameSimulator(controller, game, player);
simulator.setRecursionDepth(recursionDepth);
Score score = simulator.simulateSpellAbility(sa); Score score = simulator.simulateSpellAbility(sa);
if (score.value > bestScore.value) { if (score.value > bestScore.value) {
bestScore = score; bestScore = score;

View File

@@ -49,6 +49,10 @@ public class GameSimulatorTest extends TestCase {
return game; return game;
} }
private GameSimulator createSimulator(Game game, Player p) {
return new GameSimulator(new SimulationController(), game, p);
}
private Card findCardWithName(Game game, String name) { private Card findCardWithName(Game game, String name) {
for (Card c : game.getCardsIn(ZoneType.Battlefield)) { for (Card c : game.getCardsIn(ZoneType.Battlefield)) {
if (c.getName().equals(name)) { if (c.getName().equals(name)) {
@@ -103,7 +107,7 @@ public class GameSimulatorTest extends TestCase {
SpellAbility outlastSA = findSAWithPrefix(herald, "Outlast"); SpellAbility outlastSA = findSAWithPrefix(herald, "Outlast");
assertNotNull(outlastSA); assertNotNull(outlastSA);
GameSimulator sim = new GameSimulator(game, p); GameSimulator sim = createSimulator(game, p);
int score = sim.simulateSpellAbility(outlastSA).value; int score = sim.simulateSpellAbility(outlastSA).value;
assertTrue(score > 0); assertTrue(score > 0);
Game simGame = sim.getSimulatedGameState(); Game simGame = sim.getSimulatedGameState();
@@ -147,7 +151,7 @@ public class GameSimulatorTest extends TestCase {
SpellAbility outlastSA = findSAWithPrefix(herald, "Outlast"); SpellAbility outlastSA = findSAWithPrefix(herald, "Outlast");
assertNotNull(outlastSA); assertNotNull(outlastSA);
GameSimulator sim = new GameSimulator(game, p); GameSimulator sim = createSimulator(game, p);
int score = sim.simulateSpellAbility(outlastSA).value; int score = sim.simulateSpellAbility(outlastSA).value;
assertTrue(score > 0); assertTrue(score > 0);
Game simGame = sim.getSimulatedGameState(); Game simGame = sim.getSimulatedGameState();
@@ -170,7 +174,7 @@ public class GameSimulatorTest extends TestCase {
assertEquals(1, lion.getAmountOfKeyword("Hexproof")); assertEquals(1, lion.getAmountOfKeyword("Hexproof"));
assertEquals(1, lion.getAmountOfKeyword("Indestructible")); assertEquals(1, lion.getAmountOfKeyword("Indestructible"));
GameSimulator sim = new GameSimulator(game, p); GameSimulator sim = createSimulator(game, p);
Game simGame = sim.getSimulatedGameState(); Game simGame = sim.getSimulatedGameState();
Card lionCopy = findCardWithName(simGame, lionCardName); Card lionCopy = findCardWithName(simGame, lionCardName);
assertTrue(lionCopy.isMonstrous()); assertTrue(lionCopy.isMonstrous());
@@ -190,7 +194,7 @@ public class GameSimulatorTest extends TestCase {
game.getAction().checkStateEffects(true); game.getAction().checkStateEffects(true);
assertEquals(1, bear.getAmountOfKeyword("Unblockable")); assertEquals(1, bear.getAmountOfKeyword("Unblockable"));
GameSimulator sim = new GameSimulator(game, p); GameSimulator sim = createSimulator(game, p);
Game simGame = sim.getSimulatedGameState(); Game simGame = sim.getSimulatedGameState();
Card bearCopy = findCardWithName(simGame, bearCardName); Card bearCopy = findCardWithName(simGame, bearCardName);
assertEquals(1, bearCopy.getAmountOfKeyword("Unblockable")); assertEquals(1, bearCopy.getAmountOfKeyword("Unblockable"));
@@ -208,7 +212,7 @@ public class GameSimulatorTest extends TestCase {
game.getAction().checkStateEffects(true); game.getAction().checkStateEffects(true);
assertEquals(1, bear.getAmountOfKeyword("Lifelink")); assertEquals(1, bear.getAmountOfKeyword("Lifelink"));
GameSimulator sim = new GameSimulator(game, p); GameSimulator sim = createSimulator(game, p);
Game simGame = sim.getSimulatedGameState(); Game simGame = sim.getSimulatedGameState();
Card bearCopy = findCardWithName(simGame, bearCardName); Card bearCopy = findCardWithName(simGame, bearCardName);
assertEquals(1, bearCopy.getAmountOfKeyword("Lifelink")); assertEquals(1, bearCopy.getAmountOfKeyword("Lifelink"));
@@ -229,7 +233,7 @@ public class GameSimulatorTest extends TestCase {
SpellAbility playMerchantSa = c.getSpellAbilities().get(0); SpellAbility playMerchantSa = c.getSpellAbilities().get(0);
playMerchantSa.setActivatingPlayer(p); playMerchantSa.setActivatingPlayer(p);
GameSimulator sim = new GameSimulator(game, p); GameSimulator sim = createSimulator(game, p);
int origScore = sim.getScoreForOrigGame().value; int origScore = sim.getScoreForOrigGame().value;
int score = sim.simulateSpellAbility(playMerchantSa).value; int score = sim.simulateSpellAbility(playMerchantSa).value;
assertTrue(String.format("score=%d vs. origScore=%d", score, origScore), score > origScore); assertTrue(String.format("score=%d vs. origScore=%d", score, origScore), score > origScore);
@@ -254,7 +258,7 @@ public class GameSimulatorTest extends TestCase {
assertTrue(c2.hasStartOfKeyword("(Echo unpaid)")); assertTrue(c2.hasStartOfKeyword("(Echo unpaid)"));
c2.removeAllExtrinsicKeyword("(Echo unpaid)"); c2.removeAllExtrinsicKeyword("(Echo unpaid)");
GameSimulator sim = new GameSimulator(game, p); GameSimulator sim = createSimulator(game, p);
Game simGame = sim.getSimulatedGameState(); Game simGame = sim.getSimulatedGameState();
Card c1Copy = findCardWithName(simGame, c1Name); Card c1Copy = findCardWithName(simGame, c1Name);
assertTrue(c1Copy.hasStartOfKeyword("(Echo unpaid)")); assertTrue(c1Copy.hasStartOfKeyword("(Echo unpaid)"));
@@ -274,7 +278,7 @@ public class GameSimulatorTest extends TestCase {
assertEquals(20, p.getOpponent().getLife()); assertEquals(20, p.getOpponent().getLife());
GameSimulator sim = new GameSimulator(game, p); GameSimulator sim = createSimulator(game, p);
Game simGame = sim.getSimulatedGameState(); Game simGame = sim.getSimulatedGameState();
SpellAbility unmorphSA = findSAWithPrefix(ripper, "Morph - Reveal a black card"); SpellAbility unmorphSA = findSAWithPrefix(ripper, "Morph - Reveal a black card");
@@ -294,7 +298,7 @@ public class GameSimulatorTest extends TestCase {
game.getPhaseHandler().devModeSet(PhaseType.MAIN2, p1); game.getPhaseHandler().devModeSet(PhaseType.MAIN2, p1);
game.getAction().checkStateEffects(true); game.getAction().checkStateEffects(true);
GameSimulator sim = new GameSimulator(game, p1); GameSimulator sim = createSimulator(game, p1);
Game simGame = sim.getSimulatedGameState(); Game simGame = sim.getSimulatedGameState();
SpellAbility fractureSa = fractureP1.getSpellAbilities().get(0); SpellAbility fractureSa = fractureP1.getSpellAbilities().get(0);
@@ -321,7 +325,7 @@ public class GameSimulatorTest extends TestCase {
minusTwo.setActivatingPlayer(p); minusTwo.setActivatingPlayer(p);
assertTrue(minusTwo.canPlay()); assertTrue(minusTwo.canPlay());
GameSimulator sim = new GameSimulator(game, p); GameSimulator sim = createSimulator(game, p);
sim.simulateSpellAbility(minusTwo); sim.simulateSpellAbility(minusTwo);
Game simGame = sim.getSimulatedGameState(); Game simGame = sim.getSimulatedGameState();
Card vampireToken = findCardWithName(simGame, "Vampire"); Card vampireToken = findCardWithName(simGame, "Vampire");
@@ -360,7 +364,7 @@ public class GameSimulatorTest extends TestCase {
SpellAbility manifestSA = soulSummons.getSpellAbilities().get(0); SpellAbility manifestSA = soulSummons.getSpellAbilities().get(0);
GameSimulator sim = new GameSimulator(game, p); GameSimulator sim = createSimulator(game, p);
sim.simulateSpellAbility(manifestSA); sim.simulateSpellAbility(manifestSA);
Game simGame = sim.getSimulatedGameState(); Game simGame = sim.getSimulatedGameState();
Card manifestedCreature = findCardWithName(simGame, ""); Card manifestedCreature = findCardWithName(simGame, "");
@@ -371,7 +375,7 @@ public class GameSimulatorTest extends TestCase {
assertEquals(2, manifestedCreature.getNetPower()); assertEquals(2, manifestedCreature.getNetPower());
assertFalse(manifestedCreature.hasKeyword("Flying")); assertFalse(manifestedCreature.hasKeyword("Flying"));
GameSimulator sim2 = new GameSimulator(simGame, simGame.getPlayers().get(1)); GameSimulator sim2 = createSimulator(simGame, simGame.getPlayers().get(1));
sim2.simulateSpellAbility(unmanifestSA); sim2.simulateSpellAbility(unmanifestSA);
Game simGame2 = sim2.getSimulatedGameState(); Game simGame2 = sim2.getSimulatedGameState();
Card ornithopter = findCardWithName(simGame2, "Ornithopter"); Card ornithopter = findCardWithName(simGame2, "Ornithopter");
@@ -398,7 +402,7 @@ public class GameSimulatorTest extends TestCase {
SpellAbility manifestSA = soulSummons.getSpellAbilities().get(0); SpellAbility manifestSA = soulSummons.getSpellAbilities().get(0);
GameSimulator sim = new GameSimulator(game, p); GameSimulator sim = createSimulator(game, p);
sim.simulateSpellAbility(manifestSA); sim.simulateSpellAbility(manifestSA);
Game simGame = sim.getSimulatedGameState(); Game simGame = sim.getSimulatedGameState();
Card manifestedCreature = findCardWithName(simGame, ""); Card manifestedCreature = findCardWithName(simGame, "");
@@ -426,7 +430,7 @@ public class GameSimulatorTest extends TestCase {
SpellAbility becomeDragonSA = findSAWithPrefix(sarkhan, "+1"); SpellAbility becomeDragonSA = findSAWithPrefix(sarkhan, "+1");
assertNotNull(becomeDragonSA); assertNotNull(becomeDragonSA);
GameSimulator sim = new GameSimulator(game, p); GameSimulator sim = createSimulator(game, p);
sim.simulateSpellAbility(becomeDragonSA); sim.simulateSpellAbility(becomeDragonSA);
Game simGame = sim.getSimulatedGameState(); Game simGame = sim.getSimulatedGameState();
Card sarkhanSim = findCardWithName(simGame, sarkhanCardName); Card sarkhanSim = findCardWithName(simGame, sarkhanCardName);
@@ -459,7 +463,7 @@ public class GameSimulatorTest extends TestCase {
PossibleTargetSelector selector = new PossibleTargetSelector(game, p, sa); PossibleTargetSelector selector = new PossibleTargetSelector(game, p, sa);
while (selector.selectNextTargets()) { while (selector.selectNextTargets()) {
GameSimulator sim = new GameSimulator(game, p); GameSimulator sim = createSimulator(game, p);
sim.simulateSpellAbility(sa); sim.simulateSpellAbility(sa);
Game simGame = sim.getSimulatedGameState(); Game simGame = sim.getSimulatedGameState();
Card thopterSim = findCardWithName(simGame, ornithoperCardName); Card thopterSim = findCardWithName(simGame, ornithoperCardName);