mirror of
https://github.com/magefree/mage.git
synced 2025-12-23 20:11:59 -08:00
test framework: added commands to check declared attackers and blockers creatures (useful for AI tests, see checkAttackers and checkBlockers)
This commit is contained in:
parent
6b9532febd
commit
60112c6be5
5 changed files with 146 additions and 7 deletions
|
|
@ -6,6 +6,9 @@ import org.junit.Ignore;
|
|||
import org.junit.Test;
|
||||
import org.mage.test.serverside.base.CardTestPlayerBaseAI;
|
||||
|
||||
import java.util.stream.Collectors;
|
||||
import java.util.stream.IntStream;
|
||||
|
||||
/**
|
||||
* @author JayDi85
|
||||
*/
|
||||
|
|
@ -21,6 +24,8 @@ public class AttackAndBlockByAITest extends CardTestPlayerBaseAI {
|
|||
// 2 x 2/2 vs 0 - can't lose any attackers
|
||||
addCard(Zone.BATTLEFIELD, playerA, "Balduvian Bears", 2); // 2/2
|
||||
|
||||
checkAttackers("x2 attack", 1, playerA, "Balduvian Bears", "Balduvian Bears");
|
||||
|
||||
setStopAt(1, PhaseStep.END_TURN);
|
||||
setStrictChooseMode(true);
|
||||
execute();
|
||||
|
|
@ -35,6 +40,8 @@ public class AttackAndBlockByAITest extends CardTestPlayerBaseAI {
|
|||
addCard(Zone.BATTLEFIELD, playerA, "Balduvian Bears", 2); // 2/2
|
||||
addCard(Zone.BATTLEFIELD, playerB, "Arbor Elf", 1); // 1/1
|
||||
|
||||
checkAttackers("x2 attack", 1, playerA, "Balduvian Bears", "Balduvian Bears");
|
||||
|
||||
setStopAt(1, PhaseStep.END_TURN);
|
||||
setStrictChooseMode(true);
|
||||
execute();
|
||||
|
|
@ -49,6 +56,8 @@ public class AttackAndBlockByAITest extends CardTestPlayerBaseAI {
|
|||
addCard(Zone.BATTLEFIELD, playerA, "Balduvian Bears", 1); // 2/2
|
||||
addCard(Zone.BATTLEFIELD, playerB, "Arbor Elf", 2); // 1/1
|
||||
|
||||
checkAttackers("x1 attack", 1, playerA, "Balduvian Bears");
|
||||
|
||||
setStopAt(1, PhaseStep.END_TURN);
|
||||
setStrictChooseMode(true);
|
||||
execute();
|
||||
|
|
@ -63,6 +72,8 @@ public class AttackAndBlockByAITest extends CardTestPlayerBaseAI {
|
|||
addCard(Zone.BATTLEFIELD, playerA, "Balduvian Bears", 2); // 2/2
|
||||
addCard(Zone.BATTLEFIELD, playerB, "Arbor Elf", 2); // 1/1
|
||||
|
||||
checkAttackers("x2 attack", 1, playerA, "Balduvian Bears", "Balduvian Bears");
|
||||
|
||||
setStopAt(1, PhaseStep.END_TURN);
|
||||
setStrictChooseMode(true);
|
||||
execute();
|
||||
|
|
@ -75,6 +86,8 @@ public class AttackAndBlockByAITest extends CardTestPlayerBaseAI {
|
|||
public void test_Attack_1_small_vs_0() {
|
||||
addCard(Zone.BATTLEFIELD, playerA, "Arbor Elf", 1); // 1/1
|
||||
|
||||
checkAttackers("x1 attack", 1, playerA, "Arbor Elf");
|
||||
|
||||
setStopAt(1, PhaseStep.END_TURN);
|
||||
setStrictChooseMode(true);
|
||||
execute();
|
||||
|
|
@ -88,6 +101,8 @@ public class AttackAndBlockByAITest extends CardTestPlayerBaseAI {
|
|||
addCard(Zone.BATTLEFIELD, playerA, "Arbor Elf", 1); // 1/1
|
||||
addCard(Zone.BATTLEFIELD, playerB, "Balduvian Bears", 1); // 2/2
|
||||
|
||||
checkAttackers("no attack", 1, playerA, "");
|
||||
|
||||
setStopAt(1, PhaseStep.END_TURN);
|
||||
setStrictChooseMode(true);
|
||||
execute();
|
||||
|
|
@ -101,6 +116,8 @@ public class AttackAndBlockByAITest extends CardTestPlayerBaseAI {
|
|||
addCard(Zone.BATTLEFIELD, playerA, "Arbor Elf", 2); // 1/1
|
||||
addCard(Zone.BATTLEFIELD, playerB, "Balduvian Bears", 1); // 2/2
|
||||
|
||||
checkAttackers("no attack", 1, playerA, "");
|
||||
|
||||
setStopAt(1, PhaseStep.END_TURN);
|
||||
setStrictChooseMode(true);
|
||||
execute();
|
||||
|
|
@ -114,6 +131,11 @@ public class AttackAndBlockByAITest extends CardTestPlayerBaseAI {
|
|||
addCard(Zone.BATTLEFIELD, playerA, "Balduvian Bears", 15); // 2/2
|
||||
addCard(Zone.BATTLEFIELD, playerB, "Ancient Brontodon", 1); // 9/9
|
||||
|
||||
String needAttackers = IntStream.rangeClosed(1, 15)
|
||||
.mapToObj(x -> "Balduvian Bears")
|
||||
.collect(Collectors.joining("^"));
|
||||
checkAttackers("x15 attack", 1, playerA, needAttackers);
|
||||
|
||||
block(1, playerB, "Ancient Brontodon", "Balduvian Bears");
|
||||
|
||||
setStopAt(1, PhaseStep.END_TURN);
|
||||
|
|
@ -131,6 +153,10 @@ public class AttackAndBlockByAITest extends CardTestPlayerBaseAI {
|
|||
addCard(Zone.BATTLEFIELD, playerB, "Ancient Brontodon", 1); // 9/9
|
||||
|
||||
block(1, playerB, "Ancient Brontodon", "Balduvian Bears");
|
||||
String needAttackers = IntStream.rangeClosed(1, 10)
|
||||
.mapToObj(x -> "Balduvian Bears")
|
||||
.collect(Collectors.joining("^"));
|
||||
checkAttackers("x10 attack", 1, playerA, needAttackers);
|
||||
|
||||
setStopAt(1, PhaseStep.END_TURN);
|
||||
setStrictChooseMode(true);
|
||||
|
|
@ -146,6 +172,7 @@ public class AttackAndBlockByAITest extends CardTestPlayerBaseAI {
|
|||
addCard(Zone.BATTLEFIELD, playerB, "Ancient Brontodon", 1); // 9/9
|
||||
|
||||
block(1, playerB, "Ancient Brontodon", "Goblin Brigand");
|
||||
checkAttackers("forced x1 attack", 1, playerA, "Goblin Brigand");
|
||||
|
||||
setStopAt(1, PhaseStep.END_TURN);
|
||||
setStrictChooseMode(true);
|
||||
|
|
@ -163,6 +190,7 @@ public class AttackAndBlockByAITest extends CardTestPlayerBaseAI {
|
|||
|
||||
block(1, playerB, "Ancient Brontodon:0", "Goblin Brigand:0");
|
||||
block(1, playerB, "Ancient Brontodon:1", "Goblin Brigand:1");
|
||||
checkAttackers("forced x2 attack", 1, playerA, "Goblin Brigand", "Goblin Brigand");
|
||||
|
||||
setStopAt(1, PhaseStep.END_TURN);
|
||||
setStrictChooseMode(true);
|
||||
|
|
@ -183,6 +211,7 @@ public class AttackAndBlockByAITest extends CardTestPlayerBaseAI {
|
|||
addCard(Zone.BATTLEFIELD, playerB, "Trove of Temptation", 1); // 9/9
|
||||
|
||||
block(1, playerB, "Ancient Brontodon", "Arbor Elf");
|
||||
checkAttackers("forced x1 attack", 1, playerA, "Arbor Elf");
|
||||
|
||||
setStopAt(1, PhaseStep.END_TURN);
|
||||
setStrictChooseMode(true);
|
||||
|
|
@ -201,6 +230,7 @@ public class AttackAndBlockByAITest extends CardTestPlayerBaseAI {
|
|||
addCard(Zone.BATTLEFIELD, playerB, "Seeker of Slaanesh", 1); // 3/3
|
||||
|
||||
block(1, playerB, "Seeker of Slaanesh", "Arbor Elf");
|
||||
checkAttackers("forced x1 attack", 1, playerA, "Arbor Elf");
|
||||
|
||||
setStopAt(1, PhaseStep.END_TURN);
|
||||
setStrictChooseMode(true);
|
||||
|
|
@ -217,6 +247,8 @@ public class AttackAndBlockByAITest extends CardTestPlayerBaseAI {
|
|||
addCard(Zone.BATTLEFIELD, playerA, "Balduvian Bears", 1); // 2/2
|
||||
addCard(Zone.BATTLEFIELD, playerB, "Chainbreaker", 1); // 3/3, but with 2x -1/-1 counters
|
||||
|
||||
checkAttackers("x1 attack", 1, playerA, "Balduvian Bears");
|
||||
|
||||
setStopAt(1, PhaseStep.END_TURN);
|
||||
setStrictChooseMode(true);
|
||||
execute();
|
||||
|
|
|
|||
|
|
@ -19,6 +19,7 @@ public class BlockSimulationAITest extends CardTestPlayerBaseWithAIHelps {
|
|||
|
||||
// ai must block
|
||||
aiPlayStep(1, PhaseStep.DECLARE_BLOCKERS, playerB);
|
||||
checkBlockers("x1 blocker", 1, playerB, "Balduvian Bears");
|
||||
|
||||
setStopAt(1, PhaseStep.END_TURN);
|
||||
setStrictChooseMode(true);
|
||||
|
|
@ -37,8 +38,9 @@ public class BlockSimulationAITest extends CardTestPlayerBaseWithAIHelps {
|
|||
|
||||
attack(1, playerA, "Arbor Elf");
|
||||
|
||||
// ai must block
|
||||
// ai must block by optimal blocker
|
||||
aiPlayStep(1, PhaseStep.DECLARE_BLOCKERS, playerB);
|
||||
checkBlockers("x1 optimal blocker", 1, playerB, "Balduvian Bears");
|
||||
|
||||
setStopAt(1, PhaseStep.END_TURN);
|
||||
setStrictChooseMode(true);
|
||||
|
|
@ -58,6 +60,7 @@ public class BlockSimulationAITest extends CardTestPlayerBaseWithAIHelps {
|
|||
|
||||
// ai must block
|
||||
aiPlayStep(1, PhaseStep.DECLARE_BLOCKERS, playerB);
|
||||
checkBlockers("x1 blocker", 1, playerB, "Arbor Elf");
|
||||
|
||||
setStopAt(1, PhaseStep.END_TURN);
|
||||
setStrictChooseMode(true);
|
||||
|
|
@ -78,6 +81,7 @@ public class BlockSimulationAITest extends CardTestPlayerBaseWithAIHelps {
|
|||
|
||||
// ai must not block
|
||||
aiPlayStep(1, PhaseStep.DECLARE_BLOCKERS, playerB);
|
||||
checkBlockers("no blockers", 1, playerB, "");
|
||||
|
||||
setStopAt(1, PhaseStep.END_TURN);
|
||||
setStrictChooseMode(true);
|
||||
|
|
@ -100,6 +104,7 @@ public class BlockSimulationAITest extends CardTestPlayerBaseWithAIHelps {
|
|||
|
||||
// ai must not block
|
||||
aiPlayStep(1, PhaseStep.DECLARE_BLOCKERS, playerB);
|
||||
checkBlockers("no blockers", 1, playerB, "");
|
||||
|
||||
setStopAt(1, PhaseStep.END_TURN);
|
||||
setStrictChooseMode(true);
|
||||
|
|
@ -123,6 +128,7 @@ public class BlockSimulationAITest extends CardTestPlayerBaseWithAIHelps {
|
|||
|
||||
// ai must block bigger attacker and survive (6/6 must block 5/5)
|
||||
aiPlayStep(1, PhaseStep.DECLARE_BLOCKERS, playerB);
|
||||
checkBlockers("x1 optimal blocker", 1, playerB, "Colossal Dreadmaw");
|
||||
|
||||
setStopAt(1, PhaseStep.END_TURN);
|
||||
setStrictChooseMode(true);
|
||||
|
|
@ -151,6 +157,7 @@ public class BlockSimulationAITest extends CardTestPlayerBaseWithAIHelps {
|
|||
|
||||
// ai must block bigger attacker and survive (3/3 must block 2/2)
|
||||
aiPlayStep(1, PhaseStep.DECLARE_BLOCKERS, playerB);
|
||||
checkBlockers("x1 optimal blocker", 1, playerB, "Spectral Bears");
|
||||
|
||||
setStopAt(1, PhaseStep.END_TURN);
|
||||
setStrictChooseMode(true);
|
||||
|
|
@ -175,6 +182,7 @@ public class BlockSimulationAITest extends CardTestPlayerBaseWithAIHelps {
|
|||
|
||||
// ai must use smaller blocker and survive (3/3 must block 2/2)
|
||||
aiPlayStep(1, PhaseStep.DECLARE_BLOCKERS, playerB);
|
||||
checkBlockers("x1 optimal blocker", 1, playerB, "Spectral Bears");
|
||||
|
||||
setStopAt(1, PhaseStep.END_TURN);
|
||||
setStrictChooseMode(true);
|
||||
|
|
|
|||
|
|
@ -28,10 +28,7 @@ import mage.filter.common.*;
|
|||
import mage.filter.predicate.Predicates;
|
||||
import mage.filter.predicate.mageobject.NamePredicate;
|
||||
import mage.filter.predicate.permanent.SummoningSicknessPredicate;
|
||||
import mage.game.Game;
|
||||
import mage.game.GameImpl;
|
||||
import mage.game.Graveyard;
|
||||
import mage.game.Table;
|
||||
import mage.game.*;
|
||||
import mage.game.combat.CombatGroup;
|
||||
import mage.game.command.CommandObject;
|
||||
import mage.game.draft.Draft;
|
||||
|
|
@ -52,6 +49,7 @@ import mage.target.common.*;
|
|||
import mage.util.CardUtil;
|
||||
import mage.util.MultiAmountMessage;
|
||||
import mage.util.RandomUtil;
|
||||
import mage.watchers.common.AttackedOrBlockedThisCombatWatcher;
|
||||
import org.apache.log4j.Logger;
|
||||
import org.junit.Assert;
|
||||
|
||||
|
|
@ -839,6 +837,20 @@ public class TestPlayer implements Player {
|
|||
wasProccessed = true;
|
||||
}
|
||||
|
||||
// check attacking: attackers list
|
||||
if (params[0].equals(CHECK_COMMAND_ATTACKERS) && params.length == 2) {
|
||||
assertAttackers(action, game, computerPlayer, params[1]);
|
||||
actions.remove(action);
|
||||
wasProccessed = true;
|
||||
}
|
||||
|
||||
// check attacking: attackers list
|
||||
if (params[0].equals(CHECK_COMMAND_BLOCKERS) && params.length == 2) {
|
||||
assertBlockers(action, game, computerPlayer, params[1]);
|
||||
actions.remove(action);
|
||||
wasProccessed = true;
|
||||
}
|
||||
|
||||
// check playable ability: ability text, must have
|
||||
if (params[0].equals(CHECK_COMMAND_PLAYABLE_ABILITY) && params.length == 3) {
|
||||
assertPlayableAbility(action, game, computerPlayer, params[1], Boolean.parseBoolean(params[2]));
|
||||
|
|
@ -1418,6 +1430,64 @@ public class TestPlayer implements Player {
|
|||
}
|
||||
}
|
||||
|
||||
private void assertAttackers(PlayerAction action, Game game, Player player, String attackers) {
|
||||
AttackedOrBlockedThisCombatWatcher watcher = game.getState().getWatcher(AttackedOrBlockedThisCombatWatcher.class);
|
||||
Assert.assertNotNull(watcher);
|
||||
|
||||
List<String> actualAttackers = watcher.getAttackedThisTurnCreatures().stream()
|
||||
.map(mor -> game.getObject(mor.getSourceId()))// no needs in zcc/lki
|
||||
.filter(Objects::nonNull)
|
||||
.filter(o -> o instanceof ControllableOrOwnerable)
|
||||
.map(o -> (ControllableOrOwnerable) o)
|
||||
.filter(o -> o.getControllerOrOwnerId().equals(player.getId()))
|
||||
.map(o -> ((MageObject) o).getName())
|
||||
.sorted()
|
||||
.collect(Collectors.toList());
|
||||
List<String> needAttackers = Arrays.stream(attackers.split("\\^"))
|
||||
.filter(s -> !s.equals(TestPlayer.ATTACK_SKIP))
|
||||
.sorted()
|
||||
.collect(Collectors.toList());
|
||||
|
||||
if (!actualAttackers.equals(needAttackers)) {
|
||||
printStart(game, action.getActionName());
|
||||
System.out.println(String.format("Need attackers: %d", needAttackers.size()));
|
||||
needAttackers.forEach(s -> System.out.println(" - " + s));
|
||||
System.out.println(String.format("Actual attackers: %d", actualAttackers.size()));
|
||||
actualAttackers.forEach(s -> System.out.println(" - " + s));
|
||||
printEnd();
|
||||
Assert.fail("Found wrong attackers");
|
||||
}
|
||||
}
|
||||
|
||||
private void assertBlockers(PlayerAction action, Game game, Player player, String blockers) {
|
||||
AttackedOrBlockedThisCombatWatcher watcher = game.getState().getWatcher(AttackedOrBlockedThisCombatWatcher.class);
|
||||
Assert.assertNotNull(watcher);
|
||||
|
||||
List<String> actualBlockers = watcher.getBlockedThisTurnCreatures().stream()
|
||||
.map(mor -> game.getObject(mor.getSourceId()))// no needs in zcc/lki
|
||||
.filter(Objects::nonNull)
|
||||
.filter(o -> o instanceof ControllableOrOwnerable)
|
||||
.map(o -> (ControllableOrOwnerable) o)
|
||||
.filter(o -> o.getControllerOrOwnerId().equals(player.getId()))
|
||||
.map(o -> ((MageObject) o).getName())
|
||||
.sorted()
|
||||
.collect(Collectors.toList());
|
||||
List<String> needBlockers = Arrays.stream(blockers.split("\\^"))
|
||||
.filter(s -> !s.equals(TestPlayer.BLOCK_SKIP))
|
||||
.sorted()
|
||||
.collect(Collectors.toList());
|
||||
|
||||
if (!actualBlockers.equals(needBlockers)) {
|
||||
printStart(game, action.getActionName());
|
||||
System.out.println(String.format("Need blockers: %d", needBlockers.size()));
|
||||
needBlockers.forEach(s -> System.out.println(" - " + s));
|
||||
System.out.println(String.format("Actual blockers: %d", actualBlockers.size()));
|
||||
actualBlockers.forEach(s -> System.out.println(" - " + s));
|
||||
printEnd();
|
||||
Assert.fail("Found wrong blockers");
|
||||
}
|
||||
}
|
||||
|
||||
private void assertMayAttackDefender(PlayerAction action, Game game, Player controller, String permanentName, Player defender, boolean expectedMayAttack) {
|
||||
Permanent attackingPermanent = findPermanentWithAssert(action, game, controller, permanentName);
|
||||
|
||||
|
|
|
|||
|
|
@ -87,6 +87,8 @@ public abstract class CardTestPlayerAPIImpl extends MageTestPlayerBase implement
|
|||
public static final String CHECK_COMMAND_LIFE = "LIFE";
|
||||
public static final String CHECK_COMMAND_ABILITY = "ABILITY";
|
||||
public static final String CHECK_COMMAND_PLAYABLE_ABILITY = "PLAYABLE_ABILITY";
|
||||
public static final String CHECK_COMMAND_ATTACKERS = "ATTACKERS";
|
||||
public static final String CHECK_COMMAND_BLOCKERS = "BLOCKERS";
|
||||
public static final String CHECK_COMMAND_MAY_ATTACK_DEFENDER = "MAY_ATTACK_DEFENDER";
|
||||
public static final String CHECK_COMMAND_PERMANENT_COUNT = "PERMANENT_COUNT";
|
||||
public static final String CHECK_COMMAND_PERMANENT_TAPPED = "PERMANENT_TAPPED";
|
||||
|
|
@ -428,7 +430,33 @@ public abstract class CardTestPlayerAPIImpl extends MageTestPlayerBase implement
|
|||
}
|
||||
|
||||
/**
|
||||
* Checks whether or not a creature can attack on a given turn a defender (player only for now, could be extended to permanents)
|
||||
* Make sure in last declared attackers
|
||||
*
|
||||
* @param attackers in any order, use empty string or params for no attackers check
|
||||
*/
|
||||
public void checkAttackers(String checkName, int turnNum, TestPlayer player, String... attackers) {
|
||||
String list = String.join("^", attackers);
|
||||
if (list.isEmpty()) {
|
||||
list = TestPlayer.ATTACK_SKIP;
|
||||
}
|
||||
check(checkName, turnNum, PhaseStep.DECLARE_ATTACKERS, player, CHECK_COMMAND_ATTACKERS, list);
|
||||
}
|
||||
|
||||
/**
|
||||
* Make sure in last declared blockers
|
||||
*
|
||||
* @param blockers in any order, use empty string or params for no blockers check
|
||||
*/
|
||||
public void checkBlockers(String checkName, int turnNum, TestPlayer player, String... blockers) {
|
||||
String list = String.join("^", blockers);
|
||||
if (list.isEmpty()) {
|
||||
list = TestPlayer.BLOCK_SKIP;
|
||||
}
|
||||
check(checkName, turnNum, PhaseStep.DECLARE_BLOCKERS, player, CHECK_COMMAND_BLOCKERS, list);
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks whether a creature can attack on a given turn a defender (player only for now, could be extended to permanents)
|
||||
*
|
||||
* @param checkName String to show up if the check fails, for display purposes only.
|
||||
* @param turnNum The turn number to check on.
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue