mirror of
https://github.com/correl/mage.git
synced 2024-12-24 03:00:14 +00:00
Test framework: fixed ai play commands, added more tests
This commit is contained in:
parent
14ddb6eb28
commit
a20bca1b21
6 changed files with 258 additions and 25 deletions
|
@ -490,13 +490,9 @@ public class ComputerPlayer extends PlayerImpl implements Player {
|
|||
required = false;
|
||||
}
|
||||
|
||||
// temp lists
|
||||
List<Permanent> goodList = new ArrayList<>();
|
||||
List<Permanent> badList = new ArrayList<>();
|
||||
List<Permanent> allList = new ArrayList<>();
|
||||
List<Permanent> goodList2 = new ArrayList<>();
|
||||
List<Permanent> badList2 = new ArrayList<>();
|
||||
List<Permanent> allList2 = new ArrayList<>();
|
||||
|
||||
// TODO: improve to process multiple opponents instead random
|
||||
UUID randomOpponentId;
|
||||
|
@ -2541,6 +2537,18 @@ public class ComputerPlayer extends PlayerImpl implements Player {
|
|||
|
||||
allList.addAll(goodList);
|
||||
allList.addAll(badList);
|
||||
|
||||
// "can target all mode" don't need your/opponent lists -- all targets goes with same value
|
||||
if (outcome.isCanTargetAll()) {
|
||||
allList.sort(comparator); // bad sort
|
||||
if (outcome.isGood()) {
|
||||
Collections.reverse(allList); // good sort
|
||||
}
|
||||
goodList.clear();
|
||||
goodList.addAll(allList);
|
||||
badList.clear();
|
||||
badList.addAll(allList);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
|
208
Mage.Tests/src/test/java/org/mage/test/AI/basic/CopyAITest.java
Normal file
208
Mage.Tests/src/test/java/org/mage/test/AI/basic/CopyAITest.java
Normal file
|
@ -0,0 +1,208 @@
|
|||
package org.mage.test.AI.basic;
|
||||
|
||||
import mage.constants.PhaseStep;
|
||||
import mage.constants.Zone;
|
||||
import org.junit.Test;
|
||||
import org.mage.test.serverside.base.CardTestPlayerBaseWithAIHelps;
|
||||
|
||||
/**
|
||||
* @author JayDi85
|
||||
*/
|
||||
public class CopyAITest extends CardTestPlayerBaseWithAIHelps {
|
||||
|
||||
// AI makes decisions by two different modes:
|
||||
// 1. Simulation: If it searching playable spells then it play it in FULL SIMULATION (abilities + all possible targets)
|
||||
// 2. Response: If it searching response on dialog then it use simple target search (without simulation)
|
||||
|
||||
@Test
|
||||
public void test_CloneChoose_Manual() {
|
||||
// You may have Clone enter the battlefield as a copy of any creature on the battlefield.
|
||||
addCard(Zone.HAND, playerA, "Clone", 1); // {3}{U}
|
||||
addCard(Zone.BATTLEFIELD, playerA, "Island", 4);
|
||||
//
|
||||
addCard(Zone.BATTLEFIELD, playerA, "Arbor Elf", 1); // 1/1
|
||||
addCard(Zone.BATTLEFIELD, playerB, "Balduvian Bears", 1); // 2/2
|
||||
addCard(Zone.BATTLEFIELD, playerB, "Spectral Bears", 1); // 3/3
|
||||
|
||||
// clone
|
||||
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Clone");
|
||||
setChoice(playerA, "Yes");
|
||||
setChoice(playerA, "Spectral Bears");
|
||||
|
||||
setStopAt(1, PhaseStep.END_TURN);
|
||||
setStrictChooseMode(true);
|
||||
execute();
|
||||
assertAllCommandsUsed();
|
||||
|
||||
assertPermanentCount(playerA, "Spectral Bears", 1);
|
||||
assertPermanentCount(playerB, "Spectral Bears", 1);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void test_CloneChoose_AI_Simulation_MostValueableFromOwn() {
|
||||
// You may have Clone enter the battlefield as a copy of any creature on the battlefield.
|
||||
addCard(Zone.HAND, playerA, "Clone", 1); // {3}{U}
|
||||
addCard(Zone.BATTLEFIELD, playerA, "Island", 4);
|
||||
//
|
||||
addCard(Zone.BATTLEFIELD, playerA, "Arbor Elf", 1); // 1/1
|
||||
addCard(Zone.BATTLEFIELD, playerA, "Spectral Bears", 1); // 3/3
|
||||
//
|
||||
addCard(Zone.BATTLEFIELD, playerB, "Balduvian Bears", 1); // 2/2
|
||||
|
||||
// clone (AI must choose most valueable permanent - own)
|
||||
aiPlayPriority(1, PhaseStep.PRECOMBAT_MAIN, playerA);
|
||||
|
||||
setStopAt(1, PhaseStep.END_TURN);
|
||||
setStrictChooseMode(true);
|
||||
execute();
|
||||
assertAllCommandsUsed();
|
||||
|
||||
assertPermanentCount(playerA, "Spectral Bears", 2);
|
||||
assertPermanentCount(playerB, "Spectral Bears", 0);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void test_CloneChoose_AI_Simulation_MostValueableFromOpponent() {
|
||||
// You may have Clone enter the battlefield as a copy of any creature on the battlefield.
|
||||
addCard(Zone.HAND, playerA, "Clone", 1); // {3}{U}
|
||||
addCard(Zone.BATTLEFIELD, playerA, "Island", 4);
|
||||
//
|
||||
addCard(Zone.BATTLEFIELD, playerA, "Arbor Elf", 1); // 1/1
|
||||
//
|
||||
addCard(Zone.BATTLEFIELD, playerB, "Balduvian Bears", 1); // 2/2
|
||||
addCard(Zone.BATTLEFIELD, playerB, "Spectral Bears", 1); // 3/3
|
||||
|
||||
// clone (AI must choose most valueable permanent - opponent)
|
||||
aiPlayPriority(1, PhaseStep.PRECOMBAT_MAIN, playerA);
|
||||
|
||||
setStopAt(1, PhaseStep.END_TURN);
|
||||
setStrictChooseMode(true);
|
||||
execute();
|
||||
assertAllCommandsUsed();
|
||||
|
||||
assertPermanentCount(playerA, "Spectral Bears", 1);
|
||||
assertPermanentCount(playerB, "Spectral Bears", 1);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void test_CopyTarget_Manual() {
|
||||
// Exile target creature card from a graveyard. Dimir Doppelganger becomes a copy of that card, except it has this ability.
|
||||
addCard(Zone.BATTLEFIELD, playerA, "Dimir Doppelganger", 1); // {1}{U}{B}
|
||||
addCard(Zone.BATTLEFIELD, playerA, "Island", 2);
|
||||
addCard(Zone.BATTLEFIELD, playerA, "Swamp", 1);
|
||||
//
|
||||
addCard(Zone.GRAVEYARD, playerA, "Arbor Elf", 1); // 1/1
|
||||
addCard(Zone.GRAVEYARD, playerB, "Balduvian Bears", 1); // 2/2
|
||||
addCard(Zone.GRAVEYARD, playerB, "Spectral Bears", 1); // 3/3
|
||||
|
||||
// copy
|
||||
activateAbility(1, PhaseStep.PRECOMBAT_MAIN, playerA, "{1}{U}{B}: Exile target");
|
||||
addTarget(playerA, "Spectral Bears");
|
||||
|
||||
setStopAt(1, PhaseStep.END_TURN);
|
||||
setStrictChooseMode(true);
|
||||
execute();
|
||||
assertAllCommandsUsed();
|
||||
|
||||
assertPermanentCount(playerA, "Spectral Bears", 1);
|
||||
assertExileCount("Spectral Bears", 1);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void test_CopyTarget_AI_Simulation_MostValueableFromOwn() {
|
||||
// Exile target creature card from a graveyard. Dimir Doppelganger becomes a copy of that card, except it has this ability.
|
||||
addCard(Zone.BATTLEFIELD, playerA, "Dimir Doppelganger", 1); // {1}{U}{B}
|
||||
addCard(Zone.BATTLEFIELD, playerA, "Island", 2);
|
||||
addCard(Zone.BATTLEFIELD, playerA, "Swamp", 1);
|
||||
//
|
||||
addCard(Zone.GRAVEYARD, playerA, "Arbor Elf", 1); // 1/1
|
||||
addCard(Zone.GRAVEYARD, playerA, "Spectral Bears", 1); // 3/3
|
||||
//
|
||||
addCard(Zone.GRAVEYARD, playerB, "Balduvian Bears", 1); // 2/2
|
||||
|
||||
// copy (AI must choose most valueable permanent - own)
|
||||
aiPlayPriority(1, PhaseStep.PRECOMBAT_MAIN, playerA);
|
||||
|
||||
setStopAt(1, PhaseStep.END_TURN);
|
||||
setStrictChooseMode(true);
|
||||
execute();
|
||||
assertAllCommandsUsed();
|
||||
|
||||
assertPermanentCount(playerA, "Spectral Bears", 1);
|
||||
assertExileCount("Spectral Bears", 1);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void test_CopyTarget_AI_Simulation_MostValueableFromOpponent() {
|
||||
// Exile target creature card from a graveyard. Dimir Doppelganger becomes a copy of that card, except it has this ability.
|
||||
addCard(Zone.BATTLEFIELD, playerA, "Dimir Doppelganger", 1); // {1}{U}{B}
|
||||
addCard(Zone.BATTLEFIELD, playerA, "Island", 2);
|
||||
addCard(Zone.BATTLEFIELD, playerA, "Swamp", 1);
|
||||
//
|
||||
addCard(Zone.GRAVEYARD, playerA, "Arbor Elf", 1); // 1/1
|
||||
//
|
||||
addCard(Zone.GRAVEYARD, playerB, "Balduvian Bears", 1); // 2/2
|
||||
addCard(Zone.GRAVEYARD, playerB, "Spectral Bears", 1); // 3/3
|
||||
|
||||
// copy (AI must choose most valueable permanent - opponent)
|
||||
aiPlayPriority(1, PhaseStep.PRECOMBAT_MAIN, playerA);
|
||||
|
||||
setStopAt(1, PhaseStep.END_TURN);
|
||||
setStrictChooseMode(true);
|
||||
execute();
|
||||
assertAllCommandsUsed();
|
||||
|
||||
assertPermanentCount(playerA, "Spectral Bears", 1);
|
||||
assertExileCount("Spectral Bears", 1);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void test_CopyTarget_AI_Response_MostValueableFromOwn() {
|
||||
// Exile target creature card from a graveyard. Dimir Doppelganger becomes a copy of that card, except it has this ability.
|
||||
addCard(Zone.BATTLEFIELD, playerA, "Dimir Doppelganger", 1); // {1}{U}{B}
|
||||
addCard(Zone.BATTLEFIELD, playerA, "Island", 2);
|
||||
addCard(Zone.BATTLEFIELD, playerA, "Swamp", 1);
|
||||
//
|
||||
addCard(Zone.GRAVEYARD, playerA, "Arbor Elf", 1); // 1/1
|
||||
addCard(Zone.GRAVEYARD, playerA, "Spectral Bears", 1); // 3/3
|
||||
//
|
||||
addCard(Zone.GRAVEYARD, playerB, "Balduvian Bears", 1); // 2/2
|
||||
|
||||
// copy (AI must choose most valueable permanent - own)
|
||||
activateAbility(1, PhaseStep.PRECOMBAT_MAIN, playerA, "{1}{U}{B}: Exile target");
|
||||
//addTarget(playerA, "Spectral Bears"); // AI must choose
|
||||
|
||||
setStopAt(1, PhaseStep.END_TURN);
|
||||
//setStrictChooseMode(true); // AI must choose
|
||||
execute();
|
||||
assertAllCommandsUsed();
|
||||
|
||||
assertPermanentCount(playerA, "Spectral Bears", 1);
|
||||
assertExileCount("Spectral Bears", 1);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void test_CopyTarget_AI_Response_MostValueableFromOpponent() {
|
||||
// Exile target creature card from a graveyard. Dimir Doppelganger becomes a copy of that card, except it has this ability.
|
||||
addCard(Zone.BATTLEFIELD, playerA, "Dimir Doppelganger", 1); // {1}{U}{B}
|
||||
addCard(Zone.BATTLEFIELD, playerA, "Island", 2);
|
||||
addCard(Zone.BATTLEFIELD, playerA, "Swamp", 1);
|
||||
//
|
||||
addCard(Zone.GRAVEYARD, playerA, "Arbor Elf", 1); // 1/1
|
||||
//
|
||||
addCard(Zone.GRAVEYARD, playerB, "Balduvian Bears", 1); // 2/2
|
||||
addCard(Zone.GRAVEYARD, playerB, "Spectral Bears", 1); // 3/3
|
||||
|
||||
// copy (AI must choose most valueable permanent - opponent)
|
||||
activateAbility(1, PhaseStep.PRECOMBAT_MAIN, playerA, "{1}{U}{B}: Exile target");
|
||||
//addTarget(playerA, "Spectral Bears"); // AI must choose
|
||||
|
||||
setStopAt(1, PhaseStep.END_TURN);
|
||||
//setStrictChooseMode(true); // AI must choose
|
||||
execute();
|
||||
assertAllCommandsUsed();
|
||||
|
||||
assertPermanentCount(playerA, "Spectral Bears", 1);
|
||||
assertExileCount("Spectral Bears", 1);
|
||||
}
|
||||
}
|
|
@ -1,8 +1,7 @@
|
|||
|
||||
|
||||
package org.mage.test.player;
|
||||
|
||||
import mage.constants.PhaseStep;
|
||||
import mage.game.Game;
|
||||
|
||||
/**
|
||||
* @author BetaSteward_at_googlemail.com
|
||||
|
@ -36,4 +35,11 @@ public class PlayerAction {
|
|||
public String getActionName() {
|
||||
return this.actionName;
|
||||
}
|
||||
|
||||
/**
|
||||
* Calls after action removed from commands queue later (for multi steps action, e.g. AI related)
|
||||
*/
|
||||
public void onActionRemovedLater(Game game, TestPlayer player) {
|
||||
//
|
||||
}
|
||||
}
|
||||
|
|
|
@ -176,6 +176,10 @@ public class TestPlayer implements Player {
|
|||
actions.add(new PlayerAction(actionName, turnNum, step, action));
|
||||
}
|
||||
|
||||
public void addAction(PlayerAction playerAction) {
|
||||
actions.add(playerAction);
|
||||
}
|
||||
|
||||
public List<PlayerAction> getActions() {
|
||||
return actions;
|
||||
}
|
||||
|
@ -552,6 +556,7 @@ public class TestPlayer implements Player {
|
|||
List<PlayerAction> removed = new ArrayList<>();
|
||||
actionsToRemovesLater.forEach((action, step) -> {
|
||||
if (game.getStep().getType() != step) {
|
||||
action.onActionRemovedLater(game, this);
|
||||
actions.remove(action);
|
||||
removed.add(action);
|
||||
}
|
||||
|
@ -689,26 +694,18 @@ public class TestPlayer implements Player {
|
|||
|
||||
// play priority
|
||||
if (command.equals(AI_COMMAND_PLAY_PRIORITY)) {
|
||||
AICanChooseInStrictMode = true;
|
||||
try {
|
||||
computerPlayer.priority(game);
|
||||
actions.remove(action);
|
||||
return true;
|
||||
} finally {
|
||||
AICanChooseInStrictMode = false;
|
||||
}
|
||||
AICanChooseInStrictMode = true; // disable on action's remove
|
||||
computerPlayer.priority(game);
|
||||
actions.remove(action);
|
||||
return true;
|
||||
}
|
||||
|
||||
// play step
|
||||
if (command.equals(AI_COMMAND_PLAY_STEP)) {
|
||||
AICanChooseInStrictMode = true;
|
||||
try {
|
||||
actionsToRemovesLater.put(action, game.getStep().getType());
|
||||
computerPlayer.priority(game);
|
||||
return true;
|
||||
} finally {
|
||||
AICanChooseInStrictMode = false;
|
||||
}
|
||||
AICanChooseInStrictMode = true; // disable on action's remove
|
||||
actionsToRemovesLater.put(action, game.getStep().getType());
|
||||
computerPlayer.priority(game);
|
||||
return true;
|
||||
}
|
||||
|
||||
Assert.fail("Unknow ai command: " + command);
|
||||
|
@ -3771,4 +3768,8 @@ public class TestPlayer implements Player {
|
|||
public ComputerPlayer getComputerPlayer() {
|
||||
return computerPlayer;
|
||||
}
|
||||
|
||||
public void setAICanChooseInStrictMode(boolean AICanChooseInStrictMode) {
|
||||
this.AICanChooseInStrictMode = AICanChooseInStrictMode;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1424,7 +1424,7 @@ public abstract class CardTestPlayerAPIImpl extends MageTestPlayerBase implement
|
|||
*/
|
||||
public void aiPlayPriority(int turnNum, PhaseStep step, TestPlayer player) {
|
||||
assertAiPlayAndGameCompatible(player);
|
||||
player.addAction(turnNum, step, AI_PREFIX + AI_COMMAND_PLAY_PRIORITY);
|
||||
player.addAction(createAIPlayerAction(turnNum, step, AI_COMMAND_PLAY_PRIORITY));
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -1433,7 +1433,17 @@ public abstract class CardTestPlayerAPIImpl extends MageTestPlayerBase implement
|
|||
*/
|
||||
public void aiPlayStep(int turnNum, PhaseStep step, TestPlayer player) {
|
||||
assertAiPlayAndGameCompatible(player);
|
||||
player.addAction(turnNum, step, AI_PREFIX + AI_COMMAND_PLAY_STEP);
|
||||
player.addAction(createAIPlayerAction(turnNum, step, AI_COMMAND_PLAY_STEP));
|
||||
}
|
||||
|
||||
public PlayerAction createAIPlayerAction(int turnNum, PhaseStep step, String aiCommand) {
|
||||
// AI actions must disable and enable strict mode
|
||||
return new PlayerAction("", turnNum, step, AI_PREFIX + aiCommand) {
|
||||
@Override
|
||||
public void onActionRemovedLater(Game game, TestPlayer player) {
|
||||
player.setAICanChooseInStrictMode(false);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
private void assertAiPlayAndGameCompatible(TestPlayer player) {
|
||||
|
|
|
@ -46,7 +46,7 @@ public enum Outcome {
|
|||
// AI sorting targets by priorities (own or opponents) and selects most valueable or weakest
|
||||
private final boolean good;
|
||||
|
||||
// no different between own or opponent targets (example: copy must choose from all permanents) // TODO: copy must choose most valueable from opponent too
|
||||
// no different between own or opponent targets (example: copy must choose from all permanents)
|
||||
private boolean canTargetAll;
|
||||
|
||||
Outcome(boolean good) {
|
||||
|
|
Loading…
Reference in a new issue