diff --git a/src/main/java/forge/control/input/InputPartialParisMulligan.java b/src/main/java/forge/control/input/InputPartialParisMulligan.java index 637fd292987..60bdee6ca3d 100644 --- a/src/main/java/forge/control/input/InputPartialParisMulligan.java +++ b/src/main/java/forge/control/input/InputPartialParisMulligan.java @@ -25,6 +25,8 @@ import forge.FThreads; import forge.game.GameState; import forge.game.GameType; import forge.game.MatchController; +import forge.game.ai.ComputerUtil; +import forge.game.player.AIPlayer; import forge.game.player.Player; import forge.game.zone.Zone; import forge.game.zone.ZoneType; @@ -47,6 +49,7 @@ public class InputPartialParisMulligan extends InputBase { private static final long serialVersionUID = -8112954303001155622L; private final MatchController match; + private final GameState game; private final List lastExiled = new ArrayList(); private final List allExiled = new ArrayList(); @@ -54,6 +57,7 @@ public class InputPartialParisMulligan extends InputBase { public InputPartialParisMulligan(MatchController match0, Player humanPlayer) { super(humanPlayer); match = match0; + game = match.getCurrentGame(); } /** {@inheritDoc} */ @@ -88,12 +92,35 @@ public class InputPartialParisMulligan extends InputBase { public final void selectButtonCancel() { for(Card c : lastExiled) { - match.getCurrentGame().action.exile(c); + game.action.exile(c); } player.drawCards(lastExiled.size()-1); allExiled.addAll(lastExiled); lastExiled.clear(); + + final List aiAllExiled = new ArrayList(); + for (Player p : game.getPlayers()) { + if (!(p instanceof AIPlayer)) { + continue; + } + int ppcandidates = -1; + AIPlayer ai = (AIPlayer) p; + + while (ComputerUtil.wantMulligan(ai) && ppcandidates != 0) { + List cand = ComputerUtil.getPartialParisCandidates(ai); + ppcandidates = cand.size(); + if(ppcandidates != 0) + { + aiAllExiled.addAll(cand); + for(Card c : cand) + { + game.action.exile(c); + } + ai.drawCards(ppcandidates-1); + } + } + } if (player.getCardsIn(ZoneType.Hand).isEmpty()) { this.end(); @@ -102,9 +129,7 @@ public class InputPartialParisMulligan extends InputBase { } } - final void end() { - - final GameState game = match.getCurrentGame(); + final void end() { for(Card c : allExiled) { @@ -113,17 +138,28 @@ public class InputPartialParisMulligan extends InputBase { player.shuffle(); // Computer mulligan - //TODO: How should AI approach Partial Paris? - /* + final List aiAllExiled = new ArrayList(); for (Player p : game.getPlayers()) { if (!(p instanceof AIPlayer)) { continue; } + int ppcandidates = -1; AIPlayer ai = (AIPlayer) p; - while (ComputerUtil.wantMulligan(ai)) { - ai.doMulligan(); + + while (ComputerUtil.wantMulligan(ai) && ppcandidates != 0) { + List cand = ComputerUtil.getPartialParisCandidates(ai); + ppcandidates = cand.size(); + if(ppcandidates != 0) + { + aiAllExiled.addAll(cand); + for(Card c : cand) + { + game.action.exile(c); + } + ai.drawCards(ppcandidates-1); + } } - }*/ + } // Human Leylines & Chancellors ButtonUtil.reset(); @@ -158,7 +194,7 @@ public class InputPartialParisMulligan extends InputBase { if (GuiDialog.confirm(c0, "Use " + c0.getName() + "'s ability?")) { List hand = new ArrayList(c0.getController().getCardsIn(ZoneType.Hand)); for (Card c : hand) { - match.getCurrentGame().getAction().exile(c); + game.getAction().exile(c); } c0.getController().drawCards(hand.size()); } diff --git a/src/main/java/forge/game/ai/ComputerUtil.java b/src/main/java/forge/game/ai/ComputerUtil.java index 58926a6f45e..307c2147208 100644 --- a/src/main/java/forge/game/ai/ComputerUtil.java +++ b/src/main/java/forge/game/ai/ComputerUtil.java @@ -19,7 +19,9 @@ package forge.game.ai; import java.util.ArrayList; import java.util.Collections; +import java.util.HashMap; import java.util.List; +import java.util.Map; import java.util.Random; import com.google.common.base.Predicate; @@ -30,7 +32,9 @@ import forge.CardLists; import forge.CardPredicates; import forge.CardPredicates.Presets; import forge.CardUtil; +import forge.Color; import forge.Singletons; +import forge.card.MagicColor; import forge.card.ability.AbilityUtils; import forge.card.ability.ApiType; import forge.card.ability.effects.CharmEffect; @@ -39,6 +43,7 @@ import forge.card.cost.Cost; import forge.card.cost.CostDiscard; import forge.card.cost.CostPart; import forge.card.cost.CostPayment; +import forge.card.spellability.AbilityManaPart; import forge.card.spellability.AbilityStatic; import forge.card.spellability.SpellAbility; import forge.card.spellability.Target; @@ -1226,6 +1231,67 @@ public class ComputerUtil { return (handList.size() > ai.getAi().getIntProperty(AiProps.AI_MULLIGAN_THRESHOLD)) && hasLittleCmc0Cards; } + + public static List getPartialParisCandidates(AIPlayer ai) { + final List candidates = new ArrayList(); + final List handList = ai.getCardsIn(ZoneType.Hand); + + final List lands = CardLists.getValidCards(handList, "Card.Land", ai, null); + final List nonLands = CardLists.getValidCards(handList, "Card.nonLand", ai, null); + CardLists.sortByCmcDesc(nonLands); + + if(lands.size() >= 3 && lands.size() <= 4) + return candidates; + + if(lands.size() < 3) + { + //Not enough lands! + int tgtCandidates = Math.max(Math.abs(lands.size()-nonLands.size()), 3); + System.out.println("Partial Paris: " + ai.getName() + " lacks lands, aiming to exile " + tgtCandidates + " cards."); + + for(int i=0;i> numProducers = new HashMap>(); + for(Color col : Color.WUBRG) + { + numProducers.put(col, new ArrayList()); + } + + + for(Card c : lands) + { + for(SpellAbility sa : c.getManaAbility()) + { + AbilityManaPart abmana = sa.getManaPart(); + for(Color col : Color.WUBRG) + { + if(abmana.canProduce(col.toString())) + { + numProducers.get(col).add(c); + } + } + } + } + } + + System.out.print("Partial Paris: " + ai.getName() + " may exile "); + for(Card c : candidates) + { + System.out.print(c.toString() + ", "); + } + System.out.println(); + + if(candidates.size() < 2) + candidates.clear(); + return candidates; + } public static boolean scryWillMoveCardToBottomOfLibrary(AIPlayer player, Card c) {