diff --git a/forge-adventure/src/main/java/forge/adventure/editor/ActionEditor.java b/forge-adventure/src/main/java/forge/adventure/editor/ActionEditor.java index a680d5362d1..462fc38624b 100644 --- a/forge-adventure/src/main/java/forge/adventure/editor/ActionEditor.java +++ b/forge-adventure/src/main/java/forge/adventure/editor/ActionEditor.java @@ -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) diff --git a/forge-adventure/src/main/java/forge/adventure/editor/DialogTree.java b/forge-adventure/src/main/java/forge/adventure/editor/DialogTree.java index b553ebdfb00..f9f3a019ced 100644 --- a/forge-adventure/src/main/java/forge/adventure/editor/DialogTree.java +++ b/forge-adventure/src/main/java/forge/adventure/editor/DialogTree.java @@ -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); } diff --git a/forge-adventure/src/main/java/forge/adventure/editor/EditorMainWindow.java b/forge-adventure/src/main/java/forge/adventure/editor/EditorMainWindow.java index 881243049cc..21d737b1791 100644 --- a/forge-adventure/src/main/java/forge/adventure/editor/EditorMainWindow.java +++ b/forge-adventure/src/main/java/forge/adventure/editor/EditorMainWindow.java @@ -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() { - @Override - public Void apply(ForgePreferences preferences) { - preferences.setPref(ForgePreferences.FPref.LOAD_CARD_SCRIPTS_LAZILY, true); - return null; - } + 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); diff --git a/forge-adventure/src/main/java/forge/adventure/editor/FilePicker.java b/forge-adventure/src/main/java/forge/adventure/editor/FilePicker.java index e75f2dd30d1..cd792df408c 100644 --- a/forge-adventure/src/main/java/forge/adventure/editor/FilePicker.java +++ b/forge-adventure/src/main/java/forge/adventure/editor/FilePicker.java @@ -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); diff --git a/forge-adventure/src/main/java/forge/adventure/editor/StructureEditor.java b/forge-adventure/src/main/java/forge/adventure/editor/StructureEditor.java index 9e9ad4733a4..c25efe3f8b4 100644 --- a/forge-adventure/src/main/java/forge/adventure/editor/StructureEditor.java +++ b/forge-adventure/src/main/java/forge/adventure/editor/StructureEditor.java @@ -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); diff --git a/forge-adventure/src/main/java/forge/adventure/editor/TerrainsEditor.java b/forge-adventure/src/main/java/forge/adventure/editor/TerrainsEditor.java index 7b8a1a34090..3af4f12d352 100644 --- a/forge-adventure/src/main/java/forge/adventure/editor/TerrainsEditor.java +++ b/forge-adventure/src/main/java/forge/adventure/editor/TerrainsEditor.java @@ -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); diff --git a/forge-adventure/src/main/java/forge/adventure/editor/WorldEditor.java b/forge-adventure/src/main/java/forge/adventure/editor/WorldEditor.java index dae2600d4f4..adcbda0af1e 100644 --- a/forge-adventure/src/main/java/forge/adventure/editor/WorldEditor.java +++ b/forge-adventure/src/main/java/forge/adventure/editor/WorldEditor.java @@ -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); diff --git a/forge-ai/src/main/java/forge/ai/AiAttackController.java b/forge-ai/src/main/java/forge/ai/AiAttackController.java index 7cd10fa1357..102944ac37d 100644 --- a/forge-ai/src/main/java/forge/ai/AiAttackController.java +++ b/forge-ai/src/main/java/forge/ai/AiAttackController.java @@ -124,12 +124,7 @@ public class AiAttackController { List defenders = defender.getCreaturesInPlay(); int totalMana = ComputerUtilMana.getAvailableManaEstimate(defender, true); int manaReserved = 0; // for paying the cost to transform - Predicate canAnimate = new Predicate() { - @Override - public boolean apply(Card c) { - return !c.isTapped() && !c.isCreature() && !c.isPlaneswalker(); - } - }; + Predicate 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 getPossibleBlockers(final List blockers, final List attackers, final boolean nextTurn) { - return CardLists.filter(blockers, new Predicate() { - @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 attackers, final boolean nextTurn) { @@ -395,15 +385,10 @@ public class AiAttackController { } } // reduce the search space - final List opponentsAttackers = CardLists.filter(ai.getOpponents().getCreaturesInPlay(), new Predicate() { - @Override - public boolean apply(final Card c) { - return !c.hasSVar("EndOfTurnLeavePlay") - && (c.toughnessAssignsDamage() || c.getNetCombatDamage() > 0 // performance shortcuts - || c.getNetCombatDamage() + ComputerUtilCombat.predictPowerBonusOfAttacker(c, null, null, true) > 0) - && ComputerUtilCombat.canAttackNextTurn(c); - } - }); + final List 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)); // don't hold back creatures that can't block any of the human creatures final List blockers = getPossibleBlockers(potentialAttackers, opponentsAttackers, true); @@ -770,7 +755,7 @@ public class AiAttackController { return false; } - private final Pair getDamageFromBlockingTramplers(final List blockedAttackers, final List blockers, final int myFreeMana) { + private Pair getDamageFromBlockingTramplers(final List blockedAttackers, final List 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 defs = c.getDefenders(); if (defs.size() == 1) { return defs.getFirst(); @@ -932,31 +917,28 @@ public class AiAttackController { // check defenders in order of maximum requirements List> reqs = combat.getAttackConstraints().getRequirements().get(attacker).getSortedRequirements(); final GameEntity def = defender; - reqs.sort(new Comparator>() { - @Override - public int compare(Pair r1, Pair r2) { - if (r1.getValue() == r2.getValue()) { - // try to attack the designated defender - if (r1.getKey().equals(def) && !r2.getKey().equals(def)) { - return -1; - } - if (r2.getKey().equals(def) && !r1.getKey().equals(def)) { - return 1; - } - // otherwise PW - if (r1.getKey() instanceof Card && r2.getKey() instanceof Player) { - return -1; - } - if (r2.getKey() instanceof Card && r1.getKey() instanceof Player) { - return 1; - } - // or weakest player - if (r1.getKey() instanceof Player && r2.getKey() instanceof Player) { - return ((Player) r1.getKey()).getLife() - ((Player) r2.getKey()).getLife(); - } + reqs.sort((r1, r2) -> { + if (r1.getValue() == r2.getValue()) { + // try to attack the designated defender + if (r1.getKey().equals(def) && !r2.getKey().equals(def)) { + return -1; + } + if (r2.getKey().equals(def) && !r1.getKey().equals(def)) { + return 1; + } + // otherwise PW + if (r1.getKey() instanceof Card && r2.getKey() instanceof Player) { + return -1; + } + if (r2.getKey() instanceof Card && r1.getKey() instanceof Player) { + return 1; + } + // or weakest player + if (r1.getKey() instanceof Player && r2.getKey() instanceof Player) { + return ((Player) r1.getKey()).getLife() - ((Player) r2.getKey()).getLife(); } - return r2.getValue() - r1.getValue(); } + return r2.getValue() - r1.getValue(); }); for (Pair 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() { - @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( diff --git a/forge-ai/src/main/java/forge/ai/AiBlockController.java b/forge-ai/src/main/java/forge/ai/AiBlockController.java index f566aba2e9f..2f743b1c08a 100644 --- a/forge-ai/src/main/java/forge/ai/AiBlockController.java +++ b/forge-ai/src/main/java/forge/ai/AiBlockController.java @@ -140,23 +140,20 @@ public class AiBlockController { ComputerUtilCard.sortByEvaluateCreature(attackers); CardLists.sortByPowerDesc(attackers); //move cards like Phage the Untouchable to the front - attackers.sort(new Comparator() { - @Override - public int compare(final Card o1, final Card o2) { - if (o1.hasSVar("MustBeBlocked") && !o2.hasSVar("MustBeBlocked")) { - return -1; - } - if (!o1.hasSVar("MustBeBlocked") && o2.hasSVar("MustBeBlocked")) { - return 1; - } - if (attackingCmd.contains(o1) && !attackingCmd.contains(o2)) { - return -1; - } - if (!attackingCmd.contains(o1) && attackingCmd.contains(o2)) { - return 1; - } - return 0; + attackers.sort((o1, o2) -> { + if (o1.hasSVar("MustBeBlocked") && !o2.hasSVar("MustBeBlocked")) { + return -1; } + if (!o1.hasSVar("MustBeBlocked") && o2.hasSVar("MustBeBlocked")) { + return 1; + } + if (attackingCmd.contains(o1) && !attackingCmd.contains(o2)) { + return -1; + } + if (!attackingCmd.contains(o1) && attackingCmd.contains(o2)) { + return 1; + } + return 0; }); return attackers; } @@ -330,43 +327,35 @@ public class AiBlockController { } private Predicate rampagesOrNeedsManyToBlock(final Combat combat) { - return Predicates.or(CardPredicates.hasKeyword(Keyword.RAMPAGE), new Predicate() { - - @Override - public boolean apply(Card input) { - // select creature that has a max blocker - return StaticAbilityCantAttackBlock.getMinMaxBlocker(input, combat.getDefenderPlayerByAttacker(input)).getRight() < Integer.MAX_VALUE; - } - + 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 changesPTWhenBlocked(final boolean onlyForDefVsTrample) { - return new Predicate() { - @Override - public boolean apply(Card card) { - for (final Trigger tr : card.getTriggers()) { - if (tr.getMode() == TriggerType.AttackerBlocked) { - SpellAbility ab = tr.getOverridingAbility(); - if (ab != null) { - if (ab.getApi() == ApiType.Pump && "Self".equals(ab.getParam("Defined"))) { - String rawP = ab.getParam("NumAtt"); - String rawT = ab.getParam("NumDef"); - if ("+X".equals(rawP) && "+X".equals(rawT) && card.getSVar("X").startsWith("Count$Valid Creature.blockingTriggeredAttacker")) { - return true; - } - // TODO: maybe also predict calculated bonus above certain threshold? - } else if (ab.getApi() == ApiType.PumpAll && ab.hasParam("ValidCards") - && ab.getParam("ValidCards").startsWith("Creature.blockingSource")) { - int pBonus = AbilityUtils.calculateAmount(card, ab.getParam("NumAtt"), ab); - int tBonus = AbilityUtils.calculateAmount(card, ab.getParam("NumDef"), ab); - return (!onlyForDefVsTrample && pBonus < 0) || tBonus < 0; + return card -> { + for (final Trigger tr : card.getTriggers()) { + if (tr.getMode() == TriggerType.AttackerBlocked) { + SpellAbility ab = tr.getOverridingAbility(); + if (ab != null) { + if (ab.getApi() == ApiType.Pump && "Self".equals(ab.getParam("Defined"))) { + String rawP = ab.getParam("NumAtt"); + String rawT = ab.getParam("NumDef"); + if ("+X".equals(rawP) && "+X".equals(rawT) && card.getSVar("X").startsWith("Count$Valid Creature.blockingTriggeredAttacker")) { + return true; } + // TODO: maybe also predict calculated bonus above certain threshold? + } else if (ab.getApi() == ApiType.PumpAll && ab.hasParam("ValidCards") + && ab.getParam("ValidCards").startsWith("Creature.blockingSource")) { + int pBonus = AbilityUtils.calculateAmount(card, ab.getParam("NumAtt"), ab); + int tBonus = AbilityUtils.calculateAmount(card, ab.getParam("NumDef"), ab); + return (!onlyForDefVsTrample && pBonus < 0) || tBonus < 0; } } } - return false; } + 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() { - @Override - public boolean apply(final Card 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); + 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 blockGang = new ArrayList<>(); int absorbedDamage; // The amount of damage needed to kill the first blocker - List usableBlockers = CardLists.filter(blockers, new Predicate() { - @Override - public boolean apply(final Card c) { - return c.getNetToughness() > attacker.getNetCombatDamage() // performance shortcut - || c.getNetToughness() + ComputerUtilCombat.predictToughnessBonusOfBlocker(attacker, c, true) > attacker.getNetCombatDamage(); - } - }); + List 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() { - @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() { - @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) { diff --git a/forge-ai/src/main/java/forge/ai/AiController.java b/forge-ai/src/main/java/forge/ai/AiController.java index e7e16bc1ef4..cc70a900400 100644 --- a/forge-ai/src/main/java/forge/ai/AiController.java +++ b/forge-ai/src/main/java/forge/ai/AiController.java @@ -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,43 +436,40 @@ public class AiController { } } - landList = CardLists.filter(landList, new Predicate() { - @Override - public boolean apply(final Card c) { - CardCollectionView battlefield = player.getCardsIn(ZoneType.Battlefield); - if (canPlaySpellBasic(c, null) != AiPlayDecision.WillPlay) { + landList = CardLists.filter(landList, c -> { + CardCollectionView battlefield = player.getCardsIn(ZoneType.Battlefield); + if (canPlaySpellBasic(c, null) != AiPlayDecision.WillPlay) { + return false; + } + String name = c.getName(); + if (c.getType().isLegendary() && !name.equals("Flagstones of Trokair")) { + if (Iterables.any(battlefield, CardPredicates.nameEquals(name))) { return false; } - String name = c.getName(); - if (c.getType().isLegendary() && !name.equals("Flagstones of Trokair")) { - if (Iterables.any(battlefield, CardPredicates.nameEquals(name))) { - return false; - } - } - - final CardCollectionView hand = 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); - - if (lands.size() >= Math.max(maxCmcInHand, 6)) { - // don't play MDFC land if other side is spell and enough lands are available - if (!c.isLand() || (c.isModal() && !c.getState(CardStateName.Modal).getType().isLand())) { - return false; - } - - // don't play the land if it has cycling and enough lands are available - final FCollectionView spellAbilities = c.getSpellAbilities(); - for (final SpellAbility sa : spellAbilities) { - if (sa.isCycling()) { - return false; - } - } - } - - return player.canPlayLand(c); } + + final CardCollectionView hand1 = player.getCardsIn(ZoneType.Hand); + CardCollection lands = new CardCollection(battlefield); + 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 + if (!c.isLand() || (c.isModal() && !c.getState(CardStateName.Modal).getType().isLand())) { + return false; + } + + // don't play the land if it has cycling and enough lands are available + final FCollectionView spellAbilities = c.getSpellAbilities(); + for (final SpellAbility sa : spellAbilities) { + if (sa.isCycling()) { + return false; + } + } + } + + 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,66 +1446,60 @@ public class AiController { boolean canCastWithLandDrop = (predictedMana + 1 >= minCMCInHand) && minCMCInHand > 0 && !isTapLand; boolean cantCastAnythingNow = predictedMana < minCMCInHand; - boolean hasRelevantAbsOTB = Iterables.any(otb, new Predicate() { - @Override - public boolean apply(Card card) { - boolean isTapLand = false; - for (ReplacementEffect repl : card.getReplacementEffects()) { - // TODO: improve the detection of taplands - if (repl.getParamOrDefault("Description", "").equals("CARDNAME enters the battlefield tapped.")) { - isTapLand = true; - } + 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.")) { + isTapLand1 = true; } - - for (SpellAbility sa : card.getSpellAbilities()) { - if (sa.isAbility() - && sa.getPayCosts().getCostMana() != null - && sa.getPayCosts().getCostMana().getMana().getCMC() > 0 - && (!sa.getPayCosts().hasTapCost() || !isTapLand) - && (!sa.hasParam("ActivationZone") || sa.getParam("ActivationZone").contains("Battlefield"))) { - return true; - } - } - return false; } + + for (SpellAbility sa : card.getSpellAbilities()) { + if (sa.isAbility() + && sa.getPayCosts().getCostMana() != null + && sa.getPayCosts().getCostMana().getMana().getCMC() > 0 + && (!sa.getPayCosts().hasTapCost() || !isTapLand1) + && (!sa.hasParam("ActivationZone") || sa.getParam("ActivationZone").contains("Battlefield"))) { + return true; + } + } + return false; }); - boolean hasLandBasedEffect = Iterables.any(otb, new Predicate() { - @Override - public boolean apply(Card card) { - for (Trigger t : card.getTriggers()) { - Map params = t.getMapParams(); - if ("ChangesZone".equals(params.get("Mode")) - && params.containsKey("ValidCard") - && (!params.containsKey("AILogic") || !params.get("AILogic").equals("SafeToHold")) - && !params.get("ValidCard").contains("nonLand") - && ((params.get("ValidCard").contains("Land")) || (params.get("ValidCard").contains("Permanent"))) - && "Battlefield".equals(params.get("Destination"))) { - // Landfall and other similar triggers - return true; - } + boolean hasLandBasedEffect = Iterables.any(otb, card -> { + for (Trigger t : card.getTriggers()) { + Map params = t.getMapParams(); + if ("ChangesZone".equals(params.get("Mode")) + && params.containsKey("ValidCard") + && (!params.containsKey("AILogic") || !params.get("AILogic").equals("SafeToHold")) + && !params.get("ValidCard").contains("nonLand") + && ((params.get("ValidCard").contains("Land")) || (params.get("ValidCard").contains("Permanent"))) + && "Battlefield".equals(params.get("Destination"))) { + // Landfall and other similar triggers + return true; } - for (String sv : card.getSVars().keySet()) { - String varValue = card.getSVar(sv); - if (varValue.equals("Count$Domain")) { - for (String type : landToPlay.getType().getLandTypes()) { - if (CardType.isABasicLandType(type) && CardLists.getType(otb, type).isEmpty()) { - return true; - } - } - } - if (varValue.startsWith("Count$Valid") || sv.equals("BuffedBy")) { - if (varValue.contains("Land") || varValue.contains("Plains") || varValue.contains("Forest") - || varValue.contains("Mountain") || varValue.contains("Island") || varValue.contains("Swamp") - || varValue.contains("Wastes")) { - // In presence of various cards that get buffs like "equal to the number of lands you control", - // safer for our AI model to just play the land earlier rather than make a blunder + } + for (String sv : card.getSVars().keySet()) { + String varValue = card.getSVar(sv); + if (varValue.equals("Count$Domain")) { + for (String type : landToPlay.getType().getLandTypes()) { + if (CardType.isABasicLandType(type) && CardLists.getType(otb, type).isEmpty()) { return true; } } } - return false; + if (varValue.startsWith("Count$Valid") || sv.equals("BuffedBy")) { + if (varValue.contains("Land") || varValue.contains("Plains") || varValue.contains("Forest") + || varValue.contains("Mountain") || varValue.contains("Island") || varValue.contains("Swamp") + || varValue.contains("Wastes")) { + // In presence of various cards that get buffs like "equal to the number of lands you control", + // safer for our AI model to just play the land earlier rather than make a blunder + return true; + } + } } + 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 saList = Lists.newArrayList(); @@ -1572,12 +1562,9 @@ public class AiController { saList = ComputerUtilAbility.getSpellAbilities(cards, player); } - Iterables.removeIf(saList, new Predicate() { - @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 - // TODO allow when experimental profile? - return spellAbility instanceof LandAbility || (spellAbility.getHostCard() != null && ComputerUtilCard.isCardRemAIDeck(spellAbility.getHostCard())); - } + 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() { - @Override - public boolean apply(Card card) { - return card.getController().isOpponentOf(sa.getActivatingPlayer()) - && card.getNetToughness() <= maxToughness - && card.canBeDestroyed(); - } - }); + CardCollectionView rightToughness = CardLists.filter(pool, card -> card.getController().isOpponentOf(sa.getActivatingPlayer()) + && card.getNetToughness() <= maxToughness + && 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 diff --git a/forge-ai/src/main/java/forge/ai/AiCostDecision.java b/forge-ai/src/main/java/forge/ai/AiCostDecision.java index 847413b4f52..0da8034e52f 100644 --- a/forge-ai/src/main/java/forge/ai/AiCostDecision.java +++ b/forge-ai/src/main/java/forge/ai/AiCostDecision.java @@ -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() { - @Override - public boolean apply(Card card) { - for (final SpellAbility sa : card.getSpellAbilities()) { - if (sa.isManaAbility() && sa.getPayCosts().hasTapCost()) { - return true; - } + toExclude = CardLists.filter(toExclude, card -> { + for (final SpellAbility sa : card.getSpellAbilities()) { + if (sa.isManaAbility() && sa.getPayCosts().hasTapCost()) { + return true; } - return false; } + 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 negatives = CardLists.filter(typeList, new Predicate() { - @Override - public boolean apply(final Card crd) { - for (CounterType cType : table.filterToRemove(crd).keySet()) { - if (ComputerUtil.isNegativeCounter(cType, crd)) { - return true; - } + List negatives = CardLists.filter(typeList, crd -> { + for (CounterType cType : table.filterToRemove(crd).keySet()) { + if (ComputerUtil.isNegativeCounter(cType, crd)) { + return true; } - return false; } + 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 useless = CardLists.filter(typeList, new Predicate() { - @Override - public boolean apply(final Card crd) { - for (CounterType ctype : table.filterToRemove(crd).keySet()) { - if (ComputerUtil.isUselessCounter(ctype, crd)) { - return true; - } + List useless = CardLists.filter(typeList, crd -> { + for (CounterType ctype : table.filterToRemove(crd).keySet()) { + if (ComputerUtil.isUselessCounter(ctype, crd)) { + return true; } - return false; } + return false; }); if (!useless.isEmpty()) { @@ -710,17 +700,14 @@ 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 prefs = CardLists.filter(typeList, new Predicate() { - @Override - public boolean apply(final Card crd) { - // a Card without MaxQuestEffect doesn't need any Quest - // counters - int e = 0; - if (crd.hasSVar("MaxQuestEffect")) { - e = Integer.parseInt(crd.getSVar("MaxQuestEffect")); - } - return crd.getCounters(CounterEnumType.QUEST) > e; + List prefs = CardLists.filter(typeList, crd -> { + // a Card without MaxQuestEffect doesn't need any Quest + // counters + int e = 0; + if (crd.hasSVar("MaxQuestEffect")) { + e = Integer.parseInt(crd.getSVar("MaxQuestEffect")); } + return crd.getCounters(CounterEnumType.QUEST) > e; }); prefs.sort(Collections.reverseOrder(CardPredicates.compareByCounterType(CounterEnumType.QUEST))); diff --git a/forge-ai/src/main/java/forge/ai/AiPlayerPredicates.java b/forge-ai/src/main/java/forge/ai/AiPlayerPredicates.java index 3a7b1140f89..355f9faf2b3 100644 --- a/forge-ai/src/main/java/forge/ai/AiPlayerPredicates.java +++ b/forge-ai/src/main/java/forge/ai/AiPlayerPredicates.java @@ -11,28 +11,24 @@ import forge.game.zone.ZoneType; public final class AiPlayerPredicates { - public static final Comparator compareByZoneValue(final String type, final ZoneType zone, - final SpellAbility sa) { - return new Comparator() { - @Override - public int compare(Player arg0, Player arg1) { - CardCollectionView list0 = AbilityUtils.filterListByType(arg0.getCardsIn(zone), type, sa); - CardCollectionView list1 = AbilityUtils.filterListByType(arg1.getCardsIn(zone), type, sa); + public static Comparator 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); - int v0, v1; + int v0, v1; - if ((CardLists.getNotType(list0, "Creature").isEmpty()) - && (CardLists.getNotType(list1, "Creature").isEmpty())) { - v0 = ComputerUtilCard.evaluateCreatureList(list0); - v1 = ComputerUtilCard.evaluateCreatureList(list1); - } // otherwise evaluate both lists by CMC and pass only if human - // permanents are less valuable - else { - v0 = ComputerUtilCard.evaluatePermanentList(list0); - v1 = ComputerUtilCard.evaluatePermanentList(list1); - } - return Integer.compare(v0, v1); + if ((CardLists.getNotType(list0, "Creature").isEmpty()) + && (CardLists.getNotType(list1, "Creature").isEmpty())) { + v0 = ComputerUtilCard.evaluateCreatureList(list0); + v1 = ComputerUtilCard.evaluateCreatureList(list1); + } // otherwise evaluate both lists by CMC and pass only if human + // permanents are less valuable + else { + v0 = ComputerUtilCard.evaluatePermanentList(list0); + v1 = ComputerUtilCard.evaluatePermanentList(list1); } + return Integer.compare(v0, v1); }; } } diff --git a/forge-ai/src/main/java/forge/ai/AiProfileUtil.java b/forge-ai/src/main/java/forge/ai/AiProfileUtil.java index dfd778e36f5..672c1c12984 100644 --- a/forge-ai/src/main/java/forge/ai/AiProfileUtil.java +++ b/forge-ai/src/main/java/forge/ai/AiProfileUtil.java @@ -93,7 +93,7 @@ public class AiProfileUtil { * Load a single profile. * @param profileName a profile to load. */ - private static final Map loadProfile(final String profileName) { + private static Map loadProfile(final String profileName) { Map profileMap = new HashMap<>(); List lines = FileUtil.readFile(buildFileName(profileName)); diff --git a/forge-ai/src/main/java/forge/ai/ComputerUtil.java b/forge-ai/src/main/java/forge/ai/ComputerUtil.java index 1295698581c..da67f9b11b6 100644 --- a/forge-ai/src/main/java/forge/ai/ComputerUtil.java +++ b/forge-ai/src/main/java/forge/ai/ComputerUtil.java @@ -408,13 +408,9 @@ public class ComputerUtil { return ComputerUtilCard.getWorstLand(landsInPlay); } } - final CardCollection sacMeList = CardLists.filter(typeList, new Predicate() { - @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 dontSac = Arrays.asList("Black Lotus", "Mox Pearl", "Mox Jet", "Mox Emerald", "Mox Ruby", "Mox Sapphire", "Lotus Petal"); - CardCollection allowList = CardLists.filter(typeList, new Predicate() { - @Override - public boolean apply(Card card) { - if (card.isCreature() && ComputerUtilCard.evaluateCreature(card) > maxCreatureEval) { - return false; - } - - return (allowTokens && card.isToken()) - || (card.getCMC() >= minCMC && card.getCMC() <= maxCMC && !dontSac.contains(card.getName())); + 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() { - @Override - public int compare(final Card a, final Card b) { - if (!a.isInPlay() && b.isInPlay()) return -1; - else if (!b.isInPlay() && a.isInPlay()) return 1; - else return 0; - } + 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,40 +948,37 @@ public class ComputerUtil { } } } - remaining = CardLists.filter(remaining, new Predicate() { - @Override - public boolean apply(final Card c) { - int sacThreshold = 190; + remaining = CardLists.filter(remaining, c -> { + int sacThreshold = 190; - String logic = source.getParamOrDefault("AILogic", ""); - if (logic.startsWith("SacForDamage")) { - final int damageAmt = logic.contains("cmc") ? c.getManaCost().getCMC() : c.getNetPower(); - if (damageAmt <= 0) { - return false; - } else if (damageAmt >= ai.getOpponentsSmallestLifeTotal()) { - return true; - } else if (logic.endsWith(".GiantX2") && c.getType().hasCreatureType("Giant") - && damageAmt * 2 >= ai.getOpponentsSmallestLifeTotal()) { - return true; // TODO: generalize this for any type and actually make the AI prefer giants? - } - } - - if ("DesecrationDemon".equals(logic)) { - sacThreshold = SpecialCardAi.DesecrationDemon.getSacThreshold(); - } else if (considerSacThreshold != -1) { - sacThreshold = considerSacThreshold; - } - - if (c.hasSVar("SacMe") || ComputerUtilCard.evaluateCreature(c) < sacThreshold) { + String logic = source.getParamOrDefault("AILogic", ""); + if (logic.startsWith("SacForDamage")) { + final int damageAmt = logic.contains("cmc") ? c.getManaCost().getCMC() : c.getNetPower(); + if (damageAmt <= 0) { + return false; + } else if (damageAmt >= ai.getOpponentsSmallestLifeTotal()) { return true; + } else if (logic.endsWith(".GiantX2") && c.getType().hasCreatureType("Giant") + && damageAmt * 2 >= ai.getOpponentsSmallestLifeTotal()) { + return true; // TODO: generalize this for any type and actually make the AI prefer giants? } - - if (ComputerUtilCard.hasActiveUndyingOrPersist(c)) { - return true; - } - - return false; } + + if ("DesecrationDemon".equals(logic)) { + sacThreshold = SpecialCardAi.DesecrationDemon.getSacThreshold(); + } else if (considerSacThreshold != -1) { + sacThreshold = considerSacThreshold; + } + + if (c.hasSVar("SacMe") || ComputerUtilCard.evaluateCreature(c) < sacThreshold) { + return true; + } + + if (ComputerUtilCard.hasActiveUndyingOrPersist(c)) { + return true; + } + + 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 willBeKilled = CardLists.filter(list, new Predicate() { - @Override - public boolean apply(Card card) { - return card.isCreature() && predictCreatureWillDieThisTurn(ai, card, excludeSa); - } - }); + List 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() { - @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() { - @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() { - @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() { - @Override - public boolean apply(final Card c) { - if (c.getController() == ai) { - return !c.getSVar("Targeting").equals("Dies") && !c.getSVar("Targeting").equals("Counter"); - } - return true; + 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() { - @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 markedAsReanimator = new Predicate() { - @Override - public boolean apply(Card card) { - return "true".equalsIgnoreCase(card.getSVar("IsReanimatorCard")); - } - }; + Predicate 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() { - @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); } diff --git a/forge-ai/src/main/java/forge/ai/ComputerUtilAbility.java b/forge-ai/src/main/java/forge/ai/ComputerUtilAbility.java index 371f98f4496..1add3ce299d 100644 --- a/forge-ai/src/main/java/forge/ai/ComputerUtilAbility.java +++ b/forge-ai/src/main/java/forge/ai/ComputerUtilAbility.java @@ -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,18 +37,15 @@ public class ComputerUtilAbility { CardCollection landList = CardLists.filter(hand, Presets.LANDS); //filter out cards that can't be played - landList = CardLists.filter(landList, new Predicate() { - @Override - public boolean apply(final Card 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); - if (list.isEmpty()) { - return false; - } + 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); + if (list.isEmpty()) { + return false; } - return player.canPlayLand(c); } + return player.canPlayLand(c); }); final CardCollection landsNotInHand = new CardCollection(player.getCardsIn(ZoneType.Graveyard)); diff --git a/forge-ai/src/main/java/forge/ai/ComputerUtilCard.java b/forge-ai/src/main/java/forge/ai/ComputerUtilCard.java index 0f8b35cefa3..596aa6a88d2 100644 --- a/forge-ai/src/main/java/forge/ai/ComputerUtilCard.java +++ b/forge-ai/src/main/java/forge/ai/ComputerUtilCard.java @@ -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() { - @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 pws) { @@ -194,16 +189,11 @@ public class ComputerUtilCard { public static Card getBestEnchantmentAI(final List list, final SpellAbility spell, final boolean targeted) { List all = CardLists.filter(list, CardPredicates.Presets.ENCHANTMENTS); if (targeted) { - all = CardLists.filter(all, new Predicate() { - @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 all, final SpellAbility spell, final boolean targeted) { if (targeted) { - all = CardLists.filter(all, new Predicate() { - @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 ae = CardLists.filter(list, Predicates.and(Predicates.or(CardPredicates.Presets.ARTIFACTS, CardPredicates.Presets.ENCHANTMENTS), new Predicate() { - @Override - public boolean apply(Card card) { - return !card.hasSVar("DoNotDiscardIfAble"); - } - })); + final List 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 EvaluateCreatureComparator = new Comparator() { - @Override - public int compare(final Card a, final Card b) { - return evaluateCreature(b) - evaluateCreature(a); - } - }; - public static final Comparator EvaluateCreatureSpellComparator = new Comparator() { - @Override - public int compare(final SpellAbility a, final SpellAbility b) { - // TODO ideally we could reuse the value from the previous pass with false - return ComputerUtilAbility.saEvaluator.compareEvaluator(a, b, true); - } + public static final Comparator EvaluateCreatureComparator = (a, b) -> evaluateCreature(b) - evaluateCreature(a); + public static final Comparator 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 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>() { - @Override - public int compare(Pair o1, Pair o2) { - return o2.getValue() - o1.getValue(); - } - }); + Collections.sort(map, Comparator.>comparingInt(Pair::getValue).reversed()); // will this part be once dropped? List result = new ArrayList<>(cntColors); @@ -1006,17 +976,14 @@ public class ComputerUtilCard { return result; } - public static final Predicate AI_KNOWS_HOW_TO_PLAY_ALL_CARDS = new Predicate() { - @Override - public boolean apply(Deck d) { - for (Entry cp : d) { - for (Entry e : cp.getValue()) { - if (e.getKey().getRules().getAiHints().getRemAIDecks()) - return false; - } + public static final Predicate AI_KNOWS_HOW_TO_PLAY_ALL_CARDS = d -> { + for (Entry cp : d) { + for (Entry e : cp.getValue()) { + if (e.getKey().getRules().getAiHints().getRemAIDecks()) + return false; } - return true; } + return true; }; public static List chooseColor(SpellAbility sa, int min, int max, List colorChoices) { diff --git a/forge-ai/src/main/java/forge/ai/ComputerUtilCombat.java b/forge-ai/src/main/java/forge/ai/ComputerUtilCombat.java index 5b599b68d80..e7c520bf6aa 100644 --- a/forge-ai/src/main/java/forge/ai/ComputerUtilCombat.java +++ b/forge-ai/src/main/java/forge/ai/ComputerUtilCombat.java @@ -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 defenders = CombatUtil.getAllPossibleDefenders(attacker.getController()); - return Iterables.any(defenders, new Predicate() { - @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 list = player.getCreaturesInPlay(); - list = CardLists.filter(list, new Predicate() { - @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); } diff --git a/forge-ai/src/main/java/forge/ai/ComputerUtilCost.java b/forge-ai/src/main/java/forge/ai/ComputerUtilCost.java index 67e570be245..bfee0f90eb7 100644 --- a/forge-ai/src/main/java/forge/ai/ComputerUtilCost.java +++ b/forge-ai/src/main/java/forge/ai/ComputerUtilCost.java @@ -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() { - @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() { - @Override - public boolean apply(Card card) { - boolean hasManaSa = false; - for (final SpellAbility sa : card.getSpellAbilities()) { - if (sa.isManaAbility() && sa.getPayCosts().hasTapCost()) { - hasManaSa = true; - break; - } + nonManaSources = CardLists.filter(nonManaSources, card -> { + boolean hasManaSa = false; + for (final SpellAbility sa1 : card.getSpellAbilities()) { + if (sa1.isManaAbility() && sa1.getPayCosts().hasTapCost()) { + hasManaSa = true; + break; } - return !hasManaSa; } + return !hasManaSa; }); if (nonManaSources.size() < part.convertAmount()) { return false; diff --git a/forge-ai/src/main/java/forge/ai/ComputerUtilMana.java b/forge-ai/src/main/java/forge/ai/ComputerUtilMana.java index 9a46caa537b..0ccc2af1365 100644 --- a/forge-ai/src/main/java/forge/ai/ComputerUtilMana.java +++ b/forge-ai/src/main/java/forge/ai/ComputerUtilMana.java @@ -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() { - @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,29 +143,26 @@ public class ComputerUtilMana { System.out.println("Unsorted Abilities: " + newAbilities); } - newAbilities.sort(new Comparator() { - @Override - public int compare(final SpellAbility ability1, final SpellAbility ability2) { - int preOrder = orderedCards.indexOf(ability1.getHostCard()) - orderedCards.indexOf(ability2.getHostCard()); + newAbilities.sort((ability1, ability2) -> { + int preOrder = orderedCards.indexOf(ability1.getHostCard()) - orderedCards.indexOf(ability2.getHostCard()); - if (preOrder != 0) { - return preOrder; - } - - // Mana abilities on the same card - String shardMana = shard.toString().replaceAll("\\{", "").replaceAll("\\}", ""); - - boolean payWithAb1 = ability1.getManaPart().mana(ability1).contains(shardMana); - boolean payWithAb2 = ability2.getManaPart().mana(ability2).contains(shardMana); - - if (payWithAb1 && !payWithAb2) { - return -1; - } else if (payWithAb2 && !payWithAb1) { - return 1; - } - - return ability1.compareTo(ability2); + if (preOrder != 0) { + return preOrder; } + + // Mana abilities on the same card + String shardMana = shard.toString().replaceAll("\\{", "").replaceAll("\\}", ""); + + boolean payWithAb1 = ability1.getManaPart().mana(ability1).contains(shardMana); + boolean payWithAb2 = ability2.getManaPart().mana(ability2).contains(shardMana); + + if (payWithAb1 && !payWithAb2) { + return -1; + } else if (payWithAb2 && !payWithAb1) { + return 1; + } + + return ability1.compareTo(ability2); }); if (DEBUG_MANA_PAYMENT) { @@ -195,27 +186,21 @@ public class ComputerUtilMana { final List prefSortedAbilities = new ArrayList<>(newAbilities); final List otherSortedAbilities = new ArrayList<>(newAbilities); - prefSortedAbilities.sort(new Comparator() { - @Override - public int compare(final SpellAbility ability1, final SpellAbility ability2) { - if (ability1.getManaPart().mana(ability1).contains(preferredShard)) - return -1; - else if (ability2.getManaPart().mana(ability2).contains(preferredShard)) - return 1; + 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; - } + return 0; }); - otherSortedAbilities.sort(new Comparator() { - @Override - public int compare(final SpellAbility ability1, final SpellAbility ability2) { - if (ability1.getManaPart().mana(ability1).contains(preferredShard)) - return 1; - else if (ability2.getManaPart().mana(ability2).contains(preferredShard)) - return -1; + 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; - } + return 0; }); final List finalAbilities = new ArrayList<>(); @@ -251,24 +236,14 @@ public class ComputerUtilMana { List filteredList = Lists.newArrayList(saList); switch (manaSourceType) { case "Snow": - filteredList.sort(new Comparator() { - @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() { - @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() { - @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() { - @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 sourcesForShards) { List shardsToPay = Lists.newArrayList(cost.getDistinctShards()); // optimize order so that the shards with less available sources are considered first - shardsToPay.sort(new Comparator() { - @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 srcs = CardLists.filter(p.getCardsIn(ZoneType.Battlefield), new Predicate() { - @Override - public boolean apply(final Card c) { - return !c.getManaAbilities().isEmpty(); - } - }); + final List srcs = CardLists.filter(p.getCardsIn(ZoneType.Battlefield), c -> !c.getManaAbilities().isEmpty()); int maxProduced = 0; int producedWithCost = 0; @@ -1437,17 +1392,14 @@ 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 manaSources = CardLists.filter(list, new Predicate() { - @Override - public boolean apply(final Card c) { - for (final SpellAbility am : getAIPlayableMana(c)) { - am.setActivatingPlayer(ai, true); - if (!checkPlayable || (am.canPlay() && am.checkRestrictions(ai))) { - return true; - } + final List manaSources = CardLists.filter(list, c -> { + for (final SpellAbility am : getAIPlayableMana(c)) { + am.setActivatingPlayer(ai, true); + if (!checkPlayable || (am.canPlay() && am.checkRestrictions(ai))) { + return true; } - return false; } + return false; }); // CardListFilter final CardCollection sortedManaSources = new CardCollection(); diff --git a/forge-ai/src/main/java/forge/ai/PlayerControllerAi.java b/forge-ai/src/main/java/forge/ai/PlayerControllerAi.java index 7672c1789e5..2c15791a6d6 100644 --- a/forge-ai/src/main/java/forge/ai/PlayerControllerAi.java +++ b/forge-ai/src/main/java/forge/ai/PlayerControllerAi.java @@ -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() { - @Override - public boolean apply(Card 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"); - } + 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 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() { - @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() { - @Override - public boolean apply(final Card c) {return !c.isCreature(); - } - }); + untapped = CardLists.filter(untapped, c -> !c.isCreature()); } else { return new HashMap<>(); } diff --git a/forge-ai/src/main/java/forge/ai/SpecialAiLogic.java b/forge-ai/src/main/java/forge/ai/SpecialAiLogic.java index 059f5553c24..0bb9c6f0dae 100644 --- a/forge-ai/src/main/java/forge/ai/SpecialAiLogic.java +++ b/forge-ai/src/main/java/forge/ai/SpecialAiLogic.java @@ -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() { - @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() { - @Override - public boolean apply(Card card) { - return ComputerUtilCard.isUselessCreature(ai, card) - || card.hasSVar("SacMe") - || ComputerUtilCard.evaluateCreature(card) < selfEval; // Maybe around 150 is OK? - } - } + card -> ComputerUtilCard.isUselessCreature(ai, card) + || card.hasSVar("SacMe") + || 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() { - @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() { - @Override - public boolean apply(Card card) { - return ComputerUtilCard.isUselessCreature(ai, card) - || card.hasSVar("SacMe") - || ComputerUtilCard.evaluateCreature(card) < selfEval; // Maybe around 150 is OK? - } - } + card -> ComputerUtilCard.isUselessCreature(ai, card) + || card.hasSVar("SacMe") + || 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() { - @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() { - @Override - public boolean apply(Card card) { - return ComputerUtilCard.isUselessCreature(ai, card) - || ComputerUtilCard.evaluateCreature(card) < selfEval - || ComputerUtil.predictThreatenedObjects(ai, null, true).contains(card); - } - } + card -> ComputerUtilCard.isUselessCreature(ai, card) + || ComputerUtilCard.evaluateCreature(card) < selfEval + || 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() { - @Override - public boolean apply(Card card) { - return ComputerUtilCard.isUselessCreature(ai, card) - || card.hasSVar("SacMe") - || (isBlocking && ComputerUtilCard.evaluateCreature(card) < selfEval) - || ComputerUtil.predictThreatenedObjects(ai, null, true).contains(card); - } - } + card -> ComputerUtilCard.isUselessCreature(ai, card) + || card.hasSVar("SacMe") + || (isBlocking && ComputerUtilCard.evaluateCreature(card) < selfEval) + || ComputerUtil.predictThreatenedObjects(ai, null, true).contains(card) ); return !sacFodder.isEmpty(); diff --git a/forge-ai/src/main/java/forge/ai/SpecialCardAi.java b/forge-ai/src/main/java/forge/ai/SpecialCardAi.java index f1954f793e5..09fd85c2f2f 100644 --- a/forge-ai/src/main/java/forge/ai/SpecialCardAi.java +++ b/forge-ai/src/main/java/forge/ai/SpecialCardAi.java @@ -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 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 list) { Card chosen = null; - List aiStuffies = CardLists.filter(list, new Predicate() { - @Override - public boolean apply(final Card 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"); + List 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 creatures = CardLists.filterControlledBy(list, ai.getOpponents()); - creatures = CardLists.filter(creatures, new Predicate() { - @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"); - } - }); + // Don't enchant creatures that can survive + 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() { - @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() { - @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() { - @Override - public boolean apply(Card card) { - final Card copy = CardCopyService.getLKICopy(card); - ComputerUtilCard.applyStaticContPT(ai.getGame(), copy, null); - return copy.getNetToughness() > 0; - } + 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() { - @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() { - @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)); } diff --git a/forge-ai/src/main/java/forge/ai/ability/AttachAi.java b/forge-ai/src/main/java/forge/ai/ability/AttachAi.java index 82a5173cee4..043f493005d 100644 --- a/forge-ai/src/main/java/forge/ai/ability/AttachAi.java +++ b/forge-ai/src/main/java/forge/ai/ability/AttachAi.java @@ -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,26 +332,23 @@ 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() { - @Override - public boolean apply(final Card c) { - //Check for cards that can be sacrificed in response - for (final SpellAbility ability : c.getAllSpellAbilities()) { - if (ability.isActivatedAbility()) { - final Cost cost = ability.getPayCosts(); - for (final CostPart part : cost.getCostParts()) { - if (!(part instanceof CostSacrifice)) { - continue; - } - CostSacrifice sacCost = (CostSacrifice) part; - if (sacCost.payCostFromSource() && ComputerUtilCost.canPayCost(ability, c.getController(), false)) { - return false; - } + list = CardLists.filter(list, c -> { + //Check for cards that can be sacrificed in response + for (final SpellAbility ability : c.getAllSpellAbilities()) { + if (ability.isActivatedAbility()) { + final Cost cost = ability.getPayCosts(); + for (final CostPart part : cost.getCostParts()) { + if (!(part instanceof CostSacrifice)) { + continue; + } + CostSacrifice sacCost = (CostSacrifice) part; + if (sacCost.payCostFromSource() && ComputerUtilCost.canPayCost(ability, c.getController(), false)) { + return false; } } } - return true; } + return true; }); final Card c = ComputerUtilCard.getBestAI(list); @@ -385,43 +381,40 @@ public class AttachAi extends SpellAbilityAi { */ private static Card attachAIKeepTappedPreference(final SpellAbility sa, final List list, final boolean mandatory, final Card attachSource) { // AI For Cards like Paralyzing Grasp and Glimmerdust Nap - final List prefList = CardLists.filter(list, new Predicate() { - @Override - public boolean apply(final Card c) { - // Don't do Untapped Vigilance cards - if (c.isCreature() && c.hasKeyword(Keyword.VIGILANCE) && c.isUntapped()) { + final List prefList = CardLists.filter(list, c -> { + // Don't do Untapped Vigilance cards + if (c.isCreature() && c.hasKeyword(Keyword.VIGILANCE) && c.isUntapped()) { + return false; + } + + if (!mandatory) { + if (!c.isCreature() && !c.getType().hasSubtype("Vehicle") && !c.isTapped()) { + // try to identify if this thing can actually tap + for (SpellAbility ab : c.getAllSpellAbilities()) { + if (ab.getPayCosts().hasTapCost()) { + return true; + } + } return false; } + } - if (!mandatory) { - if (!c.isCreature() && !c.getType().hasSubtype("Vehicle") && !c.isTapped()) { - // try to identify if this thing can actually tap - for (SpellAbility ab : c.getAllSpellAbilities()) { - if (ab.getPayCosts().hasTapCost()) { - return true; - } - } + if (!c.isEnchanted()) { + return true; + } + + final Iterable auras = c.getEnchantedBy(); + for (Card aura : auras) { + SpellAbility auraSA = aura.getSpells().get(0); + if (auraSA.getApi() == ApiType.Attach) { + if ("KeepTapped".equals(auraSA.getParam("AILogic"))) { + // Don't attach multiple KeepTapped Auras to one card return false; } } - - if (!c.isEnchanted()) { - return true; - } - - final Iterable auras = c.getEnchantedBy(); - for (Card aura : auras) { - SpellAbility auraSA = aura.getSpells().get(0); - if (auraSA.getApi() == ApiType.Attach) { - if ("KeepTapped".equals(auraSA.getParam("AILogic"))) { - // Don't attach multiple KeepTapped Auras to one card - return false; - } - } - } - - return true; } + + 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 betterList = CardLists.getNotType(list, "Creature"); if (ComputerUtilAbility.getAbilitySourceName(sa).equals("Animate Artifact")) { - betterList = CardLists.filter(betterList, new Predicate() { - @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 evenBetterList = CardLists.filter(betterList, new Predicate() { - @Override - public boolean apply(final Card c) { - return c.hasKeyword(Keyword.INDESTRUCTIBLE) || c.hasKeyword(Keyword.HEXPROOF); - } - }); + List 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() { - @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() { - @Override - public boolean apply(final Card c) { - for (final SpellAbility sa : c.getSpellAbilities()) { - if (sa.isAbility() && sa.getPayCosts().hasTapCost()) { - return false; - } + evenBetterList = CardLists.filter(betterList, c -> { + for (final SpellAbility sa1 : c.getSpellAbilities()) { + if (sa1.isAbility() && sa1.getPayCosts().hasTapCost()) { + return false; } - return true; } + 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,29 +566,26 @@ 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 betterList = CardLists.filter(list, new Predicate() { - @Override - public boolean apply(final Card 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)); + List 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)); - // Reanimate Auras use "Enchant creature put onto the battlefield with CARDNAME" with Remembered - attachSourceLki.clearRemembered(); - attachSourceLki.addRemembered(lki); + // Reanimate Auras use "Enchant creature put onto the battlefield with CARDNAME" with Remembered + attachSourceLki.clearRemembered(); + attachSourceLki.addRemembered(lki); - // need to check what the cards would be on the battlefield - // do not attach yet, that would cause Events - CardCollection preList = new CardCollection(lki); - preList.add(attachSourceLki); - c.getGame().getAction().checkStaticAbilities(false, Sets.newHashSet(preList), preList); - boolean result = lki.canBeAttached(attachSourceLki, null); + // need to check what the cards would be on the battlefield + // do not attach yet, that would cause Events + CardCollection preList = new CardCollection(lki); + preList.add(attachSourceLki); + c.getGame().getAction().checkStaticAbilities(false, Sets.newHashSet(preList), preList); + boolean result = lki.canBeAttached(attachSourceLki, null); - //reset static abilities - c.getGame().getAction().checkStaticAbilities(false); + //reset static abilities + c.getGame().getAction().checkStaticAbilities(false); - return result; - } + 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() { - @Override - public boolean apply(final Card c) { - if (!c.hasKeyword(Keyword.INDESTRUCTIBLE) && (c.getLethalDamage() <= Math.abs(tgh))) { - return true; - } - - return c.getNetToughness() <= Math.abs(tgh); + 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() { - @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() { - @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() { - @Override - public boolean apply(Card card) { - if (!card.isCreature()) { - return false; - } - - return ComputerUtilCard.evaluateCreature(card) >= oldEvalRating + threshold; + prefList = CardLists.filter(prefList, c -> { + if (!c.isCreature()) { + return false; } + + 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 list, final boolean mandatory, final Card attachSource) { // AI For choosing a Card to Pump - Card c = null; + Card card = null; List magnetList = null; String stCheck = null; if (attachSource.isAura() || sa.isBestow()) { stCheck = "EnchantedBy"; - magnetList = CardLists.filter(list, new Predicate() { - @Override - public boolean apply(final Card c) { - if (!c.isCreature()) { - return false; - } - String sVar = c.getSVar("EnchantMe"); - return sVar.equals("Multiple") || (sVar.equals("Once") && !c.isEnchanted()); + 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() { - @Override - public boolean apply(final Card c) { - if (!c.isCreature()) { - return false; - } - String sVar = c.getSVar("EquipMe"); - return sVar.equals("Multiple") || (sVar.equals("Once") && !c.isEquipped()); + 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() { - @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 betterList = CardLists.filter(magnetList, new Predicate() { - @Override - public boolean apply(final Card c) { - return CombatUtil.canAttack(c, ai.getWeakestOpponent()); - } - }); + List 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() { - @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,38 +1114,30 @@ 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() { - @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() { - @Override - public boolean apply(final Card c) { - if (!keywords.isEmpty()) { - for (final String keyword : keywords) { - if (isUsefulAttachKeyword(keyword, c, sa, pow)) { - return true; - } + prefList = CardLists.filter(prefList, c -> { + if (!keywords.isEmpty()) { + for (final String keyword : keywords) { + if (isUsefulAttachKeyword(keyword, c, sa, pow)) { + return true; } } - - if (c.hasKeyword(Keyword.INFECT) && pow >= 2) { - // consider +2 power a significant bonus on Infect creatures - return true; - } - if (extraBlock && CombatUtil.canBlock(c, true) && !c.canBlockAny()) { - return true; - } - return false; } + + if (c.hasKeyword(Keyword.INFECT) && pow >= 2) { + // consider +2 power a significant bonus on Infect creatures + return true; + } + if (extraBlock && CombatUtil.canBlock(c, true) && !c.canBlockAny()) { + 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() { - @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() { - @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() { - @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() { - @Override - public boolean apply(final Card c) { - if (!c.isCreature()) { - return true; - } - return powerBonus + c.getNetPower() > 0 && ComputerUtilCombat.canAttackNextTurn(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() { - @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 list = CardUtil.getValidCardsToTarget(sa); - CardCollection preferred = CardLists.filter(list, new Predicate() { - @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 list, final String type) { Card chosen = null; - List aiType = CardLists.filter(list, new Predicate() { - @Override - public boolean apply(final Card 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 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 oppNonType = CardLists.filter(list, new Predicate() { - @Override - public boolean apply(final Card 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); + List 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()) { diff --git a/forge-ai/src/main/java/forge/ai/ability/BranchAi.java b/forge-ai/src/main/java/forge/ai/ability/BranchAi.java index 9f2206baf39..0de37578305 100644 --- a/forge-ai/src/main/java/forge/ai/ability/BranchAi.java +++ b/forge-ai/src/main/java/forge/ai/ability/BranchAi.java @@ -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() { - @Override - public boolean apply(Card card) { - final GameEntity def = combat.getDefenderByAttacker(combat.getBandOfAttacker(card)); - return def instanceof Card && ((Card)def).isBattle(); - } + 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()) { diff --git a/forge-ai/src/main/java/forge/ai/ability/ChangeZoneAi.java b/forge-ai/src/main/java/forge/ai/ability/ChangeZoneAi.java index 15d9be1eb90..22b754f3dc3 100644 --- a/forge-ai/src/main/java/forge/ai/ability/ChangeZoneAi.java +++ b/forge-ai/src/main/java/forge/ai/ability/ChangeZoneAi.java @@ -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() { - @Override - public boolean apply(final Card c) { - if (c.getType().isLegendary()) { - return !ai.isCardInPlay(c.getName()); - } - return true; + 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() { - @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() { - @Override - public boolean apply(final Card c) { - for (Card card : game.getCardsIn(ZoneType.Battlefield)) { - if (card.isValid(sa.getParam("AttachedTo"), ai, c, sa)) { - return true; - } + 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; } + return false; }); } if (sa.hasParam("AttachAfter")) { - list = CardLists.filter(list, new Predicate() { - @Override - public boolean apply(final Card c) { - for (Card card : game.getCardsIn(ZoneType.Battlefield)) { - if (card.isValid(sa.getParam("AttachAfter"), ai, c, sa)) { - return true; - } + 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; } + 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() { - @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,17 +1050,14 @@ 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() { - @Override - public boolean apply(final Card c) { - for (Card aura : c.getEnchantedBy()) { - return aura.getController().isOpponentOf(ai); - } - if (blink) { - return c.isToken(); - } - return c.isToken() || c.getCMC() > 0; + list = CardLists.filter(list, c -> { + for (Card aura : c.getEnchantedBy()) { + return aura.getController().isOpponentOf(ai); } + if (blink) { + 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() { - @Override - public boolean apply(final Card c) { - for (SpellAbility attach : c.getSpellAbilities()) { - if ("Pump".equals(attach.getParam("AILogic"))) { - return true; //only use good auras - } + list = CardLists.filter(list, c -> { + for (SpellAbility attach : c.getSpellAbilities()) { + if ("Pump".equals(attach.getParam("AILogic"))) { + return true; //only use good auras } - return false; } + 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() { - @Override - public boolean apply(final Card c) { - for (Card aura : c.getEnchantedBy()) { - if (c.getOwner().isOpponentOf(ai) && aura.getController().equals(ai)) { - return false; - } + list = CardLists.filter(list, c -> { + for (Card aura : c.getEnchantedBy()) { + if (c.getOwner().isOpponentOf(ai) && aura.getController().equals(ai)) { + return false; } - return true; } + 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() { - @Override - public boolean apply(final Card c) { - if (c.getType().isLegendary()) { - return !decider.isCardInPlay(c.getName()); - } - return true; + 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() { - @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,53 +1678,50 @@ public class ChangeZoneAi extends SpellAbilityAi { } private static CardCollection prefilterOwnListForBounceAnyNum(CardCollection fetchList, Player decider) { - fetchList = CardLists.filter(fetchList, new Predicate() { - @Override - public boolean apply(final Card card) { - if (card.isToken()) { - return false; + fetchList = CardLists.filter(fetchList, card -> { + if (card.isToken()) { + return false; + } + if (card.isCreature() && ComputerUtilCard.isUselessCreature(decider, card)) { + return true; + } + if (card.isEquipped()) { + return false; + } + if (card.isEnchanted()) { + for (Card enc : card.getEnchantedBy()) { + if (enc.getOwner().isOpponentOf(decider)) { + return true; + } } - if (card.isCreature() && ComputerUtilCard.isUselessCreature(decider, card)) { - return true; - } - if (card.isEquipped()) { - return false; - } - if (card.isEnchanted()) { - for (Card enc : card.getEnchantedBy()) { - if (enc.getOwner().isOpponentOf(decider)) { + return false; + } + if (card.hasCounters()) { + if (card.isPlaneswalker()) { + int maxLoyaltyToConsider = 2; + int loyaltyDiff = 2; + int chance = 30; + if (decider.getController().isAI()) { + AiController aic = ((PlayerControllerAi) decider.getController()).getAi(); + maxLoyaltyToConsider = aic.getIntProperty(AiProps.BLINK_RELOAD_PLANESWALKER_MAX_LOYALTY); + loyaltyDiff = aic.getIntProperty(AiProps.BLINK_RELOAD_PLANESWALKER_LOYALTY_DIFF); + chance = aic.getIntProperty(AiProps.BLINK_RELOAD_PLANESWALKER_CHANCE); + } + if (MyRandom.percentTrue(chance)) { + int curLoyalty = card.getCounters(CounterEnumType.LOYALTY); + int freshLoyalty = Integer.parseInt(card.getCurrentState().getBaseLoyalty()); + if (freshLoyalty - curLoyalty >= loyaltyDiff && curLoyalty <= maxLoyaltyToConsider) { return true; } } - return false; + } else if (card.isCreature() && card.getCounters(CounterEnumType.M1M1) > 0) { + return true; } - if (card.hasCounters()) { - if (card.isPlaneswalker()) { - int maxLoyaltyToConsider = 2; - int loyaltyDiff = 2; - int chance = 30; - if (decider.getController().isAI()) { - AiController aic = ((PlayerControllerAi) decider.getController()).getAi(); - maxLoyaltyToConsider = aic.getIntProperty(AiProps.BLINK_RELOAD_PLANESWALKER_MAX_LOYALTY); - loyaltyDiff = aic.getIntProperty(AiProps.BLINK_RELOAD_PLANESWALKER_LOYALTY_DIFF); - chance = aic.getIntProperty(AiProps.BLINK_RELOAD_PLANESWALKER_CHANCE); - } - if (MyRandom.percentTrue(chance)) { - int curLoyalty = card.getCounters(CounterEnumType.LOYALTY); - int freshLoyalty = Integer.parseInt(card.getCurrentState().getBaseLoyalty()); - if (freshLoyalty - curLoyalty >= loyaltyDiff && curLoyalty <= maxLoyaltyToConsider) { - return true; - } - } - } else if (card.isCreature() && card.getCounters(CounterEnumType.M1M1) > 0) { - return true; - } - return false; // TODO: improve for other counters - } else if (card.isAura()) { - return false; - } - return true; + return false; // TODO: improve for other counters + } else if (card.isAura()) { + 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() { - @Override - public boolean apply(final Card c) { - if (c.getType().isLegendary()) { - return !ai.isCardInPlay(c.getName()); - } - return true; + listGoal = CardLists.filter(listGoal, c -> { + if (c.getType().isLegendary()) { + return !ai.isCardInPlay(c.getName()); } + return true; }); if (!listGoal.isEmpty()) { @@ -2014,17 +1971,14 @@ public class ChangeZoneAi extends SpellAbilityAi { exiledBy.add(exiled); } } - scanList = CardLists.filter(scanList, new Predicate() { - @Override - public boolean apply(Card card) { - if (exiledBy.isEmpty()) { - return true; - } - for (Card c : exiledBy) { - return !c.getType().sharesCardTypeWith(card.getType()); - } + scanList = CardLists.filter(scanList, card -> { + if (exiledBy.isEmpty()) { return true; } + for (Card c : exiledBy) { + 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() { - @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,22 +2027,19 @@ public class ChangeZoneAi extends SpellAbilityAi { return Aggregates.random(fetchList); } - CardCollection preferredList = CardLists.filter(fetchList, new Predicate() { - @Override - public boolean apply(Card card) { - boolean playerPref = true; - if (isCurse) { - playerPref = card.getController().isOpponentOf(aiPlayer); - } else if (isOwnOnly) { - playerPref = card.getController().equals(aiPlayer) || !card.getController().isOpponentOf(aiPlayer); - } - - if (!playerPref) { - return false; - } - - return card.isValid(valid, aiPlayer, host, sa); // for things like ExilePreference:Land.Basic + CardCollection preferredList = CardLists.filter(fetchList, card -> { + boolean playerPref = true; + if (isCurse) { + playerPref = card.getController().isOpponentOf(aiPlayer); + } else if (isOwnOnly) { + playerPref = card.getController().equals(aiPlayer) || !card.getController().isOpponentOf(aiPlayer); } + + if (!playerPref) { + return false; + } + + return card.isValid(valid, aiPlayer, host, sa); // for things like ExilePreference:Land.Basic }); if (!preferredList.isEmpty()) { diff --git a/forge-ai/src/main/java/forge/ai/ability/ChooseCardAi.java b/forge-ai/src/main/java/forge/ai/ability/ChooseCardAi.java index b3b9007d4d0..2644cd786f8 100644 --- a/forge-ai/src/main/java/forge/ai/ability/ChooseCardAi.java +++ b/forge-ai/src/main/java/forge/ai/ability/ChooseCardAi.java @@ -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() { - @Override - public boolean apply(final Card 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; + 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() { - @Override - public boolean apply(final Card 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; + 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() { - @Override - public boolean apply(final Card c) { - if (c.isCreature()) { + CardCollectionView betterList = CardLists.filter(options, c -> { + if (c.isCreature()) { + return false; + } + for (SpellAbility sa1 : c.getAllSpellAbilities()) { + if (sa1.getPayCosts().hasTapCost()) { return false; } - for (SpellAbility sa : c.getAllSpellAbilities()) { - if (sa.getPayCosts().hasTapCost()) { - return false; - } - } - return true; } + return true; }); if (!betterList.isEmpty()) { choice = betterList.get(0); diff --git a/forge-ai/src/main/java/forge/ai/ability/ChooseDirectionAi.java b/forge-ai/src/main/java/forge/ai/ability/ChooseDirectionAi.java index c2cccc1f1f0..17a74f21fe0 100644 --- a/forge-ai/src/main/java/forge/ai/ability/ChooseDirectionAi.java +++ b/forge-ai/src/main/java/forge/ai/ability/ChooseDirectionAi.java @@ -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; } } diff --git a/forge-ai/src/main/java/forge/ai/ability/ChooseGenericAi.java b/forge-ai/src/main/java/forge/ai/ability/ChooseGenericAi.java index f3b2206d24d..cbfbcb29678 100644 --- a/forge-ai/src/main/java/forge/ai/ability/ChooseGenericAi.java +++ b/forge-ai/src/main/java/forge/ai/ability/ChooseGenericAi.java @@ -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 filtered = Lists.newArrayList(Iterables.filter(spells, new Predicate() { - @Override - public boolean apply(final SpellAbility sp) { - return !sp.getDescription().contains("Creature") && !sp.getDescription().contains("Land"); - } - })); + List 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) { diff --git a/forge-ai/src/main/java/forge/ai/ability/ChooseSourceAi.java b/forge-ai/src/main/java/forge/ai/ability/ChooseSourceAi.java index fa11d33b529..3cfe82c05ae 100644 --- a/forge-ai/src/main/java/forge/ai/ability/ChooseSourceAi.java +++ b/forge-ai/src/main/java/forge/ai/ability/ChooseSourceAi.java @@ -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() { - @Override - public boolean apply(final Card c) { - if (combat == null || !combat.isAttacking(c, ai) || !combat.isUnblocked(c)) { - return false; - } - return ComputerUtilCombat.damageIfUnblocked(c, ai, combat, true) > 0; + 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 permanentSources = CardLists.filter(options, new Predicate() { - @Override - public boolean apply(final Card 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; + List 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. diff --git a/forge-ai/src/main/java/forge/ai/ability/ControlExchangeAi.java b/forge-ai/src/main/java/forge/ai/ability/ControlExchangeAi.java index 34089303a29..a8a13e575c6 100644 --- a/forge-ai/src/main/java/forge/ai/ability/ControlExchangeAi.java +++ b/forge-ai/src/main/java/forge/ai/ability/ControlExchangeAi.java @@ -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() { - @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); diff --git a/forge-ai/src/main/java/forge/ai/ability/ControlGainAi.java b/forge-ai/src/main/java/forge/ai/ability/ControlGainAi.java index 9785a0b665c..0cfe07f9201 100644 --- a/forge-ai/src/main/java/forge/ai/ability/ControlGainAi.java +++ b/forge-ai/src/main/java/forge/ai/ability/ControlGainAi.java @@ -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,46 +131,43 @@ 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() { - @Override - public boolean apply(final Card c) { - if (!sa.canTarget(c)) { - return false; - } - if (sa.isTrigger()) { - return true; - } - - if (!c.canBeControlledBy(ai)) { - return false; - } - - // do not take perm control on something that leaves the play end of turn - if (!lose.contains("EOT") && c.hasSVar("EndOfTurnLeavePlay")) { - return false; - } - - if (c.isCreature()) { - if (c.getNetCombatDamage() <= 0) { - return false; - } - - // can not attack any opponent - boolean found = false; - for (final Player opp : opponents) { - if (ComputerUtilCombat.canAttackNextTurn(c, opp)) { - found = true; - break; - } - } - if (!found) { - return false; - } - } - - // do not take control on something it doesn't know how to use - return !ComputerUtilCard.isCardRemAIDeck(c); + list = CardLists.filter(list, c -> { + if (!sa.canTarget(c)) { + return false; } + if (sa.isTrigger()) { + return true; + } + + if (!c.canBeControlledBy(ai)) { + return false; + } + + // do not take perm control on something that leaves the play end of turn + if (!lose.contains("EOT") && c.hasSVar("EndOfTurnLeavePlay")) { + return false; + } + + if (c.isCreature()) { + if (c.getNetCombatDamage() <= 0) { + return false; + } + + // can not attack any opponent + boolean found = false; + for (final Player opp : opponents) { + if (ComputerUtilCombat.canAttackNextTurn(c, opp)) { + found = true; + break; + } + } + if (!found) { + return false; + } + } + + // do not take control on something it doesn't know how to use + return !ComputerUtilCard.isCardRemAIDeck(c); }); if (list.isEmpty()) { diff --git a/forge-ai/src/main/java/forge/ai/ability/ControlGainVariantAi.java b/forge-ai/src/main/java/forge/ai/ability/ControlGainVariantAi.java index 894a6951c15..e1614e460bf 100644 --- a/forge-ai/src/main/java/forge/ai/ability/ControlGainVariantAi.java +++ b/forge-ai/src/main/java/forge/ai/ability/ControlGainVariantAi.java @@ -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 list = CardLists.filter(ai.getGame().getCardsIn(ZoneType.Battlefield), new Predicate() { - @Override - public boolean apply(final Card crd) { - return crd.isCreature() && !crd.getController().equals(crd.getOwner()); - } - }); + List list = CardLists.filter(ai.getGame().getCardsIn(ZoneType.Battlefield), crd -> crd.isCreature() && !crd.getController().equals(crd.getOwner())); if (list.isEmpty()) { return false; } diff --git a/forge-ai/src/main/java/forge/ai/ability/CopyPermanentAi.java b/forge-ai/src/main/java/forge/ai/ability/CopyPermanentAi.java index 1664188ede4..9403bd0033f 100644 --- a/forge-ai/src/main/java/forge/ai/ability/CopyPermanentAi.java +++ b/forge-ai/src/main/java/forge/ai/ability/CopyPermanentAi.java @@ -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() { - @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")) { diff --git a/forge-ai/src/main/java/forge/ai/ability/CountersAi.java b/forge-ai/src/main/java/forge/ai/ability/CountersAi.java index 7be51bdecf7..1b62032a221 100644 --- a/forge-ai/src/main/java/forge/ai/ability/CountersAi.java +++ b/forge-ai/src/main/java/forge/ai/ability/CountersAi.java @@ -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() { - @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)); diff --git a/forge-ai/src/main/java/forge/ai/ability/CountersMoveAi.java b/forge-ai/src/main/java/forge/ai/ability/CountersMoveAi.java index 9cfb1c62394..84853b15bd1 100644 --- a/forge-ai/src/main/java/forge/ai/ability/CountersMoveAi.java +++ b/forge-ai/src/main/java/forge/ai/ability/CountersMoveAi.java @@ -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,26 +260,21 @@ public class CountersMoveAi extends SpellAbilityAi { // prefered logic for this: try to steal counter List oppList = CardLists.filterControlledBy(tgtCards, ai.getOpponents()); if (!oppList.isEmpty()) { - List best = CardLists.filter(oppList, new Predicate() { - - @Override - public boolean apply(Card card) { - // do not weak a useless creature if able - if (ComputerUtilCard.isUselessCreature(ai, card)) { - return false; - } - - final Card srcCardCpy = CardCopyService.getLKICopy(card); - // cant use substract on Copy - srcCardCpy.setCounters(cType, srcCardCpy.getCounters(cType) - amount); - - // do not steal a P1P1 from Undying if it would die this way - if (cType != null && cType.is(CounterEnumType.P1P1) && srcCardCpy.getNetToughness() <= 0) { - return srcCardCpy.getCounters(cType) > 0 || !card.hasKeyword(Keyword.UNDYING) || card.isToken(); - } - return true; + List best = CardLists.filter(oppList, card -> { + // do not weak a useless creature if able + if (ComputerUtilCard.isUselessCreature(ai, card)) { + return false; } + final Card srcCardCpy = CardCopyService.getLKICopy(card); + // cant use substract on Copy + srcCardCpy.setCounters(cType, srcCardCpy.getCounters(cType) - amount); + + // do not steal a P1P1 from Undying if it would die this way + if (cType != null && cType.is(CounterEnumType.P1P1) && srcCardCpy.getNetToughness() <= 0) { + return srcCardCpy.getCounters(cType) > 0 || !card.hasKeyword(Keyword.UNDYING) || card.isToken(); + } + return true; }); // if no Prefered found, try normal list @@ -303,33 +297,29 @@ public class CountersMoveAi extends SpellAbilityAi { List aiList = CardLists.filterControlledBy(tgtCards, ally); if (!aiList.isEmpty()) { - List best = CardLists.filter(aiList, new Predicate() { - - @Override - public boolean apply(Card card) { - // gain from useless - if (ComputerUtilCard.isUselessCreature(ai, card)) { - return true; - } - - // source would leave the game - if (card.hasSVar("EndOfTurnLeavePlay")) { - return true; - } - - // try to remove P1P1 from undying or evolve - if (cType != null && cType.is(CounterEnumType.P1P1)) { - if (card.hasKeyword(Keyword.UNDYING) || card.hasKeyword(Keyword.EVOLVE) - || card.hasKeyword(Keyword.ADAPT)) { - return true; - } - } - if (cType != null && cType.is(CounterEnumType.M1M1) && card.hasKeyword(Keyword.PERSIST)) { - return true; - } - - return false; + List best = CardLists.filter(aiList, card -> { + // gain from useless + if (ComputerUtilCard.isUselessCreature(ai, card)) { + return true; } + + // source would leave the game + if (card.hasSVar("EndOfTurnLeavePlay")) { + return true; + } + + // try to remove P1P1 from undying or evolve + if (cType != null && cType.is(CounterEnumType.P1P1)) { + if (card.hasKeyword(Keyword.UNDYING) || card.hasKeyword(Keyword.EVOLVE) + || card.hasKeyword(Keyword.ADAPT)) { + return true; + } + } + if (cType != null && cType.is(CounterEnumType.M1M1) && card.hasKeyword(Keyword.PERSIST)) { + return true; + } + + return false; }); if (best.isEmpty()) { @@ -379,34 +369,30 @@ public class CountersMoveAi extends SpellAbilityAi { if (ComputerUtilCard.evaluateCreature(lkiWithCounters) > ComputerUtilCard.evaluateCreature(lkiWithoutCounters)) { List aiList = CardLists.filterControlledBy(tgtCards, ai); if (!aiList.isEmpty()) { - List best = CardLists.filter(aiList, new Predicate() { - - @Override - public boolean apply(Card card) { - // gain from useless - if (ComputerUtilCard.isUselessCreature(ai, card)) { - return false; - } - - // source would leave the game - if (card.hasSVar("EndOfTurnLeavePlay")) { - return false; - } - - if (cType != null) { - if (cType.is(CounterEnumType.P1P1) && card.hasKeyword(Keyword.UNDYING)) { - return false; - } - if (cType.is(CounterEnumType.M1M1)) { - return false; - } - - if (!card.canReceiveCounters(cType)) { - return false; - } - } - return true; + List best = CardLists.filter(aiList, card -> { + // gain from useless + if (ComputerUtilCard.isUselessCreature(ai, card)) { + return false; } + + // source would leave the game + if (card.hasSVar("EndOfTurnLeavePlay")) { + return false; + } + + if (cType != null) { + if (cType.is(CounterEnumType.P1P1) && card.hasKeyword(Keyword.UNDYING)) { + return false; + } + if (cType.is(CounterEnumType.M1M1)) { + return false; + } + + if (!card.canReceiveCounters(cType)) { + return false; + } + } + return true; }); if (best.isEmpty()) { @@ -432,22 +418,18 @@ public class CountersMoveAi extends SpellAbilityAi { // try to move to something useless or something that would leave play List oppList = CardLists.filterControlledBy(tgtCards, ai.getOpponents()); if (!oppList.isEmpty()) { - List best = CardLists.filter(oppList, new Predicate() { - - @Override - public boolean apply(Card card) { - // gain from useless - if (!ComputerUtilCard.isUselessCreature(ai, card)) { - return true; - } - - // source would leave the game - if (!card.hasSVar("EndOfTurnLeavePlay")) { - return true; - } - - return false; + List best = CardLists.filter(oppList, card -> { + // gain from useless + if (!ComputerUtilCard.isUselessCreature(ai, card)) { + return true; } + + // source would leave the game + if (!card.hasSVar("EndOfTurnLeavePlay")) { + return true; + } + + return false; }); if (best.isEmpty()) { diff --git a/forge-ai/src/main/java/forge/ai/ability/CountersMultiplyAi.java b/forge-ai/src/main/java/forge/ai/ability/CountersMultiplyAi.java index 94cd736a80b..a6adb284d3c 100644 --- a/forge-ai/src/main/java/forge/ai/ability/CountersMultiplyAi.java +++ b/forge-ai/src/main/java/forge/ai/ability/CountersMultiplyAi.java @@ -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,33 +36,28 @@ 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() { - - @Override - public boolean apply(Card c) { - if (!c.hasCounters()) { - return false; - } - - if (counterType != null) { - if (c.getCounters(counterType) <= 0) { - return false; - } - if (!c.canReceiveCounters(counterType)) { - return false; - } - } else { - for (Map.Entry e : c.getCounters().entrySet()) { - // has negative counter it would double - if (ComputerUtil.isNegativeCounter(e.getKey(), c)) { - return false; - } - } - } - - return true; + list = CardLists.filter(list, c -> { + if (!c.hasCounters()) { + return false; } + if (counterType != null) { + if (c.getCounters(counterType) <= 0) { + return false; + } + if (!c.canReceiveCounters(counterType)) { + return false; + } + } else { + for (Map.Entry e : c.getCounters().entrySet()) { + // has negative counter it would double + if (ComputerUtil.isNegativeCounter(e.getKey(), c)) { + return false; + } + } + } + + return true; }); if (list.isEmpty()) { @@ -137,26 +131,21 @@ 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() { - - @Override - public boolean apply(Card c) { - if (!c.hasCounters()) { - return false; - } - - if (counterType != null) { - if (c.getCounters(counterType) <= 0) { - return false; - } - if (!c.canReceiveCounters(counterType)) { - return false; - } - } - - return true; + list = CardLists.filter(list, c -> { + if (!c.hasCounters()) { + return false; } + if (counterType != null) { + if (c.getCounters(counterType) <= 0) { + return false; + } + if (!c.canReceiveCounters(counterType)) { + return false; + } + } + + return true; }); CardCollection aiList = CardLists.filterControlledBy(list, ai); diff --git a/forge-ai/src/main/java/forge/ai/ability/CountersProliferateAi.java b/forge-ai/src/main/java/forge/ai/ability/CountersProliferateAi.java index 1eeb3c66afc..aa5e232b9fa 100644 --- a/forge-ai/src/main/java/forge/ai/ability/CountersProliferateAi.java +++ b/forge-ai/src/main/java/forge/ai/ability/CountersProliferateAi.java @@ -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,25 +30,22 @@ 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() { - @Override - public boolean apply(final Card crd) { - if (!crd.hasCounters()) { - return false; - } - - if (crd.isPlaneswalker()) { - return true; - } - - // iterate only over existing counters - for (final Map.Entry e : crd.getCounters().entrySet()) { - if (e.getValue() >= 1 && !ComputerUtil.isNegativeCounter(e.getKey(), crd)) { - return true; - } - } + cperms.addAll(CardLists.filter(p.getCardsIn(ZoneType.Battlefield), crd -> { + if (!crd.hasCounters()) { return false; } + + if (crd.isPlaneswalker()) { + return true; + } + + // iterate only over existing counters + for (final Map.Entry e : crd.getCounters().entrySet()) { + if (e.getValue() >= 1 && !ComputerUtil.isNegativeCounter(e.getKey(), crd)) { + return true; + } + } + return false; })); } @@ -58,25 +54,22 @@ 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() { - @Override - public boolean apply(final Card crd) { - if (!crd.hasCounters()) { - return false; - } - - if (crd.isPlaneswalker()) { - return false; - } - - // iterate only over existing counters - for (final Map.Entry e : crd.getCounters().entrySet()) { - if (e.getValue() >= 1 && ComputerUtil.isNegativeCounter(e.getKey(), crd)) { - return true; - } - } + hperms.addAll(CardLists.filter(o.getCardsIn(ZoneType.Battlefield), crd -> { + if (!crd.hasCounters()) { return false; } + + if (crd.isPlaneswalker()) { + return false; + } + + // iterate only over existing counters + for (final Map.Entry e : crd.getCounters().entrySet()) { + if (e.getValue() >= 1 && ComputerUtil.isNegativeCounter(e.getKey(), crd)) { + return true; + } + } + return false; })); } diff --git a/forge-ai/src/main/java/forge/ai/ability/CountersPutAi.java b/forge-ai/src/main/java/forge/ai/ability/CountersPutAi.java index 1cff702ed3a..479a5e6cf77 100644 --- a/forge-ai/src/main/java/forge/ai/ability/CountersPutAi.java +++ b/forge-ai/src/main/java/forge/ai/ability/CountersPutAi.java @@ -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() { - @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,17 +181,14 @@ public class CountersPutAi extends CountersAi { CardCollection aiCreat = CardLists.getTargetableCards(ai.getCreaturesInPlay(), sa); aiCreat = CardLists.filter(aiCreat, CardPredicates.hasCounters()); - aiCreat = CardLists.filter(aiCreat, new Predicate() { - @Override - public boolean apply(Card input) { - for (CounterType counterType : input.getCounters().keySet()) { - if (!ComputerUtil.isNegativeCounter(counterType, input) - && input.canReceiveCounters(counterType)) { - return true; - } + aiCreat = CardLists.filter(aiCreat, input -> { + for (CounterType counterType : input.getCounters().keySet()) { + if (!ComputerUtil.isNegativeCounter(counterType, input) + && input.canReceiveCounters(counterType)) { + return true; } - return false; } + 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 leastToughness = Aggregates.listWithMin(creatsYouCtrl, CardPredicates.Accessors.fnGetNetToughness); + List 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,24 +463,21 @@ public class CountersPutAi extends CountersAi { list = ComputerUtil.getSafeTargets(ai, sa, ai.getCardsIn(ZoneType.Battlefield)); } - list = CardLists.filter(list, new Predicate() { - @Override - public boolean apply(final Card c) { - // don't put the counter on the dead creature - if (sacSelf && c.equals(source)) { - return false; - } else if (hasSacCost && !ComputerUtil.shouldSacrificeThreatenedCard(ai, c, sa)) { - return false; - } - if ("NoCounterOfType".equals(sa.getParam("AILogic"))) { - for (String ctrType : types) { - if (c.getCounters(CounterType.getType(ctrType)) > 0) { - return false; - } + list = CardLists.filter(list, c -> { + // don't put the counter on the dead creature + if (sacSelf && c.equals(source)) { + return false; + } else if (hasSacCost && !ComputerUtil.shouldSacrificeThreatenedCard(ai, c, sa)) { + return false; + } + if ("NoCounterOfType".equals(sa.getParam("AILogic"))) { + for (String ctrType : types) { + if (c.getCounters(CounterType.getType(ctrType)) > 0) { + return false; } } - return sa.canTarget(c) && c.canReceiveCounters(CounterType.getType(type)); } + 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 threatening = CardLists.filter(creats, new Predicate() { - @Override - public boolean apply(Card c) { - return CombatUtil.canBlock(source, c, !isHaste) - && (c.getNetToughness() > source.getNetPower() + tributeAmount || c.hasKeyword(Keyword.DEATHTOUCH)); - } - }); + List 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 canBlock = CardLists.filter(creats, new Predicate() { - @Override - public boolean apply(Card c) { - return CombatUtil.canBlock(source, c) && (c.getNetToughness() > source.getNetPower() || c.hasKeyword(Keyword.DEATHTOUCH)); - } - }); + List canBlock = CardLists.filter(creats, c -> CombatUtil.canBlock(source, c) + && (c.getNetToughness() > source.getNetPower() || c.hasKeyword(Keyword.DEATHTOUCH)) + ); if (!canBlock.isEmpty()) { return false; } @@ -1003,22 +983,19 @@ public class CountersPutAi extends CountersAi { final CardCollection opponents = CardLists.filterControlledBy(options, ai.getOpponents()); if (!opponents.isEmpty()) { - final CardCollection negative = CardLists.filter(opponents, new Predicate() { - @Override - public boolean apply(Card input) { - if (input.hasSVar("EndOfTurnLeavePlay")) - return false; - if (ComputerUtilCard.isUselessCreature(ai, input)) - return false; - for (CounterType type : types) { - if (type.is(CounterEnumType.M1M1) && amount >= input.getNetToughness()) - return true; - if (ComputerUtil.isNegativeCounter(type, input)) { - return true; - } - } + final CardCollection negative = CardLists.filter(opponents, input -> { + if (input.hasSVar("EndOfTurnLeavePlay")) return false; + if (ComputerUtilCard.isUselessCreature(ai, input)) + return false; + for (CounterType type : types) { + if (type.is(CounterEnumType.M1M1) && amount >= input.getNetToughness()) + return true; + if (ComputerUtil.isNegativeCounter(type, input)) { + return true; + } } + 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() { - @Override - public boolean apply(Card input) { - if (input.hasSVar("EndOfTurnLeavePlay")) - return false; - return !ComputerUtilCard.isUselessCreature(ai, 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() { - @Override - public boolean apply(Card input) { - if (!input.hasKeyword(Keyword.PERSIST)) - return false; - return input.getCounters(m1m1) <= amount; - } + 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() { - @Override - public boolean apply(Card input) { - if (!input.hasKeyword(Keyword.UNDYING)) - return false; - return input.getCounters(p1p1) <= amount && input.getNetToughness() > amount; - } + 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() { - @Override - public boolean apply(Card 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); - } + 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++) { diff --git a/forge-ai/src/main/java/forge/ai/ability/CountersPutAllAi.java b/forge-ai/src/main/java/forge/ai/ability/CountersPutAllAi.java index b256e8a376e..2b8767530b4 100644 --- a/forge-ai/src/main/java/forge/ai/ability/CountersPutAllAi.java +++ b/forge-ai/src/main/java/forge/ai/ability/CountersPutAllAi.java @@ -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 killable = CardLists.filter(hList, new Predicate() { - @Override - public boolean apply(final Card c) { - return c.getNetToughness() <= amount; - } - }); + final List killable = CardLists.filter(hList, c -> c.getNetToughness() <= amount); if (!(killable.size() > 2)) { return false; } diff --git a/forge-ai/src/main/java/forge/ai/ability/CountersPutOrRemoveAi.java b/forge-ai/src/main/java/forge/ai/ability/CountersPutOrRemoveAi.java index 4a60b929783..8fde651c09c 100644 --- a/forge-ai/src/main/java/forge/ai/ability/CountersPutOrRemoveAi.java +++ b/forge-ai/src/main/java/forge/ai/ability/CountersPutOrRemoveAi.java @@ -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() { - @Override - public boolean apply(Card input) { - return input.ignoreLegendRule(); - } - }); + boolean maritEmpty = marit.isEmpty() || Iterables.contains(marit, (Predicate) 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() { - @Override - public boolean apply(Card input) { - return input.ignoreLegendRule(); - } - }); + boolean maritEmpty = marit.isEmpty() || Iterables.contains(marit, (Predicate) 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() { - @Override - public boolean apply(Card input) { - return input.ignoreLegendRule(); - } - }); + boolean maritEmpty = marit.isEmpty() || Iterables.contains(marit, (Predicate) Card::ignoreLegendRule); if (maritEmpty) { return false; diff --git a/forge-ai/src/main/java/forge/ai/ability/CountersRemoveAi.java b/forge-ai/src/main/java/forge/ai/ability/CountersRemoveAi.java index 885bb8d5f22..6a307d80773 100644 --- a/forge-ai/src/main/java/forge/ai/ability/CountersRemoveAi.java +++ b/forge-ai/src/main/java/forge/ai/ability/CountersRemoveAi.java @@ -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() { - @Override - public boolean apply(Card input) { - return input.ignoreLegendRule(); - } - }); + boolean maritEmpty = marit.isEmpty() || Iterables.contains(marit, (Predicate) Card::ignoreLegendRule); if (type.matches("All")) { // Logic Part for Vampire Hexmage diff --git a/forge-ai/src/main/java/forge/ai/ability/DamageAllAi.java b/forge-ai/src/main/java/forge/ai/ability/DamageAllAi.java index a8e2688163e..bb47c8f0c8e 100644 --- a/forge-ai/src/main/java/forge/ai/ability/DamageAllAi.java +++ b/forge-ai/src/main/java/forge/ai/ability/DamageAllAi.java @@ -253,12 +253,7 @@ public class DamageAllAi extends SpellAbilityAi { CardCollection list = CardLists.getValidCards(player.getCardsIn(ZoneType.Battlefield), validC, source.getController(), source, sa); - final Predicate filterKillable = new Predicate() { - @Override - public boolean apply(final Card c) { - return ComputerUtilCombat.predictDamageTo(c, dmg, source, false) >= ComputerUtilCombat.getDamageToKill(c, false); - } - }; + final Predicate filterKillable = c -> ComputerUtilCombat.predictDamageTo(c, dmg, source, false) >= ComputerUtilCombat.getDamageToKill(c, false); list = CardLists.getNotKeyword(list, Keyword.INDESTRUCTIBLE); list = CardLists.filter(list, filterKillable); diff --git a/forge-ai/src/main/java/forge/ai/ability/DamageDealAi.java b/forge-ai/src/main/java/forge/ai/ability/DamageDealAi.java index e1909896920..36a61d50e25 100644 --- a/forge-ai/src/main/java/forge/ai/ability/DamageDealAi.java +++ b/forge-ai/src/main/java/forge/ai/ability/DamageDealAi.java @@ -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 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() { - @Override - public boolean apply(final Card c) { - return c.getSVar("Targeting").equals("Dies") - || (ComputerUtilCombat.getEnoughDamageToKill(c, d, source, false, noPrevention) <= d) - && !ComputerUtil.canRegenerate(ai, c) - && !c.hasSVar("SacMe") - && !ComputerUtilCard.hasActiveUndyingOrPersist(c); - } - }); + 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)); // 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 hPlay = CardLists.filter(getTargetableCards(ai, sa, pl, tgt, activator, source, game), CardPredicates.Presets.PLANESWALKERS); - CardCollection killables = CardLists.filter(hPlay, new Predicate() { - @Override - public boolean apply(final Card c) { - return c.getSVar("Targeting").equals("Dies") - || (ComputerUtilCombat.getEnoughDamageToKill(c, d, source, false, noPrevention) <= d) - && !ComputerUtil.canRegenerate(ai, c) - && !c.hasSVar("SacMe"); - } - }); + 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")); // Filter AI-specific targets if provided killables = ComputerUtil.filterAITgts(sa, ai, killables, true); diff --git a/forge-ai/src/main/java/forge/ai/ability/DebuffAi.java b/forge-ai/src/main/java/forge/ai/ability/DebuffAi.java index b491dab0b6f..a3bcf73aeb3 100644 --- a/forge-ai/src/main/java/forge/ai/ability/DebuffAi.java +++ b/forge-ai/src/main/java/forge/ai/ability/DebuffAi.java @@ -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,18 +68,15 @@ public class DebuffAi extends SpellAbilityAi { List cards = AbilityUtils.getDefinedCards(source, sa.getParam("Defined"), sa); final Combat combat = game.getCombat(); - return Iterables.any(cards, new Predicate() { - @Override - public boolean apply(final Card c) { - if (c.getController().equals(sa.getActivatingPlayer()) || combat == null) - return false; + return Iterables.any(cards, c -> { + if (c.getController().equals(sa.getActivatingPlayer()) || combat == null) + return false; - if (!combat.isBlocking(c) && !combat.isAttacking(c)) { - return false; - } - // don't add duplicate negative keywords - return sa.hasParam("Keywords") && c.hasAnyKeyword(Arrays.asList(sa.getParam("Keywords").split(" & "))); + if (!combat.isBlocking(c) && !combat.isAttacking(c)) { + return false; } + // 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() { - @Override - public boolean apply(final Card c) { - return c.hasAnyKeyword(kws); // don't add duplicate negative keywords - } + list = CardLists.filter(list, c -> { + return c.hasAnyKeyword(kws); // don't add duplicate negative keywords }); } return list; diff --git a/forge-ai/src/main/java/forge/ai/ability/DelayedTriggerAi.java b/forge-ai/src/main/java/forge/ai/ability/DelayedTriggerAi.java index eb4d6da35d9..12431bb18b9 100644 --- a/forge-ai/src/main/java/forge/ai/ability/DelayedTriggerAi.java +++ b/forge-ai/src/main/java/forge/ai/ability/DelayedTriggerAi.java @@ -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,38 +58,35 @@ 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() { - @Override - public boolean apply(final Card c) { - if (!(c.isInstant() || c.isSorcery()) || c.equals(sa.getHostCard())) { - return false; - } - for (SpellAbility ab : c.getSpellAbilities()) { - if (ComputerUtilAbility.getAbilitySourceName(sa).equals(ComputerUtilAbility.getAbilitySourceName(ab)) - || ab.hasParam("AINoRecursiveCheck")) { - // prevent infinitely recursing mana ritual and other abilities with reentry - continue; - } else if ("SpellCopy".equals(ab.getParam("AILogic")) && ab.getApi() == ApiType.DelayedTrigger) { - // don't copy another copy spell, too complex for the AI - continue; - } - if (!ab.canPlay()) { - continue; - } - AiPlayDecision decision = ((PlayerControllerAi)ai.getController()).getAi().canPlaySa(ab); - // see if we can pay both for this spell and for the Effect spell we're considering - if (decision == AiPlayDecision.WillPlay || decision == AiPlayDecision.WaitForMain2) { - ManaCost costAb = ab.getPayCosts().getTotalMana(); - ManaCost total = ManaCost.combine(costSa, costAb); - SpellAbility combinedAb = ab.copyWithDefinedCost(new Cost(total, false)); - // can we pay both costs? - if (ComputerUtilMana.canPayManaCost(combinedAb, ai, 0, true)) { - return true; - } - } - } + final int count = CardLists.count(ai.getCardsIn(ZoneType.Hand), c -> { + if (!(c.isInstant() || c.isSorcery()) || c.equals(sa.getHostCard())) { return false; } + for (SpellAbility ab : c.getSpellAbilities()) { + if (ComputerUtilAbility.getAbilitySourceName(sa).equals(ComputerUtilAbility.getAbilitySourceName(ab)) + || ab.hasParam("AINoRecursiveCheck")) { + // prevent infinitely recursing mana ritual and other abilities with reentry + continue; + } else if ("SpellCopy".equals(ab.getParam("AILogic")) && ab.getApi() == ApiType.DelayedTrigger) { + // don't copy another copy spell, too complex for the AI + continue; + } + if (!ab.canPlay()) { + continue; + } + AiPlayDecision decision = ((PlayerControllerAi)ai.getController()).getAi().canPlaySa(ab); + // see if we can pay both for this spell and for the Effect spell we're considering + if (decision == AiPlayDecision.WillPlay || decision == AiPlayDecision.WaitForMain2) { + ManaCost costAb = ab.getPayCosts().getTotalMana(); + ManaCost total = ManaCost.combine(costSa, costAb); + SpellAbility combinedAb = ab.copyWithDefinedCost(new Cost(total, false)); + // can we pay both costs? + if (ComputerUtilMana.canPayManaCost(combinedAb, ai, 0, true)) { + return true; + } + } + } + return false; }); if (count == 0) { @@ -106,30 +101,27 @@ 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() { - @Override - public boolean apply(final Card c) { - if (!(c.isInstant() || c.isSorcery()) || c.hasKeyword(Keyword.REBOUND)) { - return false; - } - for (SpellAbility ab : c.getSpellAbilities()) { - if (ComputerUtilAbility.getAbilitySourceName(sa).equals(ComputerUtilAbility.getAbilitySourceName(ab)) - || ab.hasParam("AINoRecursiveCheck")) { - // prevent infinitely recursing mana ritual and other abilities with reentry - continue; - } - if (!ab.canPlay()) { - continue; - } - AiPlayDecision decision = ((PlayerControllerAi) ai.getController()).getAi().canPlaySa(ab); - if (decision == AiPlayDecision.WillPlay || decision == AiPlayDecision.WaitForMain2) { - if (ComputerUtilMana.canPayManaCost(ab, ai, 0, true)) { - return true; - } - } - } + final int count = CardLists.count(ai.getCardsIn(ZoneType.Hand), c -> { + if (!(c.isInstant() || c.isSorcery()) || c.hasKeyword(Keyword.REBOUND)) { return false; } + for (SpellAbility ab : c.getSpellAbilities()) { + if (ComputerUtilAbility.getAbilitySourceName(sa).equals(ComputerUtilAbility.getAbilitySourceName(ab)) + || ab.hasParam("AINoRecursiveCheck")) { + // prevent infinitely recursing mana ritual and other abilities with reentry + continue; + } + if (!ab.canPlay()) { + continue; + } + AiPlayDecision decision = ((PlayerControllerAi) ai.getController()).getAi().canPlaySa(ab); + if (decision == AiPlayDecision.WillPlay || decision == AiPlayDecision.WaitForMain2) { + if (ComputerUtilMana.canPayManaCost(ab, ai, 0, true)) { + return true; + } + } + } + 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() { - @Override - public boolean apply(final Card card) { - if (ComputerUtilCard.isUselessCreature(ai, card)) { - return false; - } - - return ComputerUtil.predictCreatureWillDieThisTurn(ai, card, sa); + ownCreatures = CardLists.filter(ownCreatures, card -> { + if (ComputerUtilCard.isUselessCreature(ai, card)) { + return false; } + + return ComputerUtil.predictCreatureWillDieThisTurn(ai, card, sa); }); if (!ownCreatures.isEmpty()) { diff --git a/forge-ai/src/main/java/forge/ai/ability/DestroyAi.java b/forge-ai/src/main/java/forge/ai/ability/DestroyAi.java index b1c3ec327bc..33fbacfe074 100644 --- a/forge-ai/src/main/java/forge/ai/ability/DestroyAi.java +++ b/forge-ai/src/main/java/forge/ai/ability/DestroyAi.java @@ -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,30 +169,27 @@ 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() { - @Override - public boolean apply(final Card c) { - //Check for cards that can be sacrificed in response - for (final SpellAbility ability : c.getAllSpellAbilities()) { - if (ability.isActivatedAbility()) { - final Cost cost = ability.getPayCosts(); - for (final CostPart part : cost.getCostParts()) { - if (!(part instanceof CostSacrifice)) { - continue; - } - CostSacrifice sacCost = (CostSacrifice) part; - if (sacCost.payCostFromSource() && ComputerUtilCost.canPayCost(ability, c.getController(), false)) { - return false; - } + list = CardLists.filter(list, c -> { + //Check for cards that can be sacrificed in response + for (final SpellAbility ability : c.getAllSpellAbilities()) { + if (ability.isActivatedAbility()) { + final Cost cost = ability.getPayCosts(); + for (final CostPart part : cost.getCostParts()) { + if (!(part instanceof CostSacrifice)) { + continue; + } + CostSacrifice sacCost = (CostSacrifice) part; + if (sacCost.payCostFromSource() && ComputerUtilCost.canPayCost(ability, c.getController(), false)) { + return false; } } } - if (c.hasSVar("SacMe")) { - return false; - } - //Check for undying - return !c.hasKeyword(Keyword.UNDYING) || c.getCounters(CounterEnumType.P1P1) > 0; } + if (c.hasSVar("SacMe")) { + return false; + } + //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() { - @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() { - @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 diff --git a/forge-ai/src/main/java/forge/ai/ability/DestroyAllAi.java b/forge-ai/src/main/java/forge/ai/ability/DestroyAllAi.java index 5ddf3b677f1..81a2e17303c 100644 --- a/forge-ai/src/main/java/forge/ai/ability/DestroyAllAi.java +++ b/forge-ai/src/main/java/forge/ai/ability/DestroyAllAi.java @@ -19,12 +19,7 @@ import forge.game.zone.ZoneType; public class DestroyAllAi extends SpellAbilityAi { - private static final Predicate predicate = new Predicate() { - @Override - public boolean apply(final Card c) { - return !(c.hasKeyword(Keyword.INDESTRUCTIBLE) || c.getCounters(CounterEnumType.SHIELD) > 0 || c.hasSVar("SacMe")); - } - }; + private static final Predicate 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) diff --git a/forge-ai/src/main/java/forge/ai/ability/EffectAi.java b/forge-ai/src/main/java/forge/ai/ability/EffectAi.java index b27e9208154..ab194faaf72 100644 --- a/forge-ai/src/main/java/forge/ai/ability/EffectAi.java +++ b/forge-ai/src/main/java/forge/ai/ability/EffectAi.java @@ -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 human = opp.getCreaturesInPlay(); // only count creatures that can attack or block - comp = CardLists.filter(comp, new Predicate() { - @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 attackers = comp; - human = CardLists.filter(human, new Predicate() { - @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,24 +333,20 @@ 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() { - - @Override - public boolean apply(@Nullable Card input) { - Map runParams = AbilityKey.mapFromAffected(input); - runParams.put(AbilityKey.Regeneration, true); - List repDestoryList = game.getReplacementHandler().getReplacementList(ReplacementType.Destroy, runParams, ReplacementLayer.Other); - // no Destroy Replacement, or one non-Regeneration one like Totem-Armor - if (repDestoryList.isEmpty() || Iterables.any(repDestoryList, Predicates.not(CardTraitPredicates.hasParam("Regeneration")))) { - return false; - } - - if (cantRegenerateCheckCombat(input) || cantRegenerateCheckStack(input)) { - return true; - } - + list = CardLists.filter(list, CardPredicates.Presets.CAN_BE_DESTROYED, input -> { + Map runParams = AbilityKey.mapFromAffected(input); + runParams.put(AbilityKey.Regeneration, true); + List repDestoryList = game.getReplacementHandler().getReplacementList(ReplacementType.Destroy, runParams, ReplacementLayer.Other); + // no Destroy Replacement, or one non-Regeneration one like Totem-Armor + if (repDestoryList.isEmpty() || Iterables.any(repDestoryList, Predicates.not(CardTraitPredicates.hasParam("Regeneration")))) { return false; } + + if (cantRegenerateCheckCombat(input) || cantRegenerateCheckStack(input)) { + return true; + } + + return false; }); if (list.isEmpty()) { diff --git a/forge-ai/src/main/java/forge/ai/ability/EncodeAi.java b/forge-ai/src/main/java/forge/ai/ability/EncodeAi.java index f5cc92f0134..d25ff5e8453 100644 --- a/forge-ai/src/main/java/forge/ai/ability/EncodeAi.java +++ b/forge-ai/src/main/java/forge/ai/ability/EncodeAi.java @@ -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,24 +89,16 @@ public final class EncodeAi extends SpellAbilityAi { Card choice = null; // final String logic = sa.getParam("AILogic"); // if (logic == null) { - final List attackers = CardLists.filter(list, new Predicate() { - @Override - public boolean apply(final Card c) { - return ComputerUtilCombat.canAttackNextTurn(c); - } - }); - final List unblockables = CardLists.filter(attackers, new Predicate() { - @Override - public boolean apply(final Card c) { - boolean canAttackOpponent = false; - for (Player opp : ai.getOpponents()) { - if (CombatUtil.canAttack(c, opp) && !CombatUtil.canBeBlocked(c, null, opp)) { - canAttackOpponent = true; - break; - } + final List attackers = CardLists.filter(list, ComputerUtilCombat::canAttackNextTurn); + final List unblockables = CardLists.filter(attackers, c -> { + boolean canAttackOpponent = false; + for (Player opp : ai.getOpponents()) { + if (CombatUtil.canAttack(c, opp) && !CombatUtil.canBeBlocked(c, null, opp)) { + canAttackOpponent = true; + break; } - return canAttackOpponent; } + return canAttackOpponent; }); if (!unblockables.isEmpty()) { choice = ComputerUtilCard.getBestAI(unblockables); diff --git a/forge-ai/src/main/java/forge/ai/ability/FlipOntoBattlefieldAi.java b/forge-ai/src/main/java/forge/ai/ability/FlipOntoBattlefieldAi.java index b4e6e3c1e18..b385ee9205c 100644 --- a/forge-ai/src/main/java/forge/ai/ability/FlipOntoBattlefieldAi.java +++ b/forge-ai/src/main/java/forge/ai/ability/FlipOntoBattlefieldAi.java @@ -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() { - @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(); } diff --git a/forge-ai/src/main/java/forge/ai/ability/GoadAi.java b/forge-ai/src/main/java/forge/ai/ability/GoadAi.java index 4d95e1a15eb..89ac3299d99 100644 --- a/forge-ai/src/main/java/forge/ai/ability/GoadAi.java +++ b/forge-ai/src/main/java/forge/ai/ability/GoadAi.java @@ -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,25 +30,22 @@ public class GoadAi extends SpellAbilityAi { if (game.getPlayers().size() > 2) { // use this part only in multiplayer - CardCollection betterList = CardLists.filter(list, new Predicate() { - @Override - public boolean apply(Card c) { - // filter only creatures which can attack - if (ComputerUtilCard.isUselessCreature(ai, c)) { - return false; - } - // useless - if (c.isGoadedBy(ai)) { - return false; - } - // select creatures which can attack an Opponent other than ai - for (Player o : ai.getOpponents()) { - if (ComputerUtilCombat.canAttackNextTurn(c, o)) { - return true; - } - } + CardCollection betterList = CardLists.filter(list, c -> { + // filter only creatures which can attack + if (ComputerUtilCard.isUselessCreature(ai, c)) { return false; } + // useless + if (c.isGoadedBy(ai)) { + return false; + } + // select creatures which can attack an Opponent other than ai + for (Player o : ai.getOpponents()) { + if (ComputerUtilCombat.canAttackNextTurn(c, o)) { + return true; + } + } + return false; }); // if better list is not empty, use that one instead @@ -61,20 +56,17 @@ public class GoadAi extends SpellAbilityAi { } } else { // single Player, goaded creature would attack ai - CardCollection betterList = CardLists.filter(list, new Predicate() { - @Override - public boolean apply(Card c) { - // filter only creatures which can attack - if (ComputerUtilCard.isUselessCreature(ai, c)) { - return false; - } - // useless - if (c.isGoadedBy(ai)) { - return false; - } - // select only creatures AI can block - return ComputerUtilCard.canBeBlockedProfitably(ai, c, false); + CardCollection betterList = CardLists.filter(list, c -> { + // filter only creatures which can attack + if (ComputerUtilCard.isUselessCreature(ai, c)) { + return false; } + // useless + if (c.isGoadedBy(ai)) { + return false; + } + // select only creatures AI can block + return ComputerUtilCard.canBeBlockedProfitably(ai, c, false); }); // if better list is not empty, use that one instead diff --git a/forge-ai/src/main/java/forge/ai/ability/ManaAi.java b/forge-ai/src/main/java/forge/ai/ability/ManaAi.java index 01f24b92a7b..0602f25134b 100644 --- a/forge-ai/src/main/java/forge/ai/ability/ManaAi.java +++ b/forge-ai/src/main/java/forge/ai/ability/ManaAi.java @@ -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)); } diff --git a/forge-ai/src/main/java/forge/ai/ability/ManifestBaseAi.java b/forge-ai/src/main/java/forge/ai/ability/ManifestBaseAi.java index becde70e107..7cf5d187f94 100644 --- a/forge-ai/src/main/java/forge/ai/ability/ManifestBaseAi.java +++ b/forge-ai/src/main/java/forge/ai/ability/ManifestBaseAi.java @@ -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 options, boolean isOptional, Player targetedPlayer, Map params) { if (Iterables.size(options) > 1 || isOptional) { - CardCollection filtered = CardLists.filter(options, new Predicate() { - @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); } diff --git a/forge-ai/src/main/java/forge/ai/ability/MillAi.java b/forge-ai/src/main/java/forge/ai/ability/MillAi.java index 0211d25123a..4e28ba8764b 100644 --- a/forge-ai/src/main/java/forge/ai/ability/MillAi.java +++ b/forge-ai/src/main/java/forge/ai/ability/MillAi.java @@ -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 max = Collections.max(list.entrySet(), new Comparator>(){ - @Override - public int compare(Map.Entry o1, Map.Entry o2) { - return o1.getValue() - o2.getValue(); - } - }); + Map.Entry max = Collections.max(list.entrySet(), Map.Entry.comparingByValue()); sa.getTargets().add(max.getKey()); } diff --git a/forge-ai/src/main/java/forge/ai/ability/MustBlockAi.java b/forge-ai/src/main/java/forge/ai/ability/MustBlockAi.java index 288b8f79163..1d8bc7ef22f 100644 --- a/forge-ai/src/main/java/forge/ai/ability/MustBlockAi.java +++ b/forge-ai/src/main/java/forge/ai/ability/MustBlockAi.java @@ -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,28 +121,24 @@ public class MustBlockAi extends SpellAbilityAi { private List determineBlockerFromList(final Card attacker, final Player ai, Iterable options, SpellAbility sa, final boolean onlyLethal, final boolean testTapped) { - List list = CardLists.filter(options, new Predicate() { - @Override - public boolean apply(final Card c) { - boolean tapped = c.isTapped(); - if (testTapped) { - c.setTapped(false); - } - if (!CombatUtil.canBlock(attacker, c)) { - return false; - } - if (ComputerUtilCombat.canDestroyAttacker(ai, attacker, c, null, false)) { - return false; - } - if (onlyLethal && !ComputerUtilCombat.canDestroyBlocker(ai, c, attacker, null, false)) { - return false; - } - if (testTapped) { - c.setTapped(tapped); - } - return true; + List list = CardLists.filter(options, c -> { + boolean tapped = c.isTapped(); + if (testTapped) { + c.setTapped(false); } - + if (!CombatUtil.canBlock(attacker, c)) { + return false; + } + if (ComputerUtilCombat.canDestroyAttacker(ai, attacker, c, null, false)) { + return false; + } + if (onlyLethal && !ComputerUtilCombat.canDestroyBlocker(ai, c, attacker, null, false)) { + return false; + } + if (testTapped) { + c.setTapped(tapped); + } + return true; }); return list; diff --git a/forge-ai/src/main/java/forge/ai/ability/MutateAi.java b/forge-ai/src/main/java/forge/ai/ability/MutateAi.java index 00315019dad..c0583b99cb7 100644 --- a/forge-ai/src/main/java/forge/ai/ability/MutateAi.java +++ b/forge-ai/src/main/java/forge/ai/ability/MutateAi.java @@ -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() { - @Override - public boolean apply(final Card card) { - return ComputerUtilCard.isUselessCreature(aiPlayer, card); - } - } + card -> ComputerUtilCard.isUselessCreature(aiPlayer, card) ))); if (mutateTgts.isEmpty()) { diff --git a/forge-ai/src/main/java/forge/ai/ability/PermanentCreatureAi.java b/forge-ai/src/main/java/forge/ai/ability/PermanentCreatureAi.java index 49c8ac848c4..8ff03ccc2db 100644 --- a/forge-ai/src/main/java/forge/ai/ability/PermanentCreatureAi.java +++ b/forge-ai/src/main/java/forge/ai/ability/PermanentCreatureAi.java @@ -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() { - @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; diff --git a/forge-ai/src/main/java/forge/ai/ability/PlayAi.java b/forge-ai/src/main/java/forge/ai/ability/PlayAi.java index 570e44e9d0b..5736c4f8486 100644 --- a/forge-ai/src/main/java/forge/ai/ability/PlayAi.java +++ b/forge-ai/src/main/java/forge/ai/ability/PlayAi.java @@ -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,57 +147,54 @@ public class PlayAi extends SpellAbilityAi { state = CardStateName.Original; } - List tgtCards = CardLists.filter(options, new Predicate() { - @Override - public boolean apply(final Card 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)) { - if (!sa.matchesValidParam("ValidSA", s)) { - continue; - } - if (s instanceof LandAbility) { - // might want to run some checks here but it's rare anyway - return true; - } - Spell spell = (Spell) s; - if (params != null && params.containsKey("CMCLimit")) { - Integer cmcLimit = (Integer) params.get("CMCLimit"); - if (spell.getPayCosts().getTotalMana().getCMC() > cmcLimit) - continue; - } - if (sa.hasParam("WithoutManaCost")) { - // Try to avoid casting instants and sorceries with X in their cost, since X will be assumed to be 0. - if (!(spell instanceof SpellPermanent)) { - if (spell.costHasManaX()) { - continue; - } - } - - spell = (Spell) spell.copyWithNoManaCost(); - } else if (sa.hasParam("PlayCost")) { - Cost abCost; - if ("ManaCost".equals(sa.getParam("PlayCost"))) { - abCost = new Cost(c.getManaCost(), false); - } else { - abCost = new Cost(sa.getParam("PlayCost"), false); - } - - spell = (Spell) spell.copyWithManaCostReplaced(spell.getActivatingPlayer(), abCost); - } - if (AiPlayDecision.WillPlay == ((PlayerControllerAi)ai.getController()).getAi().canPlayFromEffectAI(spell, !(isOptional || sa.hasParam("Optional")), true)) { - // Before accepting, see if the spell has a valid number of targets (it should at this point). - // Proceeding past this point if the spell is not correctly targeted will result - // in "Failed to add to stack" error and the card disappearing from the game completely. - if (!spell.isTargetNumberValid() || !ComputerUtilCost.canPayCost(spell, ai, true)) { - // if we won't be able to pay the cost, don't choose the card - return false; - } - return true; - } + List 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)) { + if (!sa.matchesValidParam("ValidSA", s)) { + continue; + } + if (s instanceof LandAbility) { + // might want to run some checks here but it's rare anyway + return true; + } + Spell spell = (Spell) s; + if (params != null && params.containsKey("CMCLimit")) { + Integer cmcLimit = (Integer) params.get("CMCLimit"); + if (spell.getPayCosts().getTotalMana().getCMC() > cmcLimit) + continue; + } + if (sa.hasParam("WithoutManaCost")) { + // Try to avoid casting instants and sorceries with X in their cost, since X will be assumed to be 0. + if (!(spell instanceof SpellPermanent)) { + if (spell.costHasManaX()) { + continue; + } + } + + spell = (Spell) spell.copyWithNoManaCost(); + } else if (sa.hasParam("PlayCost")) { + Cost abCost; + if ("ManaCost".equals(sa.getParam("PlayCost"))) { + abCost = new Cost(c.getManaCost(), false); + } else { + abCost = new Cost(sa.getParam("PlayCost"), false); + } + + spell = (Spell) spell.copyWithManaCostReplaced(spell.getActivatingPlayer(), abCost); + } + if (AiPlayDecision.WillPlay == ((PlayerControllerAi)ai.getController()).getAi().canPlayFromEffectAI(spell, !(isOptional || sa.hasParam("Optional")), true)) { + // Before accepting, see if the spell has a valid number of targets (it should at this point). + // Proceeding past this point if the spell is not correctly targeted will result + // in "Failed to add to stack" error and the card disappearing from the game completely. + if (!spell.isTargetNumberValid() || !ComputerUtilCost.canPayCost(spell, ai, true)) { + // if we won't be able to pay the cost, don't choose the card + return false; + } + return true; } - return false; } + return false; }); if (sa.hasParam("CastTransformed")) { diff --git a/forge-ai/src/main/java/forge/ai/ability/PoisonAi.java b/forge-ai/src/main/java/forge/ai/ability/PoisonAi.java index ef1ef5fbab1..78359bbd9f6 100644 --- a/forge-ai/src/main/java/forge/ai/ability/PoisonAi.java +++ b/forge-ai/src/main/java/forge/ai/ability/PoisonAi.java @@ -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() { - @Override - public boolean apply(Player input) { - if (input.cantLose()) { - return false; - } else if (!input.canReceiveCounters(CounterType.get(CounterEnumType.POISON))) { - return false; - } - return true; + 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() { - @Override - public boolean apply(Player input) { - if (input.cantLose()) { - return true; - } - return !input.canReceiveCounters(CounterType.get(CounterEnumType.POISON)); + PlayerCollection betterAllies = allies.filter(input -> { + if (input.cantLose()) { + return true; } - + return !input.canReceiveCounters(CounterType.get(CounterEnumType.POISON)); }); if (!betterAllies.isEmpty()) { allies = betterAllies; diff --git a/forge-ai/src/main/java/forge/ai/ability/PowerExchangeAi.java b/forge-ai/src/main/java/forge/ai/ability/PowerExchangeAi.java index 406ab3bd033..a4fc7eb2465 100644 --- a/forge-ai/src/main/java/forge/ai/ability/PowerExchangeAi.java +++ b/forge-ai/src/main/java/forge/ai/ability/PowerExchangeAi.java @@ -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 list = CardLists.getValidCards(ai.getGame().getCardsIn(ZoneType.Battlefield), tgt.getValidTgts(), ai, sa.getHostCard(), sa); - list = CardLists.filter(list, new Predicate() { - @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")) { diff --git a/forge-ai/src/main/java/forge/ai/ability/ProtectAi.java b/forge-ai/src/main/java/forge/ai/ability/ProtectAi.java index 346599e1cab..a30318b7462 100644 --- a/forge-ai/src/main/java/forge/ai/ability/ProtectAi.java +++ b/forge-ai/src/main/java/forge/ai/ability/ProtectAi.java @@ -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,54 +105,51 @@ public class ProtectAi extends SpellAbilityAi { CardCollection list = ai.getCreaturesInPlay(); final List threatenedObjects = ComputerUtil.predictThreatenedObjects(sa.getActivatingPlayer(), sa, true); - list = CardLists.filter(list, new Predicate() { - @Override - public boolean apply(final Card c) { - if (!c.canBeTargetedBy(sa)) { - return false; - } - - // Don't add duplicate protections - if (hasProtectionFromAll(c, gains)) { - return false; - } - - if (threatenedObjects.contains(c)) { - return true; - } - - if (combat != null) { - //creature is blocking and would be destroyed itself - if (combat.isBlocking(c) && ComputerUtilCombat.blockerWouldBeDestroyed(ai, c, combat)) { - List threats = combat.getAttackersBlockedBy(c); - return threats != null && !threats.isEmpty() && ProtectAi.toProtectFrom(threats.get(0), sa) != null; - } - - //creature is attacking and would be destroyed itself - if (combat.isAttacking(c) && combat.isBlocked(c) && ComputerUtilCombat.attackerWouldBeDestroyed(ai, c, combat)) { - CardCollection threats = combat.getBlockers(c); - if (threats != null && !threats.isEmpty()) { - ComputerUtilCard.sortByEvaluateCreature(threats); - return ProtectAi.toProtectFrom(threats.get(0), sa) != null; - } - } - } - - //make unblockable - if (ph.getPlayerTurn() == ai && ph.getPhase() == PhaseType.MAIN1) { - AiAttackController aiAtk = new AiAttackController(ai, c); - String s = aiAtk.toProtectAttacker(sa); - if (s == null) { - return false; - } - Player opponent = ai.getWeakestOpponent(); - Combat combat = ai.getGame().getCombat(); - int dmg = ComputerUtilCombat.damageIfUnblocked(c, opponent, combat, true); - float ratio = 1.0f * dmg / opponent.getLife(); - return MyRandom.getRandom().nextFloat() < ratio; - } + list = CardLists.filter(list, c -> { + if (!c.canBeTargetedBy(sa)) { return false; } + + // Don't add duplicate protections + if (hasProtectionFromAll(c, gains)) { + return false; + } + + if (threatenedObjects.contains(c)) { + return true; + } + + if (combat != null) { + //creature is blocking and would be destroyed itself + if (combat.isBlocking(c) && ComputerUtilCombat.blockerWouldBeDestroyed(ai, c, combat)) { + List threats = combat.getAttackersBlockedBy(c); + return threats != null && !threats.isEmpty() && ProtectAi.toProtectFrom(threats.get(0), sa) != null; + } + + //creature is attacking and would be destroyed itself + if (combat.isAttacking(c) && combat.isBlocked(c) && ComputerUtilCombat.attackerWouldBeDestroyed(ai, c, combat)) { + CardCollection threats = combat.getBlockers(c); + if (threats != null && !threats.isEmpty()) { + ComputerUtilCard.sortByEvaluateCreature(threats); + return ProtectAi.toProtectFrom(threats.get(0), sa) != null; + } + } + } + + //make unblockable + if (ph.getPlayerTurn() == ai && ph.getPhase() == PhaseType.MAIN1) { + AiAttackController aiAtk = new AiAttackController(ai, c); + String s = aiAtk.toProtectAttacker(sa); + if (s == null) { + return false; + } + Player opponent = ai.getWeakestOpponent(); + 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() { - @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() { - @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 forced = CardLists.filterControlledBy(list, ai); while (sa.canAddMoreTarget()) { diff --git a/forge-ai/src/main/java/forge/ai/ability/PumpAi.java b/forge-ai/src/main/java/forge/ai/ability/PumpAi.java index 6a79c8ca02d..34486c7f2e7 100644 --- a/forge-ai/src/main/java/forge/ai/ability/PumpAi.java +++ b/forge-ai/src/main/java/forge/ai/ability/PumpAi.java @@ -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,52 @@ public class PumpAi extends PumpAiBase { if (attr.isEmpty()) { return false; } - CardCollection best = CardLists.filter(attr, new Predicate() { - @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); + } else if (source.hasSVar(amountStr)) { + if ("Count$ChosenNumber".equals(source.getSVar(amountStr))) { + amount = card.getCounters(cType); + } + } + + int i = card.getCounters(cType); + if (i < amount) { + return false; + } + + final Card srcCardCpy = CardCopyService.getLKICopy(card); + // cant use substract on Copy + srcCardCpy.setCounters(cType, srcCardCpy.getCounters(cType) - amount); + + if (cType.is(CounterEnumType.P1P1) && srcCardCpy.getNetToughness() <= 0) { + return srcCardCpy.getCounters(cType) > 0 || !card.hasKeyword(Keyword.UNDYING) + || card.isToken(); + } + return false; + }); + + if (best.isEmpty()) { + best = attr; + } + + final Card card = ComputerUtilCard.getBestCreatureAI(best); + sa.getTargets().add(card); + return true; + } + } else { + final boolean sameCtrl = moveSA.getTargetRestrictions().isSameController(); + + List list = CardLists.getTargetableCards(game.getCardsIn(ZoneType.Battlefield), sa); + if (cType != null) { + list = CardLists.filter(list, CardPredicates.hasCounter(cType)); + if (list.isEmpty()) { + return false; + } + List oppList = CardLists.filterControlledBy(list, ai.getOpponents()); + if (!oppList.isEmpty() && !sameCtrl) { + List best = CardLists.filter(oppList, card -> { int amount = 0; if (StringUtils.isNumeric(amountStr)) { amount = AbilityUtils.calculateAmount(source, amountStr, moveSA); @@ -189,57 +231,7 @@ public class PumpAi extends PumpAiBase { return srcCardCpy.getCounters(cType) > 0 || !card.hasKeyword(Keyword.UNDYING) || card.isToken(); } - return false; - } - - }); - - if (best.isEmpty()) { - best = attr; - } - - final Card card = ComputerUtilCard.getBestCreatureAI(best); - sa.getTargets().add(card); - return true; - } - } else { - final boolean sameCtrl = moveSA.getTargetRestrictions().isSameController(); - - List list = CardLists.getTargetableCards(game.getCardsIn(ZoneType.Battlefield), sa); - if (cType != null) { - list = CardLists.filter(list, CardPredicates.hasCounter(cType)); - if (list.isEmpty()) { - return false; - } - List oppList = CardLists.filterControlledBy(list, ai.getOpponents()); - if (!oppList.isEmpty() && !sameCtrl) { - List best = CardLists.filter(oppList, new Predicate() { - @Override - public boolean apply(Card card) { - int amount = 0; - if (StringUtils.isNumeric(amountStr)) { - amount = AbilityUtils.calculateAmount(source, amountStr, moveSA); - } else if (source.hasSVar(amountStr)) { - if ("Count$ChosenNumber".equals(source.getSVar(amountStr))) { - amount = card.getCounters(cType); - } - } - - int i = card.getCounters(cType); - if (i < amount) { - return false; - } - - final Card srcCardCpy = CardCopyService.getLKICopy(card); - // cant use substract on Copy - srcCardCpy.setCounters(cType, srcCardCpy.getCounters(cType) - amount); - - if (cType.is(CounterEnumType.P1P1) && srcCardCpy.getNetToughness() <= 0) { - return srcCardCpy.getCounters(cType) > 0 || !card.hasKeyword(Keyword.UNDYING) - || card.isToken(); - } - return true; - } + 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() { - @Override - public boolean apply(Card card) { - for (SpellAbility sa : card.getSpellAbilities()) { - if (sa.isActivatedAbility()) { - return true; - } + list = CardLists.filter(list, Predicates.or(CardPredicates.Presets.CREATURES, card -> { + for (SpellAbility sa1 : card.getSpellAbilities()) { + if (sa1.isActivatedAbility()) { + return true; } - return false; } + 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() { - @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>() { - @Override - public int compare(Map.Entry o1, Map.Entry 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> max = Collections.max(data.entrySet(), new Comparator>>() { - @Override - public int compare(Map.Entry> o1, Map.Entry> o2) { - return o1.getValue().getValue() - o2.getValue().getValue(); - } - }); + Map.Entry> 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()), diff --git a/forge-ai/src/main/java/forge/ai/ability/PumpAiBase.java b/forge-ai/src/main/java/forge/ai/ability/PumpAiBase.java index 10d4c4bbb1f..8c9891ac567 100644 --- a/forge-ai/src/main/java/forge/ai/ability/PumpAiBase.java +++ b/forge-ai/src/main/java/forge/ai/ability/PumpAiBase.java @@ -122,15 +122,12 @@ public abstract class PumpAiBase extends SpellAbilityAi { return false; } - List attackers = CardLists.filter(ai.getCreaturesInPlay(), new Predicate() { - @Override - public boolean apply(final Card 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()); + List 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,17 +137,14 @@ public abstract class PumpAiBase extends SpellAbilityAi { return false; } - List attackers = CardLists.filter(ai.getCreaturesInPlay(), new Predicate() { - @Override - public boolean apply(final Card c) { - if (c.equals(sa.getHostCard()) && sa.getPayCosts().hasTapCost() - && (combat == null || !combat.isAttacking(c))) { - return false; - } - // 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()); + List attackers = CardLists.filter(ai.getCreaturesInPlay(), c -> { + if (c.equals(sa.getHostCard()) && sa.getPayCosts().hasTapCost() + && (combat == null || !combat.isAttacking(c))) { + return false; } + // 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 keywords, final boolean immediately) { CardCollection list = CardLists.getTargetableCards(ai.getCreaturesInPlay(), sa); - list = CardLists.filter(list, new Predicate() { - @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() { - @Override - public boolean apply(final Card 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); + 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,18 +458,15 @@ 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() { - @Override - public boolean apply(final Card c) { - if (combat == null || !combat.isAttacking(c)) { - return false; - } - if (c.getNetPower() > 0 && ai.getLife() < 5) { - return true; - } - //Don't waste a -7/-0 spell on a 1/1 creature - return c.getNetPower() + attack > -2 || c.getNetPower() > 3; + list = CardLists.filter(list, c -> { + if (combat == null || !combat.isAttacking(c)) { + return false; } + if (c.getNetPower() > 0 && ai.getLife() < 5) { + return true; + } + //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() { - @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(); diff --git a/forge-ai/src/main/java/forge/ai/ability/PumpAllAi.java b/forge-ai/src/main/java/forge/ai/ability/PumpAllAi.java index 9c9a714cdc1..26ccd6cc30f 100644 --- a/forge-ai/src/main/java/forge/ai/ability/PumpAllAi.java +++ b/forge-ai/src/main/java/forge/ai/ability/PumpAllAi.java @@ -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() { - @Override - public boolean apply(final Card c) { - if (c.getNetToughness() <= -defense) { - return true; // can kill indestructible creatures - } - return ComputerUtilCombat.getDamageToKill(c, false) <= -defense && !c.hasKeyword(Keyword.INDESTRUCTIBLE); + 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() { - @Override - public boolean apply(final Card c) { - if (c.getNetToughness() <= -defense) { - return true; // can kill indestructible creatures - } - return ComputerUtilCombat.getDamageToKill(c, false) <= -defense && !c.hasKeyword(Keyword.INDESTRUCTIBLE); + 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 diff --git a/forge-ai/src/main/java/forge/ai/ability/RepeatAi.java b/forge-ai/src/main/java/forge/ai/ability/RepeatAi.java index 3ba08023ec8..c9f25f8a456 100644 --- a/forge-ai/src/main/java/forge/ai/ability/RepeatAi.java +++ b/forge-ai/src/main/java/forge/ai/ability/RepeatAi.java @@ -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 targetableAi = Iterables.filter(ai.getCreaturesInPlay(), CardPredicates.isTargetableBy(sa)); if (!logic.endsWith("IgnoreLegendary")) { - best = ComputerUtilCard.getBestAI(Iterables.filter(targetableAi, new Predicate() { - @Override - public boolean apply(Card card) { - return card.ignoreLegendRule(); - } - })); + best = ComputerUtilCard.getBestAI(Iterables.filter(targetableAi, Card::ignoreLegendRule)); } else { best = ComputerUtilCard.getBestAI(targetableAi); } diff --git a/forge-ai/src/main/java/forge/ai/ability/RepeatEachAi.java b/forge-ai/src/main/java/forge/ai/ability/RepeatEachAi.java index bae0b6a80ce..e7ed3a5dfa7 100644 --- a/forge-ai/src/main/java/forge/ai/ability/RepeatEachAi.java +++ b/forge-ai/src/main/java/forge/ai/ability/RepeatEachAi.java @@ -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() { - @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(); } diff --git a/forge-ai/src/main/java/forge/ai/ability/SetStateAi.java b/forge-ai/src/main/java/forge/ai/ability/SetStateAi.java index 9f6477f3d07..da8dcfc2286 100644 --- a/forge-ai/src/main/java/forge/ai/ability/SetStateAi.java +++ b/forge-ai/src/main/java/forge/ai/ability/SetStateAi.java @@ -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() { - @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; diff --git a/forge-ai/src/main/java/forge/ai/ability/TapAiBase.java b/forge-ai/src/main/java/forge/ai/ability/TapAiBase.java index 04aefba1c19..d56d2fcfc25 100644 --- a/forge-ai/src/main/java/forge/ai/ability/TapAiBase.java +++ b/forge-ai/src/main/java/forge/ai/ability/TapAiBase.java @@ -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() { - @Override - public boolean apply(final Card c) { - if (c.isCreature()) { + tapList = CardLists.filter(tapList, c -> { + if (c.isCreature()) { + return true; + } + + for (final SpellAbility sa1 : c.getSpellAbilities()) { + if (sa1.isAbility() && sa1.getPayCosts().hasTapCost()) { return true; } - - for (final SpellAbility sa : c.getSpellAbilities()) { - if (sa.isAbility() && sa.getPayCosts().hasTapCost()) { - return true; - } - } - return false; } + 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() { - @Override - public boolean apply(final Card c) { - if (c.isCreature()) { + tapList = CardLists.filter(tapList, c -> { + if (c.isCreature()) { + return true; + } + + for (final SpellAbility sa12 : c.getSpellAbilities()) { + if (sa12.isAbility() && sa12.getPayCosts().hasTapCost()) { return true; } - - for (final SpellAbility sa : c.getSpellAbilities()) { - if (sa.isAbility() && sa.getPayCosts().hasTapCost()) { - return true; - } - } - return false; } + 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() { - @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 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 creatureList = CardLists.filter(tapList, new Predicate() { - @Override - public boolean apply(final Card c) { - return c.isCreature() && CombatUtil.canAttack(c, opp); - } - }); + List creatureList = CardLists.filter(tapList, c -> c.isCreature() && CombatUtil.canAttack(c, opp)); choice = ComputerUtilCard.getBestCreatureAI(creatureList); } else { // no creatures available choice = ComputerUtilCard.getMostExpensivePermanentAI(tapList); diff --git a/forge-ai/src/main/java/forge/ai/ability/TapAllAi.java b/forge-ai/src/main/java/forge/ai/ability/TapAllAi.java index 9dce57c310d..8189f4ff4c2 100644 --- a/forge-ai/src/main/java/forge/ai/ability/TapAllAi.java +++ b/forge-ai/src/main/java/forge/ai/ability/TapAllAi.java @@ -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() { - @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; diff --git a/forge-ai/src/main/java/forge/ai/ability/TokenAi.java b/forge-ai/src/main/java/forge/ai/ability/TokenAi.java index 63f53a812c0..4f2ec3db26a 100644 --- a/forge-ai/src/main/java/forge/ai/ability/TokenAi.java +++ b/forge-ai/src/main/java/forge/ai/ability/TokenAi.java @@ -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() { - @Override - public boolean apply(Card c) { - return c.getLethalDamage() == 1; - } - }); + CardCollection betterList = CardLists.filter(list, c -> c.getLethalDamage() == 1); if (!betterList.isEmpty()) { list = betterList; } diff --git a/forge-ai/src/main/java/forge/ai/ability/UntapAi.java b/forge-ai/src/main/java/forge/ai/ability/UntapAi.java index 0fb6560ca92..a3f2edb5199 100644 --- a/forge-ai/src/main/java/forge/ai/ability/UntapAi.java +++ b/forge-ai/src/main/java/forge/ai/ability/UntapAi.java @@ -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() { - @Override - public boolean apply(Card card) { - boolean hasUntapLandLogic = false; - for (SpellAbility sa : card.getSpellAbilities()) { - if ("PoolExtraMana".equals(sa.getParam("AILogic"))) { - hasUntapLandLogic = true; - break; - } + CardCollection untappingCards = CardLists.filter(ai.getCardsIn(ZoneType.Battlefield), card -> { + boolean hasUntapLandLogic = false; + for (SpellAbility sa1 : card.getSpellAbilities()) { + if ("PoolExtraMana".equals(sa1.getParam("AILogic"))) { + hasUntapLandLogic = true; + break; } - return hasUntapLandLogic && card.isUntapped(); } + return hasUntapLandLogic && card.isUntapped(); }); // TODO: currently limited to Main 2, somehow improve to let the AI use this SA at other time? diff --git a/forge-ai/src/main/java/forge/ai/simulation/GameCopier.java b/forge-ai/src/main/java/forge/ai/simulation/GameCopier.java index 2c77bbcf37e..f697679e0af 100644 --- a/forge-ai/src/main/java/forge/ai/simulation/GameCopier.java +++ b/forge-ai/src/main/java/forge/ai/simulation/GameCopier.java @@ -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; diff --git a/forge-ai/src/main/java/forge/ai/simulation/GameSimulator.java b/forge-ai/src/main/java/forge/ai/simulation/GameSimulator.java index 1e5461c323b..e78415429a9 100644 --- a/forge-ai/src/main/java/forge/ai/simulation/GameSimulator.java +++ b/forge-ai/src/main/java/forge/ai/simulation/GameSimulator.java @@ -252,32 +252,29 @@ 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() { - final Set allAffectedCards = new HashSet<>(); + opponent.runWithController(() -> { + final Set allAffectedCards = new HashSet<>(); + game.getAction().checkStateEffects(false, allAffectedCards); + game.getStack().addAllTriggeredAbilitiesToStack(); + while (!game.getStack().isEmpty() && !game.isGameOver()) { + debugPrint("Resolving:" + game.getStack().peekAbility()); + + // Resolve the top effect on the stack. + game.getStack().resolveStack(); + + // Evaluate state based effects as a result of resolving stack. + // Note: Needs to happen after resolve stack rather than at the + // top of the loop to ensure state effects are evaluated after the + // last resolved effect game.getAction().checkStateEffects(false, allAffectedCards); + + // Add any triggers additional triggers as a result of the above. + // Must be below state effects, since legendary rule is evaluated + // as part of state effects and trigger come afterward. (e.g. to + // correctly handle two Dark Depths - one having no counters). game.getStack().addAllTriggeredAbilitiesToStack(); - while (!game.getStack().isEmpty() && !game.isGameOver()) { - debugPrint("Resolving:" + game.getStack().peekAbility()); - // Resolve the top effect on the stack. - game.getStack().resolveStack(); - - // Evaluate state based effects as a result of resolving stack. - // Note: Needs to happen after resolve stack rather than at the - // top of the loop to ensure state effects are evaluated after the - // last resolved effect - game.getAction().checkStateEffects(false, allAffectedCards); - - // Add any triggers additional triggers as a result of the above. - // Must be below state effects, since legendary rule is evaluated - // as part of state effects and trigger come afterward. (e.g. to - // correctly handle two Dark Depths - one having no counters). - game.getStack().addAllTriggeredAbilitiesToStack(); - - // Continue until stack is empty. - } + // Continue until stack is empty. } }, sim); } diff --git a/forge-ai/src/main/java/forge/ai/simulation/GameStateEvaluator.java b/forge-ai/src/main/java/forge/ai/simulation/GameStateEvaluator.java index 2c7aeb76695..de05636ddc8 100644 --- a/forge-ai/src/main/java/forge/ai/simulation/GameStateEvaluator.java +++ b/forge-ai/src/main/java/forge/ai/simulation/GameStateEvaluator.java @@ -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; diff --git a/forge-core/src/main/java/forge/CardStorageReader.java b/forge-core/src/main/java/forge/CardStorageReader.java index 88440d5e5ab..d49fadaa8d5 100644 --- a/forge-core/src/main/java/forge/CardStorageReader.java +++ b/forge-core/src/main/java/forge/CardStorageReader.java @@ -227,15 +227,13 @@ public class CardStorageReader { // Iterate through txt files or zip archive. // Report relevant numbers to progress monitor model. - final Set result = new TreeSet<>(new Comparator() { - @Override - public int compare(final CardRules o1, final CardRules o2) { - if (loadingTokens) { - return String.CASE_INSENSITIVE_ORDER.compare(o1.getNormalizedName(), o2.getNormalizedName()); - } - return String.CASE_INSENSITIVE_ORDER.compare(o1.getName(), o2.getName()); - } - }); + final Set result; + if (loadingTokens) { + result = new TreeSet<>(Comparator.comparing(CardRules::getNormalizedName, String.CASE_INSENSITIVE_ORDER)); + } + 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>() { - @Override - public List call() throws Exception{ - final List res = loadCardsInRangeFromZip(entries, from, till); - cdl.countDown(); - progressObserver.report(maxParts - (int)cdl.getCount(), maxParts); - return res; - } + tasks.add(() -> { + final List 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>() { - @Override - public List call() throws Exception{ - final List res = loadCardsInRange(allFiles, from, till); - cdl.countDown(); - progressObserver.report(maxParts - (int)cdl.getCount(), maxParts); - return res; - } + tasks.add(() -> { + final List res = loadCardsInRange(allFiles, from, till); + cdl.countDown(); + progressObserver.report(maxParts - (int)cdl.getCount(), maxParts); + return res; }); } return tasks; diff --git a/forge-core/src/main/java/forge/card/CardDb.java b/forge-core/src/main/java/forge/card/CardDb.java index 85a354f57f5..17ada0b5f5b 100644 --- a/forge-core/src/main/java/forge/card/CardDb.java +++ b/forge-core/src/main/java/forge/card/CardDb.java @@ -633,20 +633,17 @@ public final class CardDb implements ICardDatabase, IDeckGenPool { cardName = cardNameRequest.cardName; isFoil = isFoil || cardNameRequest.isFoil; - List candidates = getAllCards(cardName, new Predicate() { - @Override - public boolean apply(PaperCard c) { - boolean artIndexFilter = true; - boolean collectorNumberFilter = true; - boolean setFilter = c.getEdition().equalsIgnoreCase(edition.getCode()) || - c.getEdition().equalsIgnoreCase(edition.getCode2()); - if (artIndex > 0) - artIndexFilter = (c.getArtIndex() == artIndex); - if ((collectorNumber != null) && (collectorNumber.length() > 0) - && !(collectorNumber.equals(IPaperCard.NO_COLLECTOR_NUMBER))) - collectorNumberFilter = (c.getCollectorNumber().equals(collectorNumber)); - return setFilter && artIndexFilter && collectorNumberFilter; - } + List candidates = getAllCards(cardName, c -> { + boolean artIndexFilter = true; + boolean collectorNumberFilter = true; + boolean setFilter = c.getEdition().equalsIgnoreCase(edition.getCode()) || + c.getEdition().equalsIgnoreCase(edition.getCode2()); + if (artIndex > 0) + artIndexFilter = (c.getArtIndex() == artIndex); + if ((collectorNumber != null) && (collectorNumber.length() > 0) + && !(collectorNumber.equals(IPaperCard.NO_COLLECTOR_NUMBER))) + collectorNumberFilter = (c.getCollectorNumber().equals(collectorNumber)); + return setFilter && artIndexFilter && collectorNumberFilter; }); if (candidates.isEmpty()) return null; @@ -791,26 +788,18 @@ public final class CardDb implements ICardDatabase, IDeckGenPool { Predicate cardQueryFilter; filter = (filter != null) ? filter : Predicates.alwaysTrue(); if (releaseDate != null) { - cardQueryFilter = new Predicate() { - @Override - public boolean apply(PaperCard c) { - if (c.getArtIndex() != cr.artIndex) - return false; // not interested anyway! - CardEdition ed = editions.get(c.getEdition()); - if (ed == null) return false; - if (releasedBeforeFlag) - return ed.getDate().before(releaseDate); - else - return ed.getDate().after(releaseDate); - } + cardQueryFilter = c -> { + if (c.getArtIndex() != cr.artIndex) + return false; // not interested anyway! + CardEdition ed = editions.get(c.getEdition()); + if (ed == null) return false; + if (releasedBeforeFlag) + return ed.getDate().before(releaseDate); + else + return ed.getDate().after(releaseDate); }; } else // filter candidates based on requested artIndex - cardQueryFilter = new Predicate() { - @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 acceptedEditions = Lists.newArrayList(Iterables.filter(cardEditions, new Predicate() { - @Override - public boolean apply(CardEdition ed) { - return artPref.accept(ed); - } - })); + List 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 getUniqueCardsNoAlt() { - return Maps.filterEntries(this.uniqueCardsByName, new Predicate>() { - @Override - public boolean apply(Entry e) { - if (e == null) - return false; - return e.getKey().equals(e.getValue().getName()); - } + return Maps.filterEntries(this.uniqueCardsByName, e -> { + if (e == null) + return false; + return e.getKey().equals(e.getValue().getName()); }).values(); } @@ -956,60 +937,46 @@ public final class CardDb implements ICardDatabase, IDeckGenPool { } public Collection getAllCardsNoAlt() { - return Multimaps.filterEntries(allCardsByName, new Predicate>() { - @Override - public boolean apply(Entry entry) { - return entry.getKey().equals(entry.getValue().getName()); - } - }).values(); + return Multimaps.filterEntries(allCardsByName, entry -> entry.getKey().equals(entry.getValue().getName())).values(); } public Collection getAllNonPromoCards() { - return Lists.newArrayList(Iterables.filter(getAllCards(), new Predicate() { - @Override - public boolean apply(final PaperCard paperCard) { - CardEdition edition = null; - try { - edition = editions.getEditionByCodeOrThrow(paperCard.getEdition()); - } catch (Exception ex) { - return false; - } - return edition != null && edition.getType() != Type.PROMO; + return Lists.newArrayList(Iterables.filter(getAllCards(), paperCard -> { + CardEdition edition = null; + try { + edition = editions.getEditionByCodeOrThrow(paperCard.getEdition()); + } catch (Exception ex) { + return false; } + return edition != null && edition.getType() != Type.PROMO; })); } public Collection getUniqueCardsNoAltNoOnline() { - return Lists.newArrayList(Iterables.filter(getUniqueCardsNoAlt(), new Predicate() { - @Override - public boolean apply(final PaperCard paperCard) { - CardEdition edition = null; - try { - edition = editions.getEditionByCodeOrThrow(paperCard.getEdition()); - if (edition.getType() == Type.ONLINE||edition.getType() == Type.FUNNY) - return false; - } catch (Exception ex) { + return Lists.newArrayList(Iterables.filter(getUniqueCardsNoAlt(), paperCard -> { + CardEdition edition = null; + try { + edition = editions.getEditionByCodeOrThrow(paperCard.getEdition()); + if (edition.getType() == Type.ONLINE||edition.getType() == Type.FUNNY) return false; - } - return true; + } catch (Exception ex) { + return false; } + return true; })); } public Collection getAllNonPromosNonReprintsNoAlt() { - return Lists.newArrayList(Iterables.filter(getAllCardsNoAlt(), new Predicate() { - @Override - public boolean apply(final PaperCard paperCard) { - CardEdition edition = null; - try { - edition = editions.getEditionByCodeOrThrow(paperCard.getEdition()); - if (edition.getType() == Type.PROMO || edition.getType() == Type.REPRINT || edition.getType()==Type.COLLECTOR_EDITION) - return false; - } catch (Exception ex) { + return Lists.newArrayList(Iterables.filter(getAllCardsNoAlt(), paperCard -> { + CardEdition edition = null; + try { + edition = editions.getEditionByCodeOrThrow(paperCard.getEdition()); + if (edition.getType() == Type.PROMO || edition.getType() == Type.REPRINT || edition.getType()==Type.COLLECTOR_EDITION) return false; - } - return true; + } catch (Exception ex) { + return false; } + return true; })); } @@ -1032,12 +999,7 @@ public final class CardDb implements ICardDatabase, IDeckGenPool { } public List getAllCardsNoAlt(String cardName) { - return Lists.newArrayList(Multimaps.filterEntries(allCardsByName, new Predicate>() { - @Override - public boolean apply(Entry 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))); } /** diff --git a/forge-core/src/main/java/forge/card/CardEdition.java b/forge-core/src/main/java/forge/card/CardEdition.java index 4c4346c62ba..e3b96a48b1c 100644 --- a/forge-core/src/main/java/forge/card/CardEdition.java +++ b/forge-core/src/main/java/forge/card/CardEdition.java @@ -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 { public Map getTokens() { return tokenNormalized; } - public static final Function FN_GET_CODE = new Function() { - @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 { 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 { 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 { @@ -798,12 +785,7 @@ public final class CardEdition implements Comparable { public Iterable getPrereleaseEditions() { List res = Lists.newArrayList(this); - return Iterables.filter(res, new Predicate() { - @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 { return set == null ? "" : set.getCode2(); } - public final Function FN_EDITION_BY_CODE = new Function() { - @Override - public CardEdition apply(String code) { - return Collection.this.get(code); - } - }; - - public final Comparator CARD_EDITION_COMPARATOR = new Comparator() { - @Override - public int compare(PaperCard c1, PaperCard c2) { - return Collection.this.get(c1.getEdition()).compareTo(Collection.this.get(c2.getEdition())); - } - }; + public final Comparator CARD_EDITION_COMPARATOR = Comparator.comparing(c -> Collection.this.get(c.getEdition())); public IItemReader getBoosterGenerator() { return new StorageReaderBase(null) { @@ -913,12 +883,7 @@ public final class CardEdition implements Comparable { CardDb.CardArtPreference artPreference = StaticData.instance().getCardArtPreference(); Iterable editionsWithBasicLands = Iterables.filter( StaticData.instance().getEditions().getOrderedEditions(), - com.google.common.base.Predicates.and(hasBasicLands, new Predicate() { - @Override - public boolean apply(CardEdition edition) { - return artPreference.accept(edition); - } - })); + com.google.common.base.Predicates.and(hasBasicLands, artPreference::accept)); Iterator editionsIterator = editionsWithBasicLands.iterator(); List selectedEditions = new ArrayList(); while (editionsIterator.hasNext()) @@ -954,19 +919,16 @@ public final class CardEdition implements Comparable { } } - public static final Predicate hasBasicLands = new Predicate() { - @Override - public boolean apply(CardEdition ed) { - if (ed == null) { - // Happens for new sets with "???" code - return false; - } - for(String landName : MagicColor.Constant.BASIC_LANDS) { - if (null == StaticData.instance().getCommonCards().getCard(landName, ed.getCode(), 0)) - return false; - } - return true; + public static final Predicate hasBasicLands = ed -> { + if (ed == null) { + // Happens for new sets with "???" code + return false; } + for(String landName : MagicColor.Constant.BASIC_LANDS) { + if (null == StaticData.instance().getCommonCards().getCard(landName, ed.getCode(), 0)) + return false; + } + return true; }; } diff --git a/forge-core/src/main/java/forge/card/CardFace.java b/forge-core/src/main/java/forge/card/CardFace.java index fa552d2907c..41e487afdff 100644 --- a/forge-core/src/main/java/forge/card/CardFace.java +++ b/forge-core/src/main/java/forge/card/CardFace.java @@ -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) { diff --git a/forge-core/src/main/java/forge/card/CardFacePredicates.java b/forge-core/src/main/java/forge/card/CardFacePredicates.java index 75ff7d136c4..f612a8e7088 100644 --- a/forge-core/src/main/java/forge/card/CardFacePredicates.java +++ b/forge-core/src/main/java/forge/card/CardFacePredicates.java @@ -67,12 +67,9 @@ public final class CardFacePredicates { } public static Predicate cmc(final int value) { - return new Predicate() { - @Override - public boolean apply(ICardFace input) { - ManaCost cost = input.getManaCost(); - return cost != null && cost.getCMC() == value; - } + 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 IS_BASIC_LAND = new Predicate() { - @Override - public boolean apply(final ICardFace subject) { - return subject.getType().isBasicLand(); - } - }; + public static final Predicate IS_BASIC_LAND = subject -> subject.getType().isBasicLand(); /** The Constant isNonBasicLand. */ - public static final Predicate IS_NONBASIC_LAND = new Predicate() { - @Override - public boolean apply(final ICardFace subject) { - return subject.getType().isLand() && !subject.getType().isBasicLand(); - } - }; + public static final Predicate IS_NONBASIC_LAND = subject -> subject.getType().isLand() && !subject.getType().isBasicLand(); /** The Constant isCreature. */ public static final Predicate IS_CREATURE = CardFacePredicates diff --git a/forge-core/src/main/java/forge/card/CardRarity.java b/forge-core/src/main/java/forge/card/CardRarity.java index b6f1f898067..cad70efa046 100644 --- a/forge-core/src/main/java/forge/card/CardRarity.java +++ b/forge-core/src/main/java/forge/card/CardRarity.java @@ -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 FN_GET_LONG_NAME = new Function() { - @Override - public String apply(final CardRarity rarity) { - return rarity.longName; - } - }; } diff --git a/forge-core/src/main/java/forge/card/CardRulesPredicates.java b/forge-core/src/main/java/forge/card/CardRulesPredicates.java index 96eb21e9a4c..af5d1297cc5 100644 --- a/forge-core/src/main/java/forge/card/CardRulesPredicates.java +++ b/forge-core/src/main/java/forge/card/CardRulesPredicates.java @@ -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 IS_KEPT_IN_AI_DECKS = new Predicate() { - @Override - public boolean apply(final CardRules card) { - return !card.getAiHints().getRemAIDecks(); - } - }; + public static final Predicate IS_KEPT_IN_AI_DECKS = card -> !card.getAiHints().getRemAIDecks(); /** The Constant isKeptInAiLimitedDecks. */ - public static final Predicate IS_KEPT_IN_AI_LIMITED_DECKS = new Predicate() { - @Override - public boolean apply(final CardRules card) { - return !card.getAiHints().getRemAIDecks() && !card.getAiHints().getRemNonCommanderDecks(); - } - }; + public static final Predicate IS_KEPT_IN_AI_LIMITED_DECKS = card -> !card.getAiHints().getRemAIDecks() && !card.getAiHints().getRemNonCommanderDecks(); /** The Constant isKeptInRandomDecks. */ - public static final Predicate IS_KEPT_IN_RANDOM_DECKS = new Predicate() { - @Override - public boolean apply(final CardRules card) { - return !card.getAiHints().getRemRandomDecks(); - } - }; + public static final Predicate 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 hasCreatureType(final String... creatureTypes) { - return new Predicate() { - @Override - public boolean apply(final CardRules card) { - if (!card.getType().isCreature()) { return false; } - - final Set set = card.getType().getCreatureTypes(); - for (final String creatureType : creatureTypes) { - if (set.contains(creatureType)) { - return true; - } - } - return false; - } + return card -> { + if (!card.getType().isCreature()) { 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 hasKeyword(final String keyword) { - return new Predicate() { - @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 deckHas(final DeckHints.Type type, final String has) { - return new Predicate() { - @Override - public boolean apply(final CardRules card) { - DeckHints deckHas = card.getAiHints().getDeckHas(); - return deckHas != null && deckHas.isValid() && deckHas.contains(type, has); - } + return card -> { + DeckHints deckHas = card.getAiHints().getDeckHas(); + return deckHas != null && deckHas.isValid() && deckHas.contains(type, has); }; } public static Predicate deckHasExactly(final DeckHints.Type type, final String has[]) { - return new Predicate() { - @Override - public boolean apply(final CardRules card) { - DeckHints deckHas = card.getAiHints().getDeckHas(); - return deckHas != null && deckHas.isValid() && deckHas.is(type, has); - } + 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 hasColorIdentity(final int colormask) { - return new Predicate() { - @Override - public boolean apply(final CardRules rules) { - return rules.getColorIdentity().hasNoColorsExcept(colormask); - } - }; + return rules -> rules.getColorIdentity().hasNoColorsExcept(colormask); } public static Predicate canBePartnerCommanderWith(final CardRules commander) { @@ -597,54 +554,19 @@ public final class CardRulesPredicates { public static final Predicate IS_LAND = CardRulesPredicates.coreType(true, CardType.CoreType.Land); /** The Constant isBasicLand. */ - public static final Predicate IS_BASIC_LAND = new Predicate() { - @Override - public boolean apply(final CardRules subject) { - return subject.getType().isBasicLand(); - } - }; + public static final Predicate IS_BASIC_LAND = subject -> subject.getType().isBasicLand(); /** The Constant isBasicLandNotWastes. */ - public static final Predicate IS_BASIC_LAND_NOT_WASTES = new Predicate() { - @Override - public boolean apply(final CardRules subject) { - return !subject.getName().equals("Wastes")&&subject.getType().isBasicLand(); - } - }; + public static final Predicate IS_BASIC_LAND_NOT_WASTES = subject -> !subject.getName().equals("Wastes")&&subject.getType().isBasicLand(); /** The Constant isNonBasicLand. */ - public static final Predicate IS_NONBASIC_LAND = new Predicate() { - @Override - public boolean apply(final CardRules subject) { - return subject.getType().isLand() && !subject.getType().isBasicLand(); - } - }; + public static final Predicate IS_NONBASIC_LAND = subject -> subject.getType().isLand() && !subject.getType().isBasicLand(); - public static final Predicate CAN_BE_COMMANDER = new Predicate() { - @Override - public boolean apply(final CardRules subject) { - return subject.canBeCommander(); - } - }; - public static final Predicate CAN_BE_PARTNER_COMMANDER = new Predicate() { - @Override - public boolean apply(final CardRules subject) { - return subject.canBePartnerCommander(); - } - }; + public static final Predicate CAN_BE_COMMANDER = CardRules::canBeCommander; + public static final Predicate CAN_BE_PARTNER_COMMANDER = CardRules::canBePartnerCommander; - public static final Predicate CAN_BE_OATHBREAKER = new Predicate() { - @Override - public boolean apply(final CardRules subject) { - return subject.canBeOathbreaker(); - } - }; - public static final Predicate CAN_BE_SIGNATURE_SPELL = new Predicate() { - @Override - public boolean apply(final CardRules subject) { - return subject.canBeSignatureSpell(); - } - }; + public static final Predicate CAN_BE_OATHBREAKER = CardRules::canBeOathbreaker; + public static final Predicate CAN_BE_SIGNATURE_SPELL = CardRules::canBeSignatureSpell; public static final Predicate IS_PLANESWALKER = CardRulesPredicates.coreType(true, CardType.CoreType.Planeswalker); public static final Predicate IS_BATTLE = CardRulesPredicates.coreType(true, CardType.CoreType.Battle); diff --git a/forge-core/src/main/java/forge/card/CardType.java b/forge-core/src/main/java/forge/card/CardType.java index 77ad30e76af..63e2bb8d4b6 100644 --- a/forge-core/src/main/java/forge/card/CardType.java +++ b/forge-core/src/main/java/forge/card/CardType.java @@ -493,13 +493,13 @@ public final class CardType implements Comparable, 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, CardTypeView { "Warlock"); } public static class Predicates { - public static Predicate IS_LAND_TYPE = new Predicate() { - @Override - public boolean apply(String input) { - return CardType.isALandType(input); - } - }; - public static Predicate IS_BASIC_LAND_TYPE = new Predicate() { - @Override - public boolean apply(String input) { - return CardType.isABasicLandType(input); - } - }; - public static Predicate IS_ARTIFACT_TYPE = new Predicate() { - @Override - public boolean apply(String input) { - return CardType.isAnArtifactType(input); - } - }; + public static Predicate IS_LAND_TYPE = CardType::isALandType; + public static Predicate IS_BASIC_LAND_TYPE = CardType::isABasicLandType; + public static Predicate IS_ARTIFACT_TYPE = CardType::isAnArtifactType; - public static Predicate IS_CREATURE_TYPE = new Predicate() { - @Override - public boolean apply(String input) { - return CardType.isACreatureType(input); - } - }; + public static Predicate IS_CREATURE_TYPE = CardType::isACreatureType; - public static Predicate IS_ENCHANTMENT_TYPE = new Predicate() { - @Override - public boolean apply(String input) { - return CardType.isAnEnchantmentType(input); - } - }; + public static Predicate IS_ENCHANTMENT_TYPE = CardType::isAnEnchantmentType; - public static Predicate IS_SPELL_TYPE = new Predicate() { - @Override - public boolean apply(String input) { - return CardType.isASpellType(input); - } - }; + public static Predicate IS_SPELL_TYPE = CardType::isASpellType; - public static Predicate IS_WALKER_TYPE = new Predicate() { - @Override - public boolean apply(String input) { - return CardType.isAPlaneswalkerType(input); - } - }; - public static Predicate IS_DUNGEON_TYPE = new Predicate() { - @Override - public boolean apply(String input) { - return CardType.isADungeonType(input); - } - }; - public static Predicate IS_BATTLE_TYPE = new Predicate() { - @Override - public boolean apply(String input) { - return CardType.isABattleType(input); - } - }; + public static Predicate IS_WALKER_TYPE = CardType::isAPlaneswalkerType; + public static Predicate IS_DUNGEON_TYPE = CardType::isADungeonType; + public static Predicate IS_BATTLE_TYPE = CardType::isABattleType; - public static Predicate IS_PLANAR_TYPE = new Predicate() { - @Override - public boolean apply(String input) { - return CardType.isAPlanarType(input); - } - }; + public static Predicate IS_PLANAR_TYPE = CardType::isAPlanarType; } ///////// Utility methods @@ -1036,7 +986,7 @@ public final class CardType implements Comparable, 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, 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); } diff --git a/forge-core/src/main/java/forge/card/DeckHints.java b/forge-core/src/main/java/forge/card/DeckHints.java index c9140947f1f..ef38a23da89 100644 --- a/forge-core/src/main/java/forge/card/DeckHints.java +++ b/forge-core/src/main/java/forge/card/DeckHints.java @@ -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,19 +219,16 @@ public class DeckHints { } else { tdb = null; } - return new Predicate() { - @Override - public boolean apply(final CardRules card) { - if (predicate.apply(card)) { + return card -> { + if (predicate.apply(card)) { + return true; + } + for (String tok : card.getTokens()) { + if (tdb != null && tdb.containsRule(tok) && predicate.apply(tdb.getToken(tok).getRules())) { return true; } - for (String tok : card.getTokens()) { - if (tdb != null && tdb.containsRule(tok) && predicate.apply(tdb.getToken(tok).getRules())) { - return true; - } - } - return false; } + return false; }; } diff --git a/forge-core/src/main/java/forge/card/MagicColor.java b/forge-core/src/main/java/forge/card/MagicColor.java index 40f91ea74e1..a3af1906781 100644 --- a/forge-core/src/main/java/forge/card/MagicColor.java +++ b/forge-core/src/main/java/forge/card/MagicColor.java @@ -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 FN_GET_SYMBOL = new Function() { - @Override - public String apply(final Color color) { - return color.symbol; - } - }; } diff --git a/forge-core/src/main/java/forge/card/PrintSheet.java b/forge-core/src/main/java/forge/card/PrintSheet.java index e7cc982f3b2..bf3761bc40f 100644 --- a/forge-core/src/main/java/forge/card/PrintSheet.java +++ b/forge-core/src/main/java/forge/card/PrintSheet.java @@ -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 FN_GET_KEY = new Function() { - @Override public final String apply(PrintSheet sheet) { return sheet.name; } - }; public static final IStorage initializePrintSheets(File sheetsFile, CardEdition.Collection editions) { IStorage sheets = new StorageExtendable<>("Special print runs", new PrintSheet.Reader(sheetsFile)); @@ -156,7 +151,7 @@ public class PrintSheet { public static class Reader extends StorageReaderFileSections { public Reader(File file) { - super(file, PrintSheet.FN_GET_KEY); + super(file, PrintSheet::getName); } @Override diff --git a/forge-core/src/main/java/forge/deck/CardPool.java b/forge-core/src/main/java/forge/deck/CardPool.java index 557c6d3335e..0846ae7ed49 100644 --- a/forge-core/src/main/java/forge/deck/CardPool.java +++ b/forge-core/src/main/java/forge/deck/CardPool.java @@ -318,12 +318,7 @@ public class CardPool extends ItemPool { ListMultimap editionsStatistics = this.getCardEditionsGroupedByNumberOfCards(false); List frequencyValues = new ArrayList<>(editionsStatistics.keySet()); // Sort in descending order - frequencyValues.sort(new Comparator() { - @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 { // Now Get editions corresponding to pivot frequency List pivotCandidates = new ArrayList<>(editionsStatistics.get(pivotFrequency)); // Now Sort candidates chronologically - pivotCandidates.sort(new Comparator() { - @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. diff --git a/forge-core/src/main/java/forge/deck/Deck.java b/forge-core/src/main/java/forge/deck/Deck.java index d8058eeb8cc..f15b0f65746 100644 --- a/forge-core/src/main/java/forge/deck/Deck.java +++ b/forge-core/src/main/java/forge/deck/Deck.java @@ -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 1) { //sort by type so signature spell comes after oathbreaker - Collections.sort(result, new Comparator() { - @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() { - @Override - public boolean apply(PaperCard input) { - return deckSection.validate(input); - } - }); + CardPool filteredPool = pool.getFilteredPoolWithCardsCount(deckSection::validate); // Add all the cards from ValidPool anyway! List whiteList = validatedSections.getOrDefault(s.getKey(), null); if (whiteList == null) @@ -326,12 +314,7 @@ public class Deck extends DeckBase implements Iterable() { - @Override - public boolean apply(PaperCard input) { - return !(deckSection.validate(input)); - } - }); + CardPool blackList = pool.getFilteredPoolWithCardsCount(input -> !(deckSection.validate(input))); for (Entry entry : blackList) { DeckSection cardSection = DeckSection.matchingSection(entry.getKey()); @@ -513,13 +496,6 @@ public class Deck extends DeckBase implements Iterable FN_NAME_SELECTOR = new Function() { - @Override - public String apply(Deck arg1) { - return arg1.getName(); - } - }; - /* (non-Javadoc) * @see java.lang.Iterable#iterator() */ diff --git a/forge-core/src/main/java/forge/deck/DeckFormat.java b/forge-core/src/main/java/forge/deck/DeckFormat.java index 57741678413..7abbfefc159 100644 --- a/forge-core/src/main/java/forge/deck/DeckFormat.java +++ b/forge-core/src/main/java/forge/deck/DeckFormat.java @@ -59,25 +59,16 @@ public enum DeckFormat { return null; } }, - Commander ( Range.is(99), Range.between(0, 10), 1, null, new Predicate() { - @Override - public boolean apply(PaperCard card) { - return StaticData.instance().getCommanderPredicate().apply(card); - } - }), - Oathbreaker ( Range.is(58), Range.between(0, 10), 1, null, new Predicate() { - @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() { - @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() { private final Set 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,59 +492,41 @@ public enum DeckFormat { } public Predicate isLegalDeckPredicate() { - return new Predicate() { - @Override - public boolean apply(Deck deck) { - return getDeckConformanceProblem(deck) == null; - } - }; + return deck -> getDeckConformanceProblem(deck) == null; } public Predicate hasLegalCardsPredicate(boolean enforceDeckLegality) { - return new Predicate() { - @Override - public boolean apply(Deck deck) { - if (!enforceDeckLegality) - return true; - if (cardPoolFilter != null) { - for (final Entry cp : deck.getAllCardsInASinglePool()) { - if (!cardPoolFilter.apply(cp.getKey().getRules())) { - return false; - } - } - } - if (paperCardPoolFilter != null) { - for (final Entry cp : deck.getAllCardsInASinglePool()) { - if (!paperCardPoolFilter.apply(cp.getKey())) { - System.err.println( - "Excluding deck: '" + deck.toString() + - "' Reason: '" + cp.getKey() + "' is not legal." - ); - return false; - } - } - } + return deck -> { + if (!enforceDeckLegality) return true; + if (cardPoolFilter != null) { + for (final Entry cp : deck.getAllCardsInASinglePool()) { + if (!cardPoolFilter.apply(cp.getKey().getRules())) { + return false; + } + } } + if (paperCardPoolFilter != null) { + for (final Entry cp : deck.getAllCardsInASinglePool()) { + if (!paperCardPoolFilter.apply(cp.getKey())) { + System.err.println( + "Excluding deck: '" + deck.toString() + + "' Reason: '" + cp.getKey() + "' is not legal." + ); + return false; + } + } + } + return true; }; } public Predicate isLegalCardPredicate() { - return new Predicate() { - @Override - public boolean apply(PaperCard card) { - return isLegalCard(card); - } - }; + return this::isLegalCard; } public Predicate isLegalCommanderPredicate() { - return new Predicate() { - @Override - public boolean apply(PaperCard card) { - return isLegalCommander(card.getRules()); - } - }; + return card -> isLegalCommander(card.getRules()); } public Predicate isLegalCardForCommanderPredicate(List 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); } } diff --git a/forge-core/src/main/java/forge/deck/DeckGroup.java b/forge-core/src/main/java/forge/deck/DeckGroup.java index 995fa2f1f30..ec79dd50abc 100644 --- a/forge-core/src/main/java/forge/deck/DeckGroup.java +++ b/forge-core/src/main/java/forge/deck/DeckGroup.java @@ -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 FN_NAME_SELECTOR = new Function() { - @Override - public String apply(DeckGroup arg1) { - return arg1.getName(); - } - }; - - - public static final Function FN_HUMAN_DECK = new Function() { - @Override - public Deck apply(DeckGroup arg1) { - return arg1.humanDeck; - } - }; - @Override public boolean isEmpty() { return humanDeck == null || humanDeck.isEmpty(); diff --git a/forge-core/src/main/java/forge/deck/DeckSection.java b/forge-core/src/main/java/forge/deck/DeckSection.java index ab02f3a5339..a136cb5346f 100644 --- a/forge-core/src/main/java/forge/deck/DeckSection.java +++ b/forge-core/src/main/java/forge/deck/DeckSection.java @@ -66,63 +66,42 @@ public enum DeckSection { } private static class Validators { - static final Function DECK_AND_SIDE_VALIDATOR = new Function() { - @Override - public Boolean apply(PaperCard 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 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 COMMANDER_VALIDATOR = new Function() { - @Override - public Boolean apply(PaperCard card) { - CardType t = card.getRules().getType(); - return card.getRules().canBeCommander() || t.isPlaneswalker() || card.getRules().canBeOathbreaker() || card.getRules().canBeSignatureSpell(); - } + static final Function COMMANDER_VALIDATOR = card -> { + CardType t = card.getRules().getType(); + return card.getRules().canBeCommander() || t.isPlaneswalker() || card.getRules().canBeOathbreaker() || card.getRules().canBeSignatureSpell(); }; - static final Function PLANES_VALIDATOR = new Function() { - @Override - public Boolean apply(PaperCard card) { - CardType t = card.getRules().getType(); - return t.isPlane() || t.isPhenomenon(); - } + static final Function PLANES_VALIDATOR = card -> { + CardType t = card.getRules().getType(); + return t.isPlane() || t.isPhenomenon(); }; - static final Function DUNGEON_VALIDATOR = new Function() { - @Override - public Boolean apply(PaperCard card) { - CardType t = card.getRules().getType(); - return t.isDungeon(); - } + static final Function DUNGEON_VALIDATOR = card -> { + CardType t = card.getRules().getType(); + return t.isDungeon(); }; - static final Function SCHEME_VALIDATOR = new Function() { - @Override - public Boolean apply(PaperCard card) { - CardType t = card.getRules().getType(); - return t.isScheme(); - } + static final Function SCHEME_VALIDATOR = card -> { + CardType t = card.getRules().getType(); + return t.isScheme(); }; - static final Function CONSPIRACY_VALIDATOR = new Function() { - @Override - public Boolean apply(PaperCard card) { - CardType t = card.getRules().getType(); - return t.isConspiracy(); - } + static final Function CONSPIRACY_VALIDATOR = card -> { + CardType t = card.getRules().getType(); + return t.isConspiracy(); }; - static final Function AVATAR_VALIDATOR = new Function() { - @Override - public Boolean apply(PaperCard card) { - CardType t = card.getRules().getType(); - return t.isVanguard(); - } + static final Function AVATAR_VALIDATOR = card -> { + CardType t = card.getRules().getType(); + return t.isVanguard(); }; static final Function ATTRACTION_VALIDATOR = card -> { diff --git a/forge-core/src/main/java/forge/deck/generation/DeckGeneratorBase.java b/forge-core/src/main/java/forge/deck/generation/DeckGeneratorBase.java index ff6108b499b..38da378588e 100644 --- a/forge-core/src/main/java/forge/deck/generation/DeckGeneratorBase.java +++ b/forge-core/src/main/java/forge/deck/generation/DeckGeneratorBase.java @@ -92,12 +92,12 @@ public abstract class DeckGeneratorBase { final Iterable cards = selectCardsOfMatchingColorForPlayer(forAi); // build subsets based on type - final Iterable creatures = Iterables.filter(cards, Predicates.compose(CardRulesPredicates.Presets.IS_CREATURE, PaperCard.FN_GET_RULES)); + final Iterable 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 preSpells = Predicates.compose(CardRulesPredicates.Presets.IS_NON_CREATURE_SPELL, PaperCard.FN_GET_RULES); + Predicate preSpells = Predicates.compose(CardRulesPredicates.Presets.IS_NON_CREATURE_SPELL, PaperCard::getRules); final Iterable 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 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 exceptBasicLand = Predicates.not(Predicates.compose(CardRulesPredicates.Presets.IS_BASIC_LAND, PaperCard.FN_GET_RULES)); + Predicate exceptBasicLand = Predicates.not(Predicates.compose(CardRulesPredicates.Presets.IS_BASIC_LAND, PaperCard::getRules)); for (int i = 0; i < 3 && actualSize > targetSize; i++) { Iterable matchingCards = Iterables.filter(tDeck.toFlatList(), exceptBasicLand); @@ -266,7 +266,7 @@ public abstract class DeckGeneratorBase { float requestedOverTotal = (float)cnt / totalWeight; for (ImmutablePair pair : cmcLevels) { - Iterable matchingCards = Iterables.filter(source, Predicates.compose(pair.getLeft(), PaperCard.FN_GET_RULES)); + Iterable 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 canPlay = forAi ? AI_CAN_PLAY : CardRulesPredicates.IS_KEPT_IN_RANDOM_DECKS; Predicate hasColor = new MatchColorIdentity(colors); - Predicate canUseInFormat = new Predicate() { - @Override - public boolean apply(CardRules 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(); - } + Predicate 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 countLands(ItemPool outList) { @@ -337,12 +334,9 @@ public abstract class DeckGeneratorBase { public static final Predicate AI_CAN_PLAY = Predicates.and(CardRulesPredicates.IS_KEPT_IN_AI_DECKS, CardRulesPredicates.IS_KEPT_IN_RANDOM_DECKS); - public static final Predicate COLORLESS_CARDS = new Predicate() { - @Override - public boolean apply(CardRules c) { - ManaCost mc = c.getManaCost(); - return c.getColorIdentity().isColorless() && !mc.isNoCost(); - } + public static final Predicate COLORLESS_CARDS = c -> { + ManaCost mc = c.getManaCost(); + return c.getColorIdentity().isColorless() && !mc.isNoCost(); }; public static class MatchColorIdentity implements Predicate { @@ -401,7 +395,7 @@ public abstract class DeckGeneratorBase { Predicate dualLandFilter = CardRulesPredicates.coreType(true, CardType.CoreType.Land); Predicate exceptBasicLand = Predicates.not(CardRulesPredicates.Presets.IS_BASIC_LAND); - Iterable landCards = pool.getAllCards(Predicates.compose(Predicates.and(dualLandFilter, exceptBasicLand, canPlay), PaperCard.FN_GET_RULES)); + Iterable landCards = pool.getAllCards(Predicates.compose(Predicates.and(dualLandFilter, exceptBasicLand, canPlay), PaperCard::getRules)); Iterable dualLandPatterns = Arrays.asList("Add \\{([WUBRG])\\} or \\{([WUBRG])\\}", "Add \\{([WUBRG])\\}, \\{([WUBRG])\\}, or \\{([WUBRG])\\}", "Add \\{([WUBRG])\\}\\{([WUBRG])\\}", diff --git a/forge-core/src/main/java/forge/deck/io/DeckGroupSerializer.java b/forge-core/src/main/java/forge/deck/io/DeckGroupSerializer.java index 2ab5b8b1f78..dc5019c3a39 100644 --- a/forge-core/src/main/java/forge/deck/io/DeckGroupSerializer.java +++ b/forge-core/src/main/java/forge/deck/io/DeckGroupSerializer.java @@ -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 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 implemen */ @Override protected FilenameFilter getFileFilter() { - return new FilenameFilter() { - - @Override - public boolean accept(final File dir, final String 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(); - } + 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(); }; } diff --git a/forge-core/src/main/java/forge/deck/io/DeckStorage.java b/forge-core/src/main/java/forge/deck/io/DeckStorage.java index 7cc4a229033..9f9bc30342f 100644 --- a/forge-core/src/main/java/forge/deck/io/DeckStorage.java +++ b/forge-core/src/main/java/forge/deck/io/DeckStorage.java @@ -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 implements IItemSeria private final boolean moveWronglyNamedDecks; /** Constant DCKFileFilter. */ - 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; } diff --git a/forge-core/src/main/java/forge/item/BoosterBox.java b/forge-core/src/main/java/forge/item/BoosterBox.java index e03f58a0656..54cd2f480c0 100644 --- a/forge-core/src/main/java/forge/item/BoosterBox.java +++ b/forge-core/src/main/java/forge/item/BoosterBox.java @@ -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 FN_FROM_SET = new Function() { - @Override - public BoosterBox apply(final CardEdition arg1) { - if (arg1.getBoosterBoxCount() <= 0) { - return null; - } - BoosterBox.Template d = new Template(arg1); - if (d == null) { return null; } - return new BoosterBox(arg1.getName(), d, d.cntBoosters); + + public static BoosterBox fromSet(CardEdition edition) { + if (edition.getBoosterBoxCount() <= 0) { + return null; } - }; + BoosterBox.Template d = new Template(edition); + return new BoosterBox(edition.getName(), d, d.cntBoosters); + } private final BoosterBox.Template fpData; diff --git a/forge-core/src/main/java/forge/item/BoosterPack.java b/forge-core/src/main/java/forge/item/BoosterPack.java index f505d7a3c42..33d5245cdbb 100644 --- a/forge-core/src/main/java/forge/item/BoosterPack.java +++ b/forge-core/src/main/java/forge/item/BoosterPack.java @@ -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,28 +32,22 @@ public class BoosterPack extends SealedProduct { private final int artIndex; private final int hash; - public static final Function FN_FROM_SET = new Function() { - @Override - public BoosterPack apply(final 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 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 FN_FROM_COLOR = new Function() { - @Override - public BoosterPack apply(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), - Pair.of(BoosterSlots.RARE_MYTHIC + ":color(\"" + color + "\"):!" + BoosterSlots.LAND, 1), - Pair.of(BoosterSlots.LAND + ":color(\"" + color + "\")", 1)) - )); - } - }; + 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), + Pair.of(BoosterSlots.RARE_MYTHIC + ":color(\"" + color + "\"):!" + BoosterSlots.LAND, 1), + Pair.of(BoosterSlots.LAND + ":color(\"" + color + "\")", 1)) + )); + } public BoosterPack(final String name0, final Template boosterData) { super(name0, boosterData); diff --git a/forge-core/src/main/java/forge/item/FatPack.java b/forge-core/src/main/java/forge/item/FatPack.java index 90915c4a133..cbe8dd31fce 100644 --- a/forge-core/src/main/java/forge/item/FatPack.java +++ b/forge-core/src/main/java/forge/item/FatPack.java @@ -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 FN_FROM_SET = new Function() { - @Override - public FatPack apply(final CardEdition edition) { - int boosters = edition.getFatPackCount(); - if (boosters <= 0) { return null; } + 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; } - return new FatPack(edition.getName(), d, d.cntBoosters); - } - }; + FatPack.Template d = new Template(edition); + if (null == StaticData.instance().getBoosters().get(d.getEdition())) { return null; } + return new FatPack(edition.getName(), d, d.cntBoosters); + } private final FatPack.Template fpData; diff --git a/forge-core/src/main/java/forge/item/IPaperCard.java b/forge-core/src/main/java/forge/item/IPaperCard.java index e3789c5f444..5ed0d681219 100644 --- a/forge-core/src/main/java/forge/item/IPaperCard.java +++ b/forge-core/src/main/java/forge/item/IPaperCard.java @@ -225,19 +225,8 @@ public interface IPaperCard extends InventoryItem, Serializable { public static final Predicate IS_WHITE = Predicates.color(true, false, MagicColor.WHITE); public static final Predicate IS_COLORLESS = Predicates.color(true, true, MagicColor.COLORLESS); - public static final Predicate IS_UNREBALANCED = new Predicate() { - @Override - public boolean apply(PaperCard input) { - return input.isUnRebalanced(); - } - }; - public static final Predicate IS_REBALANCED = new Predicate() { - - @Override - public boolean apply(PaperCard input) { - return input.isRebalanced(); - } - }; + public static final Predicate IS_UNREBALANCED = PaperCard::isUnRebalanced; + public static final Predicate IS_REBALANCED = PaperCard::isRebalanced; } } diff --git a/forge-core/src/main/java/forge/item/ItemPredicate.java b/forge-core/src/main/java/forge/item/ItemPredicate.java index d6365e59070..69fc7b045ac 100644 --- a/forge-core/src/main/java/forge/item/ItemPredicate.java +++ b/forge-core/src/main/java/forge/item/ItemPredicate.java @@ -19,26 +19,14 @@ public abstract class ItemPredicate { * * @return the predicate */ - public static final Predicate IsTournamentPack = new Predicate() { - - @Override - public boolean apply(final InventoryItem card) { - return card instanceof TournamentPack && !((TournamentPack) card).isStarterDeck(); - } - }; + public static final Predicate IsTournamentPack = card -> card instanceof TournamentPack && !((TournamentPack) card).isStarterDeck(); /** * Checks that the inventory item is a Starter Deck. * * @return the predicate */ - public static final Predicate IsStarterDeck = new Predicate() { - - @Override - public boolean apply(final InventoryItem card) { - return card instanceof TournamentPack && ((TournamentPack) card).isStarterDeck(); - } - }; + public static final Predicate IsStarterDeck = card -> card instanceof TournamentPack && ((TournamentPack) card).isStarterDeck(); /** * Checks that the inventory item is a Prebuilt Deck. diff --git a/forge-core/src/main/java/forge/item/PaperCard.java b/forge-core/src/main/java/forge/item/PaperCard.java index 8249607822a..64107935513 100644 --- a/forge-core/src/main/java/forge/item/PaperCard.java +++ b/forge-core/src/main/java/forge/item/PaperCard.java @@ -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, InventoryItemFromSet, return hasImage; } - /** - * Lambda to get rules for selects from list of printed cards. - */ - public static final Function FN_GET_RULES = new Function() { - @Override - public CardRules apply(final PaperCard from) { - return from.rules; - } - }; - public static final Function FN_GET_NAME = new Function() { - @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); diff --git a/forge-core/src/main/java/forge/item/PreconDeck.java b/forge-core/src/main/java/forge/item/PreconDeck.java index 074d7eb3bbd..157272c84da 100644 --- a/forge-core/src/main/java/forge/item/PreconDeck.java +++ b/forge-core/src/main/java/forge/item/PreconDeck.java @@ -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 FN_NAME_SELECTOR = new Function() { - @Override - public String apply(PreconDeck arg1) { - return arg1.getName(); - } - }; - public static class Reader extends StorageReaderFolder { public Reader(final File deckDir0) { - super(deckDir0, PreconDeck.FN_NAME_SELECTOR); + super(deckDir0, PreconDeck::getName); } @Override @@ -123,13 +114,6 @@ public class PreconDeck implements InventoryItemFromSet { return DeckStorage.DCK_FILE_FILTER; } } - - public static final Function FN_GET_DECK = new Function() { - @Override - public Deck apply(PreconDeck arg1) { - return arg1.getDeck(); - } - }; @Override public String getImageKey(boolean altState) { diff --git a/forge-core/src/main/java/forge/item/SealedProduct.java b/forge-core/src/main/java/forge/item/SealedProduct.java index 50c0cb55dfd..0070f9ca1e1 100644 --- a/forge-core/src/main/java/forge/item/SealedProduct.java +++ b/forge-core/src/main/java/forge/item/SealedProduct.java @@ -124,7 +124,7 @@ public abstract class SealedProduct implements InventoryItemFromSet { protected List getRandomBasicLands(final String setCode, final int count) { Predicate cardsRule = Predicates.and( IPaperCard.Predicates.printedInSet(setCode), - Predicates.compose(CardRulesPredicates.Presets.IS_BASIC_LAND, PaperCard.FN_GET_RULES)); + Predicates.compose(CardRulesPredicates.Presets.IS_BASIC_LAND, PaperCard::getRules)); return Aggregates.random(Iterables.filter(StaticData.instance().getCommonCards().getAllCards(), cardsRule), count); } @@ -144,6 +144,10 @@ public abstract class SealedProduct implements InventoryItemFromSet { return slots; } + public final String getName() { + return name; + } + public boolean hasSlot(String s) { for (Pair slot : getSlots()) { @@ -182,13 +186,6 @@ public abstract class SealedProduct implements InventoryItemFromSet { return sum; } - public static final Function FN_GET_NAME = new Function() { - @Override - public String apply(Template arg1) { - return arg1.name; - } - }; - @Override public String toString() { StringBuilder s = new StringBuilder(); @@ -229,7 +226,7 @@ public abstract class SealedProduct implements InventoryItemFromSet { public final static class Reader extends StorageReaderFile