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; } }