From 3b0a3e665871e011dea9ec3611924663bd2443d5 Mon Sep 17 00:00:00 2001 From: Maxmtg Date: Sat, 16 Mar 2013 20:41:02 +0000 Subject: [PATCH] Code that chooses cards to be discarded moved to PlayerController and ComputerUtil --- src/main/java/forge/CardLists.java | 3 + .../card/ability/effects/DiscardEffect.java | 150 ++---------------- .../cardfactory/CardFactorySorceries.java | 6 +- src/main/java/forge/game/ai/AiController.java | 35 ++-- src/main/java/forge/game/ai/ComputerUtil.java | 74 +++++++-- src/main/java/forge/game/player/AIPlayer.java | 5 +- .../forge/game/player/PlayerController.java | 3 + .../forge/game/player/PlayerControllerAi.java | 12 ++ .../game/player/PlayerControllerHuman.java | 8 + 9 files changed, 121 insertions(+), 175 deletions(-) diff --git a/src/main/java/forge/CardLists.java b/src/main/java/forge/CardLists.java index 44363d2e8c6..4d8f445fba9 100644 --- a/src/main/java/forge/CardLists.java +++ b/src/main/java/forge/CardLists.java @@ -24,6 +24,7 @@ import java.util.List; import com.google.common.base.Predicate; import com.google.common.base.Predicates; +import com.google.common.collect.ImmutableList; import com.google.common.collect.Iterables; import com.google.common.collect.Lists; @@ -89,6 +90,8 @@ public class CardLists { return aLen - bLen; } }; + + public static final List emptyList = ImmutableList.of(); /** *

diff --git a/src/main/java/forge/card/ability/effects/DiscardEffect.java b/src/main/java/forge/card/ability/effects/DiscardEffect.java index 27aef564e8f..d15ab566e7f 100644 --- a/src/main/java/forge/card/ability/effects/DiscardEffect.java +++ b/src/main/java/forge/card/ability/effects/DiscardEffect.java @@ -1,26 +1,18 @@ package forge.card.ability.effects; import java.util.ArrayList; -import java.util.Collections; import java.util.List; -import org.apache.commons.lang.ArrayUtils; import org.apache.commons.lang.StringUtils; -import com.google.common.base.Predicate; - import forge.Card; import forge.CardLists; import forge.card.ability.AbilityUtils; import forge.card.cardfactory.CardFactoryUtil; import forge.card.spellability.SpellAbility; import forge.card.spellability.Target; -import forge.game.ai.ComputerUtilCard; -import forge.game.player.AIPlayer; import forge.game.player.Player; import forge.game.zone.ZoneType; -import forge.gui.GuiChoose; -import forge.util.Aggregates; public class DiscardEffect extends RevealEffectBase { @Override @@ -87,44 +79,6 @@ public class DiscardEffect extends RevealEffectBase { return sb.toString(); } // discardStackDescription() - /** - * TODO: Write javadoc for this method. - * @param sa - * @param opponentHand - * @param list - */ - private Card chooseCardToDiscardFromOpponent(SpellAbility sa, List opponentHand) { - List goodChoices = CardLists.filter(opponentHand, new Predicate() { - @Override - public boolean apply(final Card c) { - if (!c.getSVar("DiscardMeByOpp").equals("") || !c.getSVar("DiscardMe").equals("")) { - return false; - } - return true; - } - }); - if (goodChoices.isEmpty()) { - goodChoices = opponentHand; - } - final List dChoices = new ArrayList(); - if (sa.hasParam("DiscardValid")) { - final String validString = sa.getParam("DiscardValid"); - if (validString.contains("Creature") && !validString.contains("nonCreature")) { - final Card c = ComputerUtilCard.getBestCreatureAI(goodChoices); - if (c != null) { - dChoices.add(ComputerUtilCard.getBestCreatureAI(goodChoices)); - } - } - } - - Collections.sort(goodChoices, CardLists.TextLenComparator); - - CardLists.sortByCmcDesc(goodChoices); - dChoices.add(goodChoices.get(0)); - - return Aggregates.random(goodChoices); - } - @Override public void resolve(SpellAbility sa) { final Card source = sa.getSourceCard(); @@ -194,11 +148,7 @@ public class DiscardEffect extends RevealEffectBase { // Reveal final List dPHand = p.getCardsIn(ZoneType.Hand); - if (p.isHuman()) { - // "reveal to computer" for information gathering - } else { - GuiChoose.oneOrNone("Revealed computer hand", dPHand); - } + p.getOpponent().getController().reveal("Reveal " + p + " hand" , dPHand, ZoneType.Hand, p); String valid = sa.hasParam("DiscardValid") ? sa.getParam("DiscardValid") : "Card"; @@ -215,7 +165,7 @@ public class DiscardEffect extends RevealEffectBase { } else if (mode.equals("RevealYouChoose") || mode.equals("RevealOppChoose") || mode.equals("TgtChoose")) { // Is Reveal you choose right? I think the wrong player is // being used? - List dPHand = new ArrayList(p.getCardsIn(ZoneType.Hand)); + List dPHand = p.getCardsIn(ZoneType.Hand); if (dPHand.isEmpty()) continue; // for loop over players @@ -224,11 +174,9 @@ public class DiscardEffect extends RevealEffectBase { int amount = StringUtils.isNumeric(amountString) ? Integer.parseInt(amountString) : CardFactoryUtil.xCount(source, source.getSVar(amountString)); dPHand = getRevealedList(p, dPHand, amount, false); } - List dPChHand = new ArrayList(dPHand); final String valid = sa.hasParam("DiscardValid") ? sa.getParam("DiscardValid") : "Card"; - String[] dValid = ArrayUtils.EMPTY_STRING_ARRAY; - dValid = valid.split(","); - dPChHand = CardLists.getValidCards(dPHand, dValid, source.getController(), source); + String[] dValid = valid.split(","); + List validCards = CardLists.getValidCards(dPHand, dValid, source.getController(), source); Player chooser = p; if (mode.equals("RevealYouChoose")) { @@ -237,60 +185,16 @@ public class DiscardEffect extends RevealEffectBase { chooser = source.getController().getOpponent(); } - List toBeDiscarded = new ArrayList(); - if (chooser.isComputer()) { - List dPChHand1 = new ArrayList(p.getCardsIn(ZoneType.Hand)); - dPChHand1 = CardLists.getValidCards(dPChHand1, dValid, source.getController(), source); - - int max = Math.min(dPChHand1.size(), numCards); - List list = new ArrayList(); - - if (!p.isOpponentOf(chooser) && p instanceof AIPlayer) { // discard AI cards - toBeDiscarded = ((AIPlayer) p).getAi().getCardsToDiscard(max, dValid, sa); - } else { - // discard hostile or human opponent - for (int i = 0; i < max; i++) { - Card dC = chooseCardToDiscardFromOpponent(sa, dPChHand1); - dPChHand1.remove(dC); - toBeDiscarded.add(dC); - } - } - - if (mode.startsWith("Reveal")) { - GuiChoose.oneOrNone("Computer has chosen", list); - } + if (mode.startsWith("Reveal") && p != chooser) + chooser.getController().reveal("Revealed " + p + " hand", dPHand, ZoneType.Hand, p); + + int minDiscardAmount = sa.hasParam("AnyNumber") || sa.hasParam("Optional") ? 0 : numCards; + int max = Math.min(validCards.size(), minDiscardAmount); - } else { - // human - if (mode.startsWith("Reveal")) { - GuiChoose.oneOrNone("Revealed " + p + " hand", dPHand); - } + List toBeDiscarded = validCards.isEmpty() ? CardLists.emptyList : chooser.getController().chooseCardsToDiscardFrom(p, sa, validCards, max); - if (sa.hasParam("AnyNumber")) { - List chosen = getDiscardedList(p, dPChHand); - - for (Card c : chosen) { - dPChHand.remove(c); - toBeDiscarded.add(c); - } - } else - for (int i = 0; i < numCards; i++) { - if (dPChHand.isEmpty()) { - break; - } - Card dC = null; - if (sa.hasParam("Optional")) { - dC = GuiChoose.oneOrNone("Choose a card to be discarded", dPChHand); - } else { - dC = GuiChoose.one("Choose a card to be discarded", dPChHand); - } - - if (dC != null) { - dPChHand.remove(dC); - toBeDiscarded.add(dC); - } - else break; - } + if (mode.startsWith("Reveal") ) { + p.getController().reveal(chooser + " has chosen", toBeDiscarded, ZoneType.Hand, p); } if (toBeDiscarded != null) { @@ -311,34 +215,4 @@ public class DiscardEffect extends RevealEffectBase { } } // discardResolve() - - public static List getDiscardedList(final Player player, final List valid) { - final List chosen = new ArrayList(); - final int validamount = Math.min(valid.size(), valid.size()); - - if (player.isHuman() && validamount > 0) { - final List selection = GuiChoose.order("Choose Which Cards to Discard", "Discarded", -1, valid, null, null); - for (final Object o : selection) { - if (o != null && o instanceof Card) { - chosen.add((Card) o); - } - } - } else { - for (int i = 0; i < validamount; i++) { - if (player.isHuman()) { - final Card o = GuiChoose.one("Choose card(s) to discard", valid); - if (o != null) { - chosen.add(o); - valid.remove(o); - } else { - break; - } - } else { // Computer - chosen.add(valid.get(0)); - valid.remove(valid.get(0)); - } - } - } - return chosen; - } } diff --git a/src/main/java/forge/card/cardfactory/CardFactorySorceries.java b/src/main/java/forge/card/cardfactory/CardFactorySorceries.java index 25ce2580b0f..c9f451986f7 100644 --- a/src/main/java/forge/card/cardfactory/CardFactorySorceries.java +++ b/src/main/java/forge/card/cardfactory/CardFactorySorceries.java @@ -473,11 +473,9 @@ public class CardFactorySorceries { int s = h.size(); min = Math.min(min, s); } - Iterator> hh = hands.iterator(); - for (Player p : Singletons.getModel().getGame().getPlayers()) { - List h = hh.next(); - int sac = h.size() - min; + for (Player p : Singletons.getModel().getGame().getPlayers()) { + int sac = p.getCardsIn(ZoneType.Hand).size() - min; if (sac == 0) { continue; } diff --git a/src/main/java/forge/game/ai/AiController.java b/src/main/java/forge/game/ai/AiController.java index 1d098e6e27a..fdbec57c938 100644 --- a/src/main/java/forge/game/ai/AiController.java +++ b/src/main/java/forge/game/ai/AiController.java @@ -525,16 +525,21 @@ public class AiController { */ public List getCardsToDiscard(final int numDiscard, final String[] uTypes, final SpellAbility sa) { List hand = new ArrayList(player.getCardsIn(ZoneType.Hand)); - Card sourceCard = null; + if ((uTypes != null) && (sa != null)) { hand = CardLists.getValidCards(hand, uTypes, sa.getActivatingPlayer(), sa.getSourceCard()); } + return getCardsToDiscard(numDiscard, hand, sa); + } - if (hand.size() < numDiscard) { + public List getCardsToDiscard(final int numDiscard, final List validCards, final SpellAbility sa) { + + if (validCards.size() < numDiscard) { return null; } - + + Card sourceCard = null; final List discardList = new ArrayList(); int count = 0; if (sa != null) { @@ -545,7 +550,7 @@ public class AiController { while (count < numDiscard) { Card prefCard = null; if (sa != null && sa.getActivatingPlayer() != null && sa.getActivatingPlayer().isOpponentOf(player)) { - for (Card c : hand) { + for (Card c : validCards) { if (c.hasKeyword("If a spell or ability an opponent controls causes you to discard CARDNAME," + " put it onto the battlefield instead of putting it into your graveyard.")) { prefCard = c; @@ -554,11 +559,11 @@ public class AiController { } } if (prefCard == null) { - prefCard = ComputerUtil.getCardPreference(player, sourceCard, "DiscardCost", hand); + prefCard = ComputerUtil.getCardPreference(player, sourceCard, "DiscardCost", validCards); } if (prefCard != null) { discardList.add(prefCard); - hand.remove(prefCard); + validCards.remove(prefCard); count++; } else { break; @@ -569,11 +574,11 @@ public class AiController { // choose rest for (int i = 0; i < discardsLeft; i++) { - if (hand.isEmpty()) { + if (validCards.isEmpty()) { continue; } final int numLandsInPlay = Iterables.size(Iterables.filter(player.getCardsIn(ZoneType.Battlefield), CardPredicates.Presets.LANDS)); - final List landsInHand = CardLists.filter(hand, CardPredicates.Presets.LANDS); + final List landsInHand = CardLists.filter(validCards, CardPredicates.Presets.LANDS); final int numLandsInHand = landsInHand.size(); // Discard a land @@ -582,21 +587,21 @@ public class AiController { if (canDiscardLands) { discardList.add(landsInHand.get(0)); - hand.remove(landsInHand.get(0)); + validCards.remove(landsInHand.get(0)); } else { // Discard other stuff - CardLists.sortByCmcDesc(hand); + CardLists.sortByCmcDesc(validCards); int numLandsAvailable = numLandsInPlay; if (numLandsInHand > 0) { numLandsAvailable++; } //Discard unplayable card - if (hand.get(0).getCMC() > numLandsAvailable) { - discardList.add(hand.get(0)); - hand.remove(hand.get(0)); + if (validCards.get(0).getCMC() > numLandsAvailable) { + discardList.add(validCards.get(0)); + validCards.remove(validCards.get(0)); } else { //Discard worst card - Card worst = ComputerUtilCard.getWorstAI(hand); + Card worst = ComputerUtilCard.getWorstAI(validCards); discardList.add(worst); - hand.remove(worst); + validCards.remove(worst); } } } diff --git a/src/main/java/forge/game/ai/ComputerUtil.java b/src/main/java/forge/game/ai/ComputerUtil.java index b8d8ad5b8cc..61194d3f465 100644 --- a/src/main/java/forge/game/ai/ComputerUtil.java +++ b/src/main/java/forge/game/ai/ComputerUtil.java @@ -1001,21 +1001,7 @@ public class ComputerUtil { for (final Card c : all) { for (final SpellAbility sa : c.getSpellAbility()) { - - if (sa.getApi() == null) { - continue; - } - - /// ???? - // if ( sa.isAbility() || sa.isSpell() && sa.getApi() != ApiType.Pump ) continue - if (sa.hasParam("AB") && !sa.getParam("AB").equals("Pump")) { - continue; - } - if (sa.hasParam("SP") && !sa.getParam("SP").equals("Pump")) { - continue; - } - - if (sa.hasParam("KW") && sa.getParam("KW").contains("Haste")) { + if (sa.getApi() == ApiType.Pump && sa.hasParam("KW") && sa.getParam("KW").contains("Haste")) { return true; } } @@ -1239,4 +1225,62 @@ public class ComputerUtil { } return bottom; } + + /** + * TODO: Write javadoc for this method. + * @param chooser + * @param discarder + * @param sa + * @param validCards + * @param min + * @return + */ + public static List getCardsToDiscardFromOpponent(AIPlayer chooser, Player discarder, SpellAbility sa, List validCards, int min) { + List goodChoices = CardLists.filter(validCards, new Predicate() { + @Override + public boolean apply(final Card c) { + if (!c.getSVar("DiscardMeByOpp").equals("") || !c.getSVar("DiscardMe").equals("")) { + return false; + } + return true; + } + }); + if (goodChoices.isEmpty()) { + goodChoices = validCards; + } + final List dChoices = new ArrayList(); + if (sa.hasParam("DiscardValid")) { + final String validString = sa.getParam("DiscardValid"); + if (validString.contains("Creature") && !validString.contains("nonCreature")) { + final Card c = ComputerUtilCard.getBestCreatureAI(goodChoices); + if (c != null) { + dChoices.add(ComputerUtilCard.getBestCreatureAI(goodChoices)); + } + } + } + + Collections.sort(goodChoices, CardLists.TextLenComparator); + + CardLists.sortByCmcDesc(goodChoices); + dChoices.add(goodChoices.get(0)); + + return Aggregates.random(goodChoices, min); + } + + /** + * TODO: Write javadoc for this method. + * @param aiChoser + * @param p + * @param sa + * @param validCards + * @param min + * @return + */ + public static List getCardsToDiscardFromFriend(AIPlayer aiChooser, Player p, SpellAbility sa, List validCards, int min) { + if (p instanceof AIPlayer) { // ask that ai player what he would like to discard + return ((AIPlayer) p).getAi().getCardsToDiscard(min, validCards, sa); + } + // no special options for human or remote friends + return getCardsToDiscardFromOpponent(aiChooser, p, sa, validCards, min); + } } diff --git a/src/main/java/forge/game/player/AIPlayer.java b/src/main/java/forge/game/player/AIPlayer.java index fa3ede2880a..4853430e809 100644 --- a/src/main/java/forge/game/player/AIPlayer.java +++ b/src/main/java/forge/game/player/AIPlayer.java @@ -111,7 +111,7 @@ public class AIPlayer extends Player { public final void discard(final int num, final SpellAbility sa) { int max = this.getCardsIn(ZoneType.Hand).size(); max = Math.min(max, num); - final List toDiscard = this.getAi().getCardsToDiscard(max, null, sa); + final List toDiscard = this.getAi().getCardsToDiscard(max, (String[])null, sa); for (int i = 0; i < toDiscard.size(); i++) { this.doDiscard(toDiscard.get(i), sa); } @@ -125,8 +125,7 @@ public class AIPlayer extends Player { if (tHand.size() > 0) { Card toDiscard = Aggregates.itemWithMin(tHand, CardPredicates.Accessors.fnGetCmc); - toDiscard.getController().discard(toDiscard, sa); // this got changed - // to doDiscard basically + discard(toDiscard, sa); // this got changed to doDiscard basically return; } this.discard(num, sa); diff --git a/src/main/java/forge/game/player/PlayerController.java b/src/main/java/forge/game/player/PlayerController.java index 49500052dc2..9b42de5ff33 100644 --- a/src/main/java/forge/game/player/PlayerController.java +++ b/src/main/java/forge/game/player/PlayerController.java @@ -108,4 +108,7 @@ public abstract class PlayerController { public abstract void reveal(String string, List cards, ZoneType zone, Player owner); public abstract ImmutablePair, List> arrangeForScry(List topN); public abstract boolean willPutCardOnTop(Card c); + + /** p = target player, validCards - possible discards, min cards to discard */ + public abstract List chooseCardsToDiscardFrom(Player p, SpellAbility sa, List validCards, int min); } diff --git a/src/main/java/forge/game/player/PlayerControllerAi.java b/src/main/java/forge/game/player/PlayerControllerAi.java index d6814d8076e..95757f81f43 100644 --- a/src/main/java/forge/game/player/PlayerControllerAi.java +++ b/src/main/java/forge/game/player/PlayerControllerAi.java @@ -255,4 +255,16 @@ public class PlayerControllerAi extends PlayerController { return true; // AI does not know what will happen next (another clash or that would become his topdeck) } + /* (non-Javadoc) + * @see forge.game.player.PlayerController#chooseCardsToDiscardFrom(forge.game.player.Player, java.util.List, int) + */ + @Override + public List chooseCardsToDiscardFrom(Player p, SpellAbility sa, List validCards, int min) { + boolean isTargetFriendly = !p.isOpponentOf(getPlayer()); + + return isTargetFriendly + ? ComputerUtil.getCardsToDiscardFromFriend(player, p, sa, validCards, min) + : ComputerUtil.getCardsToDiscardFromOpponent(player, p, sa, validCards, min); + } + } diff --git a/src/main/java/forge/game/player/PlayerControllerHuman.java b/src/main/java/forge/game/player/PlayerControllerHuman.java index 27ad4cc512d..c3d29124351 100644 --- a/src/main/java/forge/game/player/PlayerControllerHuman.java +++ b/src/main/java/forge/game/player/PlayerControllerHuman.java @@ -318,4 +318,12 @@ public class PlayerControllerHuman extends PlayerController { public boolean willPutCardOnTop(Card c) { return GuiDialog.confirm(c, "Where will you put " + c.getName() + " in your library", new String[]{"Top", "Bottom"} ); } + + /* (non-Javadoc) + * @see forge.game.player.PlayerController#chooseCardsToDiscardFrom(forge.game.player.Player, java.util.List, int) + */ + @Override + public List chooseCardsToDiscardFrom(Player p, SpellAbility sa, List valid, int minDiscard) { + return GuiChoose.order("Choose cards to Discard", "Discarded", minDiscard == 0 ? -1 : minDiscard, valid, null, null); + } }