tests: added tests for Chandra Ablaze card and some AI logic;

This commit is contained in:
Oleg Agafonov 2024-05-12 14:37:10 +04:00
parent d28b9e6d05
commit ebe04dc3a6
3 changed files with 163 additions and 18 deletions

View file

@ -169,6 +169,7 @@ public class ComputerPlayer extends PlayerImpl {
if (target.getOriginalTarget() instanceof TargetDiscard) {
findPlayables(game);
// discard not playable first
if (!unplayable.isEmpty()) {
for (int i = unplayable.size() - 1; i >= 0; i--) {
if (target.canTarget(abilityControllerId, unplayable.values().toArray(new Card[0])[i].getId(), null, game)) {

View file

@ -41,8 +41,8 @@ public final class ChandraAblaze extends CardImpl {
this.setStartingLoyalty(5);
// +1: Discard a card. If a red card is discarded this way, Chandra Ablaze deals 4 damage to any target.
LoyaltyAbility ability = new LoyaltyAbility(new ChandraAblazeEffect1(), 1);
ability.addEffect(new ChandraAblazeEffect2());
LoyaltyAbility ability = new LoyaltyAbility(new ChandraAblazeDiscardCardEffect(), 1);
ability.addEffect(new ChandraAblazeDamageEffect());
ability.addTarget(new TargetAnyTarget());
this.addAbility(ability);
@ -54,7 +54,7 @@ public final class ChandraAblaze extends CardImpl {
this.addAbility(ability);
// -7: Cast any number of red instant and/or sorcery cards from your graveyard without paying their mana costs.
ability = new LoyaltyAbility(new ChandraAblazeEffect5(), -7);
ability = new LoyaltyAbility(new ChandraAblazeCastCardsEffect(), -7);
this.addAbility(ability);
}
@ -68,20 +68,20 @@ public final class ChandraAblaze extends CardImpl {
}
}
class ChandraAblazeEffect1 extends OneShotEffect {
class ChandraAblazeDiscardCardEffect extends OneShotEffect {
public ChandraAblazeEffect1() {
public ChandraAblazeDiscardCardEffect() {
super(Outcome.Discard);
this.staticText = "Discard a card";
}
private ChandraAblazeEffect1(final ChandraAblazeEffect1 effect) {
private ChandraAblazeDiscardCardEffect(final ChandraAblazeDiscardCardEffect effect) {
super(effect);
}
@Override
public ChandraAblazeEffect1 copy() {
return new ChandraAblazeEffect1(this);
public ChandraAblazeDiscardCardEffect copy() {
return new ChandraAblazeDiscardCardEffect(this);
}
@Override
@ -107,20 +107,20 @@ class ChandraAblazeEffect1 extends OneShotEffect {
}
}
class ChandraAblazeEffect2 extends OneShotEffect {
class ChandraAblazeDamageEffect extends OneShotEffect {
public ChandraAblazeEffect2() {
public ChandraAblazeDamageEffect() {
super(Outcome.Damage);
this.staticText = "If a red card is discarded this way, {this} deals 4 damage to any target";
}
private ChandraAblazeEffect2(final ChandraAblazeEffect2 effect) {
private ChandraAblazeDamageEffect(final ChandraAblazeDamageEffect effect) {
super(effect);
}
@Override
public ChandraAblazeEffect2 copy() {
return new ChandraAblazeEffect2(this);
public ChandraAblazeDamageEffect copy() {
return new ChandraAblazeDamageEffect(this);
}
@Override
@ -143,7 +143,7 @@ class ChandraAblazeEffect2 extends OneShotEffect {
}
}
class ChandraAblazeEffect5 extends OneShotEffect {
class ChandraAblazeCastCardsEffect extends OneShotEffect {
private static final FilterCard filter = new FilterInstantOrSorceryCard();
@ -151,18 +151,18 @@ class ChandraAblazeEffect5 extends OneShotEffect {
filter.add(new ColorPredicate(ObjectColor.RED));
}
public ChandraAblazeEffect5() {
public ChandraAblazeCastCardsEffect() {
super(Outcome.PlayForFree);
this.staticText = "Cast any number of red instant and/or sorcery cards from your graveyard without paying their mana costs";
}
private ChandraAblazeEffect5(final ChandraAblazeEffect5 effect) {
private ChandraAblazeCastCardsEffect(final ChandraAblazeCastCardsEffect effect) {
super(effect);
}
@Override
public ChandraAblazeEffect5 copy() {
return new ChandraAblazeEffect5(this);
public ChandraAblazeCastCardsEffect copy() {
return new ChandraAblazeCastCardsEffect(this);
}
@Override

View file

@ -0,0 +1,144 @@
package org.mage.test.cards.single.zen;
import mage.constants.PhaseStep;
import mage.constants.Zone;
import org.junit.Ignore;
import org.junit.Test;
import org.mage.test.serverside.base.CardTestPlayerBaseWithAIHelps;
/**
* @author JayDi85
*/
public class ChandraAblazeTest extends CardTestPlayerBaseWithAIHelps {
@Test
public void test_PlusOneAbility_Manual() {
// +1: Discard a card. If a red card is discarded this way, Chandra Ablaze deals 4 damage to any target.
addCard(Zone.BATTLEFIELD, playerA, "Chandra Ablaze", 1);
addCard(Zone.HAND, playerA, "Lightning Bolt", 1);
//
addCard(Zone.BATTLEFIELD, playerA, "Grizzly Bears", 1);
addCard(Zone.BATTLEFIELD, playerB, "Silvercoat Lion", 1);
// activate +1 and kill lion
activateAbility(1, PhaseStep.PRECOMBAT_MAIN, playerA, "+1:");
addTarget(playerA, "Silvercoat Lion"); // damage
setChoice(playerA, "Lightning Bolt"); // discard
setStrictChooseMode(true);
setStopAt(1, PhaseStep.END_TURN);
execute();
assertGraveyardCount(playerB, "Silvercoat Lion", 1);
}
@Test
public void test_PlusOneAbility_AI_ChooseBetterTarget() {
// +1: Discard a card. If a red card is discarded this way, Chandra Ablaze deals 4 damage to any target.
addCard(Zone.BATTLEFIELD, playerA, "Chandra Ablaze", 1);
addCard(Zone.HAND, playerA, "Lightning Bolt", 1);
//
addCard(Zone.BATTLEFIELD, playerA, "Grizzly Bears", 1);
addCard(Zone.BATTLEFIELD, playerB, "Silvercoat Lion", 1);
// AI must choose better action (kill lion)
aiPlayPriority(1, PhaseStep.PRECOMBAT_MAIN, playerA);
setStrictChooseMode(true);
setStopAt(1, PhaseStep.END_TURN);
execute();
assertGraveyardCount(playerB, "Silvercoat Lion", 1);
}
@Test
@Ignore // TODO: current choose logic uses first target, enable after new logic implemented (by simulations or improved choice)
public void test_PlusOneAbility_AI_ChooseBetterDiscardCard() {
// +1: Discard a card. If a red card is discarded this way, Chandra Ablaze deals 4 damage to any target.
addCard(Zone.BATTLEFIELD, playerA, "Chandra Ablaze", 1);
addCard(Zone.HAND, playerA, "Glittermonger", 10); // green
addCard(Zone.HAND, playerA, "Lightning Bolt", 1); // put after green, so AI must choose better, not first
//
addCard(Zone.BATTLEFIELD, playerA, "Grizzly Bears", 1);
addCard(Zone.BATTLEFIELD, playerB, "Silvercoat Lion", 1);
// AI must choose better discard card (bolt as red, not green)
aiPlayPriority(1, PhaseStep.PRECOMBAT_MAIN, playerA);
setStrictChooseMode(true);
setStopAt(1, PhaseStep.END_TURN);
execute();
assertGraveyardCount(playerB, "Silvercoat Lion", 1);
}
@Test
public void test_PlusTwoAbility_Manual() {
// -2: Each player discards their hand, then draws three cards.
addCard(Zone.BATTLEFIELD, playerA, "Chandra Ablaze", 1);
//
addCard(Zone.HAND, playerA, "Grizzly Bears", 5);
addCard(Zone.HAND, playerB, "Silvercoat Lion", 1);
// activate -2 and discard all
activateAbility(1, PhaseStep.PRECOMBAT_MAIN, playerA, "-2:");
setStrictChooseMode(true);
setStopAt(1, PhaseStep.END_TURN);
execute();
assertHandCount(playerA, 3);
assertHandCount(playerB, 3);
assertGraveyardCount(playerA, "Grizzly Bears", 5);
assertGraveyardCount(playerB, "Silvercoat Lion", 1);
}
@Test
public void test_PlusTwoAbility_AI_MustNotSeeOpponentHand_KeepBetterHand() {
// AI must calc battlefield score by visible data, so it do not know opponent's hand,
// but it is still able to cheat by look ahead in library (e.g. it "see" result of draw actions)
// -2: Each player discards their hand, then draws three cards.
addCard(Zone.BATTLEFIELD, playerA, "Chandra Ablaze", 1);
//
// TODO: it's another bug - AI can play land in some actions chain and can't play on another,
// comment and research AI logs (possible reason: AI don't wait stack resolve)
addCard(Zone.HAND, playerA, "Mountain", 1);
//
addCard(Zone.HAND, playerA, "Grizzly Bears", 5);
addCard(Zone.HAND, playerB, "Silvercoat Lion", 1);
// must not call any abilities
aiPlayPriority(1, PhaseStep.PRECOMBAT_MAIN, playerA);
setStrictChooseMode(true);
setStopAt(1, PhaseStep.END_TURN);
execute();
// must keep better hand
assertHandCount(playerA, "Grizzly Bears", 5);
assertHandCount(playerB, "Silvercoat Lion", 1);
}
@Test
public void test_PlusTwoAbility_AI_MustNotSeeOpponentHand_KeepWorseHand() {
// -2: Each player discards their hand, then draws three cards.
addCard(Zone.BATTLEFIELD, playerA, "Chandra Ablaze", 1);
addCard(Zone.HAND, playerA, "Mountain", 1); // see prev test comments
//
addCard(Zone.HAND, playerA, "Grizzly Bears", 1);
addCard(Zone.HAND, playerB, "Silvercoat Lion", 5);
// must not call any abilities
aiPlayPriority(1, PhaseStep.PRECOMBAT_MAIN, playerA);
setStrictChooseMode(true);
setStopAt(1, PhaseStep.END_TURN);
execute();
// must keep worse hand
assertHandCount(playerA, "Grizzly Bears", 1);
assertHandCount(playerB, "Silvercoat Lion", 5);
}
}