package org.mage.test.utils;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.UUID;
import mage.Mana;
import mage.abilities.Ability;
import mage.abilities.SpellAbility;
import mage.abilities.costs.mana.ManaCost;
import mage.abilities.costs.mana.ManaCostsImpl;
import mage.abilities.mana.BasicManaAbility;
import mage.abilities.mana.BlackManaAbility;
import mage.abilities.mana.ActivatedManaAbilityImpl;
import mage.abilities.mana.RedManaAbility;
import mage.abilities.mana.WhiteManaAbility;
import mage.cards.Card;
import mage.cards.repository.CardRepository;
import mage.util.CardUtil;
import mage.util.ManaUtil;
import org.junit.Assert;
import org.junit.Test;
import org.mage.test.serverside.base.CardTestPlayerBase;
/**
* @author noxx
*/
public class ManaUtilTest extends CardTestPlayerBase {
@Test
public void test() {
testManaToPayVsLand("{R}", "Blood Crypt", 2, 1); // should use {R}
testManaToPayVsLand("{1}{R}", "Blood Crypt", 2, RedManaAbility.class); // should use {R}
testManaToPayVsLand("{R}{B}", "Blood Crypt", 2, 2); // can't auto choose to pay
testManaToPayVsLand("{2}{R}{B}", "Blood Crypt", 2, 2); // can't auto choose to pay
testManaToPayVsLand("{R}{R}{B}{B}", "Blood Crypt", 2, 2); // can't auto choose to pay
testManaToPayVsLand("{R}{G}{W}{W}{U}", "Blood Crypt", 2, RedManaAbility.class); // should use {R}
testManaToPayVsLand("{R}{R}{G}{W}{W}{U}", "Blood Crypt", 2, RedManaAbility.class); // should use {R}
testManaToPayVsLand("{R}{R}", "Blood Crypt", 2, RedManaAbility.class); // should use {R}
testManaToPayVsLand("{G}{W}", "Blood Crypt", 2, 2); // can't auto choose to pay
testManaToPayVsLand("{1}{G}{W}", "Blood Crypt", 2, 1); // should use any but auto choose it
testManaToPayVsLand("{2}{G}{W}{U}", "Blood Crypt", 2, 1); // should use any but auto choose it
testManaToPayVsLand("{3}", "Blood Crypt", 2, 1); // should use any but auto choose it
testManaToPayVsLand("{R}{R}{G}{W}{W}{U}", "Watery Grave", 2, 1); // should use {U}
testManaToPayVsLand("{R}{R}{G}{W}{W}", "Steam Vents", 2, 1); // should use {R}
testManaToPayVsLand("{R}{R}{G}{B}{U}", "Temple Garden", 2, 1); // should use {G}
testManaToPayVsLand("{W}{W}{G}{B}{U}", "Sacred Foundry", 2, 1); // should use {W}
testManaToPayVsLand("{W}{W}{R}{B}{U}", "Overgrown Tomb", 2, BlackManaAbility.class); // should use {B}
testManaToPayVsLand("{W}{W}{R}{B}{U}", "Swamp", 1, BlackManaAbility.class);
testManaToPayVsLand("{W}{W}{R}{B}{U}", "Plains", 1, WhiteManaAbility.class);
testManaToPayVsLand("{1}{R}", "Cavern of Souls", 2, 2); // can't auto choose to pay
testManaToPayVsLand("{2}", "Cavern of Souls", 2, 2); // can't auto choose to pay
testManaToPayVsLand("{2}", "Eldrazi Temple", 2, 2); // can't auto choose to pay
// hybrid mana
testManaToPayVsLand("{W/R}{W/R}{W/R}", "Sacred Foundry", 2, 1); // auto choose for hybrid mana: choose any
testManaToPayVsLand("{R}{W/R}", "Sacred Foundry", 2, RedManaAbility.class); // auto choose for hybrid mana: we should choose {R}
testManaToPayVsLand("{G}{W/R}", "Sacred Foundry", 2, 1); // auto choose for hybrid mana: choose any
testManaToPayVsLand("{G}{W/R}{W}", "Sacred Foundry", 2, WhiteManaAbility.class); // auto choose for hybrid mana: choose {W}
testManaToPayVsLand("{W/B}{W/B}", "Swamp", 1, BlackManaAbility.class);
testManaToPayVsLand("{R}", "Glimmervoid", 1, 1);
testManaToPayVsLand("{R}{1}", "Glimmervoid", 1, 1);
// we can't auto choose here:
// let say we auto choose {R}, then we have to use it to pay for {R} not {W/R} (as {W/R} is more generic cost)
// but in such case what is left to pay is {W/R}{W} and it is possible that we won't have 2 white sources
// Example: 1x Sacred Foundry 1x Mountain 1x Mountain
// we can pay {W/R}{W}{R} by using Sacred Foundry and choosing {W} then using two Mountains
// but if we auto choose {R} then we won't be able to pay the cost at all
testManaToPayVsLand("{W/R}{W}{R}", "Sacred Foundry", 2, 2);
testManaToPayVsLand("{W/R}{R/G}", "Sacred Foundry", 2, 2); // can't auto choose to pay
}
@Test
public void testManaCondensing() {
Assert.assertEquals("{5}{W}", ManaUtil.condenseManaCostString(("{1}{1}{1}{2}{W}")));
Assert.assertEquals("{4}{B}{B}", ManaUtil.condenseManaCostString("{2}{B}{2}{B}"));
Assert.assertEquals("{6}{R}{R}{R}{U}", ManaUtil.condenseManaCostString("{R}{1}{R}{2}{R}{3}{U}"));
Assert.assertEquals("{5}{B}{U}{W}", ManaUtil.condenseManaCostString("{1}{B}{W}{4}{U}"));
Assert.assertEquals("{8}{B}{G}{G}{U}", ManaUtil.condenseManaCostString("{1}{G}{1}{2}{3}{G}{B}{U}{1}"));
Assert.assertEquals("{3}{R}{U}", ManaUtil.condenseManaCostString("{3}{R}{U}"));
Assert.assertEquals("{10}", ManaUtil.condenseManaCostString("{1}{2}{3}{4}"));
Assert.assertEquals("{B}{G}{R}{U}{W}", ManaUtil.condenseManaCostString("{B}{G}{R}{U}{W}"));
Assert.assertEquals("{R}{R}", ManaUtil.condenseManaCostString("{R}{R}"));
Assert.assertEquals("{U}", ManaUtil.condenseManaCostString("{U}"));
Assert.assertEquals("{2}", ManaUtil.condenseManaCostString("{2}"));
Assert.assertEquals("", ManaUtil.condenseManaCostString("{}"));
Assert.assertEquals("{5}{C}{R}{R}{R}{U}", ManaUtil.condenseManaCostString("{R}{C}{R}{2}{R}{3}{U}"));
}
/**
* Mana.enough is used to check if a spell can be cast with an given amount
* of avalable mana
*/
@Test
public void testManaEnough() {
testManaAvailEnough("{G}", 1, "", true);
testManaAvailEnough("{G}", 0, "{G}", true);
testManaAvailEnough("{R}", 0, "{G}", false);
testManaAvailEnough("{B}", 0, "{G}", false);
testManaAvailEnough("{U}", 0, "{G}", false);
testManaAvailEnough("{W}", 0, "{G}", false);
testManaAvailEnough("{R}", 1, "", true);
testManaAvailEnough("{R}", 0, "{R}", true);
testManaAvailEnough("{G}", 0, "{R}", false);
testManaAvailEnough("{B}", 0, "{R}", false);
testManaAvailEnough("{U}", 0, "{R}", false);
testManaAvailEnough("{W}", 0, "{R}", false);
testManaAvailEnough("{U}{B}{W}{G}{R}", 4, "{R}", true);
testManaAvailEnough("{U}{B}{W}{G}{R}", 3, "{R}{B}", true);
testManaAvailEnough("{U}{U}{U}{G}{G}{2}", 2, "{U}{U}{G}{R}{B}", true);
testManaAvailEnough("{2}{U}{U}", 0, "{U}{U}{U}{U}", true);
testManaAvailEnough("{2}{U}{U}", 0, "{4}", false);
testManaAvailEnough("{2}{U}{U}", 0, "{B}{B}{4}", false);
testManaAvailEnough("{G}", 0, "{G/W}", true);
testManaAvailEnough("{G}{W}", 0, "{G/W}{G/W}", true);
testManaAvailEnough("{W}{W}", 0, "{G/W}{G/W}", true);
testManaAvailEnough("{G}{G}", 0, "{G/W}{G/W}", true);
}
/**
* Mana.enough is used to check if a spell can be cast with an given amount
* of avalable mana
*/
@Test
public void testManaIncrease() {
// cost - reduction - rest
testManaReduction("{G}{G}", "{G}", "{G}");
testManaReduction("{1}{G}{G}", "{G}", "{1}{G}");
testManaReduction("{B}{B}", "{B}", "{B}");
testManaReduction("{1}{B}{B}", "{B}", "{1}{B}");
testManaReduction("{W}{W}", "{W}", "{W}");
testManaReduction("{1}{W}{W}", "{W}", "{1}{W}");
testManaReduction("{U}{U}", "{U}", "{U}");
testManaReduction("{1}{U}{U}", "{U}", "{1}{U}");
testManaReduction("{R}{R}", "{R}", "{R}");
testManaReduction("{1}{R}{R}", "{R}", "{1}{R}");
testManaReduction("{R}{G}{B}{U}{W}", "{R}{G}{B}{U}{W}", "{0}");
// Hybrid Mana
testManaReduction("{2/B}{2/B}{2/B}", "{B}{B}", "{2/B}");
testManaReduction("{2/B}{2/B}{2/B}", "{B}{B}{B}", "{0}");
testManaReduction("{2/W}{2/W}{2/W}", "{W}{W}", "{2/W}");
testManaReduction("{2/W}{2/W}{2/W}", "{W}{W}{W}", "{0}");
testManaReduction("{G/B}{G/B}{G/B}", "{B}{G}{B}", "{0}");
}
/**
* Checks if a given mana reduction left the expected amount of mana costs
*
* @param manaCostsToPay
* @param availablyAny
* @param available
* @param expected
*/
private void testManaReduction(String manaCostsToPay, String manaToReduce, String restMana) {
SpellAbility spellAbility = new SpellAbility(new ManaCostsImpl(manaCostsToPay), "Test");
CardUtil.adjustCost(spellAbility, new ManaCostsImpl(manaToReduce), true);
Assert.assertTrue("The mana cost to pay " + manaCostsToPay + " reduced by " + manaToReduce + " should left " + restMana + " but the rest was " + spellAbility.getManaCostsToPay().getText(), spellAbility.getManaCostsToPay().getText().equals(restMana));
}
/**
* Common way to test ManaUtil.tryToAutoPay
*
* We get all mana abilities, then try to auto pay and compare to expected1
* and expected2 params.
*
* @param manaToPay Mana that should be paid using land.
* @param landName Land to use as mana producer.
* @param expected1 The amount of mana abilities the land should have.
* @param expected2 The amount of mana abilities that ManaUtil.tryToAutoPay
* should be returned after optimization.
*/
private void testManaToPayVsLand(String manaToPay, String landName, int expected1, int expected2) {
ManaCost unpaid = new ManaCostsImpl(manaToPay);
Card card = CardRepository.instance.findCard(landName).getCard();
Assert.assertNotNull(card);
HashMap<UUID, ActivatedManaAbilityImpl> useableAbilities = getManaAbilities(card);
Assert.assertEquals(expected1, useableAbilities.size());
useableAbilities = ManaUtil.tryToAutoPay(unpaid, (LinkedHashMap<UUID, ActivatedManaAbilityImpl>) useableAbilities);
Assert.assertEquals(expected2, useableAbilities.size());
}
/**
* Another way to test ManaUtil.tryToAutoPay Here we also check what ability
* was auto chosen
*
* N.B. This method can be used ONLY if we have one ability left that auto
* choose mode! That's why we assert the following: Assert.assertEquals(1,
* useableAbilities.size());
*
* We get all mana abilities, then try to auto pay and compare to expected1
* and expected2 params.
*
* @param manaToPay Mana that should be paid using land.
* @param landName Land to use as mana producer.
* @param expected1 The amount of mana abilities the land should have.
* @param expectedChosen
*/
private void testManaToPayVsLand(String manaToPay, String landName, int expected1, Class<? extends BasicManaAbility> expectedChosen) {
ManaCost unpaid = new ManaCostsImpl(manaToPay);
Card card = CardRepository.instance.findCard(landName).getCard();
Assert.assertNotNull(card);
HashMap<UUID, ActivatedManaAbilityImpl> useableAbilities = getManaAbilities(card);
Assert.assertEquals(expected1, useableAbilities.size());
useableAbilities = ManaUtil.tryToAutoPay(unpaid, (LinkedHashMap<UUID, ActivatedManaAbilityImpl>) useableAbilities);
Assert.assertEquals(1, useableAbilities.size());
ActivatedManaAbilityImpl ability = useableAbilities.values().iterator().next();
Assert.assertTrue("Wrong mana ability has been chosen", expectedChosen.isInstance(ability));
}
/**
* Checks if the given available Mana is enough to pay a given mana cost
*
* @param manaCostsToPay
* @param availablyAny
* @param available
* @param expected
*/
private void testManaAvailEnough(String manaCostsToPay, int availablyAny, String available, boolean expected) {
ManaCost unpaid = new ManaCostsImpl(manaCostsToPay);
ManaCost costAvailable = new ManaCostsImpl(available);
Mana manaAvailable = costAvailable.getMana();
manaAvailable.setAny(availablyAny);
if (expected) {
Assert.assertTrue("The available Mana " + costAvailable.getText() + " should be enough to pay the costs " + unpaid.getText(), unpaid.getMana().enough(manaAvailable));
} else {
Assert.assertFalse("The available Mana " + costAvailable.getText() + " shouldn't be enough to pay the costs " + unpaid.getText(), unpaid.getMana().enough(manaAvailable));
}
}
/**
* Extracts mana abilities from the card.
*
* @param card Card to extract mana abilities from.
* @return
*/
private HashMap<UUID, ActivatedManaAbilityImpl> getManaAbilities(Card card) {
HashMap<UUID, ActivatedManaAbilityImpl> useableAbilities = new LinkedHashMap<>();
for (Ability ability : card.getAbilities()) {
if (ability instanceof ActivatedManaAbilityImpl) {
ability.newId(); // we need to assign id manually as we are not in game
useableAbilities.put(ability.getId(), (ActivatedManaAbilityImpl) ability);
}
}
return useableAbilities;
}
}