mirror of
https://github.com/Card-Forge/forge.git
synced 2025-11-19 12:18:00 +00:00
Code that chooses cards to be discarded moved to PlayerController and ComputerUtil
This commit is contained in:
@@ -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<Card> emptyList = ImmutableList.of();
|
||||
|
||||
/**
|
||||
* <p>
|
||||
|
||||
@@ -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<Card> opponentHand) {
|
||||
List<Card> goodChoices = CardLists.filter(opponentHand, new Predicate<Card>() {
|
||||
@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<Card> dChoices = new ArrayList<Card>();
|
||||
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<Card> 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<Card> dPHand = new ArrayList<Card>(p.getCardsIn(ZoneType.Hand));
|
||||
List<Card> 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<Card> dPChHand = new ArrayList<Card>(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<Card> 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<Card> toBeDiscarded = new ArrayList<Card>();
|
||||
if (chooser.isComputer()) {
|
||||
List<Card> dPChHand1 = new ArrayList<Card>(p.getCardsIn(ZoneType.Hand));
|
||||
dPChHand1 = CardLists.getValidCards(dPChHand1, dValid, source.getController(), source);
|
||||
|
||||
int max = Math.min(dPChHand1.size(), numCards);
|
||||
List<Card> list = new ArrayList<Card>();
|
||||
|
||||
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<Card> toBeDiscarded = validCards.isEmpty() ? CardLists.emptyList : chooser.getController().chooseCardsToDiscardFrom(p, sa, validCards, max);
|
||||
|
||||
if (sa.hasParam("AnyNumber")) {
|
||||
List<Card> 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<Card> getDiscardedList(final Player player, final List<Card> valid) {
|
||||
final List<Card> chosen = new ArrayList<Card>();
|
||||
final int validamount = Math.min(valid.size(), valid.size());
|
||||
|
||||
if (player.isHuman() && validamount > 0) {
|
||||
final List<Card> 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;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -473,11 +473,9 @@ public class CardFactorySorceries {
|
||||
int s = h.size();
|
||||
min = Math.min(min, s);
|
||||
}
|
||||
Iterator<List<Card>> hh = hands.iterator();
|
||||
for (Player p : Singletons.getModel().getGame().getPlayers()) {
|
||||
|
||||
List<Card> 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;
|
||||
}
|
||||
|
||||
@@ -525,16 +525,21 @@ public class AiController {
|
||||
*/
|
||||
public List<Card> getCardsToDiscard(final int numDiscard, final String[] uTypes, final SpellAbility sa) {
|
||||
List<Card> hand = new ArrayList<Card>(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<Card> getCardsToDiscard(final int numDiscard, final List<Card> validCards, final SpellAbility sa) {
|
||||
|
||||
if (validCards.size() < numDiscard) {
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
Card sourceCard = null;
|
||||
final List<Card> discardList = new ArrayList<Card>();
|
||||
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<Card> landsInHand = CardLists.filter(hand, CardPredicates.Presets.LANDS);
|
||||
final List<Card> 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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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<Card> getCardsToDiscardFromOpponent(AIPlayer chooser, Player discarder, SpellAbility sa, List<Card> validCards, int min) {
|
||||
List<Card> goodChoices = CardLists.filter(validCards, new Predicate<Card>() {
|
||||
@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<Card> dChoices = new ArrayList<Card>();
|
||||
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<Card> getCardsToDiscardFromFriend(AIPlayer aiChooser, Player p, SpellAbility sa, List<Card> 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);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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<Card> toDiscard = this.getAi().getCardsToDiscard(max, null, sa);
|
||||
final List<Card> 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);
|
||||
|
||||
@@ -108,4 +108,7 @@ public abstract class PlayerController {
|
||||
public abstract void reveal(String string, List<Card> cards, ZoneType zone, Player owner);
|
||||
public abstract ImmutablePair<List<Card>, List<Card>> arrangeForScry(List<Card> topN);
|
||||
public abstract boolean willPutCardOnTop(Card c);
|
||||
|
||||
/** p = target player, validCards - possible discards, min cards to discard */
|
||||
public abstract List<Card> chooseCardsToDiscardFrom(Player p, SpellAbility sa, List<Card> validCards, int min);
|
||||
}
|
||||
|
||||
@@ -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<Card> chooseCardsToDiscardFrom(Player p, SpellAbility sa, List<Card> validCards, int min) {
|
||||
boolean isTargetFriendly = !p.isOpponentOf(getPlayer());
|
||||
|
||||
return isTargetFriendly
|
||||
? ComputerUtil.getCardsToDiscardFromFriend(player, p, sa, validCards, min)
|
||||
: ComputerUtil.getCardsToDiscardFromOpponent(player, p, sa, validCards, min);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -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<Card> chooseCardsToDiscardFrom(Player p, SpellAbility sa, List<Card> valid, int minDiscard) {
|
||||
return GuiChoose.order("Choose cards to Discard", "Discarded", minDiscard == 0 ? -1 : minDiscard, valid, null, null);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user