From e68a20c5fb62df7a83dcd0ef454b6610a450055a Mon Sep 17 00:00:00 2001 From: 18ths <13023067+18ths@users.noreply.github.com> Date: Thu, 11 Jun 2020 23:19:45 +0200 Subject: [PATCH] fixed and refactored balance effect (#6595) * fixed and refactored balance effect * inversed logic in balance effect - now players choose cards to keep instead to sacrifice/discard --- .../mage/test/cards/single/BalanceTest.java | 41 +++++ .../effects/common/BalanceEffect.java | 166 ++++++++---------- 2 files changed, 116 insertions(+), 91 deletions(-) create mode 100644 Mage.Tests/src/test/java/org/mage/test/cards/single/BalanceTest.java diff --git a/Mage.Tests/src/test/java/org/mage/test/cards/single/BalanceTest.java b/Mage.Tests/src/test/java/org/mage/test/cards/single/BalanceTest.java new file mode 100644 index 00000000000..b1af931ce34 --- /dev/null +++ b/Mage.Tests/src/test/java/org/mage/test/cards/single/BalanceTest.java @@ -0,0 +1,41 @@ +package org.mage.test.cards.single; + +import mage.constants.PhaseStep; +import mage.constants.Zone; +import org.junit.Test; +import org.mage.test.serverside.base.CardTestPlayerBase; + +public class BalanceTest extends CardTestPlayerBase { + + @Test + public void testBalance() { + + addCard(Zone.BATTLEFIELD, playerA, "Plains", 2); + addCard(Zone.BATTLEFIELD, playerA, "Runeclaw Bear", 3); + addCard(Zone.HAND, playerA, "Plains", 1); + addCard(Zone.HAND, playerA, "Balance"); + + addCard(Zone.BATTLEFIELD, playerB, "Swamp", 3); + addCard(Zone.BATTLEFIELD, playerB, "Runeclaw Bear", 2); + addCard(Zone.HAND, playerB, "Swamp", 2); + + castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Balance"); + + setStopAt(1, PhaseStep.BEGIN_COMBAT); + execute(); + assertAllCommandsUsed(); + + assertPermanentCount(playerA, "Plains", 2); + assertPermanentCount(playerA, "Runeclaw Bear", 2); + assertHandCount(playerA, "Plains", 1); + assertHandCount(playerA, "Balance", 0); + assertGraveyardCount(playerA, "Runeclaw Bear", 1); + assertGraveyardCount(playerA, "Balance", 1); + + assertPermanentCount(playerB, "Swamp", 2); + assertPermanentCount(playerB, "Runeclaw Bear", 2); + assertHandCount(playerB, "Swamp", 1); + assertGraveyardCount(playerB, "Swamp", 2); //1 from hand, 1 from battlefield + + } +} diff --git a/Mage/src/main/java/mage/abilities/effects/common/BalanceEffect.java b/Mage/src/main/java/mage/abilities/effects/common/BalanceEffect.java index c81187c4ad1..3f6a41bb026 100644 --- a/Mage/src/main/java/mage/abilities/effects/common/BalanceEffect.java +++ b/Mage/src/main/java/mage/abilities/effects/common/BalanceEffect.java @@ -17,19 +17,14 @@ import mage.players.Player; import mage.target.common.TargetCardInHand; import mage.target.common.TargetControlledPermanent; -import java.util.HashMap; -import java.util.Map; -import java.util.UUID; +import java.util.*; +import java.util.stream.Collectors; /** * @author emerald000 */ public class BalanceEffect extends OneShotEffect { - private static final FilterControlledPermanent filter = new FilterControlledLandPermanent("lands to keep"); - private static final FilterControlledPermanent filter2 = new FilterControlledCreaturePermanent("creatures to keep"); - private static final FilterCard filter3 = new FilterCard("cards to keep"); - public BalanceEffect() { super(Outcome.Sacrifice); staticText = "each player chooses a number of lands they control " @@ -53,108 +48,45 @@ public class BalanceEffect extends OneShotEffect { if (controller == null) { return false; } - //Lands - int minLand = Integer.MAX_VALUE; - Cards landsToSacrifice = new CardsImpl(); - for (UUID playerId : game.getState().getPlayersInRange(controller.getId(), game)) { - Player player = game.getPlayer(playerId); - if (player == null) { - continue; - } - int count = game.getBattlefield().countAll(StaticFilters.FILTER_CONTROLLED_PERMANENT_LAND, player.getId(), game); - if (count < minLand) { - minLand = count; - } - } - for (UUID playerId : game.getState().getPlayersInRange(controller.getId(), game)) { - Player player = game.getPlayer(playerId); - if (player == null) { - continue; - } - TargetControlledPermanent target = new TargetControlledPermanent(minLand, minLand, filter, true); - if (!target.choose(Outcome.Sacrifice, player.getId(), source.getSourceId(), game)) { - continue; - } - for (Permanent permanent : game.getBattlefield().getActivePermanents(StaticFilters.FILTER_CONTROLLED_PERMANENT_LAND, player.getId(), source.getSourceId(), game)) { - if (permanent != null && !target.getTargets().contains(permanent.getId())) { - landsToSacrifice.add(permanent); - } - } - } - - for (UUID cardId : landsToSacrifice) { - Permanent permanent = game.getPermanent(cardId); - if (permanent != null) { - permanent.sacrifice(source.getSourceId(), game); - } - } - - //Creatures - int minCreature = Integer.MAX_VALUE; - Cards creaturesToSacrifice = new CardsImpl(); - for (UUID playerId : game.getState().getPlayersInRange(controller.getId(), game)) { - Player player = game.getPlayer(playerId); - if (player == null) { - } - int count = game.getBattlefield().countAll(StaticFilters.FILTER_CONTROLLED_PERMANENT_LAND, player.getId(), game); - if (count < minCreature) { - minCreature = count; - } - } - - for (UUID playerId : game.getState().getPlayersInRange(controller.getId(), game)) { - Player player = game.getPlayer(playerId); - if (player == null) { - continue; - } - TargetControlledPermanent target = new TargetControlledPermanent(minCreature, minCreature, filter2, true); - if (!target.choose(Outcome.Sacrifice, player.getId(), source.getSourceId(), game)) { - continue; - } - for (Permanent permanent : game.getBattlefield().getActivePermanents(StaticFilters.FILTER_CONTROLLED_CREATURE, player.getId(), source.getSourceId(), game)) { - if (permanent != null && !target.getTargets().contains(permanent.getId())) { - creaturesToSacrifice.add(permanent); - } - } - } - - for (UUID cardId : creaturesToSacrifice) { - Permanent permanent = game.getPermanent(cardId); - if (permanent != null) { - permanent.sacrifice(source.getSourceId(), game); - } - } + choosePermanentsToKeep(game, source, controller, StaticFilters.FILTER_CONTROLLED_PERMANENT_LAND, new FilterControlledLandPermanent("lands to keep")); + choosePermanentsToKeep(game, source, controller, StaticFilters.FILTER_CONTROLLED_CREATURE, new FilterControlledCreaturePermanent("creatures to keep")); //Cards in hand - int minCard = Integer.MAX_VALUE; - Map cardsToDiscard = new HashMap<>(2); + int lowestHandSize = Integer.MAX_VALUE; for (UUID playerId : game.getState().getPlayersInRange(controller.getId(), game)) { Player player = game.getPlayer(playerId); if (player == null) { + continue; } - int count = player.getHand().size(); - if (count < minCard) { - minCard = count; - } + + lowestHandSize = Math.min(lowestHandSize, player.getHand().size()); } + Map cardsToDiscard = new HashMap<>(); for (UUID playerId : game.getState().getPlayersInRange(controller.getId(), game)) { Player player = game.getPlayer(playerId); if (player == null) { continue; } - Cards cards = new CardsImpl(); - TargetCardInHand target = new TargetCardInHand(minCard, filter3); - if (!target.choose(Outcome.Discard, player.getId(), source.getSourceId(), game)) { + + TargetCardInHand target = new TargetCardInHand(lowestHandSize, new FilterCard("cards to keep")); + if (!target.choose(Outcome.Protect, player.getId(), source.getSourceId(), game)) { continue; } - for (Card card : player.getHand().getCards(game)) { - if (card != null && !target.getTargets().contains(card.getId())) { - cards.add(card); + + Set allCardsInHand = player.getHand().getCards(game); + Set cardsToKeep = new LinkedHashSet<>(); + + for (Card card : allCardsInHand) { + if (card != null && target.getTargets().contains(card.getId())) { + cardsToKeep.add(card); } } - cardsToDiscard.put(playerId, cards); + + cardsToDiscard.put(playerId, allCardsInHand.stream() + .filter(e -> !cardsToKeep.contains(e)) + .collect(CardsImpl::new, CardsImpl::add, CardsImpl::addAll)); } for (UUID playerId : game.getState().getPlayersInRange(controller.getId(), game)) { @@ -163,6 +95,58 @@ public class BalanceEffect extends OneShotEffect { player.discard(cardsToDiscard.get(playerId), source, game); } } + return true; } + + private void choosePermanentsToKeep(Game game, Ability source, Player controller, + FilterControlledPermanent filterPermanent, FilterControlledPermanent filterPermanentDialog) { + int lowestPermanentsCount = Integer.MAX_VALUE; + for (UUID playerId : game.getState().getPlayersInRange(controller.getId(), game)) { + Player player = game.getPlayer(playerId); + if (player == null) { + continue; + } + + lowestPermanentsCount = Math.min(lowestPermanentsCount, + game.getBattlefield().countAll(filterPermanent, player.getId(), game)); + } + + List permanentsToSacrifice = new ArrayList<>(); + + for (UUID playerId : game.getState().getPlayersInRange(controller.getId(), game)) { + Player player = game.getPlayer(playerId); + if (player == null) { + continue; + } + + TargetControlledPermanent target = new TargetControlledPermanent(lowestPermanentsCount, lowestPermanentsCount, filterPermanentDialog, true); + if (!target.choose(Outcome.Protect, player.getId(), source.getSourceId(), game)) { + continue; + } + + List allPermanentsOfType = game.getBattlefield().getActivePermanents(filterPermanent, player.getId(), source.getSourceId(), game); + List permanentsToKeep = new ArrayList<>(); + + for (Permanent permanent : allPermanentsOfType) { + if (permanent != null && target.getTargets().contains(permanent.getId())) { + permanentsToKeep.add(permanent); + } + } + + List playerPermanentsToSacrifice = allPermanentsOfType.stream().filter(e -> !permanentsToKeep.contains(e)).collect(Collectors.toList()); + permanentsToSacrifice.addAll(playerPermanentsToSacrifice); + + if (playerPermanentsToSacrifice.isEmpty()) { + game.informPlayers(player.getLogName() + " chose permanents to be sacrificed: " + + playerPermanentsToSacrifice.stream().map(Permanent::getLogName).collect(Collectors.joining(", "))); + } + } + + for (Permanent permanent : permanentsToSacrifice) { + if (permanent != null) { + permanent.sacrifice(source.getSourceId(), game); + } + } + } }