forked from External/mage
329 lines
15 KiB
Java
329 lines
15 KiB
Java
/*
|
|
* Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved.
|
|
*
|
|
* Redistribution and use in source and binary forms, with or without modification, are
|
|
* permitted provided that the following conditions are met:
|
|
*
|
|
* 1. Redistributions of source code must retain the above copyright notice, this list of
|
|
* conditions and the following disclaimer.
|
|
*
|
|
* 2. Redistributions in binary form must reproduce the above copyright notice, this list
|
|
* of conditions and the following disclaimer in the documentation and/or other materials
|
|
* provided with the distribution.
|
|
*
|
|
* THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED
|
|
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
|
|
* FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR
|
|
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
|
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
|
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
|
|
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
|
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
|
|
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
*
|
|
* The views and conclusions contained in the software and documentation are those of the
|
|
* authors and should not be interpreted as representing official policies, either expressed
|
|
* or implied, of BetaSteward_at_googlemail.com.
|
|
*/
|
|
package mage.abilities.mana;
|
|
|
|
import java.util.ArrayList;
|
|
import java.util.List;
|
|
import mage.Mana;
|
|
import mage.game.Game;
|
|
|
|
/**
|
|
*
|
|
* @author BetaSteward_at_googlemail.com
|
|
*
|
|
* this class is used to build a list of all possible mana combinations it can
|
|
* be used to find all the ways to pay a mana cost or all the different mana
|
|
* combinations available to a player
|
|
*
|
|
*/
|
|
public class ManaOptions extends ArrayList<Mana> {
|
|
|
|
public ManaOptions() {
|
|
}
|
|
|
|
public ManaOptions(final ManaOptions options) {
|
|
for (Mana mana : options) {
|
|
this.add(mana.copy());
|
|
}
|
|
}
|
|
|
|
public void addMana(List<ActivatedManaAbilityImpl> abilities, Game game) {
|
|
if (isEmpty()) {
|
|
this.add(new Mana());
|
|
}
|
|
if (!abilities.isEmpty()) {
|
|
if (abilities.size() == 1) {
|
|
//if there is only one mana option available add it to all the existing options
|
|
List<Mana> netManas = abilities.get(0).getNetMana(game);
|
|
if (netManas.size() == 1) {
|
|
addMana(netManas.get(0));
|
|
} else {
|
|
List<Mana> copy = copy();
|
|
this.clear();
|
|
for (Mana netMana : netManas) {
|
|
for (Mana mana : copy) {
|
|
Mana newMana = new Mana();
|
|
newMana.add(mana);
|
|
newMana.add(netMana);
|
|
this.add(newMana);
|
|
}
|
|
}
|
|
}
|
|
|
|
} else if (abilities.size() > 1) {
|
|
//perform a union of all existing options and the new options
|
|
List<Mana> copy = copy();
|
|
this.clear();
|
|
for (ActivatedManaAbilityImpl ability : abilities) {
|
|
for (Mana netMana : ability.getNetMana(game)) {
|
|
SkipAddMana:
|
|
for (Mana mana : copy) {
|
|
Mana newMana = new Mana();
|
|
newMana.add(mana);
|
|
newMana.add(netMana);
|
|
for (Mana existingMana : this) {
|
|
if (existingMana.equalManaValue(newMana)) {
|
|
continue SkipAddMana;
|
|
}
|
|
Mana moreValuable = Mana.getMoreValuableMana(newMana, existingMana);
|
|
if (moreValuable != null) {
|
|
// only keep the more valuable mana
|
|
existingMana.setToMana(moreValuable);
|
|
continue SkipAddMana;
|
|
}
|
|
}
|
|
this.add(newMana);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
public void addManaWithCost(List<ActivatedManaAbilityImpl> abilities, Game game) {
|
|
if (isEmpty()) {
|
|
this.add(new Mana());
|
|
}
|
|
if (!abilities.isEmpty()) {
|
|
if (abilities.size() == 1) {
|
|
//if there is only one mana option available add it to all the existing options
|
|
ActivatedManaAbilityImpl ability = abilities.get(0);
|
|
List<Mana> netManas = abilities.get(0).getNetMana(game);
|
|
// no mana costs
|
|
if (ability.getManaCosts().isEmpty()) {
|
|
if (netManas.size() == 1) {
|
|
addMana(netManas.get(0));
|
|
} else {
|
|
List<Mana> copy = copy();
|
|
this.clear();
|
|
for (Mana netMana : netManas) {
|
|
for (Mana mana : copy) {
|
|
Mana newMana = new Mana();
|
|
newMana.add(mana);
|
|
newMana.add(netMana);
|
|
this.add(newMana);
|
|
}
|
|
}
|
|
}
|
|
} else // the ability has mana costs
|
|
if (netManas.size() == 1) {
|
|
subtractCostAddMana(ability.getManaCosts().getMana(), netManas.get(0), ability.getCosts().isEmpty());
|
|
} else {
|
|
List<Mana> copy = copy();
|
|
this.clear();
|
|
for (Mana netMana : netManas) {
|
|
for (Mana mana : copy) {
|
|
Mana newMana = new Mana();
|
|
newMana.add(mana);
|
|
newMana.add(netMana);
|
|
subtractCostAddMana(ability.getManaCosts().getMana(), netMana, ability.getCosts().isEmpty());
|
|
}
|
|
}
|
|
}
|
|
} else if (abilities.size() > 1) {
|
|
//perform a union of all existing options and the new options
|
|
List<Mana> copy = copy();
|
|
this.clear();
|
|
for (ActivatedManaAbilityImpl ability : abilities) {
|
|
|
|
List<Mana> netManas = ability.getNetMana(game);
|
|
|
|
if (ability.getManaCosts().isEmpty()) {
|
|
for (Mana netMana : netManas) {
|
|
for (Mana mana : copy) {
|
|
Mana newMana = new Mana();
|
|
newMana.add(mana);
|
|
newMana.add(netMana);
|
|
this.add(newMana);
|
|
}
|
|
}
|
|
} else {
|
|
for (Mana netMana : netManas) {
|
|
for (Mana previousMana : copy) {
|
|
CombineWithExisting:
|
|
for (Mana manaOption : ability.getManaCosts().getManaOptions()) {
|
|
Mana newMana = new Mana(previousMana);
|
|
if (previousMana.includesMana(manaOption)) { // costs can be paid
|
|
newMana.subtractCost(manaOption);
|
|
newMana.add(netMana);
|
|
// if the new mana is in all colors more than another already existing than replace
|
|
for (Mana existingMana : this) {
|
|
Mana moreValuable = Mana.getMoreValuableMana(newMana, existingMana);
|
|
if (moreValuable != null) {
|
|
existingMana.setToMana(moreValuable);
|
|
continue CombineWithExisting;
|
|
}
|
|
}
|
|
// no existing Mana includes this new mana so add
|
|
this.add(newMana);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
public void addMana(Mana addMana) {
|
|
if (isEmpty()) {
|
|
this.add(new Mana());
|
|
}
|
|
for (Mana mana : this) {
|
|
mana.add(addMana);
|
|
}
|
|
}
|
|
|
|
public void addMana(ManaOptions options) {
|
|
if (isEmpty()) {
|
|
this.add(new Mana());
|
|
}
|
|
if (!options.isEmpty()) {
|
|
if (options.size() == 1) {
|
|
//if there is only one mana option available add it to all the existing options
|
|
addMana(options.get(0));
|
|
} else if (options.size() > 1) {
|
|
//perform a union of all existing options and the new options
|
|
List<Mana> copy = copy();
|
|
this.clear();
|
|
for (Mana addMana : options) {
|
|
for (Mana mana : copy) {
|
|
Mana newMana = new Mana();
|
|
newMana.add(mana);
|
|
newMana.add(addMana);
|
|
this.add(newMana);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
public ManaOptions copy() {
|
|
return new ManaOptions(this);
|
|
}
|
|
|
|
public void subtractCostAddMana(Mana cost, Mana addMana, boolean onlyManaCosts) {
|
|
if (isEmpty()) {
|
|
this.add(new Mana());
|
|
}
|
|
boolean repeatable = false;
|
|
if (addMana.getAny() == 1 && addMana.count() == 1 && onlyManaCosts) {
|
|
// deactivated because it does cause loops TODO: Find reason
|
|
repeatable = true; // only replace to any with mana costs only will be repeated if able
|
|
}
|
|
List<Mana> copy = copy();
|
|
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 (cost.getGeneric() > 0 && cost.getGeneric() > (mana.getGeneric() + mana.getColorless())) {
|
|
Mana coloredCost = cost.copy();
|
|
coloredCost.setGeneric(0);
|
|
mana.subtract(coloredCost);
|
|
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);
|
|
}
|
|
this.add(newMana);
|
|
}
|
|
} else {
|
|
while (mana.includesMana(cost)) {
|
|
mana.subtractCost(cost);
|
|
mana.add(addMana);
|
|
if (!repeatable) {
|
|
break;
|
|
}
|
|
}
|
|
// Don't use mana that only reduce the available mana
|
|
if (oldMan.contains(mana) && oldMan.count() > mana.count()) {
|
|
mana.setToMana(oldMan);
|
|
}
|
|
this.add(mana);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
private List<Mana> getPossiblePayCombinations(int number, Mana manaAvailable) {
|
|
List<Mana> payCombinations = new ArrayList<>();
|
|
List<String> payCombinationsStrings = new ArrayList<>();
|
|
if (manaAvailable.countColored() > 0) {
|
|
|
|
for (int i = 0; i < number; i++) {
|
|
List<Mana> existingManas = new ArrayList<>();
|
|
if (i > 0) {
|
|
existingManas.addAll(payCombinations);
|
|
payCombinations.clear();
|
|
payCombinationsStrings.clear();
|
|
} else {
|
|
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));
|
|
addManaCombination(Mana.BlackMana(1), existingMana, payCombinations, payCombinationsStrings);
|
|
}
|
|
if (manaToPay.getBlue() > 0 && !payCombinationsStrings.contains(existingMana.toString() + Mana.BlueMana(1).toString())) {
|
|
manaToPay.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));
|
|
addManaCombination(Mana.GreenMana(1), existingMana, payCombinations, payCombinationsStrings);
|
|
}
|
|
if (manaToPay.getRed() > 0 && !payCombinationsStrings.contains(existingMana.toString() + Mana.RedMana(1).toString())) {
|
|
manaToPay.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));
|
|
addManaCombination(Mana.WhiteMana(1), existingMana, payCombinations, payCombinationsStrings);
|
|
}
|
|
}
|
|
}
|
|
} else {
|
|
payCombinations.add(Mana.ColorlessMana(number));
|
|
}
|
|
return payCombinations;
|
|
}
|
|
|
|
private void addManaCombination(Mana mana, Mana existingMana, List<Mana> payCombinations, List<String> payCombinationsStrings) {
|
|
Mana newMana = existingMana.copy();
|
|
newMana.add(mana);
|
|
payCombinations.add(newMana);
|
|
payCombinationsStrings.add(newMana.toString());
|
|
}
|
|
}
|