Test framework: fixed ai play commands, added more tests

This commit is contained in:
Oleg Agafonov 2020-03-12 02:05:06 +04:00
parent 14ddb6eb28
commit a20bca1b21
6 changed files with 258 additions and 25 deletions

View file

@ -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);
}
}

View 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);
}
}

View file

@ -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) {
//
}
}

View file

@ -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;
}
}

View file

@ -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) {

View file

@ -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) {