Miscallaneous Cleanup Part 2 - Lambdas and Method References (#5737)

* Cleanup - Unnecessary Boxing

* Cleanup - Unnecessary Unboxing

* Cleanup - For-Each Loops

* Cleanup - `indexOf != -1` -> `contains`

* Cleanup - Merge identical catch blocks

* Cleanup - Try-with-resources

* Cleanup - System.lineSeparator

* Cleanup - Reference types to primitives
Some loops over Integers were switched to IntStreams to hopefully cut down on overall boxing.

* Cleanup - Manually filling and copying arrays

* Remove unused imports

* Switch a lambda to a method reference

* Cleanup - CardPredicate Aggregates to method references

* Cleanup - Other static functions to method references

* Cleanup - Ambiguous class reference
Unclear when or how this happened...

* Cleanup - Anonymous -> Method reference

* Cleanup - Anonymous -> Lambda

* Cleanup - Comparator helper methods

* Cleanup - final method in final class

* Cleanup - private final methods

* Remove unused imports

* Convert a couple more lambdas to comparators.

* Simplify creature type list comparison.

---------

Co-authored-by: Jetz <Jetz722@gmail.com>
Co-authored-by: tool4ever <therealtoolkit@hotmail.com>
This commit is contained in:
Jetz72
2024-08-02 01:23:58 -04:00
committed by GitHub
parent 86ac0349ca
commit d62dfe1c8c
490 changed files with 6692 additions and 13091 deletions

View File

@@ -60,12 +60,7 @@ public class ActionEditor extends JComponent{
add(edit,BorderLayout.CENTER);
edit.addChangeListener(new ChangeListener() {
@Override
public void stateChanged(ChangeEvent e) {
emitChanged();
}
});
edit.addChangeListener(e -> emitChanged());
}
protected void emitChanged() {
if (updating)

View File

@@ -49,12 +49,7 @@ public class DialogTree extends JPanel {
public void addSelectionListener(){
//subscribe to valueChanged, change to that object in edit pane
dialogTree.getSelectionModel().addTreeSelectionListener(new TreeSelectionListener() {
@Override
public void valueChanged(TreeSelectionEvent e) {
emitChanged(e);
}
});
dialogTree.getSelectionModel().addTreeSelectionListener(this::emitChanged);
}

View File

@@ -3,7 +3,6 @@ package forge.adventure.editor;
import com.badlogic.gdx.tools.particleeditor.ParticleEditor;
import com.google.common.base.Function;
import forge.localinstance.properties.ForgeConstants;
import forge.localinstance.properties.ForgePreferences;
import forge.model.FModel;
@@ -23,12 +22,9 @@ public class EditorMainWindow extends JFrame {
public EditorMainWindow()
{
UIManager.LookAndFeelInfo[] var1 = UIManager.getInstalledLookAndFeels();
FModel.initialize(null, new Function<ForgePreferences, Void>() {
@Override
public Void apply(ForgePreferences preferences) {
FModel.initialize(null, preferences -> {
preferences.setPref(ForgePreferences.FPref.LOAD_CARD_SCRIPTS_LAZILY, true);
return null;
}
});
Lang.createInstance(FModel.getPreferences().getPref(ForgePreferences.FPref.UI_LANGUAGE));
Localizer.getInstance().initialize(FModel.getPreferences().getPref(ForgePreferences.FPref.UI_LANGUAGE), ForgeConstants.LANG_DIR);

View File

@@ -4,8 +4,6 @@ import forge.adventure.util.Config;
import javax.swing.*;
import javax.swing.filechooser.FileNameExtensionFilter;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.File;
import java.io.IOException;
@@ -21,12 +19,7 @@ public class FilePicker extends Box {
super(BoxLayout.X_AXIS);
this.fileEndings = fileEndings;
findButton.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
FilePicker.this.find();
}
});
findButton.addActionListener(e -> FilePicker.this.find());
add(edit);
add(findButton);

View File

@@ -68,12 +68,7 @@ public class StructureEditor extends JComponent{
add(edit,BorderLayout.CENTER);
edit.addChangeListener(new ChangeListener() {
@Override
public void stateChanged(ChangeEvent e) {
emitChanged();
}
});
edit.addChangeListener(e -> emitChanged());
}
protected void emitChanged() {
ChangeListener[] listeners = listenerList.getListeners(ChangeListener.class);

View File

@@ -60,12 +60,7 @@ public class TerrainsEditor extends JComponent{
add(edit,BorderLayout.CENTER);
edit.addChangeListener(new ChangeListener() {
@Override
public void stateChanged(ChangeEvent e) {
emitChanged();
}
});
edit.addChangeListener(e -> emitChanged());
}
protected void emitChanged() {
ChangeListener[] listeners = listenerList.getListeners(ChangeListener.class);

View File

@@ -9,8 +9,6 @@ import forge.adventure.util.Config;
import forge.adventure.util.Paths;
import javax.swing.*;
import javax.swing.event.ListSelectionEvent;
import javax.swing.event.ListSelectionListener;
import java.awt.*;
import java.io.File;
import java.io.IOException;
@@ -81,12 +79,7 @@ public class WorldEditor extends JComponent {
public WorldEditor() {
list.setCellRenderer(new BiomeDataRenderer());
list.addListSelectionListener(new ListSelectionListener() {
@Override
public void valueChanged(ListSelectionEvent e) {
WorldEditor.this.updateBiome();
}
});
list.addListSelectionListener(e -> WorldEditor.this.updateBiome());
BorderLayout layout = new BorderLayout();
setLayout(layout);
add(tabs);

View File

@@ -124,12 +124,7 @@ public class AiAttackController {
List<Card> defenders = defender.getCreaturesInPlay();
int totalMana = ComputerUtilMana.getAvailableManaEstimate(defender, true);
int manaReserved = 0; // for paying the cost to transform
Predicate<Card> canAnimate = new Predicate<Card>() {
@Override
public boolean apply(Card c) {
return !c.isTapped() && !c.isCreature() && !c.isPlaneswalker();
}
};
Predicate<Card> canAnimate = c -> !c.isTapped() && !c.isCreature() && !c.isPlaneswalker();
CardCollection tappedDefenders = new CardCollection();
for (Card c : CardLists.filter(defender.getCardsIn(ZoneType.Battlefield), canAnimate)) {
@@ -331,12 +326,7 @@ public class AiAttackController {
}
public final static List<Card> getPossibleBlockers(final List<Card> blockers, final List<Card> attackers, final boolean nextTurn) {
return CardLists.filter(blockers, new Predicate<Card>() {
@Override
public boolean apply(final Card c) {
return canBlockAnAttacker(c, attackers, nextTurn);
}
});
return CardLists.filter(blockers, c -> canBlockAnAttacker(c, attackers, nextTurn));
}
public final static boolean canBlockAnAttacker(final Card c, final List<Card> attackers, final boolean nextTurn) {
@@ -395,15 +385,10 @@ public class AiAttackController {
}
}
// reduce the search space
final List<Card> opponentsAttackers = CardLists.filter(ai.getOpponents().getCreaturesInPlay(), new Predicate<Card>() {
@Override
public boolean apply(final Card c) {
return !c.hasSVar("EndOfTurnLeavePlay")
final List<Card> opponentsAttackers = CardLists.filter(ai.getOpponents().getCreaturesInPlay(), c -> !c.hasSVar("EndOfTurnLeavePlay")
&& (c.toughnessAssignsDamage() || c.getNetCombatDamage() > 0 // performance shortcuts
|| c.getNetCombatDamage() + ComputerUtilCombat.predictPowerBonusOfAttacker(c, null, null, true) > 0)
&& ComputerUtilCombat.canAttackNextTurn(c);
}
});
&& ComputerUtilCombat.canAttackNextTurn(c));
// don't hold back creatures that can't block any of the human creatures
final List<Card> blockers = getPossibleBlockers(potentialAttackers, opponentsAttackers, true);
@@ -770,7 +755,7 @@ public class AiAttackController {
return false;
}
private final Pair<Integer, Integer> getDamageFromBlockingTramplers(final List<Card> blockedAttackers, final List<Card> blockers, final int myFreeMana) {
private Pair<Integer, Integer> getDamageFromBlockingTramplers(final List<Card> blockedAttackers, final List<Card> blockers, final int myFreeMana) {
int currentAttackTax = 0;
int trampleDamage = 0;
CardCollection remainingBlockers = new CardCollection(blockers);
@@ -797,7 +782,7 @@ public class AiAttackController {
return Pair.of(trampleDamage, currentAttackTax);
}
private final GameEntity chooseDefender(final Combat c, final boolean bAssault) {
private GameEntity chooseDefender(final Combat c, final boolean bAssault) {
final FCollectionView<GameEntity> defs = c.getDefenders();
if (defs.size() == 1) {
return defs.getFirst();
@@ -932,9 +917,7 @@ public class AiAttackController {
// check defenders in order of maximum requirements
List<Pair<GameEntity, Integer>> reqs = combat.getAttackConstraints().getRequirements().get(attacker).getSortedRequirements();
final GameEntity def = defender;
reqs.sort(new Comparator<Pair<GameEntity, Integer>>() {
@Override
public int compare(Pair<GameEntity, Integer> r1, Pair<GameEntity, Integer> r2) {
reqs.sort((r1, r2) -> {
if (r1.getValue() == r2.getValue()) {
// try to attack the designated defender
if (r1.getKey().equals(def) && !r2.getKey().equals(def)) {
@@ -956,7 +939,6 @@ public class AiAttackController {
}
}
return r2.getValue() - r1.getValue();
}
});
for (Pair<GameEntity, Integer> e : reqs) {
if (e.getRight() == 0) continue;
@@ -1406,14 +1388,9 @@ public class AiAttackController {
}
// contains only the defender's blockers that can actually block the attacker
CardCollection validBlockers = CardLists.filter(defenders, new Predicate<Card>() {
@Override
public boolean apply(Card defender) {
return CombatUtil.canBlock(attacker, defender);
}
});
CardCollection validBlockers = CardLists.filter(defenders, defender1 -> CombatUtil.canBlock(attacker, defender1));
boolean canTrampleOverDefenders = attacker.hasKeyword(Keyword.TRAMPLE) && attacker.getNetCombatDamage() > Aggregates.sum(validBlockers, CardPredicates.Accessors.fnGetNetToughness);
boolean canTrampleOverDefenders = attacker.hasKeyword(Keyword.TRAMPLE) && attacker.getNetCombatDamage() > Aggregates.sum(validBlockers, Card::getNetToughness);
// used to check that CanKillAllDangerous check makes sense in context where creatures with dangerous abilities are present
boolean dangerousBlockersPresent = Iterables.any(validBlockers, Predicates.or(

View File

@@ -140,9 +140,7 @@ public class AiBlockController {
ComputerUtilCard.sortByEvaluateCreature(attackers);
CardLists.sortByPowerDesc(attackers);
//move cards like Phage the Untouchable to the front
attackers.sort(new Comparator<Card>() {
@Override
public int compare(final Card o1, final Card o2) {
attackers.sort((o1, o2) -> {
if (o1.hasSVar("MustBeBlocked") && !o2.hasSVar("MustBeBlocked")) {
return -1;
}
@@ -156,7 +154,6 @@ public class AiBlockController {
return 1;
}
return 0;
}
});
return attackers;
}
@@ -330,21 +327,14 @@ public class AiBlockController {
}
private Predicate<Card> rampagesOrNeedsManyToBlock(final Combat combat) {
return Predicates.or(CardPredicates.hasKeyword(Keyword.RAMPAGE), new Predicate<Card>() {
@Override
public boolean apply(Card input) {
return Predicates.or(CardPredicates.hasKeyword(Keyword.RAMPAGE), input -> {
// select creature that has a max blocker
return StaticAbilityCantAttackBlock.getMinMaxBlocker(input, combat.getDefenderPlayerByAttacker(input)).getRight() < Integer.MAX_VALUE;
}
});
}
private Predicate<Card> changesPTWhenBlocked(final boolean onlyForDefVsTrample) {
return new Predicate<Card>() {
@Override
public boolean apply(Card card) {
return card -> {
for (final Trigger tr : card.getTriggers()) {
if (tr.getMode() == TriggerType.AttackerBlocked) {
SpellAbility ab = tr.getOverridingAbility();
@@ -366,7 +356,6 @@ public class AiBlockController {
}
}
return false;
}
};
}
@@ -452,15 +441,12 @@ public class AiBlockController {
// Try to add blockers that could be destroyed, but are worth less than the attacker
// Don't use blockers without First Strike or Double Strike if attacker has it
usableBlockers = CardLists.filter(blockers, new Predicate<Card>() {
@Override
public boolean apply(final Card c) {
usableBlockers = CardLists.filter(blockers, c -> {
if (ComputerUtilCombat.dealsFirstStrikeDamage(attacker, false, combat)
&& !ComputerUtilCombat.dealsFirstStrikeDamage(c, false, combat)) {
return false;
}
return lifeInDanger || wouldLikeToRandomlyTrade(attacker, c, combat) || ComputerUtilCard.evaluateCreature(c) + diff < ComputerUtilCard.evaluateCreature(attacker);
}
});
if (usableBlockers.size() < 2) {
return;
@@ -579,13 +565,8 @@ public class AiBlockController {
final List<Card> blockGang = new ArrayList<>();
int absorbedDamage; // The amount of damage needed to kill the first blocker
List<Card> usableBlockers = CardLists.filter(blockers, new Predicate<Card>() {
@Override
public boolean apply(final Card c) {
return c.getNetToughness() > attacker.getNetCombatDamage() // performance shortcut
|| c.getNetToughness() + ComputerUtilCombat.predictToughnessBonusOfBlocker(attacker, c, true) > attacker.getNetCombatDamage();
}
});
List<Card> usableBlockers = CardLists.filter(blockers, c -> c.getNetToughness() > attacker.getNetCombatDamage() // performance shortcut
|| c.getNetToughness() + ComputerUtilCombat.predictToughnessBonusOfBlocker(attacker, c, true) > attacker.getNetCombatDamage());
if (usableBlockers.size() < 2) {
return;
}
@@ -829,12 +810,7 @@ public class AiBlockController {
blockers.removeAll(combat.getBlockers(attacker));
// Don't add any blockers that won't kill the attacker because the damage would be prevented by a static effect
blockers = CardLists.filter(blockers, new Predicate<Card>() {
@Override
public boolean apply(Card blocker) {
return !ComputerUtilCombat.isCombatDamagePrevented(blocker, attacker, blocker.getNetCombatDamage());
}
});
blockers = CardLists.filter(blockers, blocker -> !ComputerUtilCombat.isCombatDamagePrevented(blocker, attacker, blocker.getNetCombatDamage()));
// Try to use safe blockers first
if (blockers.size() > 0) {
@@ -921,13 +897,9 @@ public class AiBlockController {
CardCollection pwsWithChumpBlocks = new CardCollection();
CardCollection chosenChumpBlockers = new CardCollection();
CardCollection chumpPWDefenders = CardLists.filter(this.blockersLeft, new Predicate<Card>() {
@Override
public boolean apply(Card card) {
return ComputerUtilCard.evaluateCreature(card) <= (card.isToken() ? evalThresholdToken
: evalThresholdNonToken);
}
});
CardCollection chumpPWDefenders = CardLists.filter(this.blockersLeft,
card -> ComputerUtilCard.evaluateCreature(card) <= (card.isToken() ? evalThresholdToken : evalThresholdNonToken)
);
CardLists.sortByPowerAsc(chumpPWDefenders);
if (!chumpPWDefenders.isEmpty()) {
for (final Card attacker : attackers) {

View File

@@ -37,7 +37,6 @@ import forge.game.ability.AbilityUtils;
import forge.game.ability.ApiType;
import forge.game.ability.SpellApiBased;
import forge.game.card.*;
import forge.game.card.CardPredicates.Accessors;
import forge.game.card.CardPredicates.Presets;
import forge.game.combat.Combat;
import forge.game.combat.CombatUtil;
@@ -418,7 +417,7 @@ public class AiController {
CardCollection allCards = new CardCollection(player.getCardsIn(ZoneType.Graveyard));
allCards.addAll(player.getCardsIn(ZoneType.Command));
allCards.addAll(cardsInPlay);
int maxCmcInHand = Aggregates.max(hand, CardPredicates.Accessors.fnGetCmc);
int maxCmcInHand = Aggregates.max(hand, Card::getCMC);
int max = Math.max(maxCmcInHand, 6);
// consider not playing lands if there are enough already and an ability with a discard cost is present
if (landsInPlay.size() + landList.size() > max) {
@@ -437,9 +436,7 @@ public class AiController {
}
}
landList = CardLists.filter(landList, new Predicate<Card>() {
@Override
public boolean apply(final Card c) {
landList = CardLists.filter(landList, c -> {
CardCollectionView battlefield = player.getCardsIn(ZoneType.Battlefield);
if (canPlaySpellBasic(c, null) != AiPlayDecision.WillPlay) {
return false;
@@ -451,11 +448,11 @@ public class AiController {
}
}
final CardCollectionView hand = player.getCardsIn(ZoneType.Hand);
final CardCollectionView hand1 = player.getCardsIn(ZoneType.Hand);
CardCollection lands = new CardCollection(battlefield);
lands.addAll(hand);
lands = CardLists.filter(lands, CardPredicates.Presets.LANDS);
int maxCmcInHand = Aggregates.max(hand, CardPredicates.Accessors.fnGetCmc);
lands.addAll(hand1);
lands = CardLists.filter(lands, Presets.LANDS);
int maxCmcInHand = Aggregates.max(hand1, Card::getCMC);
if (lands.size() >= Math.max(maxCmcInHand, 6)) {
// don't play MDFC land if other side is spell and enough lands are available
@@ -473,7 +470,6 @@ public class AiController {
}
return player.canPlayLand(c);
}
});
return landList;
}
@@ -1441,8 +1437,8 @@ public class AiController {
}
}
int totalCMCInHand = Aggregates.sum(inHand, CardPredicates.Accessors.fnGetCmc);
int minCMCInHand = Aggregates.min(inHand, CardPredicates.Accessors.fnGetCmc);
int totalCMCInHand = Aggregates.sum(inHand, Card::getCMC);
int minCMCInHand = Aggregates.min(inHand, Card::getCMC);
if (minCMCInHand == Integer.MAX_VALUE)
minCMCInHand = 0;
int predictedMana = ComputerUtilMana.getAvailableManaEstimate(player, true);
@@ -1450,14 +1446,12 @@ public class AiController {
boolean canCastWithLandDrop = (predictedMana + 1 >= minCMCInHand) && minCMCInHand > 0 && !isTapLand;
boolean cantCastAnythingNow = predictedMana < minCMCInHand;
boolean hasRelevantAbsOTB = Iterables.any(otb, new Predicate<Card>() {
@Override
public boolean apply(Card card) {
boolean isTapLand = false;
boolean hasRelevantAbsOTB = Iterables.any(otb, card -> {
boolean isTapLand1 = false;
for (ReplacementEffect repl : card.getReplacementEffects()) {
// TODO: improve the detection of taplands
if (repl.getParamOrDefault("Description", "").equals("CARDNAME enters the battlefield tapped.")) {
isTapLand = true;
isTapLand1 = true;
}
}
@@ -1465,18 +1459,15 @@ public class AiController {
if (sa.isAbility()
&& sa.getPayCosts().getCostMana() != null
&& sa.getPayCosts().getCostMana().getMana().getCMC() > 0
&& (!sa.getPayCosts().hasTapCost() || !isTapLand)
&& (!sa.getPayCosts().hasTapCost() || !isTapLand1)
&& (!sa.hasParam("ActivationZone") || sa.getParam("ActivationZone").contains("Battlefield"))) {
return true;
}
}
return false;
}
});
boolean hasLandBasedEffect = Iterables.any(otb, new Predicate<Card>() {
@Override
public boolean apply(Card card) {
boolean hasLandBasedEffect = Iterables.any(otb, card -> {
for (Trigger t : card.getTriggers()) {
Map<String, String> params = t.getMapParams();
if ("ChangesZone".equals(params.get("Mode"))
@@ -1509,7 +1500,6 @@ public class AiController {
}
}
return false;
}
});
// TODO: add prediction for effects that will untap a tapland as it enters the battlefield
@@ -1528,7 +1518,7 @@ public class AiController {
return true;
}
private final SpellAbility getSpellAbilityToPlay() {
private SpellAbility getSpellAbilityToPlay() {
CardCollection cards = ComputerUtilAbility.getAvailableCards(game, player);
cards = ComputerUtilCard.dedupeCards(cards);
List<SpellAbility> saList = Lists.newArrayList();
@@ -1572,12 +1562,9 @@ public class AiController {
saList = ComputerUtilAbility.getSpellAbilities(cards, player);
}
Iterables.removeIf(saList, new Predicate<SpellAbility>() {
@Override
public boolean apply(final SpellAbility spellAbility) { //don't include removedAI cards if somehow the AI can play the ability or gain control of unsupported card
Iterables.removeIf(saList, spellAbility -> { //don't include removedAI cards if somehow the AI can play the ability or gain control of unsupported card
// TODO allow when experimental profile?
return spellAbility instanceof LandAbility || (spellAbility.getHostCard() != null && ComputerUtilCard.isCardRemAIDeck(spellAbility.getHostCard()));
}
});
//update LivingEndPlayer
useLivingEnd = Iterables.any(player.getZone(ZoneType.Library), CardPredicates.nameEquals("Living End"));
@@ -1997,14 +1984,9 @@ public class AiController {
case FlipOntoBattlefield:
if ("DamageCreatures".equals(sa.getParam("AILogic"))) {
int maxToughness = Integer.parseInt(sa.getSubAbility().getParam("NumDmg"));
CardCollectionView rightToughness = CardLists.filter(pool, new Predicate<Card>() {
@Override
public boolean apply(Card card) {
return card.getController().isOpponentOf(sa.getActivatingPlayer())
CardCollectionView rightToughness = CardLists.filter(pool, card -> card.getController().isOpponentOf(sa.getActivatingPlayer())
&& card.getNetToughness() <= maxToughness
&& card.canBeDestroyed();
}
});
&& card.canBeDestroyed());
Card bestCreature = ComputerUtilCard.getBestCreatureAI(rightToughness.isEmpty() ? pool : rightToughness);
if (bestCreature != null) {
result.add(bestCreature);
@@ -2140,7 +2122,7 @@ public class AiController {
CardCollection all = CardLists.filter(game.getCardsIn(ZoneType.Battlefield), Presets.NONLAND_PERMANENTS);
CardCollection left = CardLists.filterControlledBy(all, game.getNextPlayerAfter(player, Direction.Left));
CardCollection right = CardLists.filterControlledBy(all, game.getNextPlayerAfter(player, Direction.Right));
return Aggregates.sum(left, Accessors.fnGetCmc) > Aggregates.sum(right, Accessors.fnGetCmc);
return Aggregates.sum(left, Card::getCMC) > Aggregates.sum(right, Card::getCMC);
}
return MyRandom.getRandom().nextBoolean();
}
@@ -2167,8 +2149,8 @@ public class AiController {
} else if (aiLogic.equals("CMCOppControlsByPower")) {
// TODO: improve this to check for how dangerous those creatures actually are relative to host card
CardCollectionView hand = sa.getActivatingPlayer().getOpponents().getCardsIn(ZoneType.Battlefield);
int powerEven = Aggregates.sum(CardLists.filter(hand, CardPredicates.evenCMC()), Accessors.fnGetNetPower);
int powerOdd = Aggregates.sum(CardLists.filter(hand, CardPredicates.oddCMC()), Accessors.fnGetNetPower);
int powerEven = Aggregates.sum(CardLists.filter(hand, CardPredicates.evenCMC()), Card::getNetPower);
int powerOdd = Aggregates.sum(CardLists.filter(hand, CardPredicates.oddCMC()), Card::getNetPower);
return powerOdd > powerEven;
}
return MyRandom.getRandom().nextBoolean(); // outside of any specific logic, choose randomly

View File

@@ -1,6 +1,5 @@
package forge.ai;
import com.google.common.base.Predicate;
import com.google.common.base.Predicates;
import com.google.common.collect.Lists;
import forge.card.CardType;
@@ -445,16 +444,13 @@ public class AiCostDecision extends CostDecisionMakerBase {
CardCollectionView toExclude =
CardLists.getValidCards(player.getCardsIn(ZoneType.Battlefield), type.split(";"),
ability.getActivatingPlayer(), ability.getHostCard(), ability);
toExclude = CardLists.filter(toExclude, new Predicate<Card>() {
@Override
public boolean apply(Card card) {
toExclude = CardLists.filter(toExclude, card -> {
for (final SpellAbility sa : card.getSpellAbilities()) {
if (sa.isManaAbility() && sa.getPayCosts().hasTapCost()) {
return true;
}
}
return false;
}
});
exclude.addAll(toExclude);
}
@@ -642,16 +638,13 @@ public class AiCostDecision extends CostDecisionMakerBase {
// filter for negative counters
if (c > toRemove && cost.counter == null) {
List<Card> negatives = CardLists.filter(typeList, new Predicate<Card>() {
@Override
public boolean apply(final Card crd) {
List<Card> negatives = CardLists.filter(typeList, crd -> {
for (CounterType cType : table.filterToRemove(crd).keySet()) {
if (ComputerUtil.isNegativeCounter(cType, crd)) {
return true;
}
}
return false;
}
});
if (!negatives.isEmpty()) {
@@ -673,16 +666,13 @@ public class AiCostDecision extends CostDecisionMakerBase {
// filter for useless counters
// they have no effect on the card, if they are there or removed
if (c > toRemove && cost.counter == null) {
List<Card> useless = CardLists.filter(typeList, new Predicate<Card>() {
@Override
public boolean apply(final Card crd) {
List<Card> useless = CardLists.filter(typeList, crd -> {
for (CounterType ctype : table.filterToRemove(crd).keySet()) {
if (ComputerUtil.isUselessCounter(ctype, crd)) {
return true;
}
}
return false;
}
});
if (!useless.isEmpty()) {
@@ -710,9 +700,7 @@ public class AiCostDecision extends CostDecisionMakerBase {
// try to remove Quest counter on something with enough counters for the
// effect to continue
if (c > toRemove && (cost.counter == null || cost.counter.is(CounterEnumType.QUEST))) {
List<Card> prefs = CardLists.filter(typeList, new Predicate<Card>() {
@Override
public boolean apply(final Card crd) {
List<Card> prefs = CardLists.filter(typeList, crd -> {
// a Card without MaxQuestEffect doesn't need any Quest
// counters
int e = 0;
@@ -720,7 +708,6 @@ public class AiCostDecision extends CostDecisionMakerBase {
e = Integer.parseInt(crd.getSVar("MaxQuestEffect"));
}
return crd.getCounters(CounterEnumType.QUEST) > e;
}
});
prefs.sort(Collections.reverseOrder(CardPredicates.compareByCounterType(CounterEnumType.QUEST)));

View File

@@ -11,11 +11,8 @@ import forge.game.zone.ZoneType;
public final class AiPlayerPredicates {
public static final Comparator<Player> compareByZoneValue(final String type, final ZoneType zone,
final SpellAbility sa) {
return new Comparator<Player>() {
@Override
public int compare(Player arg0, Player arg1) {
public static Comparator<Player> compareByZoneValue(final String type, final ZoneType zone, final SpellAbility sa) {
return (arg0, arg1) -> {
CardCollectionView list0 = AbilityUtils.filterListByType(arg0.getCardsIn(zone), type, sa);
CardCollectionView list1 = AbilityUtils.filterListByType(arg1.getCardsIn(zone), type, sa);
@@ -32,7 +29,6 @@ public final class AiPlayerPredicates {
v1 = ComputerUtilCard.evaluatePermanentList(list1);
}
return Integer.compare(v0, v1);
}
};
}
}

View File

@@ -93,7 +93,7 @@ public class AiProfileUtil {
* Load a single profile.
* @param profileName a profile to load.
*/
private static final Map<AiProps, String> loadProfile(final String profileName) {
private static Map<AiProps, String> loadProfile(final String profileName) {
Map<AiProps, String> profileMap = new HashMap<>();
List<String> lines = FileUtil.readFile(buildFileName(profileName));

View File

@@ -408,13 +408,9 @@ public class ComputerUtil {
return ComputerUtilCard.getWorstLand(landsInPlay);
}
}
final CardCollection sacMeList = CardLists.filter(typeList, new Predicate<Card>() {
@Override
public boolean apply(final Card c) {
return (c.hasSVar("SacMe") && Integer.parseInt(c.getSVar("SacMe")) == priority)
|| (priority == 1 && shouldSacrificeThreatenedCard(ai, c, sa));
}
});
final CardCollection sacMeList = CardLists.filter(typeList, c -> (c.hasSVar("SacMe") && Integer.parseInt(c.getSVar("SacMe")) == priority)
|| (priority == 1 && shouldSacrificeThreatenedCard(ai, c, sa))
);
if (!sacMeList.isEmpty()) {
CardLists.shuffle(sacMeList);
return sacMeList.getFirst();
@@ -429,16 +425,13 @@ public class ComputerUtil {
int maxCreatureEval = aic.getIntProperty(AiProps.SACRIFICE_DEFAULT_PREF_MAX_CREATURE_EVAL);
boolean allowTokens = aic.getBooleanProperty(AiProps.SACRIFICE_DEFAULT_PREF_ALLOW_TOKENS);
List<String> dontSac = Arrays.asList("Black Lotus", "Mox Pearl", "Mox Jet", "Mox Emerald", "Mox Ruby", "Mox Sapphire", "Lotus Petal");
CardCollection allowList = CardLists.filter(typeList, new Predicate<Card>() {
@Override
public boolean apply(Card card) {
CardCollection allowList = CardLists.filter(typeList, card -> {
if (card.isCreature() && ComputerUtilCard.evaluateCreature(card) > maxCreatureEval) {
return false;
}
return (allowTokens && card.isToken())
|| (card.getCMC() >= minCMC && card.getCMC() <= maxCMC && !dontSac.contains(card.getName()));
}
});
if (!allowList.isEmpty()) {
CardLists.sortByCmcDesc(allowList);
@@ -455,7 +448,7 @@ public class ComputerUtil {
final int landsInHand = Math.min(2, CardLists.getType(ai.getCardsIn(ZoneType.Hand), "Land").size());
final CardCollection nonLandsInHand = CardLists.getNotType(ai.getCardsIn(ZoneType.Hand), "Land");
nonLandsInHand.addAll(ai.getCardsIn(ZoneType.Library));
final int highestCMC = Math.max(6, Aggregates.max(nonLandsInHand, CardPredicates.Accessors.fnGetCmc));
final int highestCMC = Math.max(6, Aggregates.max(nonLandsInHand, Card::getCMC));
if (landsInPlay.size() + landsInHand >= highestCMC) {
// Don't need more land.
return ComputerUtilCard.getWorstLand(landsInPlay);
@@ -539,7 +532,7 @@ public class ComputerUtil {
if (!landsInHand.isEmpty()) {
final int numLandsInPlay = CardLists.count(ai.getCardsIn(ZoneType.Battlefield), CardPredicates.Presets.LANDS_PRODUCING_MANA);
final CardCollection nonLandsInHand = CardLists.getNotType(ai.getCardsIn(ZoneType.Hand), "Land");
final int highestCMC = Math.max(6, Aggregates.max(nonLandsInHand, CardPredicates.Accessors.fnGetCmc));
final int highestCMC = Math.max(6, Aggregates.max(nonLandsInHand, Card::getCMC));
if (numLandsInPlay >= highestCMC
|| (numLandsInPlay + landsInHand.size() > 6 && landsInHand.size() > 1)) {
// Don't need more land.
@@ -735,13 +728,10 @@ public class ComputerUtil {
// FIXME: This is suboptimal, maybe implement a single comparator that'll take care of all of this?
CardLists.sortByCmcDesc(typeList);
Collections.reverse(typeList);
typeList.sort(new Comparator<Card>() {
@Override
public int compare(final Card a, final Card b) {
typeList.sort((a, b) -> {
if (!a.isInPlay() && b.isInPlay()) return -1;
else if (!b.isInPlay() && a.isInPlay()) return 1;
else return 0;
}
}); // something that's not on the battlefield should come first
}
final CardCollection exileList = new CardCollection();
@@ -958,9 +948,7 @@ public class ComputerUtil {
}
}
}
remaining = CardLists.filter(remaining, new Predicate<Card>() {
@Override
public boolean apply(final Card c) {
remaining = CardLists.filter(remaining, c -> {
int sacThreshold = 190;
String logic = source.getParamOrDefault("AILogic", "");
@@ -991,7 +979,6 @@ public class ComputerUtil {
}
return false;
}
});
}
@@ -1362,7 +1349,7 @@ public class ComputerUtil {
final CardCollection landsInPlay = CardLists.filter(ai.getCardsIn(ZoneType.Battlefield), CardPredicates.Presets.LANDS_PRODUCING_MANA);
final CardCollection landsInHand = CardLists.filter(ai.getCardsIn(ZoneType.Hand), CardPredicates.Presets.LANDS);
final CardCollection nonLandsInHand = CardLists.getNotType(ai.getCardsIn(ZoneType.Hand), "Land");
final int highestCMC = Math.max(6, Aggregates.max(nonLandsInHand, CardPredicates.Accessors.fnGetCmc));
final int highestCMC = Math.max(6, Aggregates.max(nonLandsInHand, Card::getCMC));
final int discardCMC = discard.getCMC();
if (discard.isLand()) {
if (landsInPlay.size() >= highestCMC
@@ -2183,12 +2170,7 @@ public class ComputerUtil {
AiController aic = ((PlayerControllerAi)ai.getController()).getAi();
if (aic.getBooleanProperty(AiProps.AVOID_TARGETING_CREATS_THAT_WILL_DIE)) {
// Try to avoid targeting creatures that are dead on board
List<Card> willBeKilled = CardLists.filter(list, new Predicate<Card>() {
@Override
public boolean apply(Card card) {
return card.isCreature() && predictCreatureWillDieThisTurn(ai, card, excludeSa);
}
});
List<Card> willBeKilled = CardLists.filter(list, card -> card.isCreature() && predictCreatureWillDieThisTurn(ai, card, excludeSa));
list.removeAll(willBeKilled);
}
return list;
@@ -2245,13 +2227,8 @@ public class ComputerUtil {
return finalHandSize;
}
final CardCollectionView lands = CardLists.filter(handList, new Predicate<Card>() {
@Override
public boolean apply(final Card c) {
return c.getManaCost().getCMC() <= 0 && !c.hasSVar("NeedsToPlay")
&& (c.isLand() || c.isArtifact());
}
});
final CardCollectionView lands = CardLists.filter(handList, c -> c.getManaCost().getCMC() <= 0 && !c.hasSVar("NeedsToPlay")
&& (c.isLand() || c.isArtifact()));
final int handSize = handList.size();
final int landSize = lands.size();
@@ -2265,12 +2242,7 @@ public class ComputerUtil {
score += 10;
}
final CardCollectionView castables = CardLists.filter(handList, new Predicate<Card>() {
@Override
public boolean apply(final Card c) {
return c.getManaCost().getCMC() <= 0 || c.getManaCost().getCMC() <= landSize;
}
});
final CardCollectionView castables = CardLists.filter(handList, c -> c.getManaCost().getCMC() <= 0 || c.getManaCost().getCMC() <= landSize);
score += castables.size() * 2;
@@ -2431,7 +2403,7 @@ public class ComputerUtil {
} else if (c.isCreature()) {
CardCollection creaturesOTB = CardLists.filter(cardsOTB, CardPredicates.Presets.CREATURES);
int avgCreatureValue = numCards != 0 ? ComputerUtilCard.evaluateCreatureList(allCreatures) / numCards : 0;
int maxControlledCMC = Aggregates.max(creaturesOTB, CardPredicates.Accessors.fnGetCmc);
int maxControlledCMC = Aggregates.max(creaturesOTB, Card::getCMC);
if (ComputerUtilCard.evaluateCreature(c) < avgCreatureValue) {
if (creaturesOTB.size() > minCreatsToScryCreatsAway) {
@@ -2460,12 +2432,7 @@ public class ComputerUtil {
}
public static CardCollection getCardsToDiscardFromOpponent(Player chooser, Player discarder, SpellAbility sa, CardCollection validCards, int min, int max) {
CardCollection goodChoices = CardLists.filter(validCards, new Predicate<Card>() {
@Override
public boolean apply(final Card c) {
return !c.hasSVar("DiscardMeByOpp") && !c.hasSVar("DiscardMe");
}
});
CardCollection goodChoices = CardLists.filter(validCards, c -> !c.hasSVar("DiscardMeByOpp") && !c.hasSVar("DiscardMe"));
if (goodChoices.isEmpty()) {
goodChoices = validCards;
}
@@ -2859,25 +2826,17 @@ public class ComputerUtil {
}
public static CardCollection getSafeTargets(final Player ai, SpellAbility sa, CardCollectionView validCards) {
CardCollection safeCards = CardLists.filter(validCards, new Predicate<Card>() {
@Override
public boolean apply(final Card c) {
CardCollection safeCards = CardLists.filter(validCards, c -> {
if (c.getController() == ai) {
return !c.getSVar("Targeting").equals("Dies") && !c.getSVar("Targeting").equals("Counter");
}
return true;
}
});
return safeCards;
}
public static Card getKilledByTargeting(final SpellAbility sa, CardCollectionView validCards) {
CardCollection killables = CardLists.filter(validCards, new Predicate<Card>() {
@Override
public boolean apply(final Card c) {
return c.getController() != sa.getActivatingPlayer() && c.getSVar("Targeting").equals("Dies");
}
});
CardCollection killables = CardLists.filter(validCards, c -> c.getController() != sa.getActivatingPlayer() && c.getSVar("Targeting").equals("Dies"));
return ComputerUtilCard.getBestCreatureAI(killables);
}
@@ -3233,12 +3192,7 @@ public class ComputerUtil {
CardCollectionView inHand = ai.getCardsIn(ZoneType.Hand);
CardCollectionView inDeck = ai.getCardsIn(ZoneType.Library);
Predicate<Card> markedAsReanimator = new Predicate<Card>() {
@Override
public boolean apply(Card card) {
return "true".equalsIgnoreCase(card.getSVar("IsReanimatorCard"));
}
};
Predicate<Card> markedAsReanimator = card -> "true".equalsIgnoreCase(card.getSVar("IsReanimatorCard"));
int numInHand = CardLists.count(inHand, markedAsReanimator);
int numInDeck = CardLists.count(inDeck, markedAsReanimator);
@@ -3271,12 +3225,7 @@ public class ComputerUtil {
value = ComputerUtilCard.evaluateCreature(source);
}
final int totalValue = value;
list = CardLists.filter(srcList, new Predicate<Card>() {
@Override
public boolean apply(final Card c) {
return ComputerUtilCard.evaluateCreature(c) > totalValue + 30;
}
});
list = CardLists.filter(srcList, c -> ComputerUtilCard.evaluateCreature(c) > totalValue + 30);
} else {
list = CardLists.getValidCards(srcList, sa.getParam("AITgts"), sa.getActivatingPlayer(), source, sa);
}

View File

@@ -4,7 +4,6 @@ import java.util.Comparator;
import java.util.Iterator;
import java.util.List;
import com.google.common.base.Predicate;
import com.google.common.collect.Lists;
import forge.card.CardStateName;
@@ -38,9 +37,7 @@ public class ComputerUtilAbility {
CardCollection landList = CardLists.filter(hand, Presets.LANDS);
//filter out cards that can't be played
landList = CardLists.filter(landList, new Predicate<Card>() {
@Override
public boolean apply(final Card c) {
landList = CardLists.filter(landList, c -> {
if (!c.getSVar("NeedsToPlay").isEmpty()) {
final String needsToPlay = c.getSVar("NeedsToPlay");
CardCollection list = CardLists.getValidCards(game.getCardsIn(ZoneType.Battlefield), needsToPlay, c.getController(), c, null);
@@ -49,7 +46,6 @@ public class ComputerUtilAbility {
}
}
return player.canPlayLand(c);
}
});
final CardCollection landsNotInHand = new CardCollection(player.getCardsIn(ZoneType.Graveyard));

View File

@@ -58,12 +58,7 @@ public class ComputerUtilCard {
public static Card getMostExpensivePermanentAI(final CardCollectionView list, final SpellAbility spell, final boolean targeted) {
CardCollectionView all = list;
if (targeted) {
all = CardLists.filter(all, new Predicate<Card>() {
@Override
public boolean apply(final Card c) {
return c.canBeTargetedBy(spell);
}
});
all = CardLists.filter(all, c -> c.canBeTargetedBy(spell));
}
return getMostExpensivePermanentAI(all);
}
@@ -96,7 +91,7 @@ public class ComputerUtilCard {
return null;
}
// get biggest Artifact
return Aggregates.itemWithMax(all, CardPredicates.Accessors.fnGetCmc);
return Aggregates.itemWithMax(all, Card::getCMC);
}
/**
@@ -111,7 +106,7 @@ public class ComputerUtilCard {
return null;
}
// no AI logic, just return most expensive
return Aggregates.itemWithMax(all, CardPredicates.Accessors.fnGetCmc);
return Aggregates.itemWithMax(all, Card::getCMC);
}
/**
@@ -126,7 +121,7 @@ public class ComputerUtilCard {
return null;
}
// no AI logic, just return least expensive
return Aggregates.itemWithMin(all, CardPredicates.Accessors.fnGetCmc);
return Aggregates.itemWithMin(all, Card::getCMC);
}
public static Card getBestPlaneswalkerToDamage(final List<Card> pws) {
@@ -194,16 +189,11 @@ public class ComputerUtilCard {
public static Card getBestEnchantmentAI(final List<Card> list, final SpellAbility spell, final boolean targeted) {
List<Card> all = CardLists.filter(list, CardPredicates.Presets.ENCHANTMENTS);
if (targeted) {
all = CardLists.filter(all, new Predicate<Card>() {
@Override
public boolean apply(final Card c) {
return c.canBeTargetedBy(spell);
}
});
all = CardLists.filter(all, c -> c.canBeTargetedBy(spell));
}
// get biggest Enchantment
return Aggregates.itemWithMax(all, CardPredicates.Accessors.fnGetCmc);
return Aggregates.itemWithMax(all, Card::getCMC);
}
/**
@@ -342,12 +332,7 @@ public class ComputerUtilCard {
*/
public static Card getCheapestPermanentAI(Iterable<Card> all, final SpellAbility spell, final boolean targeted) {
if (targeted) {
all = CardLists.filter(all, new Predicate<Card>() {
@Override
public boolean apply(final Card c) {
return c.canBeTargetedBy(spell);
}
});
all = CardLists.filter(all, c -> c.canBeTargetedBy(spell));
}
if (Iterables.isEmpty(all)) {
return null;
@@ -524,12 +509,10 @@ public class ComputerUtilCard {
}
if (hasEnchantmants || hasArtifacts) {
final List<Card> ae = CardLists.filter(list, Predicates.and(Predicates.or(CardPredicates.Presets.ARTIFACTS, CardPredicates.Presets.ENCHANTMENTS), new Predicate<Card>() {
@Override
public boolean apply(Card card) {
return !card.hasSVar("DoNotDiscardIfAble");
}
}));
final List<Card> ae = CardLists.filter(list, Predicates.and(
Predicates.or(CardPredicates.Presets.ARTIFACTS, CardPredicates.Presets.ENCHANTMENTS),
card -> !card.hasSVar("DoNotDiscardIfAble")
));
return getCheapestPermanentAI(ae, null, false);
}
@@ -568,18 +551,10 @@ public class ComputerUtilCard {
return null;
}
public static final Comparator<Card> EvaluateCreatureComparator = new Comparator<Card>() {
@Override
public int compare(final Card a, final Card b) {
return evaluateCreature(b) - evaluateCreature(a);
}
};
public static final Comparator<SpellAbility> EvaluateCreatureSpellComparator = new Comparator<SpellAbility>() {
@Override
public int compare(final SpellAbility a, final SpellAbility b) {
public static final Comparator<Card> EvaluateCreatureComparator = (a, b) -> evaluateCreature(b) - evaluateCreature(a);
public static final Comparator<SpellAbility> EvaluateCreatureSpellComparator = (a, b) -> {
// TODO ideally we could reuse the value from the previous pass with false
return ComputerUtilAbility.saEvaluator.compareEvaluator(a, b, true);
}
};
private static final CreatureEvaluator creatureEvaluator = new CreatureEvaluator();
@@ -774,7 +749,7 @@ public class ComputerUtilCard {
// Add all cost of all auras with the same controller
if (card.isEnchanted()) {
final List<Card> auras = CardLists.filterControlledBy(card.getEnchantedBy(), card.getController());
curCMC += Aggregates.sum(auras, CardPredicates.Accessors.fnGetCmc) + auras.size();
curCMC += Aggregates.sum(auras, Card::getCMC) + auras.size();
}
if (curCMC >= bigCMC) {
@@ -990,12 +965,7 @@ public class ComputerUtilCard {
if (color.hasGreen()) map.get(4).setValue(map.get(4).getValue() + 1);
}
Collections.sort(map, new Comparator<Pair<Byte, Integer>>() {
@Override
public int compare(Pair<Byte, Integer> o1, Pair<Byte, Integer> o2) {
return o2.getValue() - o1.getValue();
}
});
Collections.sort(map, Comparator.<Pair<Byte, Integer>>comparingInt(Pair::getValue).reversed());
// will this part be once dropped?
List<String> result = new ArrayList<>(cntColors);
@@ -1006,9 +976,7 @@ public class ComputerUtilCard {
return result;
}
public static final Predicate<Deck> AI_KNOWS_HOW_TO_PLAY_ALL_CARDS = new Predicate<Deck>() {
@Override
public boolean apply(Deck d) {
public static final Predicate<Deck> AI_KNOWS_HOW_TO_PLAY_ALL_CARDS = d -> {
for (Entry<DeckSection, CardPool> cp : d) {
for (Entry<PaperCard, Integer> e : cp.getValue()) {
if (e.getKey().getRules().getAiHints().getRemAIDecks())
@@ -1016,7 +984,6 @@ public class ComputerUtilCard {
}
}
return true;
}
};
public static List<String> chooseColor(SpellAbility sa, int min, int max, List<String> colorChoices) {

View File

@@ -17,7 +17,6 @@
*/
package forge.ai;
import com.google.common.base.Predicate;
import com.google.common.collect.Iterables;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
@@ -79,11 +78,7 @@ public class ComputerUtilCombat {
*/
public static boolean canAttackNextTurn(final Card attacker) {
final Iterable<GameEntity> defenders = CombatUtil.getAllPossibleDefenders(attacker.getController());
return Iterables.any(defenders, new Predicate<GameEntity>() {
@Override public boolean apply(final GameEntity input) {
return canAttackNextTurn(attacker, input);
}
});
return Iterables.any(defenders, input -> canAttackNextTurn(attacker, input));
}
/**
@@ -138,12 +133,7 @@ public class ComputerUtilCombat {
*/
public static int getTotalFirstStrikeBlockPower(final Card attacker, final Player player) {
List<Card> list = player.getCreaturesInPlay();
list = CardLists.filter(list, new Predicate<Card>() {
@Override
public boolean apply(final Card c) {
return (c.hasFirstStrike() || c.hasDoubleStrike()) && CombatUtil.canBlock(attacker, c);
}
});
list = CardLists.filter(list, c -> (c.hasFirstStrike() || c.hasDoubleStrike()) && CombatUtil.canBlock(attacker, c));
return totalFirstStrikeDamageOfBlockers(attacker, list);
}

View File

@@ -1,6 +1,5 @@
package forge.ai;
import com.google.common.base.Predicate;
import com.google.common.base.Predicates;
import com.google.common.collect.Iterables;
import com.google.common.collect.Lists;
@@ -472,12 +471,7 @@ public class ComputerUtilCost {
String totalP = type.split("withTotalPowerGE")[1];
type = TextUtil.fastReplace(type, TextUtil.concatNoSpace("+withTotalPowerGE", totalP), "");
CardCollection exclude = CardLists.getValidCards(ai.getCardsIn(ZoneType.Battlefield), type.split(";"), source.getController(), source, sa);
exclude = CardLists.filter(exclude, new Predicate<Card>() {
@Override
public boolean apply(final Card c) {
return ComputerUtilCard.evaluateCreature(c) >= vehicleValue;
}
}); // exclude creatures >= vehicle
exclude = CardLists.filter(exclude, c -> ComputerUtilCard.evaluateCreature(c) >= vehicleValue); // exclude creatures >= vehicle
exclude.addAll(alreadyTapped);
CardCollection tappedCrew = ComputerUtil.chooseTapTypeAccumulatePower(ai, type, sa, true, Integer.parseInt(totalP), exclude);
if (tappedCrew != null) {
@@ -616,18 +610,15 @@ public class ComputerUtilCost {
CardCollectionView nonManaSources =
CardLists.getValidCards(player.getCardsIn(ZoneType.Battlefield), part.getType().split(";"),
sa.getActivatingPlayer(), sa.getHostCard(), sa);
nonManaSources = CardLists.filter(nonManaSources, new Predicate<Card>() {
@Override
public boolean apply(Card card) {
nonManaSources = CardLists.filter(nonManaSources, card -> {
boolean hasManaSa = false;
for (final SpellAbility sa : card.getSpellAbilities()) {
if (sa.isManaAbility() && sa.getPayCosts().hasTapCost()) {
for (final SpellAbility sa1 : card.getSpellAbilities()) {
if (sa1.isManaAbility() && sa1.getPayCosts().hasTapCost()) {
hasManaSa = true;
break;
}
}
return !hasManaSa;
}
});
if (nonManaSources.size() < part.convertAmount()) {
return false;

View File

@@ -1,6 +1,5 @@
package forge.ai;
import com.google.common.base.Predicate;
import com.google.common.base.Predicates;
import com.google.common.collect.*;
import forge.ai.AiCardMemory.MemorySet;
@@ -126,12 +125,7 @@ public class ComputerUtilMana {
}
}
}
orderedCards.sort(new Comparator<Card>() {
@Override
public int compare(final Card card1, final Card card2) {
return Integer.compare(manaCardMap.get(card1), manaCardMap.get(card2));
}
});
orderedCards.sort(Comparator.comparingInt(manaCardMap::get));
if (DEBUG_MANA_PAYMENT) {
System.out.print("Ordered Cards: " + orderedCards.size());
@@ -149,9 +143,7 @@ public class ComputerUtilMana {
System.out.println("Unsorted Abilities: " + newAbilities);
}
newAbilities.sort(new Comparator<SpellAbility>() {
@Override
public int compare(final SpellAbility ability1, final SpellAbility ability2) {
newAbilities.sort((ability1, ability2) -> {
int preOrder = orderedCards.indexOf(ability1.getHostCard()) - orderedCards.indexOf(ability2.getHostCard());
if (preOrder != 0) {
@@ -171,7 +163,6 @@ public class ComputerUtilMana {
}
return ability1.compareTo(ability2);
}
});
if (DEBUG_MANA_PAYMENT) {
@@ -195,27 +186,21 @@ public class ComputerUtilMana {
final List<SpellAbility> prefSortedAbilities = new ArrayList<>(newAbilities);
final List<SpellAbility> otherSortedAbilities = new ArrayList<>(newAbilities);
prefSortedAbilities.sort(new Comparator<SpellAbility>() {
@Override
public int compare(final SpellAbility ability1, final SpellAbility ability2) {
prefSortedAbilities.sort((ability1, ability2) -> {
if (ability1.getManaPart().mana(ability1).contains(preferredShard))
return -1;
else if (ability2.getManaPart().mana(ability2).contains(preferredShard))
return 1;
return 0;
}
});
otherSortedAbilities.sort(new Comparator<SpellAbility>() {
@Override
public int compare(final SpellAbility ability1, final SpellAbility ability2) {
otherSortedAbilities.sort((ability1, ability2) -> {
if (ability1.getManaPart().mana(ability1).contains(preferredShard))
return 1;
else if (ability2.getManaPart().mana(ability2).contains(preferredShard))
return -1;
return 0;
}
});
final List<SpellAbility> finalAbilities = new ArrayList<>();
@@ -251,24 +236,14 @@ public class ComputerUtilMana {
List<SpellAbility> filteredList = Lists.newArrayList(saList);
switch (manaSourceType) {
case "Snow":
filteredList.sort(new Comparator<SpellAbility>() {
@Override
public int compare(SpellAbility ab1, SpellAbility ab2) {
return ab1.getHostCard() != null && ab1.getHostCard().isSnow()
&& ab2.getHostCard() != null && !ab2.getHostCard().isSnow() ? -1 : 1;
}
});
filteredList.sort((ab1, ab2) -> ab1.getHostCard() != null && ab1.getHostCard().isSnow()
&& ab2.getHostCard() != null && !ab2.getHostCard().isSnow() ? -1 : 1);
saList = filteredList;
break;
case "Treasure":
// Try to spend only one Treasure if possible
filteredList.sort(new Comparator<SpellAbility>() {
@Override
public int compare(SpellAbility ab1, SpellAbility ab2) {
return ab1.getHostCard() != null && ab1.getHostCard().getType().hasSubtype("Treasure")
&& ab2.getHostCard() != null && !ab2.getHostCard().getType().hasSubtype("Treasure") ? -1 : 1;
}
});
filteredList.sort((ab1, ab2) -> ab1.getHostCard() != null && ab1.getHostCard().getType().hasSubtype("Treasure")
&& ab2.getHostCard() != null && !ab2.getHostCard().getType().hasSubtype("Treasure") ? -1 : 1);
SpellAbility first = filteredList.get(0);
if (first.getHostCard() != null && first.getHostCard().getType().hasSubtype("Treasure")) {
saList.remove(first);
@@ -280,22 +255,12 @@ public class ComputerUtilMana {
break;
case "TreasureMax":
// Ok to spend as many Treasures as possible
filteredList.sort(new Comparator<SpellAbility>() {
@Override
public int compare(SpellAbility ab1, SpellAbility ab2) {
return ab1.getHostCard() != null && ab1.getHostCard().getType().hasSubtype("Treasure")
&& ab2.getHostCard() != null && !ab2.getHostCard().getType().hasSubtype("Treasure") ? -1 : 1;
}
});
filteredList.sort((ab1, ab2) -> ab1.getHostCard() != null && ab1.getHostCard().getType().hasSubtype("Treasure")
&& ab2.getHostCard() != null && !ab2.getHostCard().getType().hasSubtype("Treasure") ? -1 : 1);
saList = filteredList;
break;
case "NotSameCard":
saList = Lists.newArrayList(Iterables.filter(filteredList, new Predicate<SpellAbility>() {
@Override
public boolean apply(final SpellAbility saPay) {
return !saPay.getHostCard().getName().equals(sa.getHostCard().getName());
}
}));
saList = Lists.newArrayList(Iterables.filter(filteredList, saPay -> !saPay.getHostCard().getName().equals(sa.getHostCard().getName())));
break;
default:
break;
@@ -1096,12 +1061,7 @@ public class ComputerUtilMana {
private static ManaCostShard getNextShardToPay(ManaCostBeingPaid cost, Multimap<ManaCostShard, SpellAbility> sourcesForShards) {
List<ManaCostShard> shardsToPay = Lists.newArrayList(cost.getDistinctShards());
// optimize order so that the shards with less available sources are considered first
shardsToPay.sort(new Comparator<ManaCostShard>() {
@Override
public int compare(final ManaCostShard shard1, final ManaCostShard shard2) {
return sourcesForShards.get(shard1).size() - sourcesForShards.get(shard2).size();
}
});
shardsToPay.sort(Comparator.comparingInt(shard -> sourcesForShards.get(shard).size()));
// mind the priorities
// * Pay mono-colored first
// * Pay 2/C with matching colors
@@ -1387,12 +1347,7 @@ public class ComputerUtilMana {
public static int getAvailableManaEstimate(final Player p, final boolean checkPlayable) {
int availableMana = 0;
final List<Card> srcs = CardLists.filter(p.getCardsIn(ZoneType.Battlefield), new Predicate<Card>() {
@Override
public boolean apply(final Card c) {
return !c.getManaAbilities().isEmpty();
}
});
final List<Card> srcs = CardLists.filter(p.getCardsIn(ZoneType.Battlefield), c -> !c.getManaAbilities().isEmpty());
int maxProduced = 0;
int producedWithCost = 0;
@@ -1437,9 +1392,7 @@ public class ComputerUtilMana {
//This method is currently used by AI to estimate available mana
public static CardCollection getAvailableManaSources(final Player ai, final boolean checkPlayable) {
final CardCollectionView list = CardCollection.combine(ai.getCardsIn(ZoneType.Battlefield), ai.getCardsIn(ZoneType.Hand));
final List<Card> manaSources = CardLists.filter(list, new Predicate<Card>() {
@Override
public boolean apply(final Card c) {
final List<Card> manaSources = CardLists.filter(list, c -> {
for (final SpellAbility am : getAIPlayableMana(c)) {
am.setActivatingPlayer(ai, true);
if (!checkPlayable || (am.canPlay() && am.checkRestrictions(ai))) {
@@ -1447,7 +1400,6 @@ public class ComputerUtilMana {
}
}
return false;
}
}); // CardListFilter
final CardCollection sortedManaSources = new CardCollection();

View File

@@ -570,12 +570,9 @@ public class PlayerControllerAi extends PlayerController {
if (destinationZone == ZoneType.Graveyard) {
// In presence of Volrath's Shapeshifter in deck, try to place the best creature on top of the graveyard
if (Iterables.any(getGame().getCardsInGame(), new Predicate<Card>() {
@Override
public boolean apply(Card card) {
if (Iterables.any(getGame().getCardsInGame(), card -> {
// need a custom predicate here since Volrath's Shapeshifter may have a different name OTB
return card.getOriginalState(CardStateName.Original).getName().equals("Volrath's Shapeshifter");
}
})) {
int bestValue = 0;
Card bestCreature = null;
@@ -702,7 +699,7 @@ public class PlayerControllerAi extends PlayerController {
public CardCollectionView chooseCardsToDiscardUnlessType(int num, CardCollectionView hand, String uType, SpellAbility sa) {
Iterable<Card> cardsOfType = Iterables.filter(hand, CardPredicates.restriction(uType.split(","), sa.getActivatingPlayer(), sa.getHostCard(), sa));
if (!Iterables.isEmpty(cardsOfType)) {
Card toDiscard = Aggregates.itemWithMin(cardsOfType, CardPredicates.Accessors.fnGetCmc);
Card toDiscard = Aggregates.itemWithMin(cardsOfType, Card::getCMC);
return new CardCollection(toDiscard);
}
return getAi().getCardsToDiscard(num, null, sa);
@@ -1389,21 +1386,12 @@ public class PlayerControllerAi extends PlayerController {
final Player ai = sa.getActivatingPlayer();
final PhaseHandler ph = ai.getGame().getPhaseHandler();
//Filter out mana sources that will interfere with payManaCost()
CardCollection untapped = CardLists.filter(untappedCards, new Predicate<Card>() {
@Override
public boolean apply(final Card c) {
return c.getManaAbilities().isEmpty();
}
});
CardCollection untapped = CardLists.filter(untappedCards, c -> c.getManaAbilities().isEmpty());
// Filter out creatures if AI hasn't attacked yet
if (ph.isPlayerTurn(ai) && ph.getPhase().isBefore(PhaseType.COMBAT_DECLARE_ATTACKERS)) {
if (improvise) {
untapped = CardLists.filter(untapped, new Predicate<Card>() {
@Override
public boolean apply(final Card c) {return !c.isCreature();
}
});
untapped = CardLists.filter(untapped, c -> !c.isCreature());
} else {
return new HashMap<>();
}

View File

@@ -1,6 +1,5 @@
package forge.ai;
import com.google.common.base.Predicate;
import com.google.common.collect.Iterables;
import com.google.common.collect.Sets;
@@ -91,13 +90,10 @@ public class SpecialAiLogic {
bestOwnCardToUpgrade = Iterables.getFirst(CardLists.getKeyword(listOwn, Keyword.INDESTRUCTIBLE), null);
}
if (bestOwnCardToUpgrade == null) {
bestOwnCardToUpgrade = ComputerUtilCard.getWorstCreatureAI(CardLists.filter(listOwn, new Predicate<Card>() {
@Override
public boolean apply(Card card) {
return card.isCreature() && (ComputerUtilCard.isUselessCreature(ai, card)
|| ComputerUtilCard.evaluateCreature(token) > 2 * ComputerUtilCard.evaluateCreature(card));
}
}));
bestOwnCardToUpgrade = ComputerUtilCard.getWorstCreatureAI(CardLists.filter(listOwn, card -> card.isCreature()
&& (ComputerUtilCard.isUselessCreature(ai, card)
|| ComputerUtilCard.evaluateCreature(token) > 2 * ComputerUtilCard.evaluateCreature(card))
));
}
if (bestOwnCardToUpgrade != null) {
if (ComputerUtilCard.isUselessCreature(ai, bestOwnCardToUpgrade) || (ph.getPhase().isAfter(PhaseType.COMBAT_END) || !ph.isPlayerTurn(ai))) {
@@ -145,14 +141,9 @@ public class SpecialAiLogic {
if (indestructible || (source.getNetToughness() <= dmg && source.getNetToughness() + toughnessBonus * numCreatsToSac > dmg)) {
final CardCollection sacFodder = CardLists.filter(ai.getCreaturesInPlay(),
new Predicate<Card>() {
@Override
public boolean apply(Card card) {
return ComputerUtilCard.isUselessCreature(ai, card)
card -> ComputerUtilCard.isUselessCreature(ai, card)
|| card.hasSVar("SacMe")
|| ComputerUtilCard.evaluateCreature(card) < selfEval; // Maybe around 150 is OK?
}
}
|| ComputerUtilCard.evaluateCreature(card) < selfEval // Maybe around 150 is OK?
);
return sacFodder.size() >= numCreatsToSac;
}
@@ -196,21 +187,16 @@ public class SpecialAiLogic {
// We have already attacked. Thus, see if we have a creature to sac that is worse to lose
// than the card we attacked with.
final CardCollection sacTgts = CardLists.filter(ai.getCreaturesInPlay(),
new Predicate<Card>() {
@Override
public boolean apply(Card card) {
return ComputerUtilCard.isUselessCreature(ai, card)
|| ComputerUtilCard.evaluateCreature(card) < selfEval;
}
}
card -> ComputerUtilCard.isUselessCreature(ai, card)
|| ComputerUtilCard.evaluateCreature(card) < selfEval
);
if (sacTgts.isEmpty()) {
return false;
}
final int minDefT = Aggregates.min(combat.getBlockers(source), CardPredicates.Accessors.fnGetNetToughness);
final int DefP = indestructible ? 0 : Aggregates.sum(combat.getBlockers(source), CardPredicates.Accessors.fnGetNetPower);
final int minDefT = Aggregates.min(combat.getBlockers(source), Card::getNetToughness);
final int DefP = indestructible ? 0 : Aggregates.sum(combat.getBlockers(source), Card::getNetPower);
// Make sure we don't over-sacrifice, only sac until we can survive and kill a creature
return source.getNetToughness() - source.getDamage() <= DefP || source.getNetCombatDamage() < minDefT;
@@ -218,14 +204,9 @@ public class SpecialAiLogic {
} else {
// We can't deal lethal, check if there's any sac fodder than can be used for other circumstances
final CardCollection sacFodder = CardLists.filter(ai.getCreaturesInPlay(),
new Predicate<Card>() {
@Override
public boolean apply(Card card) {
return ComputerUtilCard.isUselessCreature(ai, card)
card -> ComputerUtilCard.isUselessCreature(ai, card)
|| card.hasSVar("SacMe")
|| ComputerUtilCard.evaluateCreature(card) < selfEval; // Maybe around 150 is OK?
}
}
|| ComputerUtilCard.evaluateCreature(card) < selfEval // Maybe around 150 is OK?
);
return !sacFodder.isEmpty();
@@ -302,13 +283,8 @@ public class SpecialAiLogic {
// Check if there's anything that will die anyway that can be eaten to gain a perma-bonus
final CardCollection forcedSacTgts = CardLists.filter(relevantCreats,
new Predicate<Card>() {
@Override
public boolean apply(Card card) {
return ComputerUtil.predictThreatenedObjects(ai, null, true).contains(card)
|| (combat.isAttacking(card) && combat.isBlocked(card) && ComputerUtilCombat.combatantWouldBeDestroyed(ai, card, combat));
}
}
card -> ComputerUtil.predictThreatenedObjects(ai, null, true).contains(card)
|| (combat.isAttacking(card) && combat.isBlocked(card) && ComputerUtilCombat.combatantWouldBeDestroyed(ai, card, combat))
);
if (!forcedSacTgts.isEmpty()) {
return true;
@@ -327,14 +303,9 @@ public class SpecialAiLogic {
// than the card we attacked with. Since we're getting a permanent bonus, consider sacrificing
// things that are also threatened to be destroyed anyway.
final CardCollection sacTgts = CardLists.filter(relevantCreats,
new Predicate<Card>() {
@Override
public boolean apply(Card card) {
return ComputerUtilCard.isUselessCreature(ai, card)
card -> ComputerUtilCard.isUselessCreature(ai, card)
|| ComputerUtilCard.evaluateCreature(card) < selfEval
|| ComputerUtil.predictThreatenedObjects(ai, null, true).contains(card);
}
}
|| ComputerUtil.predictThreatenedObjects(ai, null, true).contains(card)
);
if (sacTgts.isEmpty()) {
@@ -342,8 +313,8 @@ public class SpecialAiLogic {
}
final boolean sourceCantDie = ComputerUtilCombat.combatantCantBeDestroyed(ai, source);
final int minDefT = Aggregates.min(combat.getBlockers(source), CardPredicates.Accessors.fnGetNetToughness);
final int DefP = sourceCantDie ? 0 : Aggregates.sum(combat.getBlockers(source), CardPredicates.Accessors.fnGetNetPower);
final int minDefT = Aggregates.min(combat.getBlockers(source), Card::getNetToughness);
final int DefP = sourceCantDie ? 0 : Aggregates.sum(combat.getBlockers(source), Card::getNetPower);
// Make sure we don't over-sacrifice, only sac until we can survive and kill a creature
return source.getNetToughness() - source.getDamage() <= DefP || source.getNetCombatDamage() < minDefT;
@@ -352,15 +323,10 @@ public class SpecialAiLogic {
// We can't deal lethal, check if there's any sac fodder than can be used for other circumstances
final boolean isBlocking = combat != null && combat.isBlocking(source);
final CardCollection sacFodder = CardLists.filter(relevantCreats,
new Predicate<Card>() {
@Override
public boolean apply(Card card) {
return ComputerUtilCard.isUselessCreature(ai, card)
card -> ComputerUtilCard.isUselessCreature(ai, card)
|| card.hasSVar("SacMe")
|| (isBlocking && ComputerUtilCard.evaluateCreature(card) < selfEval)
|| ComputerUtil.predictThreatenedObjects(ai, null, true).contains(card);
}
}
|| ComputerUtil.predictThreatenedObjects(ai, null, true).contains(card)
);
return !sacFodder.isEmpty();

View File

@@ -17,7 +17,6 @@
*/
package forge.ai;
import com.google.common.base.Predicate;
import com.google.common.base.Predicates;
import com.google.common.collect.Iterables;
import com.google.common.collect.Lists;
@@ -478,8 +477,8 @@ public class SpecialCardAi {
boolean cantDie = ComputerUtilCombat.combatantCantBeDestroyed(ai, source);
CardCollection opposition = isBlocking ? combat.getAttackersBlockedBy(source) : combat.getBlockers(source);
int oppP = Aggregates.sum(opposition, CardPredicates.Accessors.fnGetAttack);
int oppT = Aggregates.sum(opposition, CardPredicates.Accessors.fnGetNetToughness);
int oppP = Aggregates.sum(opposition, Card::getNetCombatDamage);
int oppT = Aggregates.sum(opposition, Card::getNetToughness);
boolean oppHasFirstStrike = false;
boolean oppCantDie = true;
@@ -561,7 +560,7 @@ public class SpecialCardAi {
}
Pair<Integer, Integer> predictedPT = getPumpedPT(ai, source.getNetCombatDamage(), source.getNetToughness());
int oppT = Aggregates.sum(potentialBlockers, CardPredicates.Accessors.fnGetNetToughness);
int oppT = Aggregates.sum(potentialBlockers, Card::getNetToughness);
return potentialBlockers.isEmpty() || (source.hasKeyword(Keyword.TRAMPLE) && predictedPT.getLeft() - oppT >= oppLife);
}
@@ -754,28 +753,23 @@ public class SpecialCardAi {
public static Card getBestAttachTarget(final Player ai, final SpellAbility sa, final List<Card> list) {
Card chosen = null;
List<Card> aiStuffies = CardLists.filter(list, new Predicate<Card>() {
@Override
public boolean apply(final Card c) {
List<Card> aiStuffies = CardLists.filter(list, c -> {
// Don't enchant creatures that can survive
if (!c.getController().equals(ai)) {
return false;
}
final String name = c.getName();
return name.equals("Stuffy Doll") || name.equals("Boros Reckoner") || name.equals("Spitemare");
}
});
if (!aiStuffies.isEmpty()) {
chosen = aiStuffies.get(0);
} else {
List<Card> creatures = CardLists.filterControlledBy(list, ai.getOpponents());
creatures = CardLists.filter(creatures, new Predicate<Card>() {
@Override
public boolean apply(final Card c) {
// Don't enchant creatures that can survive
return c.canBeDestroyed() && c.getNetCombatDamage() >= c.getNetToughness() && !c.isEnchantedBy("Guilty Conscience");
}
});
creatures = CardLists.filter(creatures, c -> c.canBeDestroyed()
&& c.getNetCombatDamage() >= c.getNetToughness()
&& !c.isEnchantedBy("Guilty Conscience")
);
chosen = ComputerUtilCard.getBestCreatureAI(creatures);
}
@@ -1385,12 +1379,7 @@ public class SpecialCardAi {
public static boolean considerMakeDragon(final Player ai, final SpellAbility sa) {
// TODO: expand this logic to make the AI force the opponent to sacrifice a big threat bigger than a 5/5 flier?
CardCollection creatures = ai.getCreaturesInPlay();
boolean hasValidTgt = !CardLists.filter(creatures, new Predicate<Card>() {
@Override
public boolean apply(Card t) {
return t.getNetPower() < 5 && t.getNetToughness() < 5;
}
}).isEmpty();
boolean hasValidTgt = !CardLists.filter(creatures, t -> t.getNetPower() < 5 && t.getNetToughness() < 5).isEmpty();
if (hasValidTgt) {
Card worstCreature = ComputerUtilCard.getWorstCreatureAI(creatures);
sa.getTargets().add(worstCreature);
@@ -1416,12 +1405,7 @@ public class SpecialCardAi {
public static class SaviorOfOllenbock {
public static boolean consider(final Player ai, final SpellAbility sa) {
CardCollection oppTargetables = CardLists.getTargetableCards(ai.getOpponents().getCreaturesInPlay(), sa);
CardCollection threats = CardLists.filter(oppTargetables, new Predicate<Card>() {
@Override
public boolean apply(Card card) {
return !ComputerUtilCard.isUselessCreature(card.getController(), card);
}
});
CardCollection threats = CardLists.filter(oppTargetables, card -> !ComputerUtilCard.isUselessCreature(card.getController(), card));
CardCollection ownTgts = CardLists.filter(ai.getCardsIn(ZoneType.Graveyard), CardPredicates.Presets.CREATURES);
// TODO: improve the conditions for when the AI is considered threatened (check the possibility of being attacked?)
@@ -1462,13 +1446,10 @@ public class SpecialCardAi {
public static boolean consider(final Player ai, final SpellAbility sa) {
int loyalty = sa.getHostCard().getCounters(CounterEnumType.LOYALTY);
CardCollection creaturesToGet = CardLists.filter(ai.getCardsIn(ZoneType.Graveyard),
Predicates.and(CardPredicates.Presets.CREATURES, CardPredicates.lessCMC(loyalty - 1), new Predicate<Card>() {
@Override
public boolean apply(Card card) {
Predicates.and(CardPredicates.Presets.CREATURES, CardPredicates.lessCMC(loyalty - 1), card -> {
final Card copy = CardCopyService.getLKICopy(card);
ComputerUtilCard.applyStaticContPT(ai.getGame(), copy, null);
return copy.getNetToughness() > 0;
}
}));
CardLists.sortByCmcDesc(creaturesToGet);
@@ -1515,12 +1496,9 @@ public class SpecialCardAi {
// Cards in library that are either below/at (preferred) or above the max CMC affordable by the AI
// (the latter might happen if we're playing a Reanimator deck with lots of fatties)
CardCollection atTargetCMCInLib = CardLists.filter(creatsInLib, new Predicate<Card>() {
@Override
public boolean apply(Card card) {
return ComputerUtilMana.hasEnoughManaSourcesToCast(card.getSpellPermanent(), ai);
}
});
CardCollection atTargetCMCInLib = CardLists.filter(creatsInLib,
card -> ComputerUtilMana.hasEnoughManaSourcesToCast(card.getSpellPermanent(), ai)
);
if (atTargetCMCInLib.isEmpty()) {
atTargetCMCInLib = CardLists.filter(creatsInLib, CardPredicates.greaterCMC(numManaSrcs));
}
@@ -1585,12 +1563,9 @@ public class SpecialCardAi {
int numManaSrcs = ComputerUtilMana.getAvailableManaEstimate(ai, false)
+ Math.min(1, manaSrcsInHand.size());
CardCollection atTargetCMCInLib = CardLists.filter(creatsInLib, new Predicate<Card>() {
@Override
public boolean apply(Card card) {
return ComputerUtilMana.hasEnoughManaSourcesToCast(card.getSpellPermanent(), ai);
}
});
CardCollection atTargetCMCInLib = CardLists.filter(creatsInLib,
card -> ComputerUtilMana.hasEnoughManaSourcesToCast(card.getSpellPermanent(), ai)
);
if (atTargetCMCInLib.isEmpty()) {
atTargetCMCInLib = CardLists.filter(creatsInLib, CardPredicates.greaterCMC(numManaSrcs));
}

View File

@@ -5,7 +5,6 @@ import java.util.*;
import forge.game.card.*;
import org.apache.commons.lang3.ObjectUtils;
import com.google.common.base.Predicate;
import com.google.common.base.Predicates;
import com.google.common.collect.Lists;
import com.google.common.collect.Sets;
@@ -333,9 +332,7 @@ public class AttachAi extends SpellAbilityAi {
list = CardLists.getNotType(list, type); // Filter out Basic Lands that have the same type as the changing type
// Don't target fetchlands
list = CardLists.filter(list, new Predicate<Card>() {
@Override
public boolean apply(final Card c) {
list = CardLists.filter(list, c -> {
//Check for cards that can be sacrificed in response
for (final SpellAbility ability : c.getAllSpellAbilities()) {
if (ability.isActivatedAbility()) {
@@ -352,7 +349,6 @@ public class AttachAi extends SpellAbilityAi {
}
}
return true;
}
});
final Card c = ComputerUtilCard.getBestAI(list);
@@ -385,9 +381,7 @@ public class AttachAi extends SpellAbilityAi {
*/
private static Card attachAIKeepTappedPreference(final SpellAbility sa, final List<Card> list, final boolean mandatory, final Card attachSource) {
// AI For Cards like Paralyzing Grasp and Glimmerdust Nap
final List<Card> prefList = CardLists.filter(list, new Predicate<Card>() {
@Override
public boolean apply(final Card c) {
final List<Card> prefList = CardLists.filter(list, c -> {
// Don't do Untapped Vigilance cards
if (c.isCreature() && c.hasKeyword(Keyword.VIGILANCE) && c.isUntapped()) {
return false;
@@ -421,7 +415,6 @@ public class AttachAi extends SpellAbilityAi {
}
return true;
}
});
final Card c = ComputerUtilCard.getBestAI(prefList);
@@ -506,24 +499,14 @@ public class AttachAi extends SpellAbilityAi {
if (list.isEmpty()) {
return null;
}
Card c = null;
Card card = null;
// AI For choosing a Card to Animate.
List<Card> betterList = CardLists.getNotType(list, "Creature");
if (ComputerUtilAbility.getAbilitySourceName(sa).equals("Animate Artifact")) {
betterList = CardLists.filter(betterList, new Predicate<Card>() {
@Override
public boolean apply(final Card c) {
return c.getCMC() > 0;
}
});
c = ComputerUtilCard.getMostExpensivePermanentAI(betterList);
betterList = CardLists.filter(betterList, c -> c.getCMC() > 0);
card = ComputerUtilCard.getMostExpensivePermanentAI(betterList);
} else {
List<Card> evenBetterList = CardLists.filter(betterList, new Predicate<Card>() {
@Override
public boolean apply(final Card c) {
return c.hasKeyword(Keyword.INDESTRUCTIBLE) || c.hasKeyword(Keyword.HEXPROOF);
}
});
List<Card> evenBetterList = CardLists.filter(betterList, c -> c.hasKeyword(Keyword.INDESTRUCTIBLE) || c.hasKeyword(Keyword.HEXPROOF));
if (!evenBetterList.isEmpty()) {
betterList = evenBetterList;
}
@@ -531,40 +514,32 @@ public class AttachAi extends SpellAbilityAi {
if (!evenBetterList.isEmpty()) {
betterList = evenBetterList;
}
evenBetterList = CardLists.filter(betterList, new Predicate<Card>() {
@Override
public boolean apply(final Card c) {
return c.getTurnInZone() != c.getGame().getPhaseHandler().getTurn();
}
});
evenBetterList = CardLists.filter(betterList, c -> c.getTurnInZone() != c.getGame().getPhaseHandler().getTurn());
if (!evenBetterList.isEmpty()) {
betterList = evenBetterList;
}
evenBetterList = CardLists.filter(betterList, new Predicate<Card>() {
@Override
public boolean apply(final Card c) {
for (final SpellAbility sa : c.getSpellAbilities()) {
if (sa.isAbility() && sa.getPayCosts().hasTapCost()) {
evenBetterList = CardLists.filter(betterList, c -> {
for (final SpellAbility sa1 : c.getSpellAbilities()) {
if (sa1.isAbility() && sa1.getPayCosts().hasTapCost()) {
return false;
}
}
return true;
}
});
if (!evenBetterList.isEmpty()) {
betterList = evenBetterList;
}
c = ComputerUtilCard.getWorstAI(betterList);
card = ComputerUtilCard.getWorstAI(betterList);
}
// If Mandatory (brought directly into play without casting) gotta
// choose something
if (c == null && mandatory) {
if (card == null && mandatory) {
return chooseLessPreferred(mandatory, list);
}
return c;
return card;
}
/**
@@ -591,9 +566,7 @@ public class AttachAi extends SpellAbilityAi {
//TODO for Reanimate Auras i need the new Attach Spell, in later versions it might be part of the Enchant Keyword
attachSourceLki.addSpellAbility(AbilityFactory.getAbility(attachSourceLki, "NewAttach"));
List<Card> betterList = CardLists.filter(list, new Predicate<Card>() {
@Override
public boolean apply(final Card c) {
List<Card> betterList = CardLists.filter(list, c -> {
final Card lki = CardCopyService.getLKICopy(c);
// need to fake it as if lki would be on the battlefield
lki.setLastKnownZone(ai.getZone(ZoneType.Battlefield));
@@ -613,7 +586,6 @@ public class AttachAi extends SpellAbilityAi {
c.getGame().getAction().checkStaticAbilities(false);
return result;
}
});
final Card c = ComputerUtilCard.getBestCreatureAI(betterList);
@@ -864,42 +836,29 @@ public class AttachAi extends SpellAbilityAi {
if (totToughness < 0) {
// Kill a creature if we can
final int tgh = totToughness;
prefList = CardLists.filter(list, new Predicate<Card>() {
@Override
public boolean apply(final Card c) {
prefList = CardLists.filter(list, c -> {
if (!c.hasKeyword(Keyword.INDESTRUCTIBLE) && (c.getLethalDamage() <= Math.abs(tgh))) {
return true;
}
return c.getNetToughness() <= Math.abs(tgh);
}
});
}
Card c = null;
Card card = null;
if (prefList == null || prefList.isEmpty()) {
prefList = new ArrayList<>(list);
} else {
c = ComputerUtilCard.getBestAI(prefList);
if (c != null) {
return c;
card = ComputerUtilCard.getBestAI(prefList);
if (card != null) {
return card;
}
}
if (!keywords.isEmpty()) {
prefList = CardLists.filter(prefList, new Predicate<Card>() {
@Override
public boolean apply(final Card c) {
return containsUsefulCurseKeyword(keywords, c, sa);
}
});
prefList = CardLists.filter(prefList, c -> containsUsefulCurseKeyword(keywords, c, sa));
} else if (totPower < 0) {
prefList = CardLists.filter(prefList, new Predicate<Card>() {
@Override
public boolean apply(final Card c) {
return c.getNetPower() > 0 && ComputerUtilCombat.canAttackNextTurn(c);
}
});
prefList = CardLists.filter(prefList, c -> c.getNetPower() > 0 && ComputerUtilCombat.canAttackNextTurn(c));
}
//some auras aren't useful in multiples
@@ -915,25 +874,22 @@ public class AttachAi extends SpellAbilityAi {
&& sa.getPayCosts() != null && sa.getPayCosts().hasSpecificCostType(CostSacrifice.class)) {
final int oldEvalRating = ComputerUtilCard.evaluateCreature(sa.getHostCard().getAttachedTo());
final int threshold = ai.isAI() ? ((PlayerControllerAi)ai.getController()).getAi().getIntProperty(AiProps.SAC_TO_REATTACH_TARGET_EVAL_THRESHOLD) : Integer.MAX_VALUE;
prefList = CardLists.filter(prefList, new Predicate<Card>() {
@Override
public boolean apply(Card card) {
if (!card.isCreature()) {
prefList = CardLists.filter(prefList, c -> {
if (!c.isCreature()) {
return false;
}
return ComputerUtilCard.evaluateCreature(card) >= oldEvalRating + threshold;
}
return ComputerUtilCard.evaluateCreature(c) >= oldEvalRating + threshold;
});
}
c = ComputerUtilCard.getBestAI(prefList);
card = ComputerUtilCard.getBestAI(prefList);
if (c == null) {
if (card == null) {
return chooseLessPreferred(mandatory, list);
}
return acceptableChoice(c, mandatory);
return acceptableChoice(card, mandatory);
}
/**
@@ -1029,41 +985,30 @@ public class AttachAi extends SpellAbilityAi {
*/
private static Card attachAIPumpPreference(final Player ai, final SpellAbility sa, final List<Card> list, final boolean mandatory, final Card attachSource) {
// AI For choosing a Card to Pump
Card c = null;
Card card = null;
List<Card> magnetList = null;
String stCheck = null;
if (attachSource.isAura() || sa.isBestow()) {
stCheck = "EnchantedBy";
magnetList = CardLists.filter(list, new Predicate<Card>() {
@Override
public boolean apply(final Card c) {
magnetList = CardLists.filter(list, c -> {
if (!c.isCreature()) {
return false;
}
String sVar = c.getSVar("EnchantMe");
return sVar.equals("Multiple") || (sVar.equals("Once") && !c.isEnchanted());
}
});
} else if (attachSource.isEquipment()) {
stCheck = "EquippedBy";
magnetList = CardLists.filter(list, new Predicate<Card>() {
@Override
public boolean apply(final Card c) {
magnetList = CardLists.filter(list, c -> {
if (!c.isCreature()) {
return false;
}
String sVar = c.getSVar("EquipMe");
return sVar.equals("Multiple") || (sVar.equals("Once") && !c.isEquipped());
}
});
} else if (attachSource.isFortification()) {
stCheck = "FortifiedBy";
magnetList = CardLists.filter(list, new Predicate<Card>() {
@Override
public boolean apply(final Card c) {
return c.isCreature() && !c.isFortified();
}
});
magnetList = CardLists.filter(list, c -> c.isCreature() && !c.isFortified());
}
// Look for triggers that will damage the creature and remove AI-owned creatures that will die
@@ -1109,23 +1054,13 @@ public class AttachAi extends SpellAbilityAi {
// Probably want to "weight" the list by amount of Enchantments and
// choose the "lightest"
List<Card> betterList = CardLists.filter(magnetList, new Predicate<Card>() {
@Override
public boolean apply(final Card c) {
return CombatUtil.canAttack(c, ai.getWeakestOpponent());
}
});
List<Card> betterList = CardLists.filter(magnetList, c -> CombatUtil.canAttack(c, ai.getWeakestOpponent()));
if (!betterList.isEmpty()) {
return ComputerUtilCard.getBestAI(betterList);
}
// Magnet List should not be attached when they are useless
betterList = CardLists.filter(magnetList, new Predicate<Card>() {
@Override
public boolean apply(final Card c) {
return !ComputerUtilCard.isUselessCreature(ai, c);
}
});
betterList = CardLists.filter(magnetList, c -> !ComputerUtilCard.isUselessCreature(ai, c));
if (!betterList.isEmpty()) {
return ComputerUtilCard.getBestAI(betterList);
@@ -1179,21 +1114,14 @@ public class AttachAi extends SpellAbilityAi {
if (totToughness < 0) {
// Don't kill my own stuff with Negative toughness Auras
final int tgh = totToughness;
prefList = CardLists.filter(prefList, new Predicate<Card>() {
@Override
public boolean apply(final Card c) {
return c.getLethalDamage() > Math.abs(tgh);
}
});
prefList = CardLists.filter(prefList, c -> c.getLethalDamage() > Math.abs(tgh));
}
//only add useful keywords unless P/T bonus is significant
if (totToughness + totPower < 4 && (!keywords.isEmpty() || grantingExtraBlock)) {
final int pow = totPower;
final boolean extraBlock = grantingExtraBlock;
prefList = CardLists.filter(prefList, new Predicate<Card>() {
@Override
public boolean apply(final Card c) {
prefList = CardLists.filter(prefList, c -> {
if (!keywords.isEmpty()) {
for (final String keyword : keywords) {
if (isUsefulAttachKeyword(keyword, c, sa, pow)) {
@@ -1210,7 +1138,6 @@ public class AttachAi extends SpellAbilityAi {
return true;
}
return false;
}
});
}
@@ -1229,21 +1156,11 @@ public class AttachAi extends SpellAbilityAi {
if (!attachSource.getName().equals("Daybreak Coronet")) {
// TODO For Auras like Rancor, that aren't as likely to lead to
// card disadvantage, this check should be skipped
prefList = CardLists.filter(prefList, new Predicate<Card>() {
@Override
public boolean apply(final Card c) {
return !c.isEnchanted() || c.hasKeyword(Keyword.HEXPROOF);
}
});
prefList = CardLists.filter(prefList, c -> !c.isEnchanted() || c.hasKeyword(Keyword.HEXPROOF));
}
// should not attach Auras to creatures that does leave the play
prefList = CardLists.filter(prefList, new Predicate<Card>() {
@Override
public boolean apply(final Card c) {
return !c.hasSVar("EndOfTurnLeavePlay");
}
});
prefList = CardLists.filter(prefList, c -> !c.hasSVar("EndOfTurnLeavePlay"));
}
// Should not attach things to crewed vehicles that will stop being creatures soon
@@ -1258,12 +1175,7 @@ public class AttachAi extends SpellAbilityAi {
}
}
if (canOnlyTargetCreatures && (attachSource.isAura() || attachSource.isEquipment())) {
prefList = CardLists.filter(prefList, new Predicate<Card>() {
@Override
public boolean apply(Card card) {
return card.getTimesCrewedThisTurn() == 0 || (attachSource.isEquipment() && attachSource.getGame().getPhaseHandler().is(PhaseType.MAIN1, ai));
}
});
prefList = CardLists.filter(prefList, c -> c.getTimesCrewedThisTurn() == 0 || (attachSource.isEquipment() && attachSource.getGame().getPhaseHandler().is(PhaseType.MAIN1, ai)));
}
if (!grantingAbilities) {
@@ -1271,17 +1183,14 @@ public class AttachAi extends SpellAbilityAi {
// Filter out creatures that can't Attack or have Defender
if (keywords.isEmpty()) {
final int powerBonus = totPower;
prefList = CardLists.filter(prefList, new Predicate<Card>() {
@Override
public boolean apply(final Card c) {
prefList = CardLists.filter(prefList, c -> {
if (!c.isCreature()) {
return true;
}
return powerBonus + c.getNetPower() > 0 && ComputerUtilCombat.canAttackNextTurn(c);
}
});
}
c = ComputerUtilCard.getBestAI(prefList);
card = ComputerUtilCard.getBestAI(prefList);
} else {
for (Card pref : prefList) {
if (pref.isLand() && pref.isUntapped()) {
@@ -1290,14 +1199,14 @@ public class AttachAi extends SpellAbilityAi {
}
// If we grant abilities, we may want to put it on something Weak?
// Possibly more defensive?
c = ComputerUtilCard.getWorstPermanentAI(prefList, false, false, false, false);
card = ComputerUtilCard.getWorstPermanentAI(prefList, false, false, false, false);
}
if (c == null) {
if (card == null) {
return chooseLessPreferred(mandatory, list);
}
return c;
return card;
}
/**
@@ -1338,22 +1247,13 @@ public class AttachAi extends SpellAbilityAi {
// Is a SA that moves target attachment
if ("MoveTgtAura".equals(sa.getParam("AILogic"))) {
CardCollection list = CardLists.filter(CardUtil.getValidCardsToTarget(sa), Predicates.or(CardPredicates.isControlledByAnyOf(aiPlayer.getOpponents()), new Predicate<Card>() {
@Override
public boolean apply(final Card card) {
return ComputerUtilCard.isUselessCreature(aiPlayer, card.getAttachedTo());
}
}));
CardCollection list = CardLists.filter(CardUtil.getValidCardsToTarget(sa), Predicates.or(CardPredicates.isControlledByAnyOf(aiPlayer.getOpponents()),
card -> ComputerUtilCard.isUselessCreature(aiPlayer, card.getAttachedTo())));
return !list.isEmpty() ? ComputerUtilCard.getBestAI(list) : null;
} else if ("Unenchanted".equals(sa.getParam("AILogic"))) {
List<Card> list = CardUtil.getValidCardsToTarget(sa);
CardCollection preferred = CardLists.filter(list, new Predicate<Card>() {
@Override
public boolean apply(final Card card) {
return !card.hasCardAttachments();
}
});
CardCollection preferred = CardLists.filter(list, card -> !card.hasCardAttachments());
return preferred.isEmpty() ? Aggregates.random(list) : Aggregates.random(preferred);
}
@@ -1687,25 +1587,19 @@ public class AttachAi extends SpellAbilityAi {
public static Card doPumpOrCurseAILogic(final Player ai, final SpellAbility sa, final List<Card> list, final String type) {
Card chosen = null;
List<Card> aiType = CardLists.filter(list, new Predicate<Card>() {
@Override
public boolean apply(final Card c) {
List<Card> aiType = CardLists.filter(list, c -> {
// Don't buff opponent's creatures of given type
if (!c.getController().equals(ai)) {
return false;
}
return c.isValid(type, ai, sa.getHostCard(), sa);
}
});
List<Card> oppNonType = CardLists.filter(list, new Predicate<Card>() {
@Override
public boolean apply(final Card c) {
List<Card> oppNonType = CardLists.filter(list, c -> {
// Don't debuff AI's own creatures not of given type
if (c.getController().equals(ai)) {
return false;
}
return !c.isValid(type, ai, sa.getHostCard(), sa) && !ComputerUtilCard.isUselessCreature(ai, c);
}
});
if (!aiType.isEmpty() && !oppNonType.isEmpty()) {

View File

@@ -1,7 +1,6 @@
package forge.ai.ability;
import com.google.common.base.Predicate;
import forge.ai.ComputerUtilCard;
import forge.ai.SpecialAiLogic;
import forge.ai.SpecialCardAi;
@@ -35,12 +34,9 @@ public class BranchAi extends SpellAbilityAi {
}
final CardCollection attackers = combat.getAttackers();
final CardCollection attackingBattle = CardLists.filter(attackers, new Predicate<Card>() {
@Override
public boolean apply(Card card) {
final CardCollection attackingBattle = CardLists.filter(attackers, card -> {
final GameEntity def = combat.getDefenderByAttacker(combat.getBandOfAttacker(card));
return def instanceof Card && ((Card)def).isBattle();
}
});
if (!attackingBattle.isEmpty()) {

View File

@@ -1,6 +1,5 @@
package forge.ai.ability;
import com.google.common.base.Predicate;
import com.google.common.base.Predicates;
import com.google.common.collect.Iterables;
import com.google.common.collect.Lists;
@@ -378,14 +377,11 @@ public class ChangeZoneAi extends SpellAbilityAi {
if (type != null && p == ai) {
// AI only "knows" about his information
list = CardLists.getValidCards(list, type, source.getController(), source, sa);
list = CardLists.filter(list, new Predicate<Card>() {
@Override
public boolean apply(final Card c) {
list = CardLists.filter(list, c -> {
if (c.getType().isLegendary()) {
return !ai.isCardInPlay(c.getName());
}
return true;
}
});
}
// TODO: prevent ai searching its own library when Ob Nixilis, Unshackled is in play
@@ -906,12 +902,7 @@ public class ChangeZoneAi extends SpellAbilityAi {
// Filter AI-specific targets if provided
list = ComputerUtil.filterAITgts(sa, ai, list, true);
if (sa.hasParam("AITgtsOnlyBetterThanSelf")) {
list = CardLists.filter(list, new Predicate<Card>() {
@Override
public boolean apply(Card card) {
return ComputerUtilCard.evaluateCreature(card) > ComputerUtilCard.evaluateCreature(source) + 30;
}
});
list = CardLists.filter(list, card -> ComputerUtilCard.evaluateCreature(card) > ComputerUtilCard.evaluateCreature(source) + 30);
}
if (source.isInZone(ZoneType.Hand)) {
@@ -921,29 +912,23 @@ public class ChangeZoneAi extends SpellAbilityAi {
list.remove(source); // spells can't target their own source, because it's actually in the stack zone
}
if (sa.hasParam("AttachedTo")) {
list = CardLists.filter(list, new Predicate<Card>() {
@Override
public boolean apply(final Card c) {
list = CardLists.filter(list, c -> {
for (Card card : game.getCardsIn(ZoneType.Battlefield)) {
if (card.isValid(sa.getParam("AttachedTo"), ai, c, sa)) {
return true;
}
}
return false;
}
});
}
if (sa.hasParam("AttachAfter")) {
list = CardLists.filter(list, new Predicate<Card>() {
@Override
public boolean apply(final Card c) {
list = CardLists.filter(list, c -> {
for (Card card : game.getCardsIn(ZoneType.Battlefield)) {
if (card.isValid(sa.getParam("AttachAfter"), ai, c, sa)) {
return true;
}
}
return false;
}
});
}
@@ -1039,12 +1024,7 @@ public class ChangeZoneAi extends SpellAbilityAi {
}
// blink logic: get my own permanents back or blink permanents with ETB effects
if (blink) {
CardCollection blinkTargets = CardLists.filter(list, new Predicate<Card>() {
@Override
public boolean apply(final Card c) {
return !c.isToken() && c.getOwner().equals(ai) && (c.getController().isOpponentOf(ai) || c.hasETBTrigger(false));
}
});
CardCollection blinkTargets = CardLists.filter(list, c -> !c.isToken() && c.getOwner().equals(ai) && (c.getController().isOpponentOf(ai) || c.hasETBTrigger(false)));
if (!blinkTargets.isEmpty()) {
CardCollection opponentBlinkTargets = CardLists.filterControlledBy(blinkTargets, ai.getOpponents());
// prefer post-combat unless targeting opponent's stuff or part of another ability
@@ -1070,9 +1050,7 @@ public class ChangeZoneAi extends SpellAbilityAi {
list = CardLists.filterControlledBy(list, ai.getOpponents());
if (!CardLists.getNotType(list, "Land").isEmpty()) {
// When bouncing opponents stuff other than lands, don't bounce cards with CMC 0
list = CardLists.filter(list, new Predicate<Card>() {
@Override
public boolean apply(final Card c) {
list = CardLists.filter(list, c -> {
for (Card aura : c.getEnchantedBy()) {
return aura.getController().isOpponentOf(ai);
}
@@ -1080,7 +1058,6 @@ public class ChangeZoneAi extends SpellAbilityAi {
return c.isToken();
}
return c.isToken() || c.getCMC() > 0;
}
});
}
}
@@ -1102,16 +1079,13 @@ public class ChangeZoneAi extends SpellAbilityAi {
// only retrieve cards from computer graveyard
list = CardLists.filterControlledBy(list, ai);
} else if (sa.hasParam("AttachedTo")) {
list = CardLists.filter(list, new Predicate<Card>() {
@Override
public boolean apply(final Card c) {
list = CardLists.filter(list, c -> {
for (SpellAbility attach : c.getSpellAbilities()) {
if ("Pump".equals(attach.getParam("AILogic"))) {
return true; //only use good auras
}
}
return false;
}
});
}
}
@@ -1135,16 +1109,13 @@ public class ChangeZoneAi extends SpellAbilityAi {
if (!sa.hasParam("AITgtOwnCards")) {
list = CardLists.filterControlledBy(list, ai.getOpponents());
list = CardLists.filter(list, new Predicate<Card>() {
@Override
public boolean apply(final Card c) {
list = CardLists.filter(list, c -> {
for (Card aura : c.getEnchantedBy()) {
if (c.getOwner().isOpponentOf(ai) && aura.getController().equals(ai)) {
return false;
}
}
return true;
}
});
}
@@ -1613,22 +1584,14 @@ public class ChangeZoneAi extends SpellAbilityAi {
// Save a card as a default, in case we can't find anything suitable.
Card first = fetchList.get(0);
if (ZoneType.Battlefield.equals(destination)) {
fetchList = CardLists.filter(fetchList, new Predicate<Card>() {
@Override
public boolean apply(final Card c) {
if (c.getType().isLegendary()) {
return !decider.isCardInPlay(c.getName());
fetchList = CardLists.filter(fetchList, c1 -> {
if (c1.getType().isLegendary()) {
return !decider.isCardInPlay(c1.getName());
}
return true;
}
});
if (player.isOpponentOf(decider) && sa.hasParam("GainControl") && activator.equals(decider)) {
fetchList = CardLists.filter(fetchList, new Predicate<Card>() {
@Override
public boolean apply(final Card c) {
return !ComputerUtilCard.isCardRemAIDeck(c) && !ComputerUtilCard.isCardRemRandomDeck(c);
}
});
fetchList = CardLists.filter(fetchList, c12 -> !ComputerUtilCard.isCardRemAIDeck(c12) && !ComputerUtilCard.isCardRemRandomDeck(c12));
}
}
if (ZoneType.Exile.equals(destination) || origin.contains(ZoneType.Battlefield)
@@ -1715,9 +1678,7 @@ public class ChangeZoneAi extends SpellAbilityAi {
}
private static CardCollection prefilterOwnListForBounceAnyNum(CardCollection fetchList, Player decider) {
fetchList = CardLists.filter(fetchList, new Predicate<Card>() {
@Override
public boolean apply(final Card card) {
fetchList = CardLists.filter(fetchList, card -> {
if (card.isToken()) {
return false;
}
@@ -1761,7 +1722,6 @@ public class ChangeZoneAi extends SpellAbilityAi {
return false;
}
return true;
}
});
return fetchList;
@@ -1866,14 +1826,11 @@ public class ChangeZoneAi extends SpellAbilityAi {
listGoal = CardLists.getValidCards(listGoal, curGoal + (curGoal.contains(".") ? "+" : ".") + "cmcGE" + goalCMC, source.getController(), source, sa);
}
listGoal = CardLists.filter(listGoal, new Predicate<Card>() {
@Override
public boolean apply(final Card c) {
listGoal = CardLists.filter(listGoal, c -> {
if (c.getType().isLegendary()) {
return !ai.isCardInPlay(c.getName());
}
return true;
}
});
if (!listGoal.isEmpty()) {
@@ -2014,9 +1971,7 @@ public class ChangeZoneAi extends SpellAbilityAi {
exiledBy.add(exiled);
}
}
scanList = CardLists.filter(scanList, new Predicate<Card>() {
@Override
public boolean apply(Card card) {
scanList = CardLists.filter(scanList, card -> {
if (exiledBy.isEmpty()) {
return true;
}
@@ -2024,7 +1979,6 @@ public class ChangeZoneAi extends SpellAbilityAi {
return !c.getType().sharesCardTypeWith(card.getType());
}
return true;
}
});
}
@@ -2061,12 +2015,7 @@ public class ChangeZoneAi extends SpellAbilityAi {
}
final CardType.CoreType determinedMaxType = maxType;
CardCollection preferredList = CardLists.filter(fetchList, new Predicate<Card>() {
@Override
public boolean apply(Card card) {
return card.getType().hasType(determinedMaxType);
}
});
CardCollection preferredList = CardLists.filter(fetchList, card -> card.getType().hasType(determinedMaxType));
CardCollection preferredOppList = CardLists.filter(preferredList, CardPredicates.isControlledByAnyOf(aiPlayer.getOpponents()));
if (!preferredOppList.isEmpty()) {
@@ -2078,9 +2027,7 @@ public class ChangeZoneAi extends SpellAbilityAi {
return Aggregates.random(fetchList);
}
CardCollection preferredList = CardLists.filter(fetchList, new Predicate<Card>() {
@Override
public boolean apply(Card card) {
CardCollection preferredList = CardLists.filter(fetchList, card -> {
boolean playerPref = true;
if (isCurse) {
playerPref = card.getController().isOpponentOf(aiPlayer);
@@ -2093,7 +2040,6 @@ public class ChangeZoneAi extends SpellAbilityAi {
}
return card.isValid(valid, aiPlayer, host, sa); // for things like ExilePreference:Land.Basic
}
});
if (!preferredList.isEmpty()) {

View File

@@ -4,7 +4,6 @@ import java.util.Collections;
import java.util.List;
import java.util.Map;
import com.google.common.base.Predicate;
import com.google.common.base.Predicates;
import com.google.common.collect.Iterables;
@@ -85,15 +84,12 @@ public class ChooseCardAi extends SpellAbilityAi {
return false;
}
final Combat combat = game.getCombat();
choices = CardLists.filter(choices, new Predicate<Card>() {
@Override
public boolean apply(final Card c) {
choices = CardLists.filter(choices, c -> {
if (!combat.isAttacking(c, ai) || !combat.isUnblocked(c)) {
return false;
}
int ref = ComputerUtilAbility.getAbilitySourceName(sa).equals("Forcefield") ? 1 : 0;
return ComputerUtilCombat.damageIfUnblocked(c, ai, combat, true) > ref;
}
});
return !choices.isEmpty();
} else if (aiLogic.equals("Ashiok")) {
@@ -201,15 +197,12 @@ public class ChooseCardAi extends SpellAbilityAi {
} else if (logic.equals("NeedsPrevention")) {
final Game game = ai.getGame();
final Combat combat = game.getCombat();
CardCollectionView better = CardLists.filter(options, new Predicate<Card>() {
@Override
public boolean apply(final Card c) {
CardCollectionView better = CardLists.filter(options, c -> {
if (combat == null || !combat.isAttacking(c, ai) || !combat.isUnblocked(c)) {
return false;
}
int ref = ComputerUtilAbility.getAbilitySourceName(sa).equals("Forcefield") ? 1 : 0;
return ComputerUtilCombat.damageIfUnblocked(c, ai, combat, true) > ref;
}
});
if (!better.isEmpty()) {
choice = ComputerUtilCard.getBestAI(better);
@@ -235,26 +228,23 @@ public class ChooseCardAi extends SpellAbilityAi {
choice = creats.get(0);
}
} else if ("NegativePowerFirst".equals(logic)) {
Card lowest = Aggregates.itemWithMin(options, CardPredicates.Accessors.fnGetNetPower);
Card lowest = Aggregates.itemWithMin(options, Card::getNetPower);
if (lowest.getNetPower() <= 0) {
choice = lowest;
} else {
choice = ComputerUtilCard.getBestCreatureAI(options);
}
} else if ("TangleWire".equals(logic)) {
CardCollectionView betterList = CardLists.filter(options, new Predicate<Card>() {
@Override
public boolean apply(final Card c) {
CardCollectionView betterList = CardLists.filter(options, c -> {
if (c.isCreature()) {
return false;
}
for (SpellAbility sa : c.getAllSpellAbilities()) {
if (sa.getPayCosts().hasTapCost()) {
for (SpellAbility sa1 : c.getAllSpellAbilities()) {
if (sa1.getPayCosts().hasTapCost()) {
return false;
}
}
return true;
}
});
if (!betterList.isEmpty()) {
choice = betterList.get(0);

View File

@@ -3,9 +3,9 @@ package forge.ai.ability;
import forge.ai.SpellAbilityAi;
import forge.game.Direction;
import forge.game.Game;
import forge.game.card.Card;
import forge.game.card.CardCollection;
import forge.game.card.CardLists;
import forge.game.card.CardPredicates;
import forge.game.card.CardPredicates.Presets;
import forge.game.player.Player;
import forge.game.spellability.SpellAbility;
@@ -28,11 +28,11 @@ public class ChooseDirectionAi extends SpellAbilityAi {
CardCollection all = CardLists.filter(game.getCardsIn(ZoneType.Battlefield), Presets.NONLAND_PERMANENTS);
CardCollection aiPermanent = CardLists.filterControlledBy(all, ai);
aiPermanent.remove(sa.getHostCard());
int aiValue = Aggregates.sum(aiPermanent, CardPredicates.Accessors.fnGetCmc);
int aiValue = Aggregates.sum(aiPermanent, Card::getCMC);
CardCollection left = CardLists.filterControlledBy(all, game.getNextPlayerAfter(ai, Direction.Left));
CardCollection right = CardLists.filterControlledBy(all, game.getNextPlayerAfter(ai, Direction.Right));
int leftValue = Aggregates.sum(left, CardPredicates.Accessors.fnGetCmc);
int rightValue = Aggregates.sum(right, CardPredicates.Accessors.fnGetCmc);
int leftValue = Aggregates.sum(left, Card::getCMC);
int rightValue = Aggregates.sum(right, Card::getCMC);
return aiValue <= leftValue && aiValue <= rightValue;
}
}

View File

@@ -1,6 +1,5 @@
package forge.ai.ability;
import com.google.common.base.Predicate;
import com.google.common.collect.Iterables;
import com.google.common.collect.Lists;
import forge.ai.*;
@@ -85,12 +84,7 @@ public class ChooseGenericAi extends SpellAbilityAi {
} else if ("Random".equals(logic)) {
return Aggregates.random(spells);
} else if ("Phasing".equals(logic)) { // Teferi's Realm : keep aggressive
List<SpellAbility> filtered = Lists.newArrayList(Iterables.filter(spells, new Predicate<SpellAbility>() {
@Override
public boolean apply(final SpellAbility sp) {
return !sp.getDescription().contains("Creature") && !sp.getDescription().contains("Land");
}
}));
List<SpellAbility> filtered = Lists.newArrayList(Iterables.filter(spells, sp -> !sp.getDescription().contains("Creature") && !sp.getDescription().contains("Land")));
return Aggregates.random(filtered);
} else if ("PayUnlessCost".equals(logic)) {
for (final SpellAbility sp : spells) {

View File

@@ -3,7 +3,6 @@ package forge.ai.ability;
import java.util.List;
import java.util.Map;
import com.google.common.base.Predicate;
import com.google.common.base.Predicates;
import com.google.common.collect.Iterables;
@@ -94,14 +93,11 @@ public class ChooseSourceAi extends SpellAbilityAi {
choices = CardLists.getValidCards(choices, sa.getParam("Choices"), host.getController(), host, sa);
}
final Combat combat = game.getCombat();
choices = CardLists.filter(choices, new Predicate<Card>() {
@Override
public boolean apply(final Card c) {
choices = CardLists.filter(choices, c -> {
if (combat == null || !combat.isAttacking(c, ai) || !combat.isUnblocked(c)) {
return false;
}
return ComputerUtilCombat.damageIfUnblocked(c, ai, combat, true) > 0;
}
});
return !choices.isEmpty();
}
@@ -124,15 +120,12 @@ public class ChooseSourceAi extends SpellAbilityAi {
final Combat combat = game.getCombat();
List<Card> permanentSources = CardLists.filter(options, new Predicate<Card>() {
@Override
public boolean apply(final Card c) {
List<Card> permanentSources = CardLists.filter(options, c -> {
if (c == null || c.getZone() == null || c.getZone().getZoneType() != ZoneType.Battlefield
|| combat == null || !combat.isAttacking(c, ai) || !combat.isUnblocked(c)) {
return false;
}
return ComputerUtilCombat.damageIfUnblocked(c, ai, combat, true) > 0;
}
});
// Try to choose the best creature for damage prevention.

View File

@@ -1,6 +1,5 @@
package forge.ai.ability;
import com.google.common.base.Predicate;
import com.google.common.collect.Lists;
import forge.ai.ComputerUtilCard;
@@ -32,12 +31,7 @@ public class ControlExchangeAi extends SpellAbilityAi {
CardCollection list =
CardLists.getValidCards(ai.getOpponents().getCardsIn(ZoneType.Battlefield), tgt.getValidTgts(), ai, sa.getHostCard(), sa);
// AI won't try to grab cards that are filtered out of AI decks on purpose
list = CardLists.filter(list, new Predicate<Card>() {
@Override
public boolean apply(final Card c) {
return !ComputerUtilCard.isCardRemAIDeck(c) && c.canBeTargetedBy(sa);
}
});
list = CardLists.filter(list, c -> !ComputerUtilCard.isCardRemAIDeck(c) && c.canBeTargetedBy(sa));
object1 = ComputerUtilCard.getBestAI(list);
if (sa.hasParam("Defined")) {
object2 = AbilityUtils.getDefinedCards(sa.getHostCard(), sa.getParam("Defined"), sa).get(0);

View File

@@ -20,7 +20,6 @@ package forge.ai.ability;
import java.util.List;
import java.util.Map;
import com.google.common.base.Predicate;
import com.google.common.collect.Iterables;
import com.google.common.collect.Lists;
@@ -132,9 +131,7 @@ public class ControlGainAi extends SpellAbilityAi {
}
// AI won't try to grab cards that are filtered out of AI decks on purpose
list = CardLists.filter(list, new Predicate<Card>() {
@Override
public boolean apply(final Card c) {
list = CardLists.filter(list, c -> {
if (!sa.canTarget(c)) {
return false;
}
@@ -171,7 +168,6 @@ public class ControlGainAi extends SpellAbilityAi {
// do not take control on something it doesn't know how to use
return !ComputerUtilCard.isCardRemAIDeck(c);
}
});
if (list.isEmpty()) {

View File

@@ -20,7 +20,6 @@ package forge.ai.ability;
import java.util.List;
import java.util.Map;
import com.google.common.base.Predicate;
import com.google.common.base.Predicates;
import com.google.common.collect.Iterables;
@@ -49,12 +48,7 @@ public class ControlGainVariantAi extends SpellAbilityAi {
String logic = sa.getParam("AILogic");
if ("GainControlOwns".equals(logic)) {
List<Card> list = CardLists.filter(ai.getGame().getCardsIn(ZoneType.Battlefield), new Predicate<Card>() {
@Override
public boolean apply(final Card crd) {
return crd.isCreature() && !crd.getController().equals(crd.getOwner());
}
});
List<Card> list = CardLists.filter(ai.getGame().getCardsIn(ZoneType.Battlefield), crd -> crd.isCreature() && !crd.getController().equals(crd.getOwner()));
if (list.isEmpty()) {
return false;
}

View File

@@ -4,7 +4,6 @@ import java.util.Collection;
import java.util.List;
import java.util.Map;
import com.google.common.base.Predicate;
import com.google.common.base.Predicates;
import com.google.common.collect.Iterables;
@@ -176,12 +175,7 @@ public class CopyPermanentAi extends SpellAbilityAi {
}
}
list = CardLists.filter(list, new Predicate<Card>() {
@Override
public boolean apply(final Card c) {
return (!c.getType().isLegendary() || canCopyLegendary) || !c.getController().equals(aiPlayer);
}
});
list = CardLists.filter(list, c -> (!c.getType().isLegendary() || canCopyLegendary) || !c.getController().equals(aiPlayer));
Card choice;
if (Iterables.any(list, Presets.CREATURES)) {
if (sa.hasParam("TargetingPlayer")) {

View File

@@ -19,7 +19,6 @@ package forge.ai.ability;
import java.util.List;
import com.google.common.base.Predicate;
import com.google.common.collect.Iterables;
import forge.ai.ComputerUtilCard;
@@ -109,12 +108,7 @@ public abstract class CountersAi extends SpellAbilityAi {
choice = ComputerUtilCard.getBestLandToAnimate(list);
}
} else if (type.equals("DIVINITY")) {
final CardCollection boon = CardLists.filter(list, new Predicate<Card>() {
@Override
public boolean apply(final Card c) {
return c.getCounters(CounterEnumType.DIVINITY) == 0;
}
});
final CardCollection boon = CardLists.filter(list, c -> c.getCounters(CounterEnumType.DIVINITY) == 0);
choice = ComputerUtilCard.getMostExpensivePermanentAI(boon);
} else if (CounterType.get(type).isKeywordCounter()) {
choice = ComputerUtilCard.getBestCreatureAI(CardLists.getNotKeyword(list, type));

View File

@@ -3,7 +3,6 @@ package forge.ai.ability;
import java.util.List;
import java.util.Map;
import com.google.common.base.Predicate;
import com.google.common.collect.Iterables;
import forge.ai.ComputerUtil;
@@ -261,10 +260,7 @@ public class CountersMoveAi extends SpellAbilityAi {
// prefered logic for this: try to steal counter
List<Card> oppList = CardLists.filterControlledBy(tgtCards, ai.getOpponents());
if (!oppList.isEmpty()) {
List<Card> best = CardLists.filter(oppList, new Predicate<Card>() {
@Override
public boolean apply(Card card) {
List<Card> best = CardLists.filter(oppList, card -> {
// do not weak a useless creature if able
if (ComputerUtilCard.isUselessCreature(ai, card)) {
return false;
@@ -279,8 +275,6 @@ public class CountersMoveAi extends SpellAbilityAi {
return srcCardCpy.getCounters(cType) > 0 || !card.hasKeyword(Keyword.UNDYING) || card.isToken();
}
return true;
}
});
// if no Prefered found, try normal list
@@ -303,10 +297,7 @@ public class CountersMoveAi extends SpellAbilityAi {
List<Card> aiList = CardLists.filterControlledBy(tgtCards, ally);
if (!aiList.isEmpty()) {
List<Card> best = CardLists.filter(aiList, new Predicate<Card>() {
@Override
public boolean apply(Card card) {
List<Card> best = CardLists.filter(aiList, card -> {
// gain from useless
if (ComputerUtilCard.isUselessCreature(ai, card)) {
return true;
@@ -329,7 +320,6 @@ public class CountersMoveAi extends SpellAbilityAi {
}
return false;
}
});
if (best.isEmpty()) {
@@ -379,10 +369,7 @@ public class CountersMoveAi extends SpellAbilityAi {
if (ComputerUtilCard.evaluateCreature(lkiWithCounters) > ComputerUtilCard.evaluateCreature(lkiWithoutCounters)) {
List<Card> aiList = CardLists.filterControlledBy(tgtCards, ai);
if (!aiList.isEmpty()) {
List<Card> best = CardLists.filter(aiList, new Predicate<Card>() {
@Override
public boolean apply(Card card) {
List<Card> best = CardLists.filter(aiList, card -> {
// gain from useless
if (ComputerUtilCard.isUselessCreature(ai, card)) {
return false;
@@ -406,7 +393,6 @@ public class CountersMoveAi extends SpellAbilityAi {
}
}
return true;
}
});
if (best.isEmpty()) {
@@ -432,10 +418,7 @@ public class CountersMoveAi extends SpellAbilityAi {
// try to move to something useless or something that would leave play
List<Card> oppList = CardLists.filterControlledBy(tgtCards, ai.getOpponents());
if (!oppList.isEmpty()) {
List<Card> best = CardLists.filter(oppList, new Predicate<Card>() {
@Override
public boolean apply(Card card) {
List<Card> best = CardLists.filter(oppList, card -> {
// gain from useless
if (!ComputerUtilCard.isUselessCreature(ai, card)) {
return true;
@@ -447,7 +430,6 @@ public class CountersMoveAi extends SpellAbilityAi {
}
return false;
}
});
if (best.isEmpty()) {

View File

@@ -4,7 +4,6 @@ import java.util.Collections;
import java.util.List;
import java.util.Map;
import com.google.common.base.Predicate;
import com.google.common.base.Predicates;
import com.google.common.collect.Iterables;
import com.google.common.collect.Lists;
@@ -37,10 +36,7 @@ public class CountersMultiplyAi extends SpellAbilityAi {
// defined are mostly Self or Creatures you control
CardCollection list = AbilityUtils.getDefinedCards(sa.getHostCard(), sa.getParam("Defined"), sa);
list = CardLists.filter(list, new Predicate<Card>() {
@Override
public boolean apply(Card c) {
list = CardLists.filter(list, c -> {
if (!c.hasCounters()) {
return false;
}
@@ -62,8 +58,6 @@ public class CountersMultiplyAi extends SpellAbilityAi {
}
return true;
}
});
if (list.isEmpty()) {
@@ -137,10 +131,7 @@ public class CountersMultiplyAi extends SpellAbilityAi {
CardCollection list = CardLists.getTargetableCards(game.getCardsIn(ZoneType.Battlefield), sa);
// pre filter targetable cards with counters and can receive one of them
list = CardLists.filter(list, new Predicate<Card>() {
@Override
public boolean apply(Card c) {
list = CardLists.filter(list, c -> {
if (!c.hasCounters()) {
return false;
}
@@ -155,8 +146,6 @@ public class CountersMultiplyAi extends SpellAbilityAi {
}
return true;
}
});
CardCollection aiList = CardLists.filterControlledBy(list, ai);

View File

@@ -4,7 +4,6 @@ import java.util.Collection;
import java.util.List;
import java.util.Map;
import com.google.common.base.Predicate;
import com.google.common.collect.Iterables;
import com.google.common.collect.Lists;
@@ -31,9 +30,7 @@ public class CountersProliferateAi extends SpellAbilityAi {
if (p.getCounters(CounterEnumType.EXPERIENCE) + p.getCounters(CounterEnumType.ENERGY) >= 1) {
allyExpOrEnergy = true;
}
cperms.addAll(CardLists.filter(p.getCardsIn(ZoneType.Battlefield), new Predicate<Card>() {
@Override
public boolean apply(final Card crd) {
cperms.addAll(CardLists.filter(p.getCardsIn(ZoneType.Battlefield), crd -> {
if (!crd.hasCounters()) {
return false;
}
@@ -49,7 +46,6 @@ public class CountersProliferateAi extends SpellAbilityAi {
}
}
return false;
}
}));
}
@@ -58,9 +54,7 @@ public class CountersProliferateAi extends SpellAbilityAi {
for (final Player o : ai.getOpponents()) {
opponentPoison |= o.getPoisonCounters() > 0 && o.canReceiveCounters(CounterEnumType.POISON);
hperms.addAll(CardLists.filter(o.getCardsIn(ZoneType.Battlefield), new Predicate<Card>() {
@Override
public boolean apply(final Card crd) {
hperms.addAll(CardLists.filter(o.getCardsIn(ZoneType.Battlefield), crd -> {
if (!crd.hasCounters()) {
return false;
}
@@ -76,7 +70,6 @@ public class CountersProliferateAi extends SpellAbilityAi {
}
}
return false;
}
}));
}

View File

@@ -1,6 +1,5 @@
package forge.ai.ability;
import com.google.common.base.Predicate;
import com.google.common.base.Predicates;
import com.google.common.collect.Iterables;
import com.google.common.collect.Lists;
@@ -171,13 +170,7 @@ public class CountersPutAi extends CountersAi {
CardCollection oppCreatM1 = CardLists.filter(oppCreat, CardPredicates.hasCounter(CounterEnumType.M1M1));
oppCreatM1 = CardLists.getNotKeyword(oppCreatM1, Keyword.UNDYING);
oppCreatM1 = CardLists.filter(oppCreatM1, new Predicate<Card>() {
@Override
public boolean apply(Card input) {
return input.getNetToughness() <= 1 && input.canReceiveCounters(CounterType.get(CounterEnumType.M1M1));
}
});
oppCreatM1 = CardLists.filter(oppCreatM1, input -> input.getNetToughness() <= 1 && input.canReceiveCounters(CounterType.get(CounterEnumType.M1M1)));
Card best = ComputerUtilCard.getBestAI(oppCreatM1);
if (best != null) {
@@ -188,9 +181,7 @@ public class CountersPutAi extends CountersAi {
CardCollection aiCreat = CardLists.getTargetableCards(ai.getCreaturesInPlay(), sa);
aiCreat = CardLists.filter(aiCreat, CardPredicates.hasCounters());
aiCreat = CardLists.filter(aiCreat, new Predicate<Card>() {
@Override
public boolean apply(Card input) {
aiCreat = CardLists.filter(aiCreat, input -> {
for (CounterType counterType : input.getCounters().keySet()) {
if (!ComputerUtil.isNegativeCounter(counterType, input)
&& input.canReceiveCounters(counterType)) {
@@ -198,7 +189,6 @@ public class CountersPutAi extends CountersAi {
}
}
return false;
}
});
// TODO check whole state which creature would be the best
@@ -251,8 +241,8 @@ public class CountersPutAi extends CountersAi {
} else if (ai.getGame().getCombat().isBlocking(source)) {
// when blocking, consider this if it's possible to save the blocker and/or kill at least one attacker
CardCollection blocked = ai.getGame().getCombat().getAttackersBlockedBy(source);
int totBlkPower = Aggregates.sum(blocked, CardPredicates.Accessors.fnGetNetPower);
int totBlkToughness = Aggregates.min(blocked, CardPredicates.Accessors.fnGetNetToughness);
int totBlkPower = Aggregates.sum(blocked, Card::getNetPower);
int totBlkToughness = Aggregates.min(blocked, Card::getNetToughness);
int numActivations = ai.getCounters(CounterEnumType.ENERGY) / sa.getPayCosts().getCostEnergy().convertAmount();
if (source.getNetToughness() + numActivations > totBlkPower
@@ -327,7 +317,7 @@ public class CountersPutAi extends CountersAi {
if (sa.hasParam("Bolster")) {
CardCollection creatsYouCtrl = ai.getCreaturesInPlay();
List<Card> leastToughness = Aggregates.listWithMin(creatsYouCtrl, CardPredicates.Accessors.fnGetNetToughness);
List<Card> leastToughness = Aggregates.listWithMin(creatsYouCtrl, Card::getNetToughness);
if (leastToughness.isEmpty()) {
return false;
}
@@ -389,7 +379,7 @@ public class CountersPutAi extends CountersAi {
sa.setXManaCostPaid(amount);
} else if ("ExiledCreatureFromGraveCMC".equals(logic)) {
// e.g. Necropolis
amount = Aggregates.max(CardLists.filter(ai.getCardsIn(ZoneType.Graveyard), CardPredicates.Presets.CREATURES), CardPredicates.Accessors.fnGetCmc);
amount = Aggregates.max(CardLists.filter(ai.getCardsIn(ZoneType.Graveyard), CardPredicates.Presets.CREATURES), Card::getCMC);
if (amount > 0 && ai.getGame().getPhaseHandler().is(PhaseType.END_OF_TURN)) {
return true;
}
@@ -473,9 +463,7 @@ public class CountersPutAi extends CountersAi {
list = ComputerUtil.getSafeTargets(ai, sa, ai.getCardsIn(ZoneType.Battlefield));
}
list = CardLists.filter(list, new Predicate<Card>() {
@Override
public boolean apply(final Card c) {
list = CardLists.filter(list, c -> {
// don't put the counter on the dead creature
if (sacSelf && c.equals(source)) {
return false;
@@ -490,7 +478,6 @@ public class CountersPutAi extends CountersAi {
}
}
return sa.canTarget(c) && c.canReceiveCounters(CounterType.getType(type));
}
});
// Filter AI-specific targets if provided
@@ -928,13 +915,9 @@ public class CountersPutAi extends CountersAi {
final int tributeAmount = AbilityUtils.calculateAmount(source, amountStr, sa);
final boolean isHaste = source.hasKeyword(Keyword.HASTE);
List<Card> threatening = CardLists.filter(creats, new Predicate<Card>() {
@Override
public boolean apply(Card c) {
return CombatUtil.canBlock(source, c, !isHaste)
&& (c.getNetToughness() > source.getNetPower() + tributeAmount || c.hasKeyword(Keyword.DEATHTOUCH));
}
});
List<Card> threatening = CardLists.filter(creats, c -> CombatUtil.canBlock(source, c, !isHaste)
&& (c.getNetToughness() > source.getNetPower() + tributeAmount || c.hasKeyword(Keyword.DEATHTOUCH))
);
if (!threatening.isEmpty()) {
return true;
}
@@ -946,12 +929,9 @@ public class CountersPutAi extends CountersAi {
return false;
} else if (logic.equals("CanBlockThisTurn")) {
// pump haste
List<Card> canBlock = CardLists.filter(creats, new Predicate<Card>() {
@Override
public boolean apply(Card c) {
return CombatUtil.canBlock(source, c) && (c.getNetToughness() > source.getNetPower() || c.hasKeyword(Keyword.DEATHTOUCH));
}
});
List<Card> canBlock = CardLists.filter(creats, c -> CombatUtil.canBlock(source, c)
&& (c.getNetToughness() > source.getNetPower() || c.hasKeyword(Keyword.DEATHTOUCH))
);
if (!canBlock.isEmpty()) {
return false;
}
@@ -1003,9 +983,7 @@ public class CountersPutAi extends CountersAi {
final CardCollection opponents = CardLists.filterControlledBy(options, ai.getOpponents());
if (!opponents.isEmpty()) {
final CardCollection negative = CardLists.filter(opponents, new Predicate<Card>() {
@Override
public boolean apply(Card input) {
final CardCollection negative = CardLists.filter(opponents, input -> {
if (input.hasSVar("EndOfTurnLeavePlay"))
return false;
if (ComputerUtilCard.isUselessCreature(ai, input))
@@ -1018,7 +996,6 @@ public class CountersPutAi extends CountersAi {
}
}
return false;
}
});
if (!negative.isEmpty()) {
return ComputerUtilCard.getBestAI(negative);
@@ -1053,13 +1030,10 @@ public class CountersPutAi extends CountersAi {
if (doNotHaveKeyword.size() > 0)
filtered = doNotHaveKeyword;
final CardCollection notUseless = CardLists.filter(filtered, new Predicate<Card>() {
@Override
public boolean apply(Card input) {
final CardCollection notUseless = CardLists.filter(filtered, input -> {
if (input.hasSVar("EndOfTurnLeavePlay"))
return false;
return !ComputerUtilCard.isUselessCreature(ai, input);
}
});
if (!notUseless.isEmpty()) {
@@ -1069,26 +1043,20 @@ public class CountersPutAi extends CountersAi {
// some special logic to reload Persist/Undying
for (CounterType type : types) {
if (p1p1.equals(type)) {
final CardCollection persist = CardLists.filter(filtered, new Predicate<Card>() {
@Override
public boolean apply(Card input) {
final CardCollection persist = CardLists.filter(filtered, input -> {
if (!input.hasKeyword(Keyword.PERSIST))
return false;
return input.getCounters(m1m1) <= amount;
}
});
if (!persist.isEmpty()) {
filtered = persist;
}
} else if (m1m1.equals(type)) {
final CardCollection undying = CardLists.filter(filtered, new Predicate<Card>() {
@Override
public boolean apply(Card input) {
final CardCollection undying = CardLists.filter(filtered, input -> {
if (!input.hasKeyword(Keyword.UNDYING))
return false;
return input.getCounters(p1p1) <= amount && input.getNetToughness() > amount;
}
});
if (!undying.isEmpty()) {
@@ -1161,15 +1129,12 @@ public class CountersPutAi extends CountersAi {
CardCollection targets = CardLists.getTargetableCards(ai.getCreaturesInPlay(), sa);
targets.remove(source);
targets = CardLists.filter(targets, new Predicate<Card>() {
@Override
public boolean apply(Card card) {
targets = CardLists.filter(targets, card -> {
boolean tgtThreatened = ComputerUtil.predictThreatenedObjects(ai, null, true).contains(card)
|| (combat != null && ((combat.isBlocked(card) && ComputerUtilCombat.attackerWouldBeDestroyed(ai, card, combat))
|| (combat.isBlocking(card) && ComputerUtilCombat.blockerWouldBeDestroyed(ai, card, combat))));
// when threatened, any non-threatened target is good to preserve the counter
return !tgtThreatened && (threatened || ComputerUtilCard.evaluateCreature(card, false, false) > ComputerUtilCard.evaluateCreature(source, false, false) + creatDiff);
}
});
Card bestTgt = ComputerUtilCard.getBestCreatureAI(targets);
@@ -1194,7 +1159,7 @@ public class CountersPutAi extends CountersAi {
}
}
int totBlkPower = Aggregates.sum(combat.getBlockers(source), CardPredicates.Accessors.fnGetNetPower);
int totBlkPower = Aggregates.sum(combat.getBlockers(source), Card::getNetPower);
if (source.getNetToughness() <= totBlkPower
&& source.getNetToughness() + amount > totBlkPower) {
return true;
@@ -1208,7 +1173,7 @@ public class CountersPutAi extends CountersAi {
}
}
int totAtkPower = Aggregates.sum(combat.getAttackersBlockedBy(source), CardPredicates.Accessors.fnGetNetPower);
int totAtkPower = Aggregates.sum(combat.getAttackersBlockedBy(source), Card::getNetPower);
if (source.getNetToughness() <= totAtkPower
&& source.getNetToughness() + amount > totAtkPower) {
return true;
@@ -1229,7 +1194,7 @@ public class CountersPutAi extends CountersAi {
Card source = sa.getHostCard();
CardCollectionView ownLib = CardLists.filter(ai.getCardsIn(ZoneType.Library), CardPredicates.isType("Creature"));
int numCtrs = source.getCounters(CounterEnumType.CHARGE);
int maxCMC = Aggregates.max(ownLib, CardPredicates.Accessors.fnGetCmc);
int maxCMC = Aggregates.max(ownLib, Card::getCMC);
int optimalCMC = 0;
int curAmount = 0;
// Assume the AI knows its deck list and realizes what it has left in its library. Could be improved to make this less cheat-y.
@@ -1247,7 +1212,7 @@ public class CountersPutAi extends CountersAi {
Card source = sa.getHostCard();
CardCollectionView oppInPlay = CardLists.filter(ai.getOpponents().getCardsIn(ZoneType.Battlefield), CardPredicates.Presets.NONLAND_PERMANENTS);
int numCtrs = source.getCounters(CounterEnumType.CHARGE);
int maxCMC = Aggregates.max(oppInPlay, CardPredicates.Accessors.fnGetCmc);
int maxCMC = Aggregates.max(oppInPlay, Card::getCMC);
int optimalCMC = 0;
int curAmount = 0;
for (int cmc = numCtrs; cmc <= maxCMC; cmc++) {

View File

@@ -3,7 +3,6 @@ package forge.ai.ability;
import java.util.List;
import java.util.Map;
import com.google.common.base.Predicate;
import com.google.common.collect.Lists;
import forge.ai.ComputerUtilCost;
@@ -95,12 +94,7 @@ public class CountersPutAllAi extends SpellAbilityAi {
if (curse) {
if (type.equals("M1M1")) {
final List<Card> killable = CardLists.filter(hList, new Predicate<Card>() {
@Override
public boolean apply(final Card c) {
return c.getNetToughness() <= amount;
}
});
final List<Card> killable = CardLists.filter(hList, c -> c.getNetToughness() <= amount);
if (!(killable.size() > 2)) {
return false;
}

View File

@@ -107,12 +107,7 @@ public class CountersPutOrRemoveAi extends SpellAbilityAi {
if (!countersList.isEmpty()) {
CardCollectionView marit = ai.getCardsIn(ZoneType.Battlefield, "Marit Lage");
boolean maritEmpty = marit.isEmpty() || Iterables.contains(marit, new Predicate<Card>() {
@Override
public boolean apply(Card input) {
return input.ignoreLegendRule();
}
});
boolean maritEmpty = marit.isEmpty() || Iterables.contains(marit, (Predicate<Card>) Card::ignoreLegendRule);
if (maritEmpty) {
CardCollectionView depthsList = CardLists.filter(countersList,
CardPredicates.nameEquals("Dark Depths"), CardPredicates.hasCounter(CounterEnumType.ICE));
@@ -237,12 +232,7 @@ public class CountersPutOrRemoveAi extends SpellAbilityAi {
// this counters are treat first to be removed
if ("Dark Depths".equals(tgt.getName()) && options.contains(CounterType.get(CounterEnumType.ICE))) {
CardCollectionView marit = ai.getCardsIn(ZoneType.Battlefield, "Marit Lage");
boolean maritEmpty = marit.isEmpty() || Iterables.contains(marit, new Predicate<Card>() {
@Override
public boolean apply(Card input) {
return input.ignoreLegendRule();
}
});
boolean maritEmpty = marit.isEmpty() || Iterables.contains(marit, (Predicate<Card>) Card::ignoreLegendRule);
if (maritEmpty) {
return CounterType.get(CounterEnumType.ICE);
@@ -288,12 +278,7 @@ public class CountersPutOrRemoveAi extends SpellAbilityAi {
} else {
if (type.is(CounterEnumType.ICE) && "Dark Depths".equals(tgt.getName())) {
CardCollectionView marit = ai.getCardsIn(ZoneType.Battlefield, "Marit Lage");
boolean maritEmpty = marit.isEmpty() || Iterables.contains(marit, new Predicate<Card>() {
@Override
public boolean apply(Card input) {
return input.ignoreLegendRule();
}
});
boolean maritEmpty = marit.isEmpty() || Iterables.contains(marit, (Predicate<Card>) Card::ignoreLegendRule);
if (maritEmpty) {
return false;

View File

@@ -118,12 +118,7 @@ public class CountersRemoveAi extends SpellAbilityAi {
list = ComputerUtil.filterAITgts(sa, ai, list, false);
CardCollectionView marit = ai.getCardsIn(ZoneType.Battlefield, "Marit Lage");
boolean maritEmpty = marit.isEmpty() || Iterables.contains(marit, new Predicate<Card>() {
@Override
public boolean apply(Card input) {
return input.ignoreLegendRule();
}
});
boolean maritEmpty = marit.isEmpty() || Iterables.contains(marit, (Predicate<Card>) Card::ignoreLegendRule);
if (type.matches("All")) {
// Logic Part for Vampire Hexmage

View File

@@ -253,12 +253,7 @@ public class DamageAllAi extends SpellAbilityAi {
CardCollection list =
CardLists.getValidCards(player.getCardsIn(ZoneType.Battlefield), validC, source.getController(), source, sa);
final Predicate<Card> filterKillable = new Predicate<Card>() {
@Override
public boolean apply(final Card c) {
return ComputerUtilCombat.predictDamageTo(c, dmg, source, false) >= ComputerUtilCombat.getDamageToKill(c, false);
}
};
final Predicate<Card> filterKillable = c -> ComputerUtilCombat.predictDamageTo(c, dmg, source, false) >= ComputerUtilCombat.getDamageToKill(c, false);
list = CardLists.getNotKeyword(list, Keyword.INDESTRUCTIBLE);
list = CardLists.filter(list, filterKillable);

View File

@@ -1,6 +1,5 @@
package forge.ai.ability;
import com.google.common.base.Predicate;
import com.google.common.base.Predicates;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
@@ -171,7 +170,7 @@ public class DamageDealAi extends DamageAiBase {
} else if ("WildHunt".equals(logic)) {
// This dummy ability will just deal 0 damage, but holds the logic for the AI for Master of Wild Hunt
List<Card> wolves = CardLists.getValidCards(ai.getCardsIn(ZoneType.Battlefield), "Creature.Wolf+untapped+YouCtrl+Other", ai, source, sa);
dmg = Aggregates.sum(wolves, CardPredicates.Accessors.fnGetNetPower);
dmg = Aggregates.sum(wolves, Card::getNetPower);
} else if ("Triskelion".equals(logic)) {
final int n = source.getCounters(CounterEnumType.P1P1);
if (n > 0) {
@@ -337,16 +336,11 @@ public class DamageDealAi extends DamageAiBase {
// Filter MustTarget requirements
StaticAbilityMustTarget.filterMustTargetCards(ai, hPlay, sa);
CardCollection killables = CardLists.filter(hPlay, new Predicate<Card>() {
@Override
public boolean apply(final Card c) {
return c.getSVar("Targeting").equals("Dies")
CardCollection killables = CardLists.filter(hPlay, c -> c.getSVar("Targeting").equals("Dies")
|| (ComputerUtilCombat.getEnoughDamageToKill(c, d, source, false, noPrevention) <= d)
&& !ComputerUtil.canRegenerate(ai, c)
&& !c.hasSVar("SacMe")
&& !ComputerUtilCard.hasActiveUndyingOrPersist(c);
}
});
&& !ComputerUtilCard.hasActiveUndyingOrPersist(c));
// Filter AI-specific targets if provided
killables = ComputerUtil.filterAITgts(sa, ai, killables, true);
@@ -416,15 +410,10 @@ public class DamageDealAi extends DamageAiBase {
final Game game = source.getGame();
List<Card> hPlay = CardLists.filter(getTargetableCards(ai, sa, pl, tgt, activator, source, game), CardPredicates.Presets.PLANESWALKERS);
CardCollection killables = CardLists.filter(hPlay, new Predicate<Card>() {
@Override
public boolean apply(final Card c) {
return c.getSVar("Targeting").equals("Dies")
CardCollection killables = CardLists.filter(hPlay, c -> c.getSVar("Targeting").equals("Dies")
|| (ComputerUtilCombat.getEnoughDamageToKill(c, d, source, false, noPrevention) <= d)
&& !ComputerUtil.canRegenerate(ai, c)
&& !c.hasSVar("SacMe");
}
});
&& !c.hasSVar("SacMe"));
// Filter AI-specific targets if provided
killables = ComputerUtil.filterAITgts(sa, ai, killables, true);

View File

@@ -4,7 +4,6 @@ import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import com.google.common.base.Predicate;
import com.google.common.collect.Iterables;
import com.google.common.collect.Lists;
@@ -69,9 +68,7 @@ public class DebuffAi extends SpellAbilityAi {
List<Card> cards = AbilityUtils.getDefinedCards(source, sa.getParam("Defined"), sa);
final Combat combat = game.getCombat();
return Iterables.any(cards, new Predicate<Card>() {
@Override
public boolean apply(final Card c) {
return Iterables.any(cards, c -> {
if (c.getController().equals(sa.getActivatingPlayer()) || combat == null)
return false;
@@ -80,7 +77,6 @@ public class DebuffAi extends SpellAbilityAi {
}
// don't add duplicate negative keywords
return sa.hasParam("Keywords") && c.hasAnyKeyword(Arrays.asList(sa.getParam("Keywords").split(" & ")));
}
});
} else {
return debuffTgtAI(ai, sa, sa.hasParam("Keywords") ? Arrays.asList(sa.getParam("Keywords").split(" & ")) : null, false);
@@ -172,11 +168,8 @@ public class DebuffAi extends SpellAbilityAi {
final Player opp = AiAttackController.choosePreferredDefenderPlayer(ai);
CardCollection list = CardLists.getTargetableCards(opp.getCreaturesInPlay(), sa);
if (!list.isEmpty()) {
list = CardLists.filter(list, new Predicate<Card>() {
@Override
public boolean apply(final Card c) {
list = CardLists.filter(list, c -> {
return c.hasAnyKeyword(kws); // don't add duplicate negative keywords
}
});
}
return list;

View File

@@ -1,10 +1,8 @@
package forge.ai.ability;
import com.google.common.base.Predicate;
import forge.ai.*;
import forge.card.mana.ManaCost;
import forge.game.ability.ApiType;
import forge.game.card.Card;
import forge.game.card.CardCollection;
import forge.game.card.CardLists;
import forge.game.cost.Cost;
@@ -60,9 +58,7 @@ public class DelayedTriggerAi extends SpellAbilityAi {
// fetch Instant or Sorcery and AI has reason to play this turn
// does not try to get itself
final ManaCost costSa = sa.getPayCosts().getTotalMana();
final int count = CardLists.count(ai.getCardsIn(ZoneType.Hand), new Predicate<Card>() {
@Override
public boolean apply(final Card c) {
final int count = CardLists.count(ai.getCardsIn(ZoneType.Hand), c -> {
if (!(c.isInstant() || c.isSorcery()) || c.equals(sa.getHostCard())) {
return false;
}
@@ -91,7 +87,6 @@ public class DelayedTriggerAi extends SpellAbilityAi {
}
}
return false;
}
});
if (count == 0) {
@@ -106,9 +101,7 @@ public class DelayedTriggerAi extends SpellAbilityAi {
// fetch Instant or Sorcery without Rebound and AI has reason to play this turn
// only need count, not the list
final int count = CardLists.count(ai.getCardsIn(ZoneType.Hand), new Predicate<Card>() {
@Override
public boolean apply(final Card c) {
final int count = CardLists.count(ai.getCardsIn(ZoneType.Hand), c -> {
if (!(c.isInstant() || c.isSorcery()) || c.hasKeyword(Keyword.REBOUND)) {
return false;
}
@@ -129,7 +122,6 @@ public class DelayedTriggerAi extends SpellAbilityAi {
}
}
return false;
}
});
if (count == 0) {
@@ -140,15 +132,12 @@ public class DelayedTriggerAi extends SpellAbilityAi {
} else if (logic.equals("SaveCreature")) {
CardCollection ownCreatures = ai.getCreaturesInPlay();
ownCreatures = CardLists.filter(ownCreatures, new Predicate<Card>() {
@Override
public boolean apply(final Card card) {
ownCreatures = CardLists.filter(ownCreatures, card -> {
if (ComputerUtilCard.isUselessCreature(ai, card)) {
return false;
}
return ComputerUtil.predictCreatureWillDieThisTurn(ai, card, sa);
}
});
if (!ownCreatures.isEmpty()) {

View File

@@ -1,6 +1,5 @@
package forge.ai.ability;
import com.google.common.base.Predicate;
import com.google.common.base.Predicates;
import forge.ai.*;
import forge.game.ability.AbilityUtils;
@@ -170,9 +169,7 @@ public class DestroyAi extends SpellAbilityAi {
if (!playReusable(ai, sa)) {
list = CardLists.filter(list, Predicates.not(CardPredicates.hasCounter(CounterEnumType.SHIELD, 1)));
list = CardLists.filter(list, new Predicate<Card>() {
@Override
public boolean apply(final Card c) {
list = CardLists.filter(list, c -> {
//Check for cards that can be sacrificed in response
for (final SpellAbility ability : c.getAllSpellAbilities()) {
if (ability.isActivatedAbility()) {
@@ -193,7 +190,6 @@ public class DestroyAi extends SpellAbilityAi {
}
//Check for undying
return !c.hasKeyword(Keyword.UNDYING) || c.getCounters(CounterEnumType.P1P1) > 0;
}
});
}
@@ -201,12 +197,7 @@ public class DestroyAi extends SpellAbilityAi {
// regeneration shield
if (!noRegen) {
// TODO filter out things that might be tougher?
list = CardLists.filter(list, new Predicate<Card>() {
@Override
public boolean apply(final Card c) {
return c.getShieldCount() == 0 && !ComputerUtil.canRegenerate(ai, c);
}
});
list = CardLists.filter(list, c -> c.getShieldCount() == 0 && !ComputerUtil.canRegenerate(ai, c));
}
// Try to avoid targeting creatures that are dead on board
@@ -340,12 +331,7 @@ public class DestroyAi extends SpellAbilityAi {
if (!noRegen) {
// TODO filter out things that could regenerate in response?
// might be tougher?
preferred = CardLists.filter(preferred, new Predicate<Card>() {
@Override
public boolean apply(final Card c) {
return c.getShieldCount() == 0;
}
});
preferred = CardLists.filter(preferred, c -> c.getShieldCount() == 0);
}
// Filter AI-specific targets if provided

View File

@@ -19,12 +19,7 @@ import forge.game.zone.ZoneType;
public class DestroyAllAi extends SpellAbilityAi {
private static final Predicate<Card> predicate = new Predicate<Card>() {
@Override
public boolean apply(final Card c) {
return !(c.hasKeyword(Keyword.INDESTRUCTIBLE) || c.getCounters(CounterEnumType.SHIELD) > 0 || c.hasSVar("SacMe"));
}
};
private static final Predicate<Card> predicate = c -> !(c.hasKeyword(Keyword.INDESTRUCTIBLE) || c.getCounters(CounterEnumType.SHIELD) > 0 || c.hasSVar("SacMe"));
/* (non-Javadoc)
* @see forge.card.abilityfactory.SpellAiLogic#doTriggerAINoCost(forge.game.player.Player, java.util.Map, forge.card.spellability.SpellAbility, boolean)

View File

@@ -1,6 +1,5 @@
package forge.ai.ability;
import com.google.common.base.Predicate;
import com.google.common.base.Predicates;
import com.google.common.collect.Iterables;
import forge.ai.*;
@@ -29,7 +28,6 @@ import forge.game.zone.MagicStack;
import forge.game.zone.ZoneType;
import forge.util.MyRandom;
import forge.util.TextUtil;
import org.checkerframework.checker.nullness.qual.Nullable;
import java.util.ArrayList;
import java.util.List;
@@ -173,22 +171,12 @@ public class EffectAi extends SpellAbilityAi {
List<Card> human = opp.getCreaturesInPlay();
// only count creatures that can attack or block
comp = CardLists.filter(comp, new Predicate<Card>() {
@Override
public boolean apply(final Card c) {
return CombatUtil.canAttack(c, opp);
}
});
comp = CardLists.filter(comp, c -> CombatUtil.canAttack(c, opp));
if (comp.size() < 2) {
continue;
}
final List<Card> attackers = comp;
human = CardLists.filter(human, new Predicate<Card>() {
@Override
public boolean apply(final Card c) {
return CombatUtil.canBlockAtLeastOne(c, attackers);
}
});
human = CardLists.filter(human, c -> CombatUtil.canBlockAtLeastOne(c, attackers));
if (human.isEmpty()) {
continue;
}
@@ -345,10 +333,7 @@ public class EffectAi extends SpellAbilityAi {
} else if (logic.equals("CantRegenerate")) {
if (sa.usesTargeting()) {
CardCollection list = CardLists.getTargetableCards(ai.getOpponents().getCardsIn(ZoneType.Battlefield), sa);
list = CardLists.filter(list, CardPredicates.Presets.CAN_BE_DESTROYED, new Predicate<Card>() {
@Override
public boolean apply(@Nullable Card input) {
list = CardLists.filter(list, CardPredicates.Presets.CAN_BE_DESTROYED, input -> {
Map<AbilityKey, Object> runParams = AbilityKey.mapFromAffected(input);
runParams.put(AbilityKey.Regeneration, true);
List<ReplacementEffect> repDestoryList = game.getReplacementHandler().getReplacementList(ReplacementType.Destroy, runParams, ReplacementLayer.Other);
@@ -362,7 +347,6 @@ public class EffectAi extends SpellAbilityAi {
}
return false;
}
});
if (list.isEmpty()) {

View File

@@ -20,8 +20,6 @@ package forge.ai.ability;
import java.util.List;
import java.util.Map;
import com.google.common.base.Predicate;
import forge.ai.ComputerUtilCard;
import forge.ai.ComputerUtilCombat;
import forge.ai.SpellAbilityAi;
@@ -91,15 +89,8 @@ public final class EncodeAi extends SpellAbilityAi {
Card choice = null;
// final String logic = sa.getParam("AILogic");
// if (logic == null) {
final List<Card> attackers = CardLists.filter(list, new Predicate<Card>() {
@Override
public boolean apply(final Card c) {
return ComputerUtilCombat.canAttackNextTurn(c);
}
});
final List<Card> unblockables = CardLists.filter(attackers, new Predicate<Card>() {
@Override
public boolean apply(final Card c) {
final List<Card> attackers = CardLists.filter(list, ComputerUtilCombat::canAttackNextTurn);
final List<Card> unblockables = CardLists.filter(attackers, c -> {
boolean canAttackOpponent = false;
for (Player opp : ai.getOpponents()) {
if (CombatUtil.canAttack(c, opp) && !CombatUtil.canBeBlocked(c, null, opp)) {
@@ -108,7 +99,6 @@ public final class EncodeAi extends SpellAbilityAi {
}
}
return canAttackOpponent;
}
});
if (!unblockables.isEmpty()) {
choice = ComputerUtilCard.getBestAI(unblockables);

View File

@@ -2,9 +2,7 @@ package forge.ai.ability;
import java.util.Map;
import com.google.common.base.Predicate;
import forge.ai.SpellAbilityAi;
import forge.game.card.Card;
import forge.game.card.CardCollectionView;
import forge.game.card.CardLists;
import forge.game.phase.PhaseHandler;
@@ -26,12 +24,7 @@ public class FlipOntoBattlefieldAi extends SpellAbilityAi {
if ("DamageCreatures".equals(logic)) {
int maxToughness = Integer.parseInt(sa.getSubAbility().getParam("NumDmg"));
CardCollectionView rightToughness = CardLists.filter(aiPlayer.getOpponents().getCreaturesInPlay(), new Predicate<Card>() {
@Override
public boolean apply(Card card) {
return card.getNetToughness() <= maxToughness && card.canBeDestroyed();
}
});
CardCollectionView rightToughness = CardLists.filter(aiPlayer.getOpponents().getCreaturesInPlay(), card -> card.getNetToughness() <= maxToughness && card.canBeDestroyed());
return !rightToughness.isEmpty();
}

View File

@@ -2,8 +2,6 @@ package forge.ai.ability;
import java.util.List;
import com.google.common.base.Predicate;
import forge.ai.ComputerUtilCard;
import forge.ai.ComputerUtilCombat;
import forge.ai.SpellAbilityAi;
@@ -32,9 +30,7 @@ public class GoadAi extends SpellAbilityAi {
if (game.getPlayers().size() > 2) {
// use this part only in multiplayer
CardCollection betterList = CardLists.filter(list, new Predicate<Card>() {
@Override
public boolean apply(Card c) {
CardCollection betterList = CardLists.filter(list, c -> {
// filter only creatures which can attack
if (ComputerUtilCard.isUselessCreature(ai, c)) {
return false;
@@ -50,7 +46,6 @@ public class GoadAi extends SpellAbilityAi {
}
}
return false;
}
});
// if better list is not empty, use that one instead
@@ -61,9 +56,7 @@ public class GoadAi extends SpellAbilityAi {
}
} else {
// single Player, goaded creature would attack ai
CardCollection betterList = CardLists.filter(list, new Predicate<Card>() {
@Override
public boolean apply(Card c) {
CardCollection betterList = CardLists.filter(list, c -> {
// filter only creatures which can attack
if (ComputerUtilCard.isUselessCreature(ai, c)) {
return false;
@@ -74,7 +67,6 @@ public class GoadAi extends SpellAbilityAi {
}
// select only creatures AI can block
return ComputerUtilCard.canBeBlockedProfitably(ai, c, false);
}
});
// if better list is not empty, use that one instead

View File

@@ -245,7 +245,7 @@ public class ManaAi extends SpellAbilityAi {
if (logic.startsWith("ManaRitualBattery")) {
// Don't remove more counters than would be needed to cast the more expensive thing we want to cast,
// otherwise the AI grabs too many counters at once.
int maxCtrs = Aggregates.max(castableSpells, CardPredicates.Accessors.fnGetCmc) - manaSurplus;
int maxCtrs = Aggregates.max(castableSpells, Card::getCMC) - manaSurplus;
sa.setXManaCostPaid(Math.min(numCounters, maxCtrs));
}

View File

@@ -2,7 +2,6 @@ package forge.ai.ability;
import java.util.Map;
import com.google.common.base.Predicate;
import com.google.common.collect.Iterables;
import forge.ai.ComputerUtil;
@@ -138,12 +137,7 @@ public abstract class ManifestBaseAi extends SpellAbilityAi {
@Override
protected Card chooseSingleCard(final Player ai, final SpellAbility sa, Iterable<Card> options, boolean isOptional, Player targetedPlayer, Map<String, Object> params) {
if (Iterables.size(options) > 1 || isOptional) {
CardCollection filtered = CardLists.filter(options, new Predicate<Card>() {
@Override
public boolean apply(Card input) {
return shouldApply(input, ai, sa);
}
});
CardCollection filtered = CardLists.filter(options, input -> shouldApply(input, ai, sa));
if (!filtered.isEmpty()) {
return ComputerUtilCard.getBestAI(filtered);
}

View File

@@ -1,7 +1,6 @@
package forge.ai.ability;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;
import java.util.Map;
@@ -159,13 +158,7 @@ public class MillAi extends SpellAbilityAi {
}
// select Player which would cause the most damage
// JAVA 1.8 use Map.Entry.comparingByValue()
Map.Entry<Player, Integer> max = Collections.max(list.entrySet(), new Comparator<Map.Entry<Player,Integer>>(){
@Override
public int compare(Map.Entry<Player, Integer> o1, Map.Entry<Player, Integer> o2) {
return o1.getValue() - o2.getValue();
}
});
Map.Entry<Player, Integer> max = Collections.max(list.entrySet(), Map.Entry.comparingByValue());
sa.getTargets().add(max.getKey());
}

View File

@@ -3,7 +3,6 @@ package forge.ai.ability;
import java.util.List;
import java.util.Map;
import com.google.common.base.Predicate;
import com.google.common.collect.Iterables;
import forge.ai.AiCardMemory;
@@ -122,9 +121,7 @@ public class MustBlockAi extends SpellAbilityAi {
private List<Card> determineBlockerFromList(final Card attacker, final Player ai, Iterable<Card> options, SpellAbility sa,
final boolean onlyLethal, final boolean testTapped) {
List<Card> list = CardLists.filter(options, new Predicate<Card>() {
@Override
public boolean apply(final Card c) {
List<Card> list = CardLists.filter(options, c -> {
boolean tapped = c.isTapped();
if (testTapped) {
c.setTapped(false);
@@ -142,8 +139,6 @@ public class MustBlockAi extends SpellAbilityAi {
c.setTapped(tapped);
}
return true;
}
});
return list;

View File

@@ -2,7 +2,6 @@ package forge.ai.ability;
import java.util.Map;
import com.google.common.base.Predicate;
import com.google.common.base.Predicates;
import forge.ai.ComputerUtil;
@@ -29,12 +28,7 @@ public class MutateAi extends SpellAbilityAi {
CardPredicates.hasKeyword(Keyword.DEFENDER),
CardPredicates.hasKeyword("CARDNAME can't attack."),
CardPredicates.hasKeyword("CARDNAME can't block."),
new Predicate<Card>() {
@Override
public boolean apply(final Card card) {
return ComputerUtilCard.isUselessCreature(aiPlayer, card);
}
}
card -> ComputerUtilCard.isUselessCreature(aiPlayer, card)
)));
if (mutateTgts.isEmpty()) {

View File

@@ -3,8 +3,6 @@ package forge.ai.ability;
import forge.game.card.CardCopyService;
import org.apache.commons.lang3.StringUtils;
import com.google.common.base.Predicate;
import forge.ai.AiController;
import forge.ai.AiProps;
import forge.ai.ComputerUtil;
@@ -146,12 +144,9 @@ public class PermanentCreatureAi extends PermanentAi {
if (combat != null && combat.getDefendingPlayers().contains(ai)) {
// Currently we use a rather simplistic assumption that if we're behind on creature count on board,
// a flashed in creature might prove to be good as an additional defender
int numUntappedPotentialBlockers = CardLists.filter(ai.getCreaturesInPlay(), new Predicate<Card>() {
@Override
public boolean apply(final Card card) {
return card.isUntapped() && !ComputerUtilCard.isUselessCreature(ai, card);
}
}).size();
int numUntappedPotentialBlockers = CardLists.filter(ai.getCreaturesInPlay(),
card1 -> card1.isUntapped() && !ComputerUtilCard.isUselessCreature(ai, card1)
).size();
if (combat.getAttackersOf(ai).size() > numUntappedPotentialBlockers) {
valuableBlocker = true;

View File

@@ -1,6 +1,5 @@
package forge.ai.ability;
import com.google.common.base.Predicate;
import com.google.common.collect.Iterables;
import forge.ai.*;
import forge.card.CardStateName;
@@ -148,9 +147,7 @@ public class PlayAi extends SpellAbilityAi {
state = CardStateName.Original;
}
List<Card> tgtCards = CardLists.filter(options, new Predicate<Card>() {
@Override
public boolean apply(final Card c) {
List<Card> tgtCards = CardLists.filter(options, c -> {
// TODO needs to be aligned for MDFC along with getAbilityToPlay so the knowledge
// of which spell was the reason for the choice can be used there
for (SpellAbility s : AbilityUtils.getSpellsFromPlayEffect(c, ai, state, false)) {
@@ -198,7 +195,6 @@ public class PlayAi extends SpellAbilityAi {
}
}
return false;
}
});
if (sa.hasParam("CastTransformed")) {

View File

@@ -1,7 +1,5 @@
package forge.ai.ability;
import com.google.common.base.Predicate;
import forge.ai.ComputerUtil;
import forge.ai.SpellAbilityAi;
import forge.game.ability.AbilityUtils;
@@ -86,17 +84,13 @@ public class PoisonAi extends SpellAbilityAi {
PlayerCollection tgts = ai.getOpponents().filter(PlayerPredicates.isTargetableBy(sa));
if (!tgts.isEmpty()) {
// try to select a opponent that can lose through poison counters
PlayerCollection betterTgts = tgts.filter(new Predicate<Player>() {
@Override
public boolean apply(Player input) {
PlayerCollection betterTgts = tgts.filter(input -> {
if (input.cantLose()) {
return false;
} else if (!input.canReceiveCounters(CounterType.get(CounterEnumType.POISON))) {
return false;
}
return true;
}
});
if (!betterTgts.isEmpty()) {
@@ -120,15 +114,11 @@ public class PoisonAi extends SpellAbilityAi {
PlayerCollection allies = ai.getAllies().filter(PlayerPredicates.isTargetableBy(sa));
if (!allies.isEmpty()) {
// some ally would be unaffected
PlayerCollection betterAllies = allies.filter(new Predicate<Player>() {
@Override
public boolean apply(Player input) {
PlayerCollection betterAllies = allies.filter(input -> {
if (input.cantLose()) {
return true;
}
return !input.canReceiveCounters(CounterType.get(CounterEnumType.POISON));
}
});
if (!betterAllies.isEmpty()) {
allies = betterAllies;

View File

@@ -2,8 +2,6 @@ package forge.ai.ability;
import java.util.List;
import com.google.common.base.Predicate;
import forge.ai.ComputerUtilCard;
import forge.ai.SpellAbilityAi;
import forge.game.ability.AbilityUtils;
@@ -30,12 +28,7 @@ public class PowerExchangeAi extends SpellAbilityAi {
List<Card> list =
CardLists.getValidCards(ai.getGame().getCardsIn(ZoneType.Battlefield), tgt.getValidTgts(), ai, sa.getHostCard(), sa);
list = CardLists.filter(list, new Predicate<Card>() {
@Override
public boolean apply(final Card c) {
return c.canBeTargetedBy(sa) && c.getController() != ai;
}
});
list = CardLists.filter(list, c -> c.canBeTargetedBy(sa) && c.getController() != ai);
CardLists.sortByPowerDesc(list);
c1 = list.isEmpty() ? null : list.get(0);
if (sa.hasParam("Defined")) {

View File

@@ -3,8 +3,6 @@ package forge.ai.ability;
import java.util.ArrayList;
import java.util.List;
import com.google.common.base.Predicate;
import forge.ai.AiAttackController;
import forge.ai.ComputerUtil;
import forge.ai.ComputerUtilCard;
@@ -107,9 +105,7 @@ public class ProtectAi extends SpellAbilityAi {
CardCollection list = ai.getCreaturesInPlay();
final List<GameObject> threatenedObjects = ComputerUtil.predictThreatenedObjects(sa.getActivatingPlayer(), sa, true);
list = CardLists.filter(list, new Predicate<Card>() {
@Override
public boolean apply(final Card c) {
list = CardLists.filter(list, c -> {
if (!c.canBeTargetedBy(sa)) {
return false;
}
@@ -148,13 +144,12 @@ public class ProtectAi extends SpellAbilityAi {
return false;
}
Player opponent = ai.getWeakestOpponent();
Combat combat = ai.getGame().getCombat();
int dmg = ComputerUtilCombat.damageIfUnblocked(c, opponent, combat, true);
Combat combat1 = ai.getGame().getCombat();
int dmg = ComputerUtilCombat.damageIfUnblocked(c, opponent, combat1, true);
float ratio = 1.0f * dmg / opponent.getLife();
return MyRandom.getRandom().nextFloat() < ratio;
}
return false;
}
});
return list;
}
@@ -266,19 +261,9 @@ public class ProtectAi extends SpellAbilityAi {
}
CardCollection pref = CardLists.filterControlledBy(list, ai);
pref = CardLists.filter(pref, new Predicate<Card>() {
@Override
public boolean apply(final Card c) {
return !hasProtectionFromAll(c, ProtectEffect.getProtectionList(sa));
}
});
pref = CardLists.filter(pref, c -> !hasProtectionFromAll(c, ProtectEffect.getProtectionList(sa)));
final CardCollection pref2 = CardLists.filterControlledBy(list, ai);
pref = CardLists.filter(pref, new Predicate<Card>() {
@Override
public boolean apply(final Card c) {
return !hasProtectionFromAny(c, ProtectEffect.getProtectionList(sa));
}
});
pref = CardLists.filter(pref, c -> !hasProtectionFromAny(c, ProtectEffect.getProtectionList(sa)));
final List<Card> forced = CardLists.filterControlledBy(list, ai);
while (sa.canAddMoreTarget()) {

View File

@@ -1,6 +1,5 @@
package forge.ai.ability;
import com.google.common.base.Predicate;
import com.google.common.base.Predicates;
import com.google.common.collect.Iterables;
import com.google.common.collect.Lists;
@@ -164,9 +163,7 @@ public class PumpAi extends PumpAiBase {
if (attr.isEmpty()) {
return false;
}
CardCollection best = CardLists.filter(attr, new Predicate<Card>() {
@Override
public boolean apply(Card card) {
CardCollection best = CardLists.filter(attr, card -> {
int amount = 0;
if (StringUtils.isNumeric(amountStr)) {
amount = AbilityUtils.calculateAmount(source, amountStr, moveSA);
@@ -190,8 +187,6 @@ public class PumpAi extends PumpAiBase {
|| card.isToken();
}
return false;
}
});
if (best.isEmpty()) {
@@ -213,9 +208,7 @@ public class PumpAi extends PumpAiBase {
}
List<Card> oppList = CardLists.filterControlledBy(list, ai.getOpponents());
if (!oppList.isEmpty() && !sameCtrl) {
List<Card> best = CardLists.filter(oppList, new Predicate<Card>() {
@Override
public boolean apply(Card card) {
List<Card> best = CardLists.filter(oppList, card -> {
int amount = 0;
if (StringUtils.isNumeric(amountStr)) {
amount = AbilityUtils.calculateAmount(source, amountStr, moveSA);
@@ -239,7 +232,6 @@ public class PumpAi extends PumpAiBase {
|| card.isToken();
}
return true;
}
});
if (best.isEmpty()) {
@@ -520,16 +512,13 @@ public class PumpAi extends PumpAiBase {
// Detain target nonland permanent: don't target noncreature permanents that don't have
// any activated abilities.
if ("DetainNonLand".equals(sa.getParam("AILogic"))) {
list = CardLists.filter(list, Predicates.or(CardPredicates.Presets.CREATURES, new Predicate<Card>() {
@Override
public boolean apply(Card card) {
for (SpellAbility sa : card.getSpellAbilities()) {
if (sa.isActivatedAbility()) {
list = CardLists.filter(list, Predicates.or(CardPredicates.Presets.CREATURES, card -> {
for (SpellAbility sa1 : card.getSpellAbilities()) {
if (sa1.isActivatedAbility()) {
return true;
}
}
return false;
}
}));
}
@@ -548,12 +537,7 @@ public class PumpAi extends PumpAiBase {
if ("BetterCreatureThanSource".equals(sa.getParam("AILogic"))) {
// Don't target cards that are not better in value than the targeting card
final int sourceValue = ComputerUtilCard.evaluateCreature(source);
list = CardLists.filter(list, new Predicate<Card>() {
@Override
public boolean apply(Card card) {
return card.isCreature() && ComputerUtilCard.evaluateCreature(card) > sourceValue + 30;
}
});
list = CardLists.filter(list, card -> card.isCreature() && ComputerUtilCard.evaluateCreature(card) > sourceValue + 30);
}
if ("ReplaySpell".equals(sa.getParam("AILogic"))) {
@@ -819,23 +803,11 @@ public class PumpAi extends PumpAiBase {
}
values.keySet().removeAll(toRemove);
// JAVA 1.8 use Map.Entry.comparingByValue()
data.put(opp, Collections.max(values.entrySet(), new Comparator<Map.Entry<String, Integer>>() {
@Override
public int compare(Map.Entry<String, Integer> o1, Map.Entry<String, Integer> o2) {
return o1.getValue() - o2.getValue();
}
}));
data.put(opp, Collections.max(values.entrySet(), Map.Entry.comparingByValue()));
}
if (!data.isEmpty()) {
// JAVA 1.8 use Map.Entry.comparingByValue() somehow
Map.Entry<Player, Map.Entry<String, Integer>> max = Collections.max(data.entrySet(), new Comparator<Map.Entry<Player, Map.Entry<String, Integer>>>() {
@Override
public int compare(Map.Entry<Player, Map.Entry<String, Integer>> o1, Map.Entry<Player, Map.Entry<String, Integer>> o2) {
return o1.getValue().getValue() - o2.getValue().getValue();
}
});
Map.Entry<Player, Map.Entry<String, Integer>> max = Collections.max(data.entrySet(), Comparator.comparingInt(o -> o.getValue().getValue()));
// filter list again by the opponent and a creature of the wanted name that can be targeted
list = CardLists.filter(CardLists.filterControlledBy(list, max.getKey()),

View File

@@ -122,15 +122,12 @@ public abstract class PumpAiBase extends SpellAbilityAi {
return false;
}
List<Card> attackers = CardLists.filter(ai.getCreaturesInPlay(), new Predicate<Card>() {
@Override
public boolean apply(final Card c) {
List<Card> attackers = CardLists.filter(ai.getCreaturesInPlay(), c -> {
if (c.equals(sa.getHostCard()) && sa.getPayCosts().hasTapCost()
&& (combat == null || !combat.isAttacking(c))) {
return false;
}
return (combat != null && combat.isAttacking(c)) || CombatUtil.canAttack(c, card.getController());
}
});
return CombatUtil.canBlockAtLeastOne(card, attackers);
}
@@ -140,9 +137,7 @@ public abstract class PumpAiBase extends SpellAbilityAi {
return false;
}
List<Card> attackers = CardLists.filter(ai.getCreaturesInPlay(), new Predicate<Card>() {
@Override
public boolean apply(final Card c) {
List<Card> attackers = CardLists.filter(ai.getCreaturesInPlay(), c -> {
if (c.equals(sa.getHostCard()) && sa.getPayCosts().hasTapCost()
&& (combat == null || !combat.isAttacking(c))) {
return false;
@@ -150,7 +145,6 @@ public abstract class PumpAiBase extends SpellAbilityAi {
// the cards controller needs to be the one attacked
return (combat != null && combat.isAttacking(c) && card.getController().equals(combat.getDefenderPlayerByAttacker(c))) ||
CombatUtil.canAttack(c, card.getController());
}
});
return CombatUtil.canBlockAtLeastOne(card, attackers);
} else if (keyword.endsWith("This card doesn't untap during your next untap step.")) {
@@ -416,12 +410,7 @@ public abstract class PumpAiBase extends SpellAbilityAi {
protected CardCollection getPumpCreatures(final Player ai, final SpellAbility sa, final int defense, final int attack,
final List<String> keywords, final boolean immediately) {
CardCollection list = CardLists.getTargetableCards(ai.getCreaturesInPlay(), sa);
list = CardLists.filter(list, new Predicate<Card>() {
@Override
public boolean apply(final Card c) {
return ComputerUtilCard.shouldPumpCard(ai, sa, c, defense, attack, keywords, immediately);
}
});
list = CardLists.filter(list, c -> ComputerUtilCard.shouldPumpCard(ai, sa, c, defense, attack, keywords, immediately));
return list;
}
@@ -449,14 +438,11 @@ public abstract class PumpAiBase extends SpellAbilityAi {
}
if (defense < 0) { // with spells that give -X/-X, compi will try to destroy a creature
list = CardLists.filter(list, new Predicate<Card>() {
@Override
public boolean apply(final Card c) {
list = CardLists.filter(list, c -> {
if (c.getSVar("Targeting").equals("Dies") || c.getNetToughness() <= -defense) {
return true; // can kill indestructible creatures
}
return ComputerUtilCombat.getDamageToKill(c, false) <= -defense && !c.hasKeyword(Keyword.INDESTRUCTIBLE);
}
}); // leaves all creatures that will be destroyed
} // -X/-X end
else if (attack < 0 && !game.getReplacementHandler().isPreventCombatDamageThisTurn()) {
@@ -472,9 +458,7 @@ public abstract class PumpAiBase extends SpellAbilityAi {
} else {
// Human active, only curse attacking creatures
if (game.getPhaseHandler().getPhase().isBefore(PhaseType.COMBAT_DECLARE_BLOCKERS)) {
list = CardLists.filter(list, new Predicate<Card>() {
@Override
public boolean apply(final Card c) {
list = CardLists.filter(list, c -> {
if (combat == null || !combat.isAttacking(c)) {
return false;
}
@@ -483,7 +467,6 @@ public abstract class PumpAiBase extends SpellAbilityAi {
}
//Don't waste a -7/-0 spell on a 1/1 creature
return c.getNetPower() + attack > -2 || c.getNetPower() > 3;
}
});
} else {
list = new CardCollection();
@@ -501,12 +484,7 @@ public abstract class PumpAiBase extends SpellAbilityAi {
}
}
list = CardLists.filter(list, new Predicate<Card>() {
@Override
public boolean apply(final Card c) {
return containsUsefulKeyword(ai, keywords, c, sa, attack);
}
});
list = CardLists.filter(list, c -> containsUsefulKeyword(ai, keywords, c, sa, attack));
} else if (sa.hasParam("NumAtt") || sa.hasParam("NumDef")) {
// X is zero
list = new CardCollection();

View File

@@ -4,7 +4,6 @@ import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import com.google.common.base.Predicate;
import com.google.common.collect.Iterables;
import forge.ai.ComputerUtil;
@@ -85,23 +84,17 @@ public class PumpAllAi extends PumpAiBase {
if (sa.isCurse()) {
if (defense < 0) { // try to destroy creatures
comp = CardLists.filter(comp, new Predicate<Card>() {
@Override
public boolean apply(final Card c) {
comp = CardLists.filter(comp, c -> {
if (c.getNetToughness() <= -defense) {
return true; // can kill indestructible creatures
}
return ComputerUtilCombat.getDamageToKill(c, false) <= -defense && !c.hasKeyword(Keyword.INDESTRUCTIBLE);
}
}); // leaves all creatures that will be destroyed
human = CardLists.filter(human, new Predicate<Card>() {
@Override
public boolean apply(final Card c) {
human = CardLists.filter(human, c -> {
if (c.getNetToughness() <= -defense) {
return true; // can kill indestructible creatures
}
return ComputerUtilCombat.getDamageToKill(c, false) <= -defense && !c.hasKeyword(Keyword.INDESTRUCTIBLE);
}
}); // leaves all creatures that will be destroyed
} // -X/-X end
else if (power < 0) { // -X/-0

View File

@@ -3,7 +3,6 @@ package forge.ai.ability;
import java.util.Map;
import com.google.common.base.Predicate;
import com.google.common.collect.Iterables;
import forge.ai.*;
import forge.game.card.Card;
@@ -56,12 +55,7 @@ public class RepeatAi extends SpellAbilityAi {
Card best = null;
Iterable<Card> targetableAi = Iterables.filter(ai.getCreaturesInPlay(), CardPredicates.isTargetableBy(sa));
if (!logic.endsWith("IgnoreLegendary")) {
best = ComputerUtilCard.getBestAI(Iterables.filter(targetableAi, new Predicate<Card>() {
@Override
public boolean apply(Card card) {
return card.ignoreLegendRule();
}
}));
best = ComputerUtilCard.getBestAI(Iterables.filter(targetableAi, Card::ignoreLegendRule));
} else {
best = ComputerUtilCard.getBestAI(targetableAi);
}

View File

@@ -3,8 +3,6 @@ package forge.ai.ability;
import java.util.List;
import java.util.Map;
import com.google.common.base.Predicate;
import forge.ai.ComputerUtilCard;
import forge.ai.SpecialCardAi;
import forge.ai.SpellAbilityAi;
@@ -97,12 +95,7 @@ public class RepeatEachAi extends SpellAbilityAi {
return hitOpp;
} else if ("EquipAll".equals(logic)) {
if (aiPlayer.getGame().getPhaseHandler().is(PhaseType.MAIN1, aiPlayer)) {
final CardCollection unequipped = CardLists.filter(aiPlayer.getCardsIn(ZoneType.Battlefield), new Predicate<Card>() {
@Override
public boolean apply(Card card) {
return card.isEquipment() && card.getAttachedTo() != sa.getHostCard();
}
});
final CardCollection unequipped = CardLists.filter(aiPlayer.getCardsIn(ZoneType.Battlefield), card -> card.isEquipment() && card.getAttachedTo() != sa.getHostCard());
return !unequipped.isEmpty();
}

View File

@@ -3,8 +3,6 @@ package forge.ai.ability;
import java.util.List;
import java.util.Map;
import com.google.common.base.Predicate;
import forge.ai.ComputerUtilCard;
import forge.ai.ComputerUtilCost;
import forge.ai.SpellAbilityAi;
@@ -75,12 +73,7 @@ public class SetStateAi extends SpellAbilityAi {
sa.resetTargets();
// select only the ones that can transform
CardCollection list = CardLists.filter(CardUtil.getValidCardsToTarget(sa), CardPredicates.Presets.CREATURES, new Predicate<Card>() {
@Override
public boolean apply(Card c) {
return c.canTransform(sa);
}
});
CardCollection list = CardLists.filter(CardUtil.getValidCardsToTarget(sa), CardPredicates.Presets.CREATURES, c -> c.canTransform(sa));
if (list.isEmpty()) {
return false;

View File

@@ -109,39 +109,33 @@ public abstract class TapAiBase extends SpellAbilityAi {
final Game game = ai.getGame();
CardCollection tapList = CardLists.getTargetableCards(ai.getOpponents().getCardsIn(ZoneType.Battlefield), sa);
tapList = CardLists.filter(tapList, Presets.CAN_TAP);
tapList = CardLists.filter(tapList, new Predicate<Card>() {
@Override
public boolean apply(final Card c) {
tapList = CardLists.filter(tapList, c -> {
if (c.isCreature()) {
return true;
}
for (final SpellAbility sa : c.getSpellAbilities()) {
if (sa.isAbility() && sa.getPayCosts().hasTapCost()) {
for (final SpellAbility sa1 : c.getSpellAbilities()) {
if (sa1.isAbility() && sa1.getPayCosts().hasTapCost()) {
return true;
}
}
return false;
}
});
//use broader approach when the cost is a positive thing
if (tapList.isEmpty() && ComputerUtil.activateForCost(sa, ai)) {
tapList = CardLists.getTargetableCards(ai.getOpponents().getCardsIn(ZoneType.Battlefield), sa);
tapList = CardLists.filter(tapList, new Predicate<Card>() {
@Override
public boolean apply(final Card c) {
tapList = CardLists.filter(tapList, c -> {
if (c.isCreature()) {
return true;
}
for (final SpellAbility sa : c.getSpellAbilities()) {
if (sa.isAbility() && sa.getPayCosts().hasTapCost()) {
for (final SpellAbility sa12 : c.getSpellAbilities()) {
if (sa12.isAbility() && sa12.getPayCosts().hasTapCost()) {
return true;
}
}
return false;
}
});
}
@@ -187,12 +181,7 @@ public abstract class TapAiBase extends SpellAbilityAi {
//Combat has already started
attackers = game.getCombat().getAttackers();
} else {
attackers = CardLists.filter(ai.getCreaturesInPlay(), new Predicate<Card>() {
@Override
public boolean apply(final Card c) {
return CombatUtil.canAttack(c, opp);
}
});
attackers = CardLists.filter(ai.getCreaturesInPlay(), c -> CombatUtil.canAttack(c, opp));
attackers.remove(source);
}
Predicate<Card> findBlockers = CardPredicates.possibleBlockerForAtLeastOne(attackers);
@@ -209,12 +198,7 @@ public abstract class TapAiBase extends SpellAbilityAi {
&& phase.getPhase().isBefore(PhaseType.COMBAT_DECLARE_ATTACKERS)) {
// Tap creatures possible blockers before combat during AI's turn.
if (Iterables.any(tapList, CardPredicates.Presets.CREATURES)) {
List<Card> creatureList = CardLists.filter(tapList, new Predicate<Card>() {
@Override
public boolean apply(final Card c) {
return c.isCreature() && CombatUtil.canAttack(c, opp);
}
});
List<Card> creatureList = CardLists.filter(tapList, c -> c.isCreature() && CombatUtil.canAttack(c, opp));
choice = ComputerUtilCard.getBestCreatureAI(creatureList);
} else { // no creatures available
choice = ComputerUtilCard.getMostExpensivePermanentAI(tapList);

View File

@@ -2,7 +2,6 @@ package forge.ai.ability;
import java.util.List;
import com.google.common.base.Predicate;
import com.google.common.collect.Iterables;
import forge.ai.ComputerUtilCombat;
@@ -75,12 +74,7 @@ public class TapAllAi extends SpellAbilityAi {
// in AI's turn, check if there are possible attackers, before tapping blockers
if (game.getPhaseHandler().isPlayerTurn(ai)) {
validTappables = ai.getCardsIn(ZoneType.Battlefield);
final boolean any = Iterables.any(validTappables, new Predicate<Card>() {
@Override
public boolean apply(final Card c) {
return CombatUtil.canAttack(c) && ComputerUtilCombat.canAttackNextTurn(c);
}
});
final boolean any = Iterables.any(validTappables, c -> CombatUtil.canAttack(c) && ComputerUtilCombat.canAttackNextTurn(c));
return any;
}
return true;

View File

@@ -3,7 +3,6 @@ package forge.ai.ability;
import java.util.List;
import java.util.Map;
import com.google.common.base.Predicate;
import com.google.common.collect.Iterables;
import forge.ai.AiController;
@@ -182,12 +181,7 @@ public class TokenAi extends SpellAbilityAi {
} else {
// Flash Foliage
CardCollection list = CardLists.getTargetableCards(ai.getOpponents().getCardsIn(ZoneType.Battlefield), sa);
CardCollection betterList = CardLists.filter(list, new Predicate<Card>() {
@Override
public boolean apply(Card c) {
return c.getLethalDamage() == 1;
}
});
CardCollection betterList = CardLists.filter(list, c -> c.getLethalDamage() == 1);
if (!betterList.isEmpty()) {
list = betterList;
}

View File

@@ -1,6 +1,5 @@
package forge.ai.ability;
import com.google.common.base.Predicate;
import com.google.common.base.Predicates;
import com.google.common.collect.Iterables;
import forge.ai.*;
@@ -408,18 +407,15 @@ public class UntapAi extends SpellAbilityAi {
// (it may actually be possible to enable this for sorceries, but that'll need some canPlay shenanigans)
CardCollection playable = CardLists.filter(inHand, Presets.PERMANENTS);
CardCollection untappingCards = CardLists.filter(ai.getCardsIn(ZoneType.Battlefield), new Predicate<Card>() {
@Override
public boolean apply(Card card) {
CardCollection untappingCards = CardLists.filter(ai.getCardsIn(ZoneType.Battlefield), card -> {
boolean hasUntapLandLogic = false;
for (SpellAbility sa : card.getSpellAbilities()) {
if ("PoolExtraMana".equals(sa.getParam("AILogic"))) {
for (SpellAbility sa1 : card.getSpellAbilities()) {
if ("PoolExtraMana".equals(sa1.getParam("AILogic"))) {
hasUntapLandLogic = true;
break;
}
}
return hasUntapLandLogic && card.isUntapped();
}
});
// TODO: currently limited to Main 2, somehow improve to let the AI use this SA at other time?

View File

@@ -197,12 +197,7 @@ public class GameCopier {
// TODO update thisTurnCast
if (advanceToPhase != null) {
newGame.getPhaseHandler().devAdvanceToPhase(advanceToPhase, new Runnable() {
@Override
public void run() {
GameSimulator.resolveStack(newGame, aiPlayer.getWeakestOpponent());
}
});
newGame.getPhaseHandler().devAdvanceToPhase(advanceToPhase, () -> GameSimulator.resolveStack(newGame, aiPlayer.getWeakestOpponent()));
}
return newGame;

View File

@@ -252,9 +252,7 @@ public class GameSimulator {
// TODO: This needs to set an AI controller for all opponents, in case of multiplayer.
PlayerControllerAi sim = new PlayerControllerAi(game, opponent, opponent.getLobbyPlayer());
sim.setUseSimulation(true);
opponent.runWithController(new Runnable() {
@Override
public void run() {
opponent.runWithController(() -> {
final Set<Card> allAffectedCards = new HashSet<>();
game.getAction().checkStateEffects(false, allAffectedCards);
game.getStack().addAllTriggeredAbilitiesToStack();
@@ -278,7 +276,6 @@ public class GameSimulator {
// Continue until stack is empty.
}
}
}, sim);
}

View File

@@ -59,12 +59,7 @@ public class GameStateEvaluator {
gameCopy = copier.makeCopy(null, aiPlayer);
}
gameCopy.getPhaseHandler().devAdvanceToPhase(PhaseType.COMBAT_DAMAGE, new Runnable() {
@Override
public void run() {
GameSimulator.resolveStack(gameCopy, aiPlayer.getWeakestOpponent());
}
});
gameCopy.getPhaseHandler().devAdvanceToPhase(PhaseType.COMBAT_DAMAGE, () -> GameSimulator.resolveStack(gameCopy, aiPlayer.getWeakestOpponent()));
CombatSimResult result = new CombatSimResult();
result.copier = copier;
result.gameCopy = gameCopy;

View File

@@ -227,15 +227,13 @@ public class CardStorageReader {
// Iterate through txt files or zip archive.
// Report relevant numbers to progress monitor model.
final Set<CardRules> result = new TreeSet<>(new Comparator<CardRules>() {
@Override
public int compare(final CardRules o1, final CardRules o2) {
final Set<CardRules> result;
if (loadingTokens) {
return String.CASE_INSENSITIVE_ORDER.compare(o1.getNormalizedName(), o2.getNormalizedName());
result = new TreeSet<>(Comparator.comparing(CardRules::getNormalizedName, String.CASE_INSENSITIVE_ORDER));
}
return String.CASE_INSENSITIVE_ORDER.compare(o1.getName(), o2.getName());
else {
result = new TreeSet<>(Comparator.comparing(CardRules::getName, String.CASE_INSENSITIVE_ORDER));
}
});
if (loadCardsLazily) {
return result;
@@ -321,14 +319,11 @@ public class CardStorageReader {
for (int iPart = 0; iPart < maxParts; iPart++) {
final int from = iPart * filesPerPart;
final int till = iPart == maxParts - 1 ? totalFiles : from + filesPerPart;
tasks.add(new Callable<List<CardRules>>() {
@Override
public List<CardRules> call() throws Exception{
tasks.add(() -> {
final List<CardRules> res = loadCardsInRangeFromZip(entries, from, till);
cdl.countDown();
progressObserver.report(maxParts - (int)cdl.getCount(), maxParts);
return res;
}
});
}
return tasks;
@@ -342,14 +337,11 @@ public class CardStorageReader {
for (int iPart = 0; iPart < maxParts; iPart++) {
final int from = iPart * filesPerPart;
final int till = iPart == maxParts - 1 ? totalFiles : from + filesPerPart;
tasks.add(new Callable<List<CardRules>>() {
@Override
public List<CardRules> call() throws Exception{
tasks.add(() -> {
final List<CardRules> res = loadCardsInRange(allFiles, from, till);
cdl.countDown();
progressObserver.report(maxParts - (int)cdl.getCount(), maxParts);
return res;
}
});
}
return tasks;

View File

@@ -633,9 +633,7 @@ public final class CardDb implements ICardDatabase, IDeckGenPool {
cardName = cardNameRequest.cardName;
isFoil = isFoil || cardNameRequest.isFoil;
List<PaperCard> candidates = getAllCards(cardName, new Predicate<PaperCard>() {
@Override
public boolean apply(PaperCard c) {
List<PaperCard> candidates = getAllCards(cardName, c -> {
boolean artIndexFilter = true;
boolean collectorNumberFilter = true;
boolean setFilter = c.getEdition().equalsIgnoreCase(edition.getCode()) ||
@@ -646,7 +644,6 @@ public final class CardDb implements ICardDatabase, IDeckGenPool {
&& !(collectorNumber.equals(IPaperCard.NO_COLLECTOR_NUMBER)))
collectorNumberFilter = (c.getCollectorNumber().equals(collectorNumber));
return setFilter && artIndexFilter && collectorNumberFilter;
}
});
if (candidates.isEmpty())
return null;
@@ -791,9 +788,7 @@ public final class CardDb implements ICardDatabase, IDeckGenPool {
Predicate<PaperCard> cardQueryFilter;
filter = (filter != null) ? filter : Predicates.alwaysTrue();
if (releaseDate != null) {
cardQueryFilter = new Predicate<PaperCard>() {
@Override
public boolean apply(PaperCard c) {
cardQueryFilter = c -> {
if (c.getArtIndex() != cr.artIndex)
return false; // not interested anyway!
CardEdition ed = editions.get(c.getEdition());
@@ -802,15 +797,9 @@ public final class CardDb implements ICardDatabase, IDeckGenPool {
return ed.getDate().before(releaseDate);
else
return ed.getDate().after(releaseDate);
}
};
} else // filter candidates based on requested artIndex
cardQueryFilter = new Predicate<PaperCard>() {
@Override
public boolean apply(PaperCard card) {
return card.getArtIndex() == cr.artIndex;
}
};
cardQueryFilter = card -> card.getArtIndex() == cr.artIndex;
cardQueryFilter = Predicates.and(cardQueryFilter, filter);
cards = getAllCards(cr.cardName, cardQueryFilter);
// Note: No need to check whether "cards" is empty; the next for loop will validate condition at L699
@@ -838,12 +827,7 @@ public final class CardDb implements ICardDatabase, IDeckGenPool {
return null; // nothing to do
// Filter Cards Editions based on set preferences
List<CardEdition> acceptedEditions = Lists.newArrayList(Iterables.filter(cardEditions, new Predicate<CardEdition>() {
@Override
public boolean apply(CardEdition ed) {
return artPref.accept(ed);
}
}));
List<CardEdition> acceptedEditions = Lists.newArrayList(Iterables.filter(cardEditions, artPref::accept));
/* At this point, it may be possible that Art Preference is too-strict for the requested card!
i.e. acceptedEditions.size() == 0!
@@ -908,13 +892,10 @@ public final class CardDb implements ICardDatabase, IDeckGenPool {
}
public Collection<PaperCard> getUniqueCardsNoAlt() {
return Maps.filterEntries(this.uniqueCardsByName, new Predicate<Entry<String, PaperCard>>() {
@Override
public boolean apply(Entry<String, PaperCard> e) {
return Maps.filterEntries(this.uniqueCardsByName, e -> {
if (e == null)
return false;
return e.getKey().equals(e.getValue().getName());
}
}).values();
}
@@ -956,18 +937,11 @@ public final class CardDb implements ICardDatabase, IDeckGenPool {
}
public Collection<PaperCard> getAllCardsNoAlt() {
return Multimaps.filterEntries(allCardsByName, new Predicate<Entry<String, PaperCard>>() {
@Override
public boolean apply(Entry<String, PaperCard> entry) {
return entry.getKey().equals(entry.getValue().getName());
}
}).values();
return Multimaps.filterEntries(allCardsByName, entry -> entry.getKey().equals(entry.getValue().getName())).values();
}
public Collection<PaperCard> getAllNonPromoCards() {
return Lists.newArrayList(Iterables.filter(getAllCards(), new Predicate<PaperCard>() {
@Override
public boolean apply(final PaperCard paperCard) {
return Lists.newArrayList(Iterables.filter(getAllCards(), paperCard -> {
CardEdition edition = null;
try {
edition = editions.getEditionByCodeOrThrow(paperCard.getEdition());
@@ -975,14 +949,11 @@ public final class CardDb implements ICardDatabase, IDeckGenPool {
return false;
}
return edition != null && edition.getType() != Type.PROMO;
}
}));
}
public Collection<PaperCard> getUniqueCardsNoAltNoOnline() {
return Lists.newArrayList(Iterables.filter(getUniqueCardsNoAlt(), new Predicate<PaperCard>() {
@Override
public boolean apply(final PaperCard paperCard) {
return Lists.newArrayList(Iterables.filter(getUniqueCardsNoAlt(), paperCard -> {
CardEdition edition = null;
try {
edition = editions.getEditionByCodeOrThrow(paperCard.getEdition());
@@ -992,14 +963,11 @@ public final class CardDb implements ICardDatabase, IDeckGenPool {
return false;
}
return true;
}
}));
}
public Collection<PaperCard> getAllNonPromosNonReprintsNoAlt() {
return Lists.newArrayList(Iterables.filter(getAllCardsNoAlt(), new Predicate<PaperCard>() {
@Override
public boolean apply(final PaperCard paperCard) {
return Lists.newArrayList(Iterables.filter(getAllCardsNoAlt(), paperCard -> {
CardEdition edition = null;
try {
edition = editions.getEditionByCodeOrThrow(paperCard.getEdition());
@@ -1009,7 +977,6 @@ public final class CardDb implements ICardDatabase, IDeckGenPool {
return false;
}
return true;
}
}));
}
@@ -1032,12 +999,7 @@ public final class CardDb implements ICardDatabase, IDeckGenPool {
}
public List<PaperCard> getAllCardsNoAlt(String cardName) {
return Lists.newArrayList(Multimaps.filterEntries(allCardsByName, new Predicate<Entry<String, PaperCard>>() {
@Override
public boolean apply(Entry<String, PaperCard> entry) {
return entry.getKey().equals(entry.getValue().getName());
}
}).get(getName(cardName)));
return Lists.newArrayList(Multimaps.filterEntries(allCardsByName, entry -> entry.getKey().equals(entry.getValue().getName())).get(getName(cardName)));
}
/**

View File

@@ -17,7 +17,6 @@
*/
package forge.card;
import com.google.common.base.Function;
import com.google.common.base.Predicate;
import com.google.common.collect.*;
import forge.StaticData;
@@ -423,13 +422,6 @@ public final class CardEdition implements Comparable<CardEdition> {
public Map<String, Integer> getTokens() { return tokenNormalized; }
public static final Function<CardEdition, String> FN_GET_CODE = new Function<CardEdition, String>() {
@Override
public String apply(final CardEdition arg1) {
return arg1.getCode();
}
};
@Override
public int compareTo(final CardEdition o) {
if (o == null) {
@@ -542,12 +534,12 @@ public final class CardEdition implements Comparable<CardEdition> {
private final boolean isCustomEditions;
public Reader(File path) {
super(path, CardEdition.FN_GET_CODE);
super(path, CardEdition::getCode);
this.isCustomEditions = false;
}
public Reader(File path, boolean isCustomEditions) {
super(path, CardEdition.FN_GET_CODE);
super(path, CardEdition::getCode);
this.isCustomEditions = isCustomEditions;
}
@@ -737,12 +729,7 @@ public final class CardEdition implements Comparable<CardEdition> {
return TXT_FILE_FILTER;
}
public static final FilenameFilter TXT_FILE_FILTER = new FilenameFilter() {
@Override
public boolean accept(final File dir, final String name) {
return name.endsWith(".txt");
}
};
public static final FilenameFilter TXT_FILE_FILTER = (dir, name) -> name.endsWith(".txt");
}
public static class Collection extends StorageBase<CardEdition> {
@@ -798,12 +785,7 @@ public final class CardEdition implements Comparable<CardEdition> {
public Iterable<CardEdition> getPrereleaseEditions() {
List<CardEdition> res = Lists.newArrayList(this);
return Iterables.filter(res, new Predicate<CardEdition>() {
@Override
public boolean apply(final CardEdition edition) {
return edition.getPrerelease() != null;
}
});
return Iterables.filter(res, edition -> edition.getPrerelease() != null);
}
public CardEdition getEditionByCodeOrThrow(final String code) {
@@ -822,19 +804,7 @@ public final class CardEdition implements Comparable<CardEdition> {
return set == null ? "" : set.getCode2();
}
public final Function<String, CardEdition> FN_EDITION_BY_CODE = new Function<String, CardEdition>() {
@Override
public CardEdition apply(String code) {
return Collection.this.get(code);
}
};
public final Comparator<PaperCard> CARD_EDITION_COMPARATOR = new Comparator<PaperCard>() {
@Override
public int compare(PaperCard c1, PaperCard c2) {
return Collection.this.get(c1.getEdition()).compareTo(Collection.this.get(c2.getEdition()));
}
};
public final Comparator<PaperCard> CARD_EDITION_COMPARATOR = Comparator.comparing(c -> Collection.this.get(c.getEdition()));
public IItemReader<SealedProduct.Template> getBoosterGenerator() {
return new StorageReaderBase<SealedProduct.Template>(null) {
@@ -913,12 +883,7 @@ public final class CardEdition implements Comparable<CardEdition> {
CardDb.CardArtPreference artPreference = StaticData.instance().getCardArtPreference();
Iterable<CardEdition> editionsWithBasicLands = Iterables.filter(
StaticData.instance().getEditions().getOrderedEditions(),
com.google.common.base.Predicates.and(hasBasicLands, new Predicate<CardEdition>() {
@Override
public boolean apply(CardEdition edition) {
return artPreference.accept(edition);
}
}));
com.google.common.base.Predicates.and(hasBasicLands, artPreference::accept));
Iterator<CardEdition> editionsIterator = editionsWithBasicLands.iterator();
List<CardEdition> selectedEditions = new ArrayList<CardEdition>();
while (editionsIterator.hasNext())
@@ -954,9 +919,7 @@ public final class CardEdition implements Comparable<CardEdition> {
}
}
public static final Predicate<CardEdition> hasBasicLands = new Predicate<CardEdition>() {
@Override
public boolean apply(CardEdition ed) {
public static final Predicate<CardEdition> hasBasicLands = ed -> {
if (ed == null) {
// Happens for new sets with "???" code
return false;
@@ -966,7 +929,6 @@ public final class CardEdition implements Comparable<CardEdition> {
return false;
}
return true;
}
};
}

View File

@@ -243,7 +243,7 @@ final class CardFace implements ICardFace, Cloneable {
/** {@inheritDoc} */
@Override
public final Object clone() {
public Object clone() {
try {
return super.clone();
} catch (final Exception ex) {

View File

@@ -67,12 +67,9 @@ public final class CardFacePredicates {
}
public static Predicate<ICardFace> cmc(final int value) {
return new Predicate<ICardFace>() {
@Override
public boolean apply(ICardFace input) {
return input -> {
ManaCost cost = input.getManaCost();
return cost != null && cost.getCMC() == value;
}
};
}
@@ -138,20 +135,10 @@ public final class CardFacePredicates {
public static class Presets {
/** The Constant isBasicLand. */
public static final Predicate<ICardFace> IS_BASIC_LAND = new Predicate<ICardFace>() {
@Override
public boolean apply(final ICardFace subject) {
return subject.getType().isBasicLand();
}
};
public static final Predicate<ICardFace> IS_BASIC_LAND = subject -> subject.getType().isBasicLand();
/** The Constant isNonBasicLand. */
public static final Predicate<ICardFace> IS_NONBASIC_LAND = new Predicate<ICardFace>() {
@Override
public boolean apply(final ICardFace subject) {
return subject.getType().isLand() && !subject.getType().isBasicLand();
}
};
public static final Predicate<ICardFace> IS_NONBASIC_LAND = subject -> subject.getType().isLand() && !subject.getType().isBasicLand();
/** The Constant isCreature. */
public static final Predicate<ICardFace> IS_CREATURE = CardFacePredicates

View File

@@ -17,8 +17,6 @@
*/
package forge.card;
import com.google.common.base.Function;
public enum CardRarity {
BasicLand("L", "Basic Land"),
Common("C", "Common"),
@@ -58,10 +56,4 @@ public enum CardRarity {
return Unknown;
}
public static final Function<CardRarity, String> FN_GET_LONG_NAME = new Function<CardRarity, String>() {
@Override
public String apply(final CardRarity rarity) {
return rarity.longName;
}
};
}

View File

@@ -1,8 +1,6 @@
package forge.card;
import java.util.ArrayList;
import java.util.List;
import java.util.Set;
import java.util.*;
import org.apache.commons.lang3.StringUtils;
@@ -21,28 +19,13 @@ import forge.util.PredicateString;
public final class CardRulesPredicates {
/** The Constant isKeptInAiDecks. */
public static final Predicate<CardRules> IS_KEPT_IN_AI_DECKS = new Predicate<CardRules>() {
@Override
public boolean apply(final CardRules card) {
return !card.getAiHints().getRemAIDecks();
}
};
public static final Predicate<CardRules> IS_KEPT_IN_AI_DECKS = card -> !card.getAiHints().getRemAIDecks();
/** The Constant isKeptInAiLimitedDecks. */
public static final Predicate<CardRules> IS_KEPT_IN_AI_LIMITED_DECKS = new Predicate<CardRules>() {
@Override
public boolean apply(final CardRules card) {
return !card.getAiHints().getRemAIDecks() && !card.getAiHints().getRemNonCommanderDecks();
}
};
public static final Predicate<CardRules> IS_KEPT_IN_AI_LIMITED_DECKS = card -> !card.getAiHints().getRemAIDecks() && !card.getAiHints().getRemNonCommanderDecks();
/** The Constant isKeptInRandomDecks. */
public static final Predicate<CardRules> IS_KEPT_IN_RANDOM_DECKS = new Predicate<CardRules>() {
@Override
public boolean apply(final CardRules card) {
return !card.getAiHints().getRemRandomDecks();
}
};
public static final Predicate<CardRules> IS_KEPT_IN_RANDOM_DECKS = card -> !card.getAiHints().getRemRandomDecks();
// Static builder methods - they choose concrete implementation by themselves
/**
@@ -160,19 +143,9 @@ public final class CardRulesPredicates {
}
public static Predicate<CardRules> hasCreatureType(final String... creatureTypes) {
return new Predicate<CardRules>() {
@Override
public boolean apply(final CardRules card) {
return card -> {
if (!card.getType().isCreature()) { return false; }
final Set<String> set = card.getType().getCreatureTypes();
for (final String creatureType : creatureTypes) {
if (set.contains(creatureType)) {
return true;
}
}
return false;
}
return !Collections.disjoint(card.getType().getCreatureTypes(), Arrays.asList(creatureTypes));
};
}
@@ -184,12 +157,7 @@ public final class CardRulesPredicates {
* @return the predicate
*/
public static Predicate<CardRules> hasKeyword(final String keyword) {
return new Predicate<CardRules>() {
@Override
public boolean apply(final CardRules card) {
return Iterables.any(card.getAllFaces(), cf -> cf != null && card.hasStartOfKeyword(keyword, cf));
}
};
return card -> Iterables.any(card.getAllFaces(), cf -> cf != null && card.hasStartOfKeyword(keyword, cf));
}
/**
@@ -202,22 +170,16 @@ public final class CardRulesPredicates {
* @return the predicate
*/
public static Predicate<CardRules> deckHas(final DeckHints.Type type, final String has) {
return new Predicate<CardRules>() {
@Override
public boolean apply(final CardRules card) {
return card -> {
DeckHints deckHas = card.getAiHints().getDeckHas();
return deckHas != null && deckHas.isValid() && deckHas.contains(type, has);
}
};
}
public static Predicate<CardRules> deckHasExactly(final DeckHints.Type type, final String has[]) {
return new Predicate<CardRules>() {
@Override
public boolean apply(final CardRules card) {
return card -> {
DeckHints deckHas = card.getAiHints().getDeckHas();
return deckHas != null && deckHas.isValid() && deckHas.is(type, has);
}
};
}
@@ -348,12 +310,7 @@ public final class CardRulesPredicates {
}
public static Predicate<CardRules> hasColorIdentity(final int colormask) {
return new Predicate<CardRules>() {
@Override
public boolean apply(final CardRules rules) {
return rules.getColorIdentity().hasNoColorsExcept(colormask);
}
};
return rules -> rules.getColorIdentity().hasNoColorsExcept(colormask);
}
public static Predicate<CardRules> canBePartnerCommanderWith(final CardRules commander) {
@@ -597,54 +554,19 @@ public final class CardRulesPredicates {
public static final Predicate<CardRules> IS_LAND = CardRulesPredicates.coreType(true, CardType.CoreType.Land);
/** The Constant isBasicLand. */
public static final Predicate<CardRules> IS_BASIC_LAND = new Predicate<CardRules>() {
@Override
public boolean apply(final CardRules subject) {
return subject.getType().isBasicLand();
}
};
public static final Predicate<CardRules> IS_BASIC_LAND = subject -> subject.getType().isBasicLand();
/** The Constant isBasicLandNotWastes. */
public static final Predicate<CardRules> IS_BASIC_LAND_NOT_WASTES = new Predicate<CardRules>() {
@Override
public boolean apply(final CardRules subject) {
return !subject.getName().equals("Wastes")&&subject.getType().isBasicLand();
}
};
public static final Predicate<CardRules> IS_BASIC_LAND_NOT_WASTES = subject -> !subject.getName().equals("Wastes")&&subject.getType().isBasicLand();
/** The Constant isNonBasicLand. */
public static final Predicate<CardRules> IS_NONBASIC_LAND = new Predicate<CardRules>() {
@Override
public boolean apply(final CardRules subject) {
return subject.getType().isLand() && !subject.getType().isBasicLand();
}
};
public static final Predicate<CardRules> IS_NONBASIC_LAND = subject -> subject.getType().isLand() && !subject.getType().isBasicLand();
public static final Predicate<CardRules> CAN_BE_COMMANDER = new Predicate<CardRules>() {
@Override
public boolean apply(final CardRules subject) {
return subject.canBeCommander();
}
};
public static final Predicate<CardRules> CAN_BE_PARTNER_COMMANDER = new Predicate<CardRules>() {
@Override
public boolean apply(final CardRules subject) {
return subject.canBePartnerCommander();
}
};
public static final Predicate<CardRules> CAN_BE_COMMANDER = CardRules::canBeCommander;
public static final Predicate<CardRules> CAN_BE_PARTNER_COMMANDER = CardRules::canBePartnerCommander;
public static final Predicate<CardRules> CAN_BE_OATHBREAKER = new Predicate<CardRules>() {
@Override
public boolean apply(final CardRules subject) {
return subject.canBeOathbreaker();
}
};
public static final Predicate<CardRules> CAN_BE_SIGNATURE_SPELL = new Predicate<CardRules>() {
@Override
public boolean apply(final CardRules subject) {
return subject.canBeSignatureSpell();
}
};
public static final Predicate<CardRules> CAN_BE_OATHBREAKER = CardRules::canBeOathbreaker;
public static final Predicate<CardRules> CAN_BE_SIGNATURE_SPELL = CardRules::canBeSignatureSpell;
public static final Predicate<CardRules> IS_PLANESWALKER = CardRulesPredicates.coreType(true, CardType.CoreType.Planeswalker);
public static final Predicate<CardRules> IS_BATTLE = CardRulesPredicates.coreType(true, CardType.CoreType.Battle);

View File

@@ -493,13 +493,13 @@ public final class CardType implements Comparable<CardType>, CardTypeView {
}
@Override
public final boolean isAttachment() { return isAura() || isEquipment() || isFortification(); }
public boolean isAttachment() { return isAura() || isEquipment() || isFortification(); }
@Override
public final boolean isAura() { return hasSubtype("Aura"); }
public boolean isAura() { return hasSubtype("Aura"); }
@Override
public final boolean isEquipment() { return hasSubtype("Equipment"); }
public boolean isEquipment() { return hasSubtype("Equipment"); }
@Override
public final boolean isFortification() { return hasSubtype("Fortification"); }
public boolean isFortification() { return hasSubtype("Fortification"); }
public boolean isAttraction() {
return hasSubtype("Attraction");
}
@@ -858,71 +858,21 @@ public final class CardType implements Comparable<CardType>, CardTypeView {
"Warlock");
}
public static class Predicates {
public static Predicate<String> IS_LAND_TYPE = new Predicate<String>() {
@Override
public boolean apply(String input) {
return CardType.isALandType(input);
}
};
public static Predicate<String> IS_BASIC_LAND_TYPE = new Predicate<String>() {
@Override
public boolean apply(String input) {
return CardType.isABasicLandType(input);
}
};
public static Predicate<String> IS_ARTIFACT_TYPE = new Predicate<String>() {
@Override
public boolean apply(String input) {
return CardType.isAnArtifactType(input);
}
};
public static Predicate<String> IS_LAND_TYPE = CardType::isALandType;
public static Predicate<String> IS_BASIC_LAND_TYPE = CardType::isABasicLandType;
public static Predicate<String> IS_ARTIFACT_TYPE = CardType::isAnArtifactType;
public static Predicate<String> IS_CREATURE_TYPE = new Predicate<String>() {
@Override
public boolean apply(String input) {
return CardType.isACreatureType(input);
}
};
public static Predicate<String> IS_CREATURE_TYPE = CardType::isACreatureType;
public static Predicate<String> IS_ENCHANTMENT_TYPE = new Predicate<String>() {
@Override
public boolean apply(String input) {
return CardType.isAnEnchantmentType(input);
}
};
public static Predicate<String> IS_ENCHANTMENT_TYPE = CardType::isAnEnchantmentType;
public static Predicate<String> IS_SPELL_TYPE = new Predicate<String>() {
@Override
public boolean apply(String input) {
return CardType.isASpellType(input);
}
};
public static Predicate<String> IS_SPELL_TYPE = CardType::isASpellType;
public static Predicate<String> IS_WALKER_TYPE = new Predicate<String>() {
@Override
public boolean apply(String input) {
return CardType.isAPlaneswalkerType(input);
}
};
public static Predicate<String> IS_DUNGEON_TYPE = new Predicate<String>() {
@Override
public boolean apply(String input) {
return CardType.isADungeonType(input);
}
};
public static Predicate<String> IS_BATTLE_TYPE = new Predicate<String>() {
@Override
public boolean apply(String input) {
return CardType.isABattleType(input);
}
};
public static Predicate<String> IS_WALKER_TYPE = CardType::isAPlaneswalkerType;
public static Predicate<String> IS_DUNGEON_TYPE = CardType::isADungeonType;
public static Predicate<String> IS_BATTLE_TYPE = CardType::isABattleType;
public static Predicate<String> IS_PLANAR_TYPE = new Predicate<String>() {
@Override
public boolean apply(String input) {
return CardType.isAPlanarType(input);
}
};
public static Predicate<String> IS_PLANAR_TYPE = CardType::isAPlanarType;
}
///////// Utility methods
@@ -1036,7 +986,7 @@ public final class CardType implements Comparable<CardType>, CardTypeView {
*
* @deprecated
*/
public static final String getSingularType(final String type) {
public static String getSingularType(final String type) {
if (Constant.singularTypes.containsKey(type)) {
return Constant.singularTypes.get(type);
}
@@ -1049,7 +999,7 @@ public final class CardType implements Comparable<CardType>, CardTypeView {
* @param type a String.
* @return the corresponding type.
*/
public static final String getPluralType(final String type) {
public static String getPluralType(final String type) {
if (Constant.pluralTypes.containsKey(type)) {
return Constant.pluralTypes.get(type);
}

View File

@@ -172,11 +172,11 @@ public class DeckHints {
// this is case ABILITY, but other types can also use this when the implicit parsing would miss
String[] params = param.split("\\|");
for (String ability : params) {
Iterables.addAll(cards, getMatchingItems(cardList, CardRulesPredicates.deckHas(type, ability), PaperCard.FN_GET_RULES));
Iterables.addAll(cards, getMatchingItems(cardList, CardRulesPredicates.deckHas(type, ability), PaperCard::getRules));
}
// bonus if a DeckHas can satisfy the type with multiple ones
if (params.length > 1) {
Iterables.addAll(cards, getMatchingItems(cardList, CardRulesPredicates.deckHasExactly(type, params), PaperCard.FN_GET_RULES));
Iterables.addAll(cards, getMatchingItems(cardList, CardRulesPredicates.deckHasExactly(type, params), PaperCard::getRules));
}
for (String p : params) {
@@ -184,19 +184,19 @@ public class DeckHints {
case COLOR:
ColorSet cc = ColorSet.fromNames(p);
if (cc.isColorless()) {
Iterables.addAll(cards, getMatchingItems(cardList, CardRulesPredicates.Presets.IS_COLORLESS, PaperCard.FN_GET_RULES));
Iterables.addAll(cards, getMatchingItems(cardList, CardRulesPredicates.Presets.IS_COLORLESS, PaperCard::getRules));
} else {
Iterables.addAll(cards, getMatchingItems(cardList, CardRulesPredicates.isColor(cc.getColor()), PaperCard.FN_GET_RULES));
Iterables.addAll(cards, getMatchingItems(cardList, CardRulesPredicates.isColor(cc.getColor()), PaperCard::getRules));
}
break;
case KEYWORD:
Iterables.addAll(cards, getMatchingItems(cardList, CardRulesPredicates.hasKeyword(p), PaperCard.FN_GET_RULES));
Iterables.addAll(cards, getMatchingItems(cardList, CardRulesPredicates.hasKeyword(p), PaperCard::getRules));
break;
case NAME:
Iterables.addAll(cards, getMatchingItems(cardList, CardRulesPredicates.name(StringOp.EQUALS, p), PaperCard.FN_GET_RULES));
Iterables.addAll(cards, getMatchingItems(cardList, CardRulesPredicates.name(StringOp.EQUALS, p), PaperCard::getRules));
break;
case TYPE:
Iterables.addAll(cards, getMatchingItems(cardList, CardRulesPredicates.joinedType(StringOp.CONTAINS_IC, p), PaperCard.FN_GET_RULES));
Iterables.addAll(cards, getMatchingItems(cardList, CardRulesPredicates.joinedType(StringOp.CONTAINS_IC, p), PaperCard::getRules));
break;
case NONE:
case ABILITY: // already done above
@@ -219,9 +219,7 @@ public class DeckHints {
} else {
tdb = null;
}
return new Predicate<CardRules>() {
@Override
public boolean apply(final CardRules card) {
return card -> {
if (predicate.apply(card)) {
return true;
}
@@ -231,7 +229,6 @@ public class DeckHints {
}
}
return false;
}
};
}

View File

@@ -1,6 +1,5 @@
package forge.card;
import com.google.common.base.Function;
import com.google.common.collect.ImmutableList;
/**
@@ -181,10 +180,4 @@ public final class MagicColor {
}
}
public static final Function<Color, String> FN_GET_SYMBOL = new Function<Color, String>() {
@Override
public String apply(final Color color) {
return color.symbol;
}
};
}

View File

@@ -6,8 +6,6 @@ import java.util.Collection;
import java.util.List;
import java.util.Map.Entry;
import com.google.common.base.Function;
import forge.deck.CardPool;
import forge.item.PaperCard;
import forge.util.ItemPool;
@@ -22,9 +20,6 @@ import forge.util.storage.StorageReaderFileSections;
*
*/
public class PrintSheet {
public static final Function<PrintSheet, String> FN_GET_KEY = new Function<PrintSheet, String>() {
@Override public final String apply(PrintSheet sheet) { return sheet.name; }
};
public static final IStorage<PrintSheet> initializePrintSheets(File sheetsFile, CardEdition.Collection editions) {
IStorage<PrintSheet> sheets = new StorageExtendable<>("Special print runs", new PrintSheet.Reader(sheetsFile));
@@ -156,7 +151,7 @@ public class PrintSheet {
public static class Reader extends StorageReaderFileSections<PrintSheet> {
public Reader(File file) {
super(file, PrintSheet.FN_GET_KEY);
super(file, PrintSheet::getName);
}
@Override

View File

@@ -318,12 +318,7 @@ public class CardPool extends ItemPool<PaperCard> {
ListMultimap<Integer, CardEdition> editionsStatistics = this.getCardEditionsGroupedByNumberOfCards(false);
List<Integer> frequencyValues = new ArrayList<>(editionsStatistics.keySet());
// Sort in descending order
frequencyValues.sort(new Comparator<Integer>() {
@Override
public int compare(Integer f1, Integer f2) {
return (f1.compareTo(f2)) * -1;
}
});
frequencyValues.sort(Comparator.reverseOrder());
float weightedMean = 0;
int sumWeights = 0;
for (Integer freq : frequencyValues) {
@@ -351,12 +346,7 @@ public class CardPool extends ItemPool<PaperCard> {
// Now Get editions corresponding to pivot frequency
List<CardEdition> pivotCandidates = new ArrayList<>(editionsStatistics.get(pivotFrequency));
// Now Sort candidates chronologically
pivotCandidates.sort(new Comparator<CardEdition>() {
@Override
public int compare(CardEdition ed1, CardEdition ed2) {
return ed1.compareTo(ed2);
}
});
pivotCandidates.sort(CardEdition::compareTo);
boolean searchPolicyAndPoolAreCompliant = isLatestCardArtPreference == this.isModern();
if (!searchPolicyAndPoolAreCompliant)
Collections.reverse(pivotCandidates); // reverse to have latest-first.

View File

@@ -17,8 +17,6 @@
*/
package forge.deck;
import com.google.common.base.Function;
import com.google.common.base.Predicate;
import com.google.common.collect.Lists;
import forge.StaticData;
import forge.card.CardDb;
@@ -125,12 +123,7 @@ public class Deck extends DeckBase implements Iterable<Entry<DeckSection, CardPo
result.add(c.getKey());
}
if (result.size() > 1) { //sort by type so signature spell comes after oathbreaker
Collections.sort(result, new Comparator<PaperCard>() {
@Override
public int compare(final PaperCard c1, final PaperCard c2) {
return Boolean.compare(c1.getRules().canBeSignatureSpell(), c2.getRules().canBeSignatureSpell());
}
});
Collections.sort(result, Comparator.comparing(c -> c.getRules().canBeSignatureSpell()));
}
return result;
}
@@ -309,12 +302,7 @@ public class Deck extends DeckBase implements Iterable<Entry<DeckSection, CardPo
continue; // pool empty, no card has been found!
// Filter pool by applying DeckSection Validation schema for Card Types (to avoid inconsistencies)
CardPool filteredPool = pool.getFilteredPoolWithCardsCount(new Predicate<PaperCard>() {
@Override
public boolean apply(PaperCard input) {
return deckSection.validate(input);
}
});
CardPool filteredPool = pool.getFilteredPoolWithCardsCount(deckSection::validate);
// Add all the cards from ValidPool anyway!
List<String> whiteList = validatedSections.getOrDefault(s.getKey(), null);
if (whiteList == null)
@@ -326,12 +314,7 @@ public class Deck extends DeckBase implements Iterable<Entry<DeckSection, CardPo
validatedSections.put(s.getKey(), whiteList);
if (filteredPool.countDistinct() != pool.countDistinct()) {
CardPool blackList = pool.getFilteredPoolWithCardsCount(new Predicate<PaperCard>() {
@Override
public boolean apply(PaperCard input) {
return !(deckSection.validate(input));
}
});
CardPool blackList = pool.getFilteredPoolWithCardsCount(input -> !(deckSection.validate(input)));
for (Entry<PaperCard, Integer> entry : blackList) {
DeckSection cardSection = DeckSection.matchingSection(entry.getKey());
@@ -513,13 +496,6 @@ public class Deck extends DeckBase implements Iterable<Entry<DeckSection, CardPo
return releaseDate.compareTo(referenceReleaseDate) < 0;
}
public static final Function<Deck, String> FN_NAME_SELECTOR = new Function<Deck, String>() {
@Override
public String apply(Deck arg1) {
return arg1.getName();
}
};
/* (non-Javadoc)
* @see java.lang.Iterable#iterator()
*/

View File

@@ -59,25 +59,16 @@ public enum DeckFormat {
return null;
}
},
Commander ( Range.is(99), Range.between(0, 10), 1, null, new Predicate<PaperCard>() {
@Override
public boolean apply(PaperCard card) {
return StaticData.instance().getCommanderPredicate().apply(card);
}
}),
Oathbreaker ( Range.is(58), Range.between(0, 10), 1, null, new Predicate<PaperCard>() {
@Override
public boolean apply(PaperCard card) {
return StaticData.instance().getOathbreakerPredicate().apply(card);
}
}),
Commander ( Range.is(99), Range.between(0, 10), 1, null,
card -> StaticData.instance().getCommanderPredicate().apply(card)
),
Oathbreaker ( Range.is(58), Range.between(0, 10), 1, null,
card -> StaticData.instance().getOathbreakerPredicate().apply(card)
),
Pauper ( Range.is(60), Range.between(0, 10), 1),
Brawl ( Range.is(59), Range.between(0, 15), 1, null, new Predicate<PaperCard>() {
@Override
public boolean apply(PaperCard card) {
return StaticData.instance().getBrawlPredicate().apply(card);
}
}),
Brawl ( Range.is(59), Range.between(0, 15), 1, null,
card -> StaticData.instance().getBrawlPredicate().apply(card)
),
TinyLeaders ( Range.is(49), Range.between(0, 10), 1, new Predicate<CardRules>() {
private final Set<String> bannedCards = ImmutableSet.of(
"Ancestral Recall", "Balance", "Black Lotus", "Black Vise", "Channel", "Chaos Orb", "Contract From Below", "Counterbalance", "Darkpact", "Demonic Attorney", "Demonic Tutor", "Earthcraft", "Edric, Spymaster of Trest", "Falling Star",
@@ -501,18 +492,11 @@ public enum DeckFormat {
}
public Predicate<Deck> isLegalDeckPredicate() {
return new Predicate<Deck>() {
@Override
public boolean apply(Deck deck) {
return getDeckConformanceProblem(deck) == null;
}
};
return deck -> getDeckConformanceProblem(deck) == null;
}
public Predicate<Deck> hasLegalCardsPredicate(boolean enforceDeckLegality) {
return new Predicate<Deck>() {
@Override
public boolean apply(Deck deck) {
return deck -> {
if (!enforceDeckLegality)
return true;
if (cardPoolFilter != null) {
@@ -534,26 +518,15 @@ public enum DeckFormat {
}
}
return true;
}
};
}
public Predicate<PaperCard> isLegalCardPredicate() {
return new Predicate<PaperCard>() {
@Override
public boolean apply(PaperCard card) {
return isLegalCard(card);
}
};
return this::isLegalCard;
}
public Predicate<PaperCard> isLegalCommanderPredicate() {
return new Predicate<PaperCard>() {
@Override
public boolean apply(PaperCard card) {
return isLegalCommander(card.getRules());
}
};
return card -> isLegalCommander(card.getRules());
}
public Predicate<PaperCard> isLegalCardForCommanderPredicate(List<PaperCard> commanders) {
@@ -567,6 +540,6 @@ public enum DeckFormat {
//Notably, no partner ability or combination of partner abilities can ever let a player have more than two commanders.
predicate = Predicates.or(predicate, CardRulesPredicates.canBePartnerCommanderWith(commanders.get(0).getRules()));
}
return Predicates.compose(predicate, PaperCard.FN_GET_RULES);
return Predicates.compose(predicate, PaperCard::getRules);
}
}

View File

@@ -23,8 +23,6 @@ import java.util.Collections;
import java.util.Comparator;
import java.util.List;
import com.google.common.base.Function;
/**
* Related decks usually pertaining to a limited experience like draft or sealed
* This file represents a human player deck and all opposing AI decks
@@ -32,6 +30,10 @@ import com.google.common.base.Function;
*/
public class DeckGroup extends DeckBase {
public DeckGroup() {
this("");
}
/**
* Instantiates a new deck group.
*
@@ -137,21 +139,6 @@ public class DeckGroup extends DeckBase {
return new DeckGroup(name0);
}
public static final Function<DeckGroup, String> FN_NAME_SELECTOR = new Function<DeckGroup, String>() {
@Override
public String apply(DeckGroup arg1) {
return arg1.getName();
}
};
public static final Function<DeckGroup, Deck> FN_HUMAN_DECK = new Function<DeckGroup, Deck>() {
@Override
public Deck apply(DeckGroup arg1) {
return arg1.humanDeck;
}
};
@Override
public boolean isEmpty() {
return humanDeck == null || humanDeck.isEmpty();

View File

@@ -66,63 +66,42 @@ public enum DeckSection {
}
private static class Validators {
static final Function<PaperCard, Boolean> DECK_AND_SIDE_VALIDATOR = new Function<PaperCard, Boolean>() {
@Override
public Boolean apply(PaperCard card) {
static final Function<PaperCard, Boolean> DECK_AND_SIDE_VALIDATOR = card -> {
CardType t = card.getRules().getType();
// NOTE: Same rules applies to both Deck and Side, despite "Conspiracy cards" are allowed
// in the SideBoard (see Rule 313.2)
// Those will be matched later, in case (see `Deck::validateDeferredSections`)
return !t.isConspiracy() && !t.isDungeon() && !t.isPhenomenon() && !t.isPlane() && !t.isScheme() && !t.isVanguard();
}
};
static final Function<PaperCard, Boolean> COMMANDER_VALIDATOR = new Function<PaperCard, Boolean>() {
@Override
public Boolean apply(PaperCard card) {
static final Function<PaperCard, Boolean> COMMANDER_VALIDATOR = card -> {
CardType t = card.getRules().getType();
return card.getRules().canBeCommander() || t.isPlaneswalker() || card.getRules().canBeOathbreaker() || card.getRules().canBeSignatureSpell();
}
};
static final Function<PaperCard, Boolean> PLANES_VALIDATOR = new Function<PaperCard, Boolean>() {
@Override
public Boolean apply(PaperCard card) {
static final Function<PaperCard, Boolean> PLANES_VALIDATOR = card -> {
CardType t = card.getRules().getType();
return t.isPlane() || t.isPhenomenon();
}
};
static final Function<PaperCard, Boolean> DUNGEON_VALIDATOR = new Function<PaperCard, Boolean>() {
@Override
public Boolean apply(PaperCard card) {
static final Function<PaperCard, Boolean> DUNGEON_VALIDATOR = card -> {
CardType t = card.getRules().getType();
return t.isDungeon();
}
};
static final Function<PaperCard, Boolean> SCHEME_VALIDATOR = new Function<PaperCard, Boolean>() {
@Override
public Boolean apply(PaperCard card) {
static final Function<PaperCard, Boolean> SCHEME_VALIDATOR = card -> {
CardType t = card.getRules().getType();
return t.isScheme();
}
};
static final Function<PaperCard, Boolean> CONSPIRACY_VALIDATOR = new Function<PaperCard, Boolean>() {
@Override
public Boolean apply(PaperCard card) {
static final Function<PaperCard, Boolean> CONSPIRACY_VALIDATOR = card -> {
CardType t = card.getRules().getType();
return t.isConspiracy();
}
};
static final Function<PaperCard, Boolean> AVATAR_VALIDATOR = new Function<PaperCard, Boolean>() {
@Override
public Boolean apply(PaperCard card) {
static final Function<PaperCard, Boolean> AVATAR_VALIDATOR = card -> {
CardType t = card.getRules().getType();
return t.isVanguard();
}
};
static final Function<PaperCard, Boolean> ATTRACTION_VALIDATOR = card -> {

View File

@@ -92,12 +92,12 @@ public abstract class DeckGeneratorBase {
final Iterable<PaperCard> cards = selectCardsOfMatchingColorForPlayer(forAi);
// build subsets based on type
final Iterable<PaperCard> creatures = Iterables.filter(cards, Predicates.compose(CardRulesPredicates.Presets.IS_CREATURE, PaperCard.FN_GET_RULES));
final Iterable<PaperCard> creatures = Iterables.filter(cards, Predicates.compose(CardRulesPredicates.Presets.IS_CREATURE, PaperCard::getRules));
final int creatCnt = (int) Math.ceil(getCreaturePercentage() * size);
trace.append("Creatures to add:").append(creatCnt).append("\n");
addCmcAdjusted(creatures, creatCnt, cmcLevels);
Predicate<PaperCard> preSpells = Predicates.compose(CardRulesPredicates.Presets.IS_NON_CREATURE_SPELL, PaperCard.FN_GET_RULES);
Predicate<PaperCard> preSpells = Predicates.compose(CardRulesPredicates.Presets.IS_NON_CREATURE_SPELL, PaperCard::getRules);
final Iterable<PaperCard> spells = Iterables.filter(cards, preSpells);
final int spellCnt = (int) Math.ceil(getSpellPercentage() * size);
trace.append("Spells to add:").append(spellCnt).append("\n");
@@ -114,9 +114,9 @@ public abstract class DeckGeneratorBase {
Predicate<PaperCard> isSetBasicLand;
if (edition !=null){
isSetBasicLand = Predicates.and(IPaperCard.Predicates.printedInSet(edition),
Predicates.compose(CardRulesPredicates.Presets.IS_BASIC_LAND, PaperCard.FN_GET_RULES));
Predicates.compose(CardRulesPredicates.Presets.IS_BASIC_LAND, PaperCard::getRules));
}else{
isSetBasicLand = Predicates.compose(CardRulesPredicates.Presets.IS_BASIC_LAND, PaperCard.FN_GET_RULES);
isSetBasicLand = Predicates.compose(CardRulesPredicates.Presets.IS_BASIC_LAND, PaperCard::getRules);
}
landPool = new DeckGenPool(StaticData.instance().getCommonCards().getAllCards(isSetBasicLand));
@@ -239,7 +239,7 @@ public abstract class DeckGeneratorBase {
addSome(targetSize - actualSize, tDeck.toFlatList());
}
else if (actualSize > targetSize) {
Predicate<PaperCard> exceptBasicLand = Predicates.not(Predicates.compose(CardRulesPredicates.Presets.IS_BASIC_LAND, PaperCard.FN_GET_RULES));
Predicate<PaperCard> exceptBasicLand = Predicates.not(Predicates.compose(CardRulesPredicates.Presets.IS_BASIC_LAND, PaperCard::getRules));
for (int i = 0; i < 3 && actualSize > targetSize; i++) {
Iterable<PaperCard> matchingCards = Iterables.filter(tDeck.toFlatList(), exceptBasicLand);
@@ -266,7 +266,7 @@ public abstract class DeckGeneratorBase {
float requestedOverTotal = (float)cnt / totalWeight;
for (ImmutablePair<FilterCMC, Integer> pair : cmcLevels) {
Iterable<PaperCard> matchingCards = Iterables.filter(source, Predicates.compose(pair.getLeft(), PaperCard.FN_GET_RULES));
Iterable<PaperCard> matchingCards = Iterables.filter(source, Predicates.compose(pair.getLeft(), PaperCard::getRules));
int cmcCountForPool = (int) Math.ceil(pair.getRight() * desiredOverTotal);
int addOfThisCmc = Math.round(pair.getRight() * requestedOverTotal);
@@ -288,18 +288,15 @@ public abstract class DeckGeneratorBase {
// remove cards that generated decks don't like
Predicate<CardRules> canPlay = forAi ? AI_CAN_PLAY : CardRulesPredicates.IS_KEPT_IN_RANDOM_DECKS;
Predicate<CardRules> hasColor = new MatchColorIdentity(colors);
Predicate<CardRules> canUseInFormat = new Predicate<CardRules>() {
@Override
public boolean apply(CardRules c) {
Predicate<CardRules> canUseInFormat = c -> {
// FIXME: should this be limited to AI only (!forAi) or should it be generally applied to all random generated decks?
return !c.getAiHints().getRemNonCommanderDecks() || format.hasCommander();
}
};
if (useArtifacts) {
hasColor = Predicates.or(hasColor, COLORLESS_CARDS);
}
return Iterables.filter(pool.getAllCards(), Predicates.compose(Predicates.and(canPlay, hasColor, canUseInFormat), PaperCard.FN_GET_RULES));
return Iterables.filter(pool.getAllCards(), Predicates.compose(Predicates.and(canPlay, hasColor, canUseInFormat), PaperCard::getRules));
}
protected static Map<String, Integer> countLands(ItemPool<PaperCard> outList) {
@@ -337,12 +334,9 @@ public abstract class DeckGeneratorBase {
public static final Predicate<CardRules> AI_CAN_PLAY = Predicates.and(CardRulesPredicates.IS_KEPT_IN_AI_DECKS, CardRulesPredicates.IS_KEPT_IN_RANDOM_DECKS);
public static final Predicate<CardRules> COLORLESS_CARDS = new Predicate<CardRules>() {
@Override
public boolean apply(CardRules c) {
public static final Predicate<CardRules> COLORLESS_CARDS = c -> {
ManaCost mc = c.getManaCost();
return c.getColorIdentity().isColorless() && !mc.isNoCost();
}
};
public static class MatchColorIdentity implements Predicate<CardRules> {
@@ -401,7 +395,7 @@ public abstract class DeckGeneratorBase {
Predicate<CardRules> dualLandFilter = CardRulesPredicates.coreType(true, CardType.CoreType.Land);
Predicate<CardRules> exceptBasicLand = Predicates.not(CardRulesPredicates.Presets.IS_BASIC_LAND);
Iterable<PaperCard> landCards = pool.getAllCards(Predicates.compose(Predicates.and(dualLandFilter, exceptBasicLand, canPlay), PaperCard.FN_GET_RULES));
Iterable<PaperCard> landCards = pool.getAllCards(Predicates.compose(Predicates.and(dualLandFilter, exceptBasicLand, canPlay), PaperCard::getRules));
Iterable<String> dualLandPatterns = Arrays.asList("Add \\{([WUBRG])\\} or \\{([WUBRG])\\}",
"Add \\{([WUBRG])\\}, \\{([WUBRG])\\}, or \\{([WUBRG])\\}",
"Add \\{([WUBRG])\\}\\{([WUBRG])\\}",

View File

@@ -21,6 +21,7 @@ import java.io.File;
import java.io.FilenameFilter;
import java.util.List;
import forge.deck.DeckBase;
import org.apache.commons.lang3.StringUtils;
import com.google.common.collect.ImmutableList;
@@ -45,7 +46,7 @@ public class DeckGroupSerializer extends StorageReaderFolder<DeckGroup> implemen
* @param deckDir0 the deck dir0
*/
public DeckGroupSerializer(final File deckDir0, String rootDir0) {
super(deckDir0, DeckGroup.FN_NAME_SELECTOR);
super(deckDir0, DeckBase::getName);
rootDir = rootDir0;
}
@@ -122,16 +123,12 @@ public class DeckGroupSerializer extends StorageReaderFolder<DeckGroup> implemen
*/
@Override
protected FilenameFilter getFileFilter() {
return new FilenameFilter() {
@Override
public boolean accept(final File dir, final String name) {
return (dir, name) -> {
final File testSubject = new File(dir, name);
final boolean isVisibleFolder = testSubject.isDirectory() && !testSubject.isHidden();
final boolean hasGoodName = StringUtils.isNotEmpty(name) && !name.startsWith(".");
final File fileHumanDeck = new File(testSubject, DeckGroupSerializer.humanDeckFile);
return isVisibleFolder && hasGoodName && fileHumanDeck.exists();
}
};
}

View File

@@ -23,6 +23,7 @@ import java.util.List;
import java.util.Map;
import forge.deck.Deck;
import forge.deck.DeckBase;
import forge.util.FileSection;
import forge.util.FileUtil;
import forge.util.IItemReader;
@@ -39,19 +40,14 @@ public class DeckStorage extends StorageReaderFolder<Deck> implements IItemSeria
private final boolean moveWronglyNamedDecks;
/** Constant <code>DCKFileFilter</code>. */
public static final FilenameFilter DCK_FILE_FILTER = new FilenameFilter() {
@Override
public boolean accept(final File dir, final String name) {
return name.endsWith(FILE_EXTENSION);
}
};
public static final FilenameFilter DCK_FILE_FILTER = (dir, name) -> name.endsWith(FILE_EXTENSION);
public DeckStorage(final File deckDir0, final String rootDir0) {
this(deckDir0, rootDir0, false);
}
public DeckStorage(final File deckDir0, final String rootDir0, boolean moveWrongDecks) {
super(deckDir0, Deck.FN_NAME_SELECTOR);
super(deckDir0, DeckBase::getName);
rootDir = rootDir0;
moveWronglyNamedDecks = moveWrongDecks;
}

View File

@@ -22,24 +22,19 @@ import java.util.ArrayList;
import org.apache.commons.lang3.tuple.Pair;
import com.google.common.base.Function;
import forge.ImageKeys;
import forge.StaticData;
import forge.card.CardEdition;
public class BoosterBox extends BoxedProduct {
public static final Function<CardEdition, BoosterBox> FN_FROM_SET = new Function<CardEdition, BoosterBox>() {
@Override
public BoosterBox apply(final CardEdition arg1) {
if (arg1.getBoosterBoxCount() <= 0) {
public static BoosterBox fromSet(CardEdition edition) {
if (edition.getBoosterBoxCount() <= 0) {
return null;
}
BoosterBox.Template d = new Template(arg1);
if (d == null) { return null; }
return new BoosterBox(arg1.getName(), d, d.cntBoosters);
BoosterBox.Template d = new Template(edition);
return new BoosterBox(edition.getName(), d, d.cntBoosters);
}
};
private final BoosterBox.Template fpData;

View File

@@ -20,7 +20,6 @@ package forge.item;
import org.apache.commons.lang3.tuple.Pair;
import com.google.common.base.Function;
import com.google.common.collect.ImmutableList;
import forge.ImageKeys;
@@ -33,20 +32,15 @@ public class BoosterPack extends SealedProduct {
private final int artIndex;
private final int hash;
public static final Function<CardEdition, BoosterPack> FN_FROM_SET = new Function<CardEdition, BoosterPack>() {
@Override
public BoosterPack apply(final CardEdition edition) {
public static BoosterPack fromSet(CardEdition edition) {
String boosterKind = edition.getRandomBoosterKind();
Template d = edition.getBoosterTemplate(boosterKind);
StringBuilder sb = new StringBuilder(edition.getName());
sb.append(" ").append(boosterKind);
return new BoosterPack(sb.toString(), d);
}
};
public static final Function<String, BoosterPack> FN_FROM_COLOR = new Function<String, BoosterPack>() {
@Override
public BoosterPack apply(final String color) {
public static BoosterPack fromColor(final String color) {
return new BoosterPack(color, new Template("?", ImmutableList.of(
Pair.of(BoosterSlots.COMMON + ":color(\"" + color + "\"):!" + BoosterSlots.LAND, 11),
Pair.of(BoosterSlots.UNCOMMON + ":color(\"" + color + "\"):!" + BoosterSlots.LAND, 3),
@@ -54,7 +48,6 @@ public class BoosterPack extends SealedProduct {
Pair.of(BoosterSlots.LAND + ":color(\"" + color + "\")", 1))
));
}
};
public BoosterPack(final String name0, final Template boosterData) {
super(name0, boosterData);

View File

@@ -22,25 +22,20 @@ import java.util.List;
import org.apache.commons.lang3.tuple.Pair;
import com.google.common.base.Function;
import forge.ImageKeys;
import forge.StaticData;
import forge.card.CardEdition;
import forge.item.generation.BoosterGenerator;
public class FatPack extends BoxedProduct {
public static final Function<CardEdition, FatPack> FN_FROM_SET = new Function<CardEdition, FatPack>() {
@Override
public FatPack apply(final CardEdition edition) {
public static FatPack fromSet(final CardEdition edition) {
int boosters = edition.getFatPackCount();
if (boosters <= 0) { return null; }
FatPack.Template d = new Template(edition);
if (d == null || null == StaticData.instance().getBoosters().get(d.getEdition())) { return null; }
if (null == StaticData.instance().getBoosters().get(d.getEdition())) { return null; }
return new FatPack(edition.getName(), d, d.cntBoosters);
}
};
private final FatPack.Template fpData;

View File

@@ -225,19 +225,8 @@ public interface IPaperCard extends InventoryItem, Serializable {
public static final Predicate<PaperCard> IS_WHITE = Predicates.color(true, false, MagicColor.WHITE);
public static final Predicate<PaperCard> IS_COLORLESS = Predicates.color(true, true, MagicColor.COLORLESS);
public static final Predicate<PaperCard> IS_UNREBALANCED = new Predicate<PaperCard>() {
@Override
public boolean apply(PaperCard input) {
return input.isUnRebalanced();
}
};
public static final Predicate<PaperCard> IS_REBALANCED = new Predicate<PaperCard>() {
@Override
public boolean apply(PaperCard input) {
return input.isRebalanced();
}
};
public static final Predicate<PaperCard> IS_UNREBALANCED = PaperCard::isUnRebalanced;
public static final Predicate<PaperCard> IS_REBALANCED = PaperCard::isRebalanced;
}
}

View File

@@ -19,26 +19,14 @@ public abstract class ItemPredicate {
*
* @return the predicate
*/
public static final Predicate<InventoryItem> IsTournamentPack = new Predicate<InventoryItem>() {
@Override
public boolean apply(final InventoryItem card) {
return card instanceof TournamentPack && !((TournamentPack) card).isStarterDeck();
}
};
public static final Predicate<InventoryItem> IsTournamentPack = card -> card instanceof TournamentPack && !((TournamentPack) card).isStarterDeck();
/**
* Checks that the inventory item is a Starter Deck.
*
* @return the predicate
*/
public static final Predicate<InventoryItem> IsStarterDeck = new Predicate<InventoryItem>() {
@Override
public boolean apply(final InventoryItem card) {
return card instanceof TournamentPack && ((TournamentPack) card).isStarterDeck();
}
};
public static final Predicate<InventoryItem> IsStarterDeck = card -> card instanceof TournamentPack && ((TournamentPack) card).isStarterDeck();
/**
* Checks that the inventory item is a Prebuilt Deck.

View File

@@ -17,7 +17,6 @@
*/
package forge.item;
import com.google.common.base.Function;
import forge.ImageKeys;
import forge.StaticData;
import forge.card.*;
@@ -160,22 +159,6 @@ public class PaperCard implements Comparable<IPaperCard>, InventoryItemFromSet,
return hasImage;
}
/**
* Lambda to get rules for selects from list of printed cards.
*/
public static final Function<PaperCard, CardRules> FN_GET_RULES = new Function<PaperCard, CardRules>() {
@Override
public CardRules apply(final PaperCard from) {
return from.rules;
}
};
public static final Function<PaperCard, String> FN_GET_NAME = new Function<PaperCard, String>() {
@Override
public String apply(final PaperCard from) {
return from.getName();
}
};
public PaperCard(final CardRules rules0, final String edition0, final CardRarity rarity0) {
this(rules0, edition0, rarity0, IPaperCard.DEFAULT_ART_INDEX, false,
IPaperCard.NO_COLLECTOR_NUMBER, IPaperCard.NO_ARTIST_NAME, IPaperCard.NO_FUNCTIONAL_VARIANT);

View File

@@ -22,8 +22,6 @@ import java.io.FilenameFilter;
import java.util.List;
import java.util.Map;
import com.google.common.base.Function;
import forge.ImageKeys;
import forge.StaticData;
import forge.deck.Deck;
@@ -89,16 +87,9 @@ public class PreconDeck implements InventoryItemFromSet {
return this.description;
}
public static final Function<PreconDeck, String> FN_NAME_SELECTOR = new Function<PreconDeck, String>() {
@Override
public String apply(PreconDeck arg1) {
return arg1.getName();
}
};
public static class Reader extends StorageReaderFolder<PreconDeck> {
public Reader(final File deckDir0) {
super(deckDir0, PreconDeck.FN_NAME_SELECTOR);
super(deckDir0, PreconDeck::getName);
}
@Override
@@ -124,13 +115,6 @@ public class PreconDeck implements InventoryItemFromSet {
}
}
public static final Function<PreconDeck, Deck> FN_GET_DECK = new Function<PreconDeck, Deck>() {
@Override
public Deck apply(PreconDeck arg1) {
return arg1.getDeck();
}
};
@Override
public String getImageKey(boolean altState) {
return ImageKeys.PRECON_PREFIX + imageFilename;

Some files were not shown because too many files have changed in this diff Show More