* Some rework/fixes/optimizations of calculation of available mana.

This commit is contained in:
LevelX2 2018-06-24 01:23:49 +02:00
parent e71c54593e
commit fdddbbbbe6
5 changed files with 190 additions and 29 deletions

View file

@ -1,4 +1,3 @@
package mage.cards.c;
import java.util.UUID;
@ -28,9 +27,9 @@ public final class CabalCoffers extends CardImpl {
}
public CabalCoffers(UUID ownerId, CardSetInfo setInfo) {
super(ownerId,setInfo,new CardType[]{CardType.LAND},"");
super(ownerId, setInfo, new CardType[]{CardType.LAND}, "");
// {2}, {tap}: Add {B} for each Swamp you control.
// {2}, {T}: Add {B} for each Swamp you control.
Ability ability = new DynamicManaAbility(Mana.BlackMana(1), new PermanentsOnBattlefieldCount(filter), new GenericManaCost(2));
ability.addCost(new TapSourceCost());
this.addAbility(ability);

View file

@ -454,4 +454,103 @@ public class ManaOptionsTest extends CardTestPlayerBase {
Assert.assertEquals("mana variations don't fit", 1, manaOptions.size());
assertManaOptions("{C}{C}", manaOptions);
}
@Test
public void testManaSourcesWithCosts() {
// {T}: Add {C} to your mana pool.
// {5}, {T}: Add {W}{U}{B}{R}{G} to your mana pool.
addCard(Zone.BATTLEFIELD, playerA, "Crystal Quarry", 1);
// {T}: Add {C} to your mana pool.
// {W/B}, {T}: Add {W}{W}, {W}{B}, or {B}{B} to your mana pool.
addCard(Zone.BATTLEFIELD, playerA, "Fetid Heath", 3);
addCard(Zone.BATTLEFIELD, playerA, "Plains", 3);
setStopAt(1, PhaseStep.UPKEEP);
execute();
ManaOptions manaOptions = playerA.getAvailableManaTest(currentGame);
assertDuplicatedManaOptions(manaOptions);
Assert.assertEquals("mana variations don't fit", 16, manaOptions.size());
assertManaOptions("{C}{C}{C}{C}{W}{W}{W}", manaOptions);
assertManaOptions("{C}{C}{C}{W}{W}{W}{W}", manaOptions);
assertManaOptions("{C}{C}{C}{W}{W}{W}{B}", manaOptions);
assertManaOptions("{C}{C}{C}{W}{W}{B}{B}", manaOptions);
assertManaOptions("{C}{C}{W}{W}{W}{W}{W}", manaOptions);
assertManaOptions("{C}{C}{W}{W}{W}{W}{B}", manaOptions);
assertManaOptions("{C}{C}{W}{W}{W}{B}{B}", manaOptions);
assertManaOptions("{C}{C}{W}{W}{B}{B}{B}", manaOptions);
assertManaOptions("{C}{C}{W}{B}{B}{B}{B}", manaOptions);
assertManaOptions("{C}{W}{W}{W}{W}{W}{W}", manaOptions);
assertManaOptions("{C}{W}{W}{W}{W}{W}{B}", manaOptions);
assertManaOptions("{C}{W}{W}{W}{W}{B}{B}", manaOptions);
assertManaOptions("{C}{W}{W}{W}{B}{B}{B}", manaOptions);
assertManaOptions("{C}{W}{W}{B}{B}{B}{B}", manaOptions);
assertManaOptions("{C}{W}{B}{B}{B}{B}{B}", manaOptions);
assertManaOptions("{C}{B}{B}{B}{B}{B}{B}", manaOptions);
}
@Test
public void testSungrassPrairie() {
// {1}, {T}: Add {G}{W}.
addCard(Zone.BATTLEFIELD, playerA, "Sungrass Prairie", 1);
// {T}: Add one mana of any color to your mana pool.
addCard(Zone.BATTLEFIELD, playerA, "Alloy Myr", 2);
setStopAt(3, PhaseStep.PRECOMBAT_MAIN);
execute();
ManaOptions manaOptions = playerA.getAvailableManaTest(currentGame);
assertDuplicatedManaOptions(manaOptions);
Assert.assertEquals("mana variations don't fit", 2, manaOptions.size());
assertManaOptions("{W}{G}{Any}", manaOptions);
assertManaOptions("{Any}{Any}", manaOptions);
}
@Test
public void testSungrassPrairie2() {
// {1}, {T}: Add {G}{W}.
addCard(Zone.BATTLEFIELD, playerA, "Sungrass Prairie", 5);
// ({T}: Add {U} or {W} to your mana pool.)
addCard(Zone.BATTLEFIELD, playerA, "Tundra", 9);
// ({T}: Add {G} or {U} to your mana pool.)
addCard(Zone.BATTLEFIELD, playerA, "Tropical Island", 3);
setStopAt(3, PhaseStep.PRECOMBAT_MAIN);
execute();
ManaOptions manaOptions = playerA.getAvailableManaTest(currentGame);
assertDuplicatedManaOptions(manaOptions);
Assert.assertEquals("mana variations don't fit", 88, manaOptions.size());
assertManaOptions("{W}{W}{W}{W}{W}{W}{W}{W}{W}{G}{G}{G}{G}{G}{G}{G}{G}", manaOptions);
assertManaOptions("{W}{W}{W}{W}{W}{W}{W}{W}{U}{G}{G}{G}{G}{G}{G}{G}{G}", manaOptions);
}
@Test
public void testSungrassPrairie3() {
// {1}, {T}: Add {G}{W}.
addCard(Zone.BATTLEFIELD, playerA, "Sungrass Prairie", 1);
// ({T}: Add {U} or {W} to your mana pool.)
addCard(Zone.BATTLEFIELD, playerA, "Tundra", 1);
// ({T}: Add {G} or {U} to your mana pool.)
addCard(Zone.BATTLEFIELD, playerA, "Tropical Island", 1);
setStopAt(3, PhaseStep.PRECOMBAT_MAIN);
execute();
ManaOptions manaOptions = playerA.getAvailableManaTest(currentGame);
assertDuplicatedManaOptions(manaOptions);
Assert.assertEquals("mana variations don't fit", 4, manaOptions.size());
assertManaOptions("{U}{U}", manaOptions);
assertManaOptions("{W}{G}{G}", manaOptions);
assertManaOptions("{W}{U}{G}", manaOptions);
assertManaOptions("{W}{W}{G}", manaOptions);
}
}

View file

@ -1051,7 +1051,8 @@ public class Mana implements Comparable<Mana>, Serializable, Copyable<Mana> {
/**
* Returns if this {@link Mana} object has more than or equal values of mana
* as the passed in {@link Mana} object.
* as the passed in {@link Mana} object. Ignores {Any} mana to prevent
* endless iterations.
*
* @param mana the mana to compare with
* @return if this object has more than or equal mana to the passed in
@ -1090,13 +1091,44 @@ public class Mana implements Comparable<Mana>, Serializable, Copyable<Mana> {
moreMana = mana1;
lessMana = mana2;
}
if (lessMana.getWhite() > moreMana.getWhite()
|| lessMana.getRed() > moreMana.getRed()
|| lessMana.getGreen() > moreMana.getGreen()
|| lessMana.getBlue() > moreMana.getBlue()
|| lessMana.getBlack() > moreMana.getBlack()
|| lessMana.getColorless() > moreMana.getColorless()
|| lessMana.getAny() > moreMana.getAny()) {
int anyDiff = mana2.getAny() - mana1.getAny();
if (lessMana.getWhite() > moreMana.getWhite()) {
anyDiff -= lessMana.getWhite() - moreMana.getWhite();
if (anyDiff < 0) {
return null;
}
}
if (lessMana.getRed() > moreMana.getRed()) {
anyDiff -= lessMana.getRed() - moreMana.getRed();
if (anyDiff < 0) {
return null;
}
}
if (lessMana.getGreen() > moreMana.getGreen()) {
anyDiff -= lessMana.getGreen() - moreMana.getGreen();
if (anyDiff < 0) {
return null;
}
}
if (lessMana.getBlue() > moreMana.getBlue()) {
anyDiff -= lessMana.getBlue() - moreMana.getBlue();
if (anyDiff < 0) {
return null;
}
}
if (lessMana.getBlack() > moreMana.getBlack()) {
anyDiff -= lessMana.getBlack() - moreMana.getBlack();
if (anyDiff < 0) {
return null;
}
}
if (lessMana.getColorless() > moreMana.getColorless()) {
anyDiff -= lessMana.getColorless() - moreMana.getColorless();
if (anyDiff < 0) {
return null;
}
}
if (lessMana.getAny() > moreMana.getAny()) {
return null;
}
return moreMana;

View file

@ -114,6 +114,7 @@ public class ManaOptions extends ArrayList<Mana> {
}
public void addManaWithCost(List<ActivatedManaAbilityImpl> abilities, Game game) {
int replaces = 0;
if (isEmpty()) {
this.add(new Mana());
}
@ -187,7 +188,8 @@ public class ManaOptions extends ArrayList<Mana> {
Mana moreValuable = Mana.getMoreValuableMana(newMana, existingMana);
if (moreValuable != null) {
existingMana.setToMana(moreValuable);
logger.trace("mana replaced " + newMana.toString() + " <=> " + existingMana.toString() + " from " + ability.getRule());
replaces++;
// logger.info("mana replaced " + newMana.toString() + " <=> " + existingMana.toString() + " from " + ability.getRule());
continue CombineWithExisting;
}
}
@ -203,6 +205,10 @@ public class ManaOptions extends ArrayList<Mana> {
}
}
}
if (this.size() > 5 || replaces > 5) {
logger.info("ManaOptionsCosts " + this.size() + " Ign:" + replaces + " => " + this.toString());
logger.info("Abilities: " + abilities.toString());
}
}
public void addMana(Mana addMana) {
@ -255,20 +261,28 @@ public class ManaOptions extends ArrayList<Mana> {
this.clear();
for (Mana mana : copy) {
Mana oldMan = mana.copy();
if (mana.includesMana(cost)) {
// colorless costs can be paid with different colored mana, can lead to different color combinations
if (mana.includesMana(cost)) { // it can be paid
// generic mana costs can be paid with different colored mana, can lead to different color combinations
if (cost.getGeneric() > 0 && cost.getGeneric() > (mana.getGeneric() + mana.getColorless())) {
Mana coloredCost = cost.copy();
coloredCost.setGeneric(0);
mana.subtract(coloredCost);
boolean oldManaWasReplaced = false;
for (Mana payCombination : getPossiblePayCombinations(cost.getGeneric(), mana)) {
Mana newMana = mana.copy();
newMana.subtract(payCombination);
newMana.add(addMana);
if (oldMan.contains(newMana) && oldMan.count() > newMana.count()) {
newMana.setToMana(oldMan);
Mana moreValuable = Mana.getMoreValuableMana(oldMan, newMana);
if (!oldMan.equals(moreValuable)) {
this.add(newMana);
if (moreValuable != null) {
oldManaWasReplaced = true; // the new mana includes all possibilities of the old one
}
}
this.add(newMana);
}
if (!oldManaWasReplaced) {
this.add(oldMan);
}
} else {
while (mana.includesMana(cost)) {
@ -303,28 +317,33 @@ public class ManaOptions extends ArrayList<Mana> {
existingManas.add(new Mana());
}
for (Mana existingMana : existingManas) {
Mana manaToPay = manaAvailable.copy();
manaToPay.subtract(existingMana);
if (manaToPay.getBlack() > 0 && !payCombinationsStrings.contains(existingMana.toString() + Mana.BlackMana(1).toString())) {
manaToPay.subtract(Mana.BlackMana(1));
Mana manaToPayFrom = manaAvailable.copy();
manaToPayFrom.subtract(existingMana);
if (manaToPayFrom.getBlack() > 0 && !payCombinationsStrings.contains(existingMana.toString() + Mana.BlackMana(1).toString())) {
manaToPayFrom.subtract(Mana.BlackMana(1));
addManaCombination(Mana.BlackMana(1), existingMana, payCombinations, payCombinationsStrings);
}
if (manaToPay.getBlue() > 0 && !payCombinationsStrings.contains(existingMana.toString() + Mana.BlueMana(1).toString())) {
manaToPay.subtract(Mana.BlueMana(1));
if (manaToPayFrom.getBlue() > 0 && !payCombinationsStrings.contains(existingMana.toString() + Mana.BlueMana(1).toString())) {
manaToPayFrom.subtract(Mana.BlueMana(1));
addManaCombination(Mana.BlueMana(1), existingMana, payCombinations, payCombinationsStrings);
}
if (manaToPay.getGreen() > 0 && !payCombinationsStrings.contains(existingMana.toString() + Mana.GreenMana(1).toString())) {
manaToPay.subtract(Mana.GreenMana(1));
if (manaToPayFrom.getGreen() > 0 && !payCombinationsStrings.contains(existingMana.toString() + Mana.GreenMana(1).toString())) {
manaToPayFrom.subtract(Mana.GreenMana(1));
addManaCombination(Mana.GreenMana(1), existingMana, payCombinations, payCombinationsStrings);
}
if (manaToPay.getRed() > 0 && !payCombinationsStrings.contains(existingMana.toString() + Mana.RedMana(1).toString())) {
manaToPay.subtract(Mana.RedMana(1));
if (manaToPayFrom.getRed() > 0 && !payCombinationsStrings.contains(existingMana.toString() + Mana.RedMana(1).toString())) {
manaToPayFrom.subtract(Mana.RedMana(1));
addManaCombination(Mana.RedMana(1), existingMana, payCombinations, payCombinationsStrings);
}
if (manaToPay.getWhite() > 0 && !payCombinationsStrings.contains(existingMana.toString() + Mana.WhiteMana(1).toString())) {
manaToPay.subtract(Mana.WhiteMana(1));
if (manaToPayFrom.getWhite() > 0 && !payCombinationsStrings.contains(existingMana.toString() + Mana.WhiteMana(1).toString())) {
manaToPayFrom.subtract(Mana.WhiteMana(1));
addManaCombination(Mana.WhiteMana(1), existingMana, payCombinations, payCombinationsStrings);
}
// Pay with any only needed if colored payment was not possible
if (payCombinations.isEmpty() && manaToPayFrom.getAny() > 0 && !payCombinationsStrings.contains(existingMana.toString() + Mana.AnyMana(1).toString())) {
manaToPayFrom.subtract(Mana.AnyMana(1));
addManaCombination(Mana.AnyMana(1), existingMana, payCombinations, payCombinationsStrings);
}
}
}
} else {
@ -352,5 +371,16 @@ public class ManaOptions extends ArrayList<Mana> {
list.add(s);
}
}
// Remove fully included variations
for (int i = this.size() - 1; i >= 0; i--) {
for (int ii = 0; ii < i; ii++) {
Mana moreValuable = Mana.getMoreValuableMana(this.get(i), this.get(ii));
if (moreValuable != null) {
this.get(ii).setToMana(moreValuable);
this.remove(i);
break;
}
}
}
}
}

View file

@ -2647,6 +2647,7 @@ public abstract class PlayerImpl implements Player, Serializable {
available.addMana(manaAbilities, game);
}
for (Abilities<ActivatedManaAbilityImpl> manaAbilities : sourceWithCosts) {
available.removeDuplicated();
available.addManaWithCost(manaAbilities, game);
}