diff --git a/src/main/java/forge/card/ability/effects/ScryEffect.java b/src/main/java/forge/card/ability/effects/ScryEffect.java index 714f389fa39..72e22124e8a 100644 --- a/src/main/java/forge/card/ability/effects/ScryEffect.java +++ b/src/main/java/forge/card/ability/effects/ScryEffect.java @@ -1,12 +1,19 @@ package forge.card.ability.effects; +import java.util.ArrayList; +import java.util.Collections; import java.util.List; +import org.apache.commons.lang3.tuple.ImmutablePair; + +import forge.Card; import forge.card.ability.AbilityUtils; import forge.card.ability.SpellAbilityEffect; import forge.card.spellability.SpellAbility; import forge.card.spellability.Target; import forge.game.player.Player; +import forge.game.zone.PlayerZone; +import forge.game.zone.ZoneType; public class ScryEffect extends SpellAbilityEffect { @@ -42,7 +49,38 @@ public class ScryEffect extends SpellAbilityEffect { for (final Player p : tgtPlayers) { if ((tgt == null) || p.canBeTargetedBy(sa)) { - p.scry(num); + scry(p, num); + } + } + } + + /** + *

+ * scry. + *

+ * + * @param numScry + * a int. + */ + public final void scry(Player p, int numScry) { + final List topN = new ArrayList(); + final PlayerZone library = p.getZone(ZoneType.Library); + numScry = Math.min(numScry, library.size()); + for (int i = 0; i < numScry; i++) { + topN.add(library.get(i)); + } + + ImmutablePair, List> lists = p.getController().arrangeForScry(topN); + + for(Card c : lists.getRight()) { + p.getGame().getAction().moveToBottomOfLibrary(c); + } + + List toTop = lists.getLeft(); + if ( null != toTop ) { + Collections.reverse(toTop); // the last card in list will become topmost in library, have to revert thus. + for(Card c : toTop) { + p.getGame().getAction().moveToLibrary(c); } } } diff --git a/src/main/java/forge/game/ai/ComputerUtil.java b/src/main/java/forge/game/ai/ComputerUtil.java index 5d3cf8d97f9..b8d8ad5b8cc 100644 --- a/src/main/java/forge/game/ai/ComputerUtil.java +++ b/src/main/java/forge/game/ai/ComputerUtil.java @@ -24,6 +24,7 @@ import java.util.Random; import com.google.common.base.Predicate; +import com.google.common.collect.Iterables; import forge.Card; import forge.CardLists; @@ -1223,4 +1224,19 @@ public class ComputerUtil { return (handList.size() > AI_MULLIGAN_THRESHOLD) && hasLittleCmc0Cards; } + + + public static boolean scryWillMoveCardToBottomOfLibrary(AIPlayer player, Card c) { + boolean bottom = false; + if (c.isBasicLand()) { + List bl = player.getCardsIn(ZoneType.Battlefield); + int nBasicLands = Iterables.size(Iterables.filter(bl, CardPredicates.Presets.BASIC_LANDS)); + bottom = nBasicLands > 5; // if control more than 5 Basic land, probably don't need more + } else if (c.isCreature()) { + List cl = player.getCardsIn(ZoneType.Battlefield); + cl = CardLists.filter(cl, CardPredicates.Presets.CREATURES); + bottom = cl.size() > 5; // if control more than 5 Creatures, probably don't need more + } + return bottom; + } } diff --git a/src/main/java/forge/game/player/AIPlayer.java b/src/main/java/forge/game/player/AIPlayer.java index 066b2482a67..fd928405cc8 100644 --- a/src/main/java/forge/game/player/AIPlayer.java +++ b/src/main/java/forge/game/player/AIPlayer.java @@ -20,7 +20,6 @@ package forge.game.player; import java.util.List; import java.util.Random; -import com.google.common.collect.Iterables; import forge.Card; import forge.CardLists; @@ -135,41 +134,6 @@ public class AIPlayer extends Player { // ///////////////////////// - /** {@inheritDoc} */ - @Override - protected final void doScry(final List topN, final int n) { - int num = n; - for (int i = 0; i < num; i++) { - boolean bottom = false; - if (topN.get(i).isBasicLand()) { - List bl = this.getCardsIn(ZoneType.Battlefield); - int nBasicLands = Iterables.size(Iterables.filter(bl, CardPredicates.Presets.BASIC_LANDS)); - - bottom = nBasicLands > 5; // if control more than 5 Basic land, - // probably don't need more - } else if (topN.get(i).isCreature()) { - List cl = this.getCardsIn(ZoneType.Battlefield); - cl = CardLists.filter(cl, CardPredicates.Presets.CREATURES); - bottom = cl.size() > 5; // if control more than 5 Creatures, - // probably don't need more - } - if (bottom) { - final Card c = topN.get(i); - game.getAction().moveToBottomOfLibrary(c); - // topN.remove(c); - } - } - num = topN.size(); - // put the rest on top in random order - for (int i = 0; i < num; i++) { - final Random rndm = MyRandom.getRandom(); - final int r = rndm.nextInt(topN.size()); - final Card c = topN.get(r); - game.getAction().moveToLibrary(c); - topN.remove(r); - } - } - /** {@inheritDoc} */ @Override public final void sacrificePermanent(final String prompt, final List choices) { diff --git a/src/main/java/forge/game/player/HumanPlayer.java b/src/main/java/forge/game/player/HumanPlayer.java index fe39a66595b..6fc76bb1463 100644 --- a/src/main/java/forge/game/player/HumanPlayer.java +++ b/src/main/java/forge/game/player/HumanPlayer.java @@ -117,31 +117,6 @@ public class HumanPlayer extends Player { Singletons.getModel().getMatch().getInput().setInputInterrupt(PlayerUtil.inputChainsDiscard()); } - /** {@inheritDoc} */ - @Override - protected final void doScry(final List topN, final int n) { - int num = n; - for (int i = 0; i < num; i++) { - final Card c = GuiChoose.oneOrNone("Put on bottom of library.", topN); - if (c != null) { - topN.remove(c); - game.getAction().moveToBottomOfLibrary(c); - } else { - // no card chosen for the bottom - break; - } - } - num = topN.size(); - for (int i = 0; i < num; i++) { - final Card c = GuiChoose.one("Put on top of library.", topN); - if (c != null) { - topN.remove(c); - game.getAction().moveToLibrary(c); - } - // no else - a card must have been chosen - } - } - /** {@inheritDoc} */ @Override public final void sacrificePermanent(final String prompt, final List choices) { diff --git a/src/main/java/forge/game/player/Player.java b/src/main/java/forge/game/player/Player.java index 4e16c286a29..b6098f654bb 100644 --- a/src/main/java/forge/game/player/Player.java +++ b/src/main/java/forge/game/player/Player.java @@ -192,6 +192,10 @@ public abstract class Player extends GameEntity implements Comparable { this.setName(lobbyPlayer.getName()); } + public GameState getGame() { // I'll probably regret about this + return game; + } + public final PlayerStatistics getStats() { return stats; } @@ -1844,35 +1848,7 @@ public abstract class Player extends GameEntity implements Comparable { // ////////////////////////////// // ////////////////////////////// - /** - *

- * doScry. - *

- * - * @param topN - * a {@link forge.CardList} object. - * @param n - * a int. - */ - protected abstract void doScry(List topN, int n); - /** - *

- * scry. - *

- * - * @param numScry - * a int. - */ - public final void scry(int numScry) { - final List topN = new ArrayList(); - final PlayerZone library = this.getZone(ZoneType.Library); - numScry = Math.min(numScry, library.size()); - for (int i = 0; i < numScry; i++) { - topN.add(library.get(i)); - } - this.doScry(topN, topN.size()); - } // ///////////////////////////// diff --git a/src/main/java/forge/game/player/PlayerController.java b/src/main/java/forge/game/player/PlayerController.java index bc3fc07cb41..4a5352cf301 100644 --- a/src/main/java/forge/game/player/PlayerController.java +++ b/src/main/java/forge/game/player/PlayerController.java @@ -3,6 +3,8 @@ package forge.game.player; import java.util.List; import java.util.Map; +import org.apache.commons.lang3.tuple.ImmutablePair; + import forge.Card; import forge.GameEntity; import forge.card.spellability.SpellAbility; @@ -104,4 +106,5 @@ public abstract class PlayerController { /** Shows the card to this player*/ public abstract void reveal(String string, List cards, ZoneType zone, Player owner); + public abstract ImmutablePair, List> arrangeForScry(List topN); } diff --git a/src/main/java/forge/game/player/PlayerControllerAi.java b/src/main/java/forge/game/player/PlayerControllerAi.java index 696043136cc..c179c49a099 100644 --- a/src/main/java/forge/game/player/PlayerControllerAi.java +++ b/src/main/java/forge/game/player/PlayerControllerAi.java @@ -1,8 +1,12 @@ package forge.game.player; +import java.util.ArrayList; +import java.util.Collections; import java.util.List; import java.util.Map; +import org.apache.commons.lang3.tuple.ImmutablePair; + import forge.Card; import forge.GameEntity; import forge.card.spellability.Spell; @@ -228,4 +232,21 @@ public class PlayerControllerAi extends PlayerController { // We don't know how to reveal cards to AI } + @Override + public ImmutablePair, List> arrangeForScry(List topN) { + List toBottom = new ArrayList(); + List toTop = new ArrayList(); + + for (Card c: topN) { + if (ComputerUtil.scryWillMoveCardToBottomOfLibrary(player, c)) + toBottom.add(c); + else + toTop.add(c); + } + + // put the rest on top in random order + Collections.shuffle(toTop); + return ImmutablePair.of(toTop, toBottom); + } + } diff --git a/src/main/java/forge/game/player/PlayerControllerHuman.java b/src/main/java/forge/game/player/PlayerControllerHuman.java index 1bd07544911..4c483c25291 100644 --- a/src/main/java/forge/game/player/PlayerControllerHuman.java +++ b/src/main/java/forge/game/player/PlayerControllerHuman.java @@ -8,6 +8,7 @@ import java.util.Map; import javax.swing.JOptionPane; import org.apache.commons.lang3.StringUtils; +import org.apache.commons.lang3.tuple.ImmutablePair; import forge.Card; import forge.GameEntity; @@ -288,4 +289,12 @@ public class PlayerControllerHuman extends PlayerController { message = String.format("Looking at %s's %s", owner, zone); GuiChoose.oneOrNone(message, cards); } + + @Override + public ImmutablePair, List> arrangeForScry(List topN) { + List toBottom = GuiChoose.order("Select cards to be put on the bottom of your library", "Cards to put on the bottom", -1, topN, null, null); + topN.removeAll(toBottom); + List toTop = topN.isEmpty() ? null : GuiChoose.order("Arrange cards to be put on top of your library", "Cards arranged", 0, topN, null, null); + return ImmutablePair.of(toTop, toBottom); + } }