mirror of
https://github.com/correl/mage.git
synced 2024-11-15 03:00:16 +00:00
[UI] Resolved Issue#460: Simplify hybrid mana use
This commit is contained in:
parent
2a3db04be1
commit
62b959f6b1
3 changed files with 300 additions and 62 deletions
|
@ -26,13 +26,13 @@ public class ManaUtilTest extends CardTestPlayerBase {
|
|||
@Test
|
||||
public void test() {
|
||||
testManaToPayVsLand("{R}", "Blood Crypt", 2, 1); // should use {R}
|
||||
testManaToPayVsLand("{1}{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, 1); // should use {R}
|
||||
testManaToPayVsLand("{R}{R}{G}{W}{W}{U}", "Blood Crypt", 2, 1); // should use {R}
|
||||
testManaToPayVsLand("{R}{R}", "Blood Crypt", 2, 1); // should use {R}
|
||||
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
|
||||
|
@ -60,6 +60,8 @@ public class ManaUtilTest extends CardTestPlayerBase {
|
|||
// 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
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -129,4 +129,12 @@ public class HybridManaCost extends ManaCostImpl {
|
|||
public boolean containsColor(ColoredManaSymbol coloredManaSymbol) {
|
||||
return mana1.equals(coloredManaSymbol) || mana2.equals(coloredManaSymbol);
|
||||
}
|
||||
|
||||
public ColoredManaSymbol getMana1() {
|
||||
return mana1;
|
||||
}
|
||||
|
||||
public ColoredManaSymbol getMana2() {
|
||||
return mana2;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,16 +1,15 @@
|
|||
package mage.util;
|
||||
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.UUID;
|
||||
import mage.Mana;
|
||||
import mage.ManaSymbol;
|
||||
import mage.abilities.costs.mana.ManaCost;
|
||||
import mage.abilities.mana.BasicManaAbility;
|
||||
import mage.abilities.mana.BlackManaAbility;
|
||||
import mage.abilities.mana.BlueManaAbility;
|
||||
import mage.abilities.mana.GreenManaAbility;
|
||||
import mage.abilities.mana.ManaAbility;
|
||||
import mage.abilities.mana.RedManaAbility;
|
||||
import mage.abilities.mana.WhiteManaAbility;
|
||||
import mage.abilities.costs.mana.ManaSymbols;
|
||||
import mage.abilities.mana.*;
|
||||
|
||||
import java.util.HashSet;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.Set;
|
||||
import java.util.UUID;
|
||||
|
||||
/**
|
||||
* @author noxx
|
||||
|
@ -42,63 +41,292 @@ public class ManaUtil {
|
|||
* @return List of mana abilities permanent may produce and are reasonable for unpaid mana
|
||||
*/
|
||||
public static LinkedHashMap<UUID, ManaAbility> tryToAutoPay(ManaCost unpaid, LinkedHashMap<UUID, ManaAbility> useableAbilities) {
|
||||
|
||||
// first check if we have only basic mana abilities
|
||||
for (ManaAbility ability : useableAbilities.values()) {
|
||||
if (!(ability instanceof BasicManaAbility)) {
|
||||
// return map as-is without any modification
|
||||
return useableAbilities;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if (unpaid != null) {
|
||||
Mana mana = unpaid.getMana();
|
||||
// first check if we have only basic mana abilities
|
||||
for (ManaAbility ability : useableAbilities.values()) {
|
||||
if (!(ability instanceof BasicManaAbility)) {
|
||||
// return map as-is without any modification
|
||||
return useableAbilities;
|
||||
}
|
||||
}
|
||||
int countColorfull = 0;
|
||||
int countColorless = 0;
|
||||
ManaAbility chosenManaAbility = null;
|
||||
for (ManaAbility ability : useableAbilities.values()) {
|
||||
if (ability instanceof RedManaAbility && mana.contains(Mana.RedMana)) {
|
||||
chosenManaAbility = ability;
|
||||
countColorfull++;
|
||||
}
|
||||
if (ability instanceof BlackManaAbility && mana.contains(Mana.BlackMana)) {
|
||||
chosenManaAbility = ability;
|
||||
countColorfull++;
|
||||
}
|
||||
if (ability instanceof BlueManaAbility && mana.contains(Mana.BlueMana)) {
|
||||
chosenManaAbility = ability;
|
||||
countColorfull++;
|
||||
}
|
||||
if (ability instanceof WhiteManaAbility && mana.contains(Mana.WhiteMana)) {
|
||||
chosenManaAbility = ability;
|
||||
countColorfull++;
|
||||
}
|
||||
if (ability instanceof GreenManaAbility && mana.contains(Mana.GreenMana)) {
|
||||
chosenManaAbility = ability;
|
||||
countColorfull++;
|
||||
}
|
||||
}
|
||||
ManaSymbols symbols = ManaSymbols.buildFromManaCost(unpaid);
|
||||
Mana unpaidMana = unpaid.getMana();
|
||||
|
||||
if (countColorfull == 0) { // seems there is no colorful mana we can use
|
||||
// try to pay {1}
|
||||
if (mana.getColorless() > 0) {
|
||||
// use first
|
||||
return replace(useableAbilities, useableAbilities.values().iterator().next());
|
||||
}
|
||||
|
||||
// return map as-is without any modification
|
||||
return useableAbilities;
|
||||
if (!symbols.isEmpty()) {
|
||||
return getManaAbilitiesUsingManaSymbols(useableAbilities, symbols, unpaidMana);
|
||||
} else {
|
||||
return getManaAbilitiesUsingMana(unpaid, useableAbilities);
|
||||
}
|
||||
|
||||
if (countColorfull > 1) { // we can't auto choose as there are variant of mana payment
|
||||
// return map as-is without any modification
|
||||
return useableAbilities;
|
||||
}
|
||||
|
||||
return replace(useableAbilities, chosenManaAbility);
|
||||
}
|
||||
|
||||
return useableAbilities;
|
||||
}
|
||||
|
||||
private static LinkedHashMap<UUID, ManaAbility> getManaAbilitiesUsingManaSymbols(LinkedHashMap<UUID, ManaAbility> useableAbilities, ManaSymbols symbols, Mana unpaidMana) {
|
||||
Set<ManaSymbol> countColored = new HashSet<>();
|
||||
|
||||
ManaAbility chosenManaAbility = null;
|
||||
ManaAbility chosenManaAbilityForHybrid;
|
||||
for (ManaAbility ability : useableAbilities.values()) {
|
||||
chosenManaAbility = getManaAbility(symbols, countColored, chosenManaAbility, ability);
|
||||
|
||||
chosenManaAbilityForHybrid = checkRedMana(symbols, countColored, ability);
|
||||
chosenManaAbility = chosenManaAbilityForHybrid != null ? chosenManaAbilityForHybrid : chosenManaAbility;
|
||||
checkBlackMana(symbols, countColored, ability);
|
||||
chosenManaAbility = chosenManaAbilityForHybrid != null ? chosenManaAbilityForHybrid : chosenManaAbility;
|
||||
checkBlueMana(symbols, countColored, ability);
|
||||
chosenManaAbility = chosenManaAbilityForHybrid != null ? chosenManaAbilityForHybrid : chosenManaAbility;
|
||||
checkWhiteMana(symbols, countColored, ability);
|
||||
chosenManaAbility = chosenManaAbilityForHybrid != null ? chosenManaAbilityForHybrid : chosenManaAbility;
|
||||
checkGreenMana(symbols, countColored, ability);
|
||||
chosenManaAbility = chosenManaAbilityForHybrid != null ? chosenManaAbilityForHybrid : chosenManaAbility;
|
||||
}
|
||||
|
||||
if (countColored.size() == 0) { // seems there is no colorful mana we can pay for
|
||||
// try to pay {1}
|
||||
if (unpaidMana.getColorless() > 0) {
|
||||
// use any (lets choose first)
|
||||
return replace(useableAbilities, useableAbilities.values().iterator().next());
|
||||
}
|
||||
|
||||
// return map as-is without any modification
|
||||
return useableAbilities;
|
||||
}
|
||||
|
||||
if (countColored.size() > 1) {
|
||||
// we may try to pay for hybrid mana symbol
|
||||
Set<ManaSymbol> temp = new HashSet<>();
|
||||
temp.addAll(countColored);
|
||||
for (ManaSymbol manaSymbol : countColored) {
|
||||
// idea: if we have {W/R} symbol then we can remove it if symbols contain {W} or {R}
|
||||
// but only if it doesn't contain both of them
|
||||
if (manaSymbol.isHybrid()) {
|
||||
boolean found1 = countColored.contains(manaSymbol.getManaSymbol1());
|
||||
boolean found2 = countColored.contains(manaSymbol.getManaSymbol2());
|
||||
if (found1 && !found2) {
|
||||
temp.remove(manaSymbol);
|
||||
} else if (!found1 && found2) {
|
||||
temp.remove(manaSymbol);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// we got another chance for auto pay
|
||||
if (temp.size() == 1) {
|
||||
for (ManaAbility ability : useableAbilities.values()) {
|
||||
chosenManaAbility = getManaAbility(symbols, countColored, chosenManaAbility, ability);
|
||||
}
|
||||
return replace(useableAbilities, chosenManaAbility);
|
||||
}
|
||||
|
||||
// we can't auto choose as there are variants of mana payment
|
||||
// return map as-is without any modification
|
||||
return useableAbilities;
|
||||
}
|
||||
|
||||
return replace(useableAbilities, chosenManaAbility);
|
||||
}
|
||||
|
||||
private static ManaAbility getManaAbility(ManaSymbols symbols, Set<ManaSymbol> countColored, ManaAbility chosenManaAbility, ManaAbility ability) {
|
||||
if (ability instanceof RedManaAbility && symbols.contains(ManaSymbol.R)) {
|
||||
chosenManaAbility = ability;
|
||||
countColored.add(ManaSymbol.R);
|
||||
}
|
||||
if (ability instanceof BlackManaAbility && symbols.contains(ManaSymbol.B)) {
|
||||
chosenManaAbility = ability;
|
||||
countColored.add(ManaSymbol.B);
|
||||
}
|
||||
if (ability instanceof BlueManaAbility && symbols.contains(ManaSymbol.U)) {
|
||||
chosenManaAbility = ability;
|
||||
countColored.add(ManaSymbol.U);
|
||||
}
|
||||
if (ability instanceof WhiteManaAbility && symbols.contains(ManaSymbol.W)) {
|
||||
chosenManaAbility = ability;
|
||||
countColored.add(ManaSymbol.W);
|
||||
}
|
||||
if (ability instanceof GreenManaAbility && symbols.contains(ManaSymbol.G)) {
|
||||
chosenManaAbility = ability;
|
||||
countColored.add(ManaSymbol.G);
|
||||
}
|
||||
return chosenManaAbility;
|
||||
}
|
||||
|
||||
/**
|
||||
* Counts DIFFERENT hybrid mana symbols.
|
||||
*
|
||||
* @param symbols
|
||||
* @return
|
||||
*/
|
||||
private static int countUniqueHybridSymbols(Set<ManaSymbol> symbols) {
|
||||
int count = 0;
|
||||
for (ManaSymbol symbol : symbols) {
|
||||
if (symbol.isHybrid()) {
|
||||
count++;
|
||||
}
|
||||
}
|
||||
return count;
|
||||
}
|
||||
|
||||
private static ManaAbility checkBlackMana(ManaSymbols symbols, Set<ManaSymbol> countColored, ManaAbility ability) {
|
||||
ManaAbility chosenManaAbilityForHybrid = null;
|
||||
if (ability instanceof BlackManaAbility) {
|
||||
if (symbols.contains(ManaSymbol.HYBRID_BR)) {
|
||||
chosenManaAbilityForHybrid = ability;
|
||||
countColored.add(ManaSymbol.HYBRID_BR);
|
||||
} else if (symbols.contains(ManaSymbol.HYBRID_BG)) {
|
||||
chosenManaAbilityForHybrid = ability;
|
||||
countColored.add(ManaSymbol.HYBRID_BG);
|
||||
} else if (symbols.contains(ManaSymbol.HYBRID_UB)) {
|
||||
chosenManaAbilityForHybrid = ability;
|
||||
countColored.add(ManaSymbol.HYBRID_UB);
|
||||
} else if (symbols.contains(ManaSymbol.HYBRID_WB)) {
|
||||
chosenManaAbilityForHybrid = ability;
|
||||
countColored.add(ManaSymbol.HYBRID_WB);
|
||||
}
|
||||
}
|
||||
|
||||
return chosenManaAbilityForHybrid;
|
||||
}
|
||||
|
||||
private static ManaAbility checkRedMana(ManaSymbols symbols, Set<ManaSymbol> countColored, ManaAbility ability) {
|
||||
ManaAbility chosenManaAbilityForHybrid = null;
|
||||
if (ability instanceof RedManaAbility) {
|
||||
if (symbols.contains(ManaSymbol.HYBRID_BR)) {
|
||||
chosenManaAbilityForHybrid = ability;
|
||||
countColored.add(ManaSymbol.HYBRID_BR);
|
||||
} else if (symbols.contains(ManaSymbol.HYBRID_RG)) {
|
||||
chosenManaAbilityForHybrid = ability;
|
||||
countColored.add(ManaSymbol.HYBRID_RG);
|
||||
} else if (symbols.contains(ManaSymbol.HYBRID_RW)) {
|
||||
chosenManaAbilityForHybrid = ability;
|
||||
countColored.add(ManaSymbol.HYBRID_RW);
|
||||
} else if (symbols.contains(ManaSymbol.HYBRID_UR)) {
|
||||
chosenManaAbilityForHybrid = ability;
|
||||
countColored.add(ManaSymbol.HYBRID_UR);
|
||||
}
|
||||
}
|
||||
return chosenManaAbilityForHybrid;
|
||||
}
|
||||
|
||||
private static ManaAbility checkBlueMana(ManaSymbols symbols, Set<ManaSymbol> countColored, ManaAbility ability) {
|
||||
ManaAbility chosenManaAbilityForHybrid = null;
|
||||
if (ability instanceof BlueManaAbility) {
|
||||
if (symbols.contains(ManaSymbol.HYBRID_UB)) {
|
||||
chosenManaAbilityForHybrid = ability;
|
||||
countColored.add(ManaSymbol.HYBRID_UB);
|
||||
} else if (symbols.contains(ManaSymbol.HYBRID_UR)) {
|
||||
chosenManaAbilityForHybrid = ability;
|
||||
countColored.add(ManaSymbol.HYBRID_UR);
|
||||
} else if (symbols.contains(ManaSymbol.HYBRID_WU)) {
|
||||
chosenManaAbilityForHybrid = ability;
|
||||
countColored.add(ManaSymbol.HYBRID_WU);
|
||||
} else if (symbols.contains(ManaSymbol.HYBRID_GU)) {
|
||||
chosenManaAbilityForHybrid = ability;
|
||||
countColored.add(ManaSymbol.HYBRID_GU);
|
||||
}
|
||||
}
|
||||
return chosenManaAbilityForHybrid;
|
||||
}
|
||||
|
||||
private static ManaAbility checkWhiteMana(ManaSymbols symbols, Set<ManaSymbol> countColored, ManaAbility ability) {
|
||||
ManaAbility chosenManaAbilityForHybrid = null;
|
||||
if (ability instanceof WhiteManaAbility) {
|
||||
if (symbols.contains(ManaSymbol.HYBRID_WU)) {
|
||||
chosenManaAbilityForHybrid = ability;
|
||||
countColored.add(ManaSymbol.HYBRID_WU);
|
||||
} else if (symbols.contains(ManaSymbol.HYBRID_WB)) {
|
||||
chosenManaAbilityForHybrid = ability;
|
||||
countColored.add(ManaSymbol.HYBRID_WB);
|
||||
} else if (symbols.contains(ManaSymbol.HYBRID_GW)) {
|
||||
chosenManaAbilityForHybrid = ability;
|
||||
countColored.add(ManaSymbol.HYBRID_GW);
|
||||
} else if (symbols.contains(ManaSymbol.HYBRID_RW)) {
|
||||
chosenManaAbilityForHybrid = ability;
|
||||
countColored.add(ManaSymbol.HYBRID_RW);
|
||||
}
|
||||
}
|
||||
return chosenManaAbilityForHybrid;
|
||||
}
|
||||
|
||||
private static ManaAbility checkGreenMana(ManaSymbols symbols, Set<ManaSymbol> countColored, ManaAbility ability) {
|
||||
ManaAbility chosenManaAbilityForHybrid = null;
|
||||
if (ability instanceof GreenManaAbility) {
|
||||
if (symbols.contains(ManaSymbol.HYBRID_GW)) {
|
||||
chosenManaAbilityForHybrid = ability;
|
||||
countColored.add(ManaSymbol.HYBRID_GW);
|
||||
} else if (symbols.contains(ManaSymbol.HYBRID_GU)) {
|
||||
chosenManaAbilityForHybrid = ability;
|
||||
countColored.add(ManaSymbol.HYBRID_GU);
|
||||
} else if (symbols.contains(ManaSymbol.HYBRID_BG)) {
|
||||
chosenManaAbilityForHybrid = ability;
|
||||
countColored.add(ManaSymbol.HYBRID_BG);
|
||||
} else if (symbols.contains(ManaSymbol.HYBRID_RG)) {
|
||||
chosenManaAbilityForHybrid = ability;
|
||||
countColored.add(ManaSymbol.HYBRID_RG);
|
||||
}
|
||||
}
|
||||
return chosenManaAbilityForHybrid;
|
||||
}
|
||||
|
||||
/**
|
||||
* This is old method that uses unpaid mana to filter out some abilities.
|
||||
* The only disadvantage is that it can't handle hybrid mana correctly.
|
||||
*
|
||||
* @param unpaid
|
||||
* @param useableAbilities
|
||||
* @return
|
||||
*/
|
||||
private static LinkedHashMap<UUID, ManaAbility> getManaAbilitiesUsingMana(ManaCost unpaid, LinkedHashMap<UUID, ManaAbility> useableAbilities) {
|
||||
Mana mana = unpaid.getMana();
|
||||
|
||||
int countColorfull = 0;
|
||||
int countColorless = 0;
|
||||
ManaAbility chosenManaAbility = null;
|
||||
for (ManaAbility ability : useableAbilities.values()) {
|
||||
if (ability instanceof RedManaAbility && mana.contains(Mana.RedMana)) {
|
||||
chosenManaAbility = ability;
|
||||
countColorfull++;
|
||||
}
|
||||
if (ability instanceof BlackManaAbility && mana.contains(Mana.BlackMana)) {
|
||||
chosenManaAbility = ability;
|
||||
countColorfull++;
|
||||
}
|
||||
if (ability instanceof BlueManaAbility && mana.contains(Mana.BlueMana)) {
|
||||
chosenManaAbility = ability;
|
||||
countColorfull++;
|
||||
}
|
||||
if (ability instanceof WhiteManaAbility && mana.contains(Mana.WhiteMana)) {
|
||||
chosenManaAbility = ability;
|
||||
countColorfull++;
|
||||
}
|
||||
if (ability instanceof GreenManaAbility && mana.contains(Mana.GreenMana)) {
|
||||
chosenManaAbility = ability;
|
||||
countColorfull++;
|
||||
}
|
||||
}
|
||||
|
||||
if (countColorfull == 0) { // seems there is no colorful mana we can use
|
||||
// try to pay {1}
|
||||
if (mana.getColorless() > 0) {
|
||||
// use any (lets choose first)
|
||||
return replace(useableAbilities, useableAbilities.values().iterator().next());
|
||||
}
|
||||
|
||||
// return map as-is without any modification
|
||||
return useableAbilities;
|
||||
}
|
||||
|
||||
if (countColorfull > 1) { // we can't auto choose as there are variants of mana payment
|
||||
// return map as-is without any modification
|
||||
return useableAbilities;
|
||||
}
|
||||
|
||||
return replace(useableAbilities, chosenManaAbility);
|
||||
}
|
||||
|
||||
private static LinkedHashMap<UUID, ManaAbility> replace(LinkedHashMap<UUID, ManaAbility> useableAbilities, ManaAbility chosenManaAbility) {
|
||||
// modify the map with the chosen mana ability
|
||||
useableAbilities.clear();
|
||||
|
|
Loading…
Reference in a new issue