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) { if (target.getOriginalTarget() instanceof TargetDiscard) {
findPlayables(game); findPlayables(game);
// discard not playable first
if (!unplayable.isEmpty()) { if (!unplayable.isEmpty()) {
for (int i = unplayable.size() - 1; i >= 0; i--) { for (int i = unplayable.size() - 1; i >= 0; i--) {
if (target.canTarget(abilityControllerId, unplayable.values().toArray(new Card[0])[i].getId(), null, game)) { 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); this.setStartingLoyalty(5);
// +1: Discard a card. If a red card is discarded this way, Chandra Ablaze deals 4 damage to any target. // +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); LoyaltyAbility ability = new LoyaltyAbility(new ChandraAblazeDiscardCardEffect(), 1);
ability.addEffect(new ChandraAblazeEffect2()); ability.addEffect(new ChandraAblazeDamageEffect());
ability.addTarget(new TargetAnyTarget()); ability.addTarget(new TargetAnyTarget());
this.addAbility(ability); this.addAbility(ability);
@ -54,7 +54,7 @@ public final class ChandraAblaze extends CardImpl {
this.addAbility(ability); this.addAbility(ability);
// -7: Cast any number of red instant and/or sorcery cards from your graveyard without paying their mana costs. // -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); 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); super(Outcome.Discard);
this.staticText = "Discard a card"; this.staticText = "Discard a card";
} }
private ChandraAblazeEffect1(final ChandraAblazeEffect1 effect) { private ChandraAblazeDiscardCardEffect(final ChandraAblazeDiscardCardEffect effect) {
super(effect); super(effect);
} }
@Override @Override
public ChandraAblazeEffect1 copy() { public ChandraAblazeDiscardCardEffect copy() {
return new ChandraAblazeEffect1(this); return new ChandraAblazeDiscardCardEffect(this);
} }
@Override @Override
@ -107,20 +107,20 @@ class ChandraAblazeEffect1 extends OneShotEffect {
} }
} }
class ChandraAblazeEffect2 extends OneShotEffect { class ChandraAblazeDamageEffect extends OneShotEffect {
public ChandraAblazeEffect2() { public ChandraAblazeDamageEffect() {
super(Outcome.Damage); super(Outcome.Damage);
this.staticText = "If a red card is discarded this way, {this} deals 4 damage to any target"; 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); super(effect);
} }
@Override @Override
public ChandraAblazeEffect2 copy() { public ChandraAblazeDamageEffect copy() {
return new ChandraAblazeEffect2(this); return new ChandraAblazeDamageEffect(this);
} }
@Override @Override
@ -143,7 +143,7 @@ class ChandraAblazeEffect2 extends OneShotEffect {
} }
} }
class ChandraAblazeEffect5 extends OneShotEffect { class ChandraAblazeCastCardsEffect extends OneShotEffect {
private static final FilterCard filter = new FilterInstantOrSorceryCard(); private static final FilterCard filter = new FilterInstantOrSorceryCard();
@ -151,18 +151,18 @@ class ChandraAblazeEffect5 extends OneShotEffect {
filter.add(new ColorPredicate(ObjectColor.RED)); filter.add(new ColorPredicate(ObjectColor.RED));
} }
public ChandraAblazeEffect5() { public ChandraAblazeCastCardsEffect() {
super(Outcome.PlayForFree); super(Outcome.PlayForFree);
this.staticText = "Cast any number of red instant and/or sorcery cards from your graveyard without paying their mana costs"; 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); super(effect);
} }
@Override @Override
public ChandraAblazeEffect5 copy() { public ChandraAblazeCastCardsEffect copy() {
return new ChandraAblazeEffect5(this); return new ChandraAblazeCastCardsEffect(this);
} }
@Override @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);
}
}