Test framework improves (Monte Carlo AI):

* Added support to test Monte Carlo AI (CardTestPlayerBaseWithMonteCarloAIHelps - any aiXXX commands);
* Added Quick Start button to test Monte Carlo AI games (MCTS);
This commit is contained in:
Oleg Agafonov 2020-04-14 20:09:36 +04:00
parent a7ac35a82d
commit 79c5c7a6a5
6 changed files with 224 additions and 47 deletions

View file

@ -0,0 +1,42 @@
package org.mage.test.cards.requirement;
import mage.constants.PhaseStep;
import mage.constants.Zone;
import org.junit.Test;
import org.mage.test.serverside.base.CardTestPlayerBaseWithMonteCarloAIHelps;
/**
* @author JayDi85
*/
public class BecomeBlockTriggersMonteCarloAITest extends CardTestPlayerBaseWithMonteCarloAIHelps {
// continue from BecomeBlockTriggersTest
@Test
public void test_AI_CantBlockAgain() {
// Monte Carlo bug: Triggered ability triggered twice (should be once), see https://github.com/magefree/mage/issues/6367
removeAllCardsFromHand(playerA);
removeAllCardsFromHand(playerB);
// All creatures able to block Nessian Boar do so.
// Whenever Nessian Boar becomes blocked by a creature, that creatures controller draws a card.
addCard(Zone.BATTLEFIELD, playerA, "Nessian Boar", 1);
//
addCard(Zone.BATTLEFIELD, playerB, "Balduvian Bears", 1);
// auto-block by requirement effect
attack(1, playerA, "Nessian Boar");
// AI can't block same creature twice
aiPlayStep(1, PhaseStep.DECLARE_BLOCKERS, playerB);
setStopAt(1, PhaseStep.END_TURN);
setStrictChooseMode(true);
execute();
assertAllCommandsUsed();
assertGraveyardCount(playerA, 0);
assertGraveyardCount(playerB, 1);
assertHandCount(playerA, 0);
assertHandCount(playerB, 1);
}
}

View file

@ -0,0 +1,73 @@
package org.mage.test.player;
import mage.MageObject;
import mage.abilities.ActivatedAbility;
import mage.abilities.SpellAbility;
import mage.constants.Outcome;
import mage.constants.RangeOfInfluence;
import mage.game.Game;
import mage.player.ai.ComputerPlayerMCTS;
import mage.target.Target;
import java.util.LinkedHashMap;
import java.util.UUID;
/**
* @author JayDi85
*/
// mock class to override AI logic in tests
public class TestComputerPlayerMonteCarlo extends ComputerPlayerMCTS {
private TestPlayer testPlayerLink;
public TestComputerPlayerMonteCarlo(String name, RangeOfInfluence range, int skill) {
super(name, range, skill);
}
public void setTestPlayerLink(TestPlayer testPlayerLink) {
this.testPlayerLink = testPlayerLink;
}
@Override
public SpellAbility chooseSpellAbilityForCast(SpellAbility ability, Game game, boolean noMana) {
// copy-paste for TestComputerXXX
// workaround to cast fused cards in tests by it's NAMES (Wear, Tear, Wear // Tear)
// reason: TestPlayer uses outer computerPlayer to cast, not TestPlayer
switch (ability.getSpellAbilityType()) {
case SPLIT:
case SPLIT_FUSED:
case SPLIT_AFTERMATH:
if (!this.testPlayerLink.getChoices().isEmpty()) {
MageObject object = game.getObject(ability.getSourceId());
if (object != null) {
LinkedHashMap<UUID, ActivatedAbility> useableAbilities = getSpellAbilities(playerId, object, game.getState().getZone(object.getId()), game);
// left, right or fused cast
for (String choose : this.testPlayerLink.getChoices()) {
for (ActivatedAbility activatedAbility : useableAbilities.values()) {
if (activatedAbility instanceof SpellAbility) {
if (((SpellAbility) activatedAbility).getCardName().equals(choose)) {
return (SpellAbility) activatedAbility;
}
}
}
}
}
}
}
// default implementation by AI
return super.chooseSpellAbilityForCast(ability, game, noMana);
}
@Override
public boolean choose(Outcome outcome, Target target, UUID sourceId, Game game) {
// copy-paste for TestComputerXXX
// workaround for discard spells
// reason: TestPlayer uses outer computerPlayer to discard but inner code uses choose
return testPlayerLink.choose(outcome, target, sourceId, game);
}
}

View file

@ -0,0 +1,22 @@
package org.mage.test.serverside.base;
import mage.constants.RangeOfInfluence;
import org.mage.test.player.TestComputerPlayerMonteCarlo;
import org.mage.test.player.TestPlayer;
/**
* Base class but with Monte Carlo computer player to test single AI commands (it's different from full AI simulation from CardTestPlayerBaseAI):
* 1. AI don't play normal priorities (you must use ai*** commands to play it);
* 2. AI will choose in non strict mode (it's simulated ComputerPlayerMCTS, not simple ComputerPlayer from basic tests)
*
* @author JayDi85
*/
public abstract class CardTestPlayerBaseWithMonteCarloAIHelps extends CardTestPlayerBase {
@Override
protected TestPlayer createPlayer(String name, RangeOfInfluence rangeOfInfluence) {
TestPlayer testPlayer = new TestPlayer(new TestComputerPlayerMonteCarlo(name, RangeOfInfluence.ONE, 6));
testPlayer.setAIPlayer(false); // AI can't play it by itself, use AI commands
return testPlayer;
}
}