From de4befb9c26406b82059f19f1bcffbb6959bcc6a Mon Sep 17 00:00:00 2001 From: Oleg Agafonov Date: Mon, 1 Apr 2019 07:34:46 +0400 Subject: [PATCH] * Sideboarding: fixed that it possible to auto-submit 40 cards deck instead 60 in constructed formats (#5579); Sideboarding: fixed that cheated deck with sideboard can be used instead lose the game; --- .../src/mage/deck/AusHighlander.java | 4 +- .../src/mage/deck/Brawl.java | 13 +++-- .../src/mage/deck/Commander.java | 14 ++++- .../src/mage/deck/Freeform.java | 16 ++++-- .../src/mage/deck/FreeformCommander.java | 19 +++++-- .../src/mage/deck/Momir.java | 23 +++++--- .../src/mage/deck/PennyDreadfulCommander.java | 14 ++++- .../src/mage/deck/TinyLeaders.java | 14 ++++- .../src/mage/deck/Limited.java | 19 +++++-- .../java/mage/player/ai/ComputerPlayer.java | 56 ++++++++++--------- .../main/java/mage/server/MageServerImpl.java | 11 ++-- .../src/main/java/mage/server/Main.java | 2 +- .../java/mage/server/TableController.java | 30 +++++----- .../mage/test/serverside/PlayGameTest.java | 11 ++-- .../test/serverside/TestPlayRandomGame.java | 11 ++-- .../org/mage/test/utils/DeckTestUtils.java | 4 +- .../java/mage/cards/decks/Constructed.java | 15 ++++- .../java/mage/cards/decks/DeckValidator.java | 14 +++-- .../cards/decks}/DeckValidatorFactory.java | 12 +--- .../main/java/mage/game/match/MatchImpl.java | 4 +- .../java/mage/game/match/MatchPlayer.java | 12 ++-- .../game/tournament/TournamentPlayer.java | 10 ++-- 22 files changed, 204 insertions(+), 124 deletions(-) rename {Mage.Server/src/main/java/mage/server/game => Mage/src/main/java/mage/cards/decks}/DeckValidatorFactory.java (86%) diff --git a/Mage.Server.Plugins/Mage.Deck.Constructed/src/mage/deck/AusHighlander.java b/Mage.Server.Plugins/Mage.Deck.Constructed/src/mage/deck/AusHighlander.java index b994ddf4a27..51bbb20fc0f 100644 --- a/Mage.Server.Plugins/Mage.Deck.Constructed/src/mage/deck/AusHighlander.java +++ b/Mage.Server.Plugins/Mage.Deck.Constructed/src/mage/deck/AusHighlander.java @@ -95,8 +95,8 @@ public class AusHighlander extends Constructed { public boolean validate(Deck deck) { boolean valid = true; - if (deck.getCards().size() != 60) { - invalid.put("Deck", "Must contain 60 singleton cards: has " + (deck.getCards().size()) + " cards"); + if (deck.getCards().size() != getDeckMinSize()) { + invalid.put("Deck", "Must contain " + getDeckMinSize() + " singleton cards: has " + (deck.getCards().size()) + " cards"); valid = false; } if (deck.getSideboard().size() > 15) { diff --git a/Mage.Server.Plugins/Mage.Deck.Constructed/src/mage/deck/Brawl.java b/Mage.Server.Plugins/Mage.Deck.Constructed/src/mage/deck/Brawl.java index 7e136506588..08e1f2e4aa7 100644 --- a/Mage.Server.Plugins/Mage.Deck.Constructed/src/mage/deck/Brawl.java +++ b/Mage.Server.Plugins/Mage.Deck.Constructed/src/mage/deck/Brawl.java @@ -1,14 +1,14 @@ package mage.deck; -import java.util.*; import mage.abilities.common.CanBeYourCommanderAbility; import mage.cards.Card; import mage.cards.decks.Constructed; import mage.cards.decks.Deck; import mage.filter.FilterMana; +import java.util.*; + /** - * * @author spjspj */ public class Brawl extends Constructed { @@ -30,13 +30,18 @@ public class Brawl extends Constructed { super(name); } + @Override + public int getSideboardMinSize() { + return 1; + } + @Override public boolean validate(Deck deck) { boolean valid = true; FilterMana colorIdentity = new FilterMana(); - if (deck.getCards().size() + deck.getSideboard().size() != 60) { - invalid.put("Deck", "Must contain 60 cards: has " + (deck.getCards().size() + deck.getSideboard().size()) + " cards"); + if (deck.getCards().size() + deck.getSideboard().size() != getDeckMinSize()) { + invalid.put("Deck", "Must contain " + getDeckMinSize() + " cards: has " + (deck.getCards().size() + deck.getSideboard().size()) + " cards"); valid = false; } diff --git a/Mage.Server.Plugins/Mage.Deck.Constructed/src/mage/deck/Commander.java b/Mage.Server.Plugins/Mage.Deck.Constructed/src/mage/deck/Commander.java index a14bf538925..8798896e6aa 100644 --- a/Mage.Server.Plugins/Mage.Deck.Constructed/src/mage/deck/Commander.java +++ b/Mage.Server.Plugins/Mage.Deck.Constructed/src/mage/deck/Commander.java @@ -74,13 +74,23 @@ public class Commander extends Constructed { super(name); } + @Override + public int getDeckMinSize() { + return 99; + } + + @Override + public int getSideboardMinSize() { + return 1; + } + @Override public boolean validate(Deck deck) { boolean valid = true; FilterMana colorIdentity = new FilterMana(); - if (deck.getCards().size() + deck.getSideboard().size() != 100) { - invalid.put("Deck", "Must contain 100 cards: has " + (deck.getCards().size() + deck.getSideboard().size()) + " cards"); + if (deck.getCards().size() + deck.getSideboard().size() != getDeckMinSize() + getSideboardMinSize()) { + invalid.put("Deck", "Must contain " + getDeckMinSize() + getSideboardMinSize() + " cards: has " + (deck.getCards().size() + deck.getSideboard().size()) + " cards"); valid = false; } diff --git a/Mage.Server.Plugins/Mage.Deck.Constructed/src/mage/deck/Freeform.java b/Mage.Server.Plugins/Mage.Deck.Constructed/src/mage/deck/Freeform.java index 70e6d0feaf6..41733f91163 100644 --- a/Mage.Server.Plugins/Mage.Deck.Constructed/src/mage/deck/Freeform.java +++ b/Mage.Server.Plugins/Mage.Deck.Constructed/src/mage/deck/Freeform.java @@ -1,11 +1,9 @@ - package mage.deck; import mage.cards.decks.Deck; import mage.cards.decks.DeckValidator; /** - * * @author fireshoes */ public class Freeform extends DeckValidator { @@ -14,12 +12,22 @@ public class Freeform extends DeckValidator { super("Constructed - Freeform"); } + @Override + public int getDeckMinSize() { + return 40; + } + + @Override + public int getSideboardMinSize() { + return 0; + } + @Override public boolean validate(Deck deck) { boolean valid = true; // http://magic.wizards.com/en/gameinfo/gameplay/formats/freeform - if (deck.getCards().size() < 40) { - invalid.put("Deck", "Must contain at least 40 cards: has only " + deck.getCards().size() + " cards"); + if (deck.getCards().size() < getDeckMinSize()) { + invalid.put("Deck", "Must contain at least " + getDeckMinSize() + " cards: has only " + deck.getCards().size() + " cards"); valid = false; } return valid; diff --git a/Mage.Server.Plugins/Mage.Deck.Constructed/src/mage/deck/FreeformCommander.java b/Mage.Server.Plugins/Mage.Deck.Constructed/src/mage/deck/FreeformCommander.java index 983861cd23d..0172a141336 100644 --- a/Mage.Server.Plugins/Mage.Deck.Constructed/src/mage/deck/FreeformCommander.java +++ b/Mage.Server.Plugins/Mage.Deck.Constructed/src/mage/deck/FreeformCommander.java @@ -1,7 +1,5 @@ - package mage.deck; -import java.util.*; import mage.abilities.Ability; import mage.abilities.keyword.PartnerAbility; import mage.abilities.keyword.PartnerWithAbility; @@ -12,8 +10,9 @@ import mage.cards.decks.Constructed; import mage.cards.decks.Deck; import mage.filter.FilterMana; +import java.util.*; + /** - * * @author spjspj */ public class FreeformCommander extends Constructed { @@ -35,13 +34,23 @@ public class FreeformCommander extends Constructed { super(name); } + @Override + public int getDeckMinSize() { + return 99; + } + + @Override + public int getSideboardMinSize() { + return 1; + } + @Override public boolean validate(Deck deck) { boolean valid = true; FilterMana colorIdentity = new FilterMana(); - if (deck.getCards().size() + deck.getSideboard().size() != 100) { - invalid.put("Deck", "Must contain 100 cards: has " + (deck.getCards().size() + deck.getSideboard().size()) + " cards"); + if (deck.getCards().size() + deck.getSideboard().size() != getDeckMinSize() + getSideboardMinSize()) { + invalid.put("Deck", "Must contain " + getDeckMinSize() + getSideboardMinSize() + " cards: has " + (deck.getCards().size() + deck.getSideboard().size()) + " cards"); valid = false; } diff --git a/Mage.Server.Plugins/Mage.Deck.Constructed/src/mage/deck/Momir.java b/Mage.Server.Plugins/Mage.Deck.Constructed/src/mage/deck/Momir.java index a9e24077599..ab5500ebd2b 100644 --- a/Mage.Server.Plugins/Mage.Deck.Constructed/src/mage/deck/Momir.java +++ b/Mage.Server.Plugins/Mage.Deck.Constructed/src/mage/deck/Momir.java @@ -1,15 +1,14 @@ - package mage.deck; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.List; import mage.cards.Card; import mage.cards.decks.Deck; import mage.cards.decks.DeckValidator; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; + /** - * * @author nigelzor */ public class Momir extends DeckValidator { @@ -22,12 +21,22 @@ public class Momir extends DeckValidator { super(name); } + @Override + public int getDeckMinSize() { + return 60; + } + + @Override + public int getSideboardMinSize() { + return 0; + } + @Override public boolean validate(Deck deck) { boolean valid = true; - if (deck.getCards().size() != 60) { - invalid.put("Deck", "Must contain 60 cards: has " + deck.getCards().size() + " cards"); + if (deck.getCards().size() != getDeckMinSize()) { + invalid.put("Deck", "Must contain " + getDeckMinSize() + " cards: has " + deck.getCards().size() + " cards"); valid = false; } diff --git a/Mage.Server.Plugins/Mage.Deck.Constructed/src/mage/deck/PennyDreadfulCommander.java b/Mage.Server.Plugins/Mage.Deck.Constructed/src/mage/deck/PennyDreadfulCommander.java index 56fc7e5d7d9..6629b25dc39 100644 --- a/Mage.Server.Plugins/Mage.Deck.Constructed/src/mage/deck/PennyDreadfulCommander.java +++ b/Mage.Server.Plugins/Mage.Deck.Constructed/src/mage/deck/PennyDreadfulCommander.java @@ -36,13 +36,23 @@ public class PennyDreadfulCommander extends Constructed { super(name); } + @Override + public int getDeckMinSize() { + return 99; + } + + @Override + public int getSideboardMinSize() { + return 1; + } + @Override public boolean validate(Deck deck) { boolean valid = true; FilterMana colorIdentity = new FilterMana(); - if (deck.getCards().size() + deck.getSideboard().size() != 100) { - invalid.put("Deck", "Must contain 100 cards: has " + (deck.getCards().size() + deck.getSideboard().size()) + " cards"); + if (deck.getCards().size() + deck.getSideboard().size() != getDeckMinSize() + getSideboardMinSize()) { + invalid.put("Deck", "Must contain " + getDeckMinSize() + +getSideboardMinSize() + " cards: has " + (deck.getCards().size() + deck.getSideboard().size()) + " cards"); valid = false; } diff --git a/Mage.Server.Plugins/Mage.Deck.Constructed/src/mage/deck/TinyLeaders.java b/Mage.Server.Plugins/Mage.Deck.Constructed/src/mage/deck/TinyLeaders.java index b26b2a59605..0ae64e86e46 100644 --- a/Mage.Server.Plugins/Mage.Deck.Constructed/src/mage/deck/TinyLeaders.java +++ b/Mage.Server.Plugins/Mage.Deck.Constructed/src/mage/deck/TinyLeaders.java @@ -82,6 +82,16 @@ public class TinyLeaders extends Constructed { super(name); } + @Override + public int getDeckMinSize() { + return 49; // commander gives from deck name + } + + @Override + public int getSideboardMinSize() { + return 0; + } + /** * @param deck * @return - True if deck is valid @@ -90,8 +100,8 @@ public class TinyLeaders extends Constructed { public boolean validate(Deck deck) { boolean valid = true; - if (deck.getCards().size() != 49) { - invalid.put("Deck", "Must contain 49 cards: has " + deck.getCards().size() + " cards"); + if (deck.getCards().size() != getDeckMinSize()) { + invalid.put("Deck", "Must contain " + getDeckMinSize() + " cards: has " + deck.getCards().size() + " cards"); valid = false; } diff --git a/Mage.Server.Plugins/Mage.Deck.Limited/src/mage/deck/Limited.java b/Mage.Server.Plugins/Mage.Deck.Limited/src/mage/deck/Limited.java index 727425721e3..30d32964e01 100644 --- a/Mage.Server.Plugins/Mage.Deck.Limited/src/mage/deck/Limited.java +++ b/Mage.Server.Plugins/Mage.Deck.Limited/src/mage/deck/Limited.java @@ -1,12 +1,9 @@ - - package mage.deck; import mage.cards.decks.Deck; import mage.cards.decks.DeckValidator; /** - * * @author BetaSteward_at_googlemail.com */ public class Limited extends DeckValidator { @@ -15,12 +12,22 @@ public class Limited extends DeckValidator { super("Limited"); } + @Override + public int getDeckMinSize() { + return 40; + } + + @Override + public int getSideboardMinSize() { + return 0; + } + @Override public boolean validate(Deck deck) { - boolean valid = true; + boolean valid = true; //20091005 - 100.2b - if (deck.getCards().size() < 40) { - invalid.put("Deck", "Must contain at least 40 cards: has only " + deck.getCards().size() + " cards"); + if (deck.getCards().size() < getDeckMinSize()) { + invalid.put("Deck", "Must contain at least " + getDeckMinSize() + " cards: has only " + deck.getCards().size() + " cards"); valid = false; } diff --git a/Mage.Server.Plugins/Mage.Player.AI/src/main/java/mage/player/ai/ComputerPlayer.java b/Mage.Server.Plugins/Mage.Player.AI/src/main/java/mage/player/ai/ComputerPlayer.java index 5015fcf7030..cbb0be94855 100644 --- a/Mage.Server.Plugins/Mage.Player.AI/src/main/java/mage/player/ai/ComputerPlayer.java +++ b/Mage.Server.Plugins/Mage.Player.AI/src/main/java/mage/player/ai/ComputerPlayer.java @@ -17,6 +17,8 @@ import mage.cards.Card; import mage.cards.Cards; import mage.cards.CardsImpl; import mage.cards.decks.Deck; +import mage.cards.decks.DeckValidator; +import mage.cards.decks.DeckValidatorFactory; import mage.cards.repository.CardCriteria; import mage.cards.repository.CardInfo; import mage.cards.repository.CardRepository; @@ -200,7 +202,7 @@ public class ComputerPlayer extends PlayerImpl implements Player { } } for (Permanent permanent : targets) { - if (((TargetPermanent) target).canTarget(abilityControllerId, permanent.getId(), null, game) && !target.getTargets().contains(permanent.getId())) { + if (target.canTarget(abilityControllerId, permanent.getId(), null, game) && !target.getTargets().contains(permanent.getId())) { // stop to add targets if not needed and outcome is no advantage for AI player if (target.getNumberOfTargets() == target.getTargets().size()) { if (outcome.isGood() && hasOpponent(permanent.getControllerId(), game)) { @@ -487,7 +489,7 @@ public class ComputerPlayer extends PlayerImpl implements Player { Collections.reverse(targets); } for (Permanent permanent : targets) { - if (((TargetControlledPermanent) target).canTarget(abilityControllerId, permanent.getId(), source, game)) { + if (target.canTarget(abilityControllerId, permanent.getId(), source, game)) { target.addTarget(permanent.getId(), source, game); if (target.getNumberOfTargets() <= target.getTargets().size() && (!outcome.isGood() || target.getMaxNumberOfTargets() <= target.getTargets().size())) { return true; @@ -516,7 +518,7 @@ public class ComputerPlayer extends PlayerImpl implements Player { targets = game.getBattlefield().getActivePermanents(t.getFilter(), playerId, game); } for (Permanent permanent : targets) { - if (((TargetPermanent) target).canTarget(abilityControllerId, permanent.getId(), source, game)) { + if (target.canTarget(abilityControllerId, permanent.getId(), source, game)) { target.addTarget(permanent.getId(), source, game); if (!outcomeTargets || target.getMaxNumberOfTargets() <= target.getTargets().size()) { return true; @@ -740,7 +742,7 @@ public class ComputerPlayer extends PlayerImpl implements Player { outcomeTargets = false; } for (Permanent permanent : targets) { - if (((TargetSpellOrPermanent) target).canTarget(abilityControllerId, permanent.getId(), source, game)) { + if (target.canTarget(abilityControllerId, permanent.getId(), source, game)) { target.addTarget(permanent.getId(), source, game); if (!outcomeTargets || target.getMaxNumberOfTargets() <= target.getTargets().size()) { return true; @@ -750,7 +752,7 @@ public class ComputerPlayer extends PlayerImpl implements Player { if (!game.getStack().isEmpty()) { for (StackObject stackObject : game.getStack()) { if (stackObject instanceof Spell && source != null && !source.getId().equals(stackObject.getStackAbility().getId())) { - if (((TargetSpellOrPermanent) target).getFilter().match(stackObject, game)) { + if (target.getFilter().match(stackObject, game)) { return tryAddTarget(target, stackObject.getId(), source, game); } } @@ -812,7 +814,7 @@ public class ComputerPlayer extends PlayerImpl implements Player { if (target.getOriginalTarget() instanceof TargetCardInExile) { List cards = new ArrayList<>(); - for (UUID uuid : ((TargetCardInExile) target).possibleTargets(source.getSourceId(), source.getControllerId(), game)) { + for (UUID uuid : target.possibleTargets(source.getSourceId(), source.getControllerId(), game)) { Card card = game.getCard(uuid); if (card != null) { cards.add(card); @@ -829,7 +831,7 @@ public class ComputerPlayer extends PlayerImpl implements Player { } if (target.getOriginalTarget() instanceof TargetActivatedAbility) { List stackObjects = new ArrayList<>(); - for (UUID uuid : ((TargetActivatedAbility) target).possibleTargets(source.getSourceId(), source.getControllerId(), game)) { + for (UUID uuid : target.possibleTargets(source.getSourceId(), source.getControllerId(), game)) { StackObject stackObject = game.getStack().getStackObject(uuid); if (stackObject != null) { stackObjects.add(stackObject); @@ -1358,9 +1360,7 @@ public class ComputerPlayer extends PlayerImpl implements Player { } // pay phyrexian life costs if (cost instanceof PhyrexianManaCost) { - if (cost.pay(null, game, null, playerId, false, null) || permittingObject != null) { - return true; - } + return cost.pay(null, game, null, playerId, false, null) || permittingObject != null; } return false; } @@ -1828,22 +1828,22 @@ public class ComputerPlayer extends PlayerImpl implements Player { } } - public static Deck buildDeck(List cardPool, final List colors) { - return buildDeck(cardPool, colors, false); + public static Deck buildDeck(int deckMinSize, List cardPool, final List colors) { + return buildDeck(deckMinSize, cardPool, colors, false); } - public static Deck buildDeck(List cardPool, final List colors, boolean onlyBasicLands) { + public static Deck buildDeck(int deckMinSize, List cardPool, final List colors, boolean onlyBasicLands) { if (onlyBasicLands) { - return buildDeckWithOnlyBasicLands(cardPool); + return buildDeckWithOnlyBasicLands(deckMinSize, cardPool); } else { - return buildDeckWithNormalCards(cardPool, colors); + return buildDeckWithNormalCards(deckMinSize, cardPool, colors); } } - public static Deck buildDeckWithOnlyBasicLands(List cardPool) { + public static Deck buildDeckWithOnlyBasicLands(int deckMinSize, List cardPool) { // random cards from card pool Deck deck = new Deck(); - final int DECK_SIZE = 40; + final int DECK_SIZE = deckMinSize != 0 ? deckMinSize : 40; List sortedCards = new ArrayList<>(cardPool); if (sortedCards.size() > 0) { @@ -1857,11 +1857,11 @@ public class ComputerPlayer extends PlayerImpl implements Player { } } - public static Deck buildDeckWithNormalCards(List cardPool, final List colors) { + public static Deck buildDeckWithNormalCards(int deckMinSize, List cardPool, final List colors) { // top 23 cards plus basic lands until 40 deck size Deck deck = new Deck(); - final int DECK_SIZE = 40; - final int DECK_CARDS_COUNT = 23; + final int DECK_SIZE = deckMinSize != 0 ? deckMinSize : 40; + final int DECK_CARDS_COUNT = Math.floorDiv(deckMinSize * 23, 40); // 23 from 40 final int DECK_LANDS_COUNT = DECK_SIZE - DECK_CARDS_COUNT; // sort card pool by top score @@ -1946,15 +1946,17 @@ public class ComputerPlayer extends PlayerImpl implements Player { @Override public void construct(Tournament tournament, Deck deck) { - if (deck != null && deck.getCards().size() < 40 && !deck.getSideboard().isEmpty()) { - //pick the top 23 cards + DeckValidator deckValidator = DeckValidatorFactory.instance.createDeckValidator(tournament.getOptions().getMatchOptions().getDeckType()); + int deckMinSize = deckValidator != null ? deckValidator.getDeckMinSize() : 0; + + if (deck != null && deck.getCards().size() < deckMinSize && !deck.getSideboard().isEmpty()) { if (chosenColors == null) { for (Card card : deck.getSideboard()) { rememberPick(card, RateCard.rateCard(card, null)); } chosenColors = chooseDeckColorsIfPossible(); } - deck = buildDeck(new ArrayList<>(deck.getSideboard()), chosenColors); + deck = buildDeck(deckMinSize, new ArrayList<>(deck.getSideboard()), chosenColors); } tournament.submitDeck(playerId, deck); } @@ -2430,21 +2432,21 @@ public class ComputerPlayer extends PlayerImpl implements Player { private boolean setTargetPlayer(Outcome outcome, Target target, Ability source, UUID sourceId, UUID abilityControllerId, UUID randomOpponentId, Game game) { if (target.getOriginalTarget() instanceof TargetOpponent) { if (source == null) { - if (((TargetOpponent) target).canTarget(randomOpponentId, game)) { + if (target.canTarget(randomOpponentId, game)) { target.add(randomOpponentId, game); return true; } - } else if (((TargetOpponent) target).canTarget(randomOpponentId, source, game)) { + } else if (target.canTarget(randomOpponentId, source, game)) { target.add(randomOpponentId, game); return true; } for (UUID currentId : game.getOpponents(abilityControllerId)) { if (source == null) { - if (((TargetOpponent) target).canTarget(currentId, game)) { + if (target.canTarget(currentId, game)) { target.add(currentId, game); return true; } - } else if (((TargetOpponent) target).canTarget(currentId, source, game)) { + } else if (target.canTarget(currentId, source, game)) { target.add(currentId, game); return true; } diff --git a/Mage.Server/src/main/java/mage/server/MageServerImpl.java b/Mage.Server/src/main/java/mage/server/MageServerImpl.java index 83abdafa5b6..f36fc7f5e1f 100644 --- a/Mage.Server/src/main/java/mage/server/MageServerImpl.java +++ b/Mage.Server/src/main/java/mage/server/MageServerImpl.java @@ -2,6 +2,7 @@ package mage.server; import mage.MageException; import mage.cards.decks.DeckCardLists; +import mage.cards.decks.DeckValidatorFactory; import mage.cards.repository.CardInfo; import mage.cards.repository.CardRepository; import mage.cards.repository.ExpansionInfo; @@ -142,7 +143,7 @@ public class MageServerImpl implements MageServer { return SessionManager.instance.connectUser(sessionId, userName, password, userIdStr); } catch (MageException ex) { if (ex instanceof MageVersionException) { - throw (MageVersionException) ex; + throw ex; } handleException(ex); } @@ -268,7 +269,7 @@ public class MageServerImpl implements MageServer { } @Override - public boolean joinTable(final String sessionId, final UUID roomId, final UUID tableId, final String name, final PlayerType playerType, final int skill, final DeckCardLists deckList, final String password) throws MageException, GameException { + public boolean joinTable(final String sessionId, final UUID roomId, final UUID tableId, final String name, final PlayerType playerType, final int skill, final DeckCardLists deckList, final String password) throws MageException { return executeWithResult("joinTable", sessionId, new ActionWithBooleanResult() { @Override public Boolean execute() throws MageException { @@ -293,7 +294,7 @@ public class MageServerImpl implements MageServer { } @Override - public boolean joinTournamentTable(final String sessionId, final UUID roomId, final UUID tableId, final String name, final PlayerType playerType, final int skill, final DeckCardLists deckList, final String password) throws MageException, GameException { + public boolean joinTournamentTable(final String sessionId, final UUID roomId, final UUID tableId, final String name, final PlayerType playerType, final int skill, final DeckCardLists deckList, final String password) throws MageException { return executeWithResult("joinTournamentTable", sessionId, new ActionWithBooleanResult() { @Override public Boolean execute() throws MageException { @@ -321,7 +322,7 @@ public class MageServerImpl implements MageServer { } @Override - public boolean submitDeck(final String sessionId, final UUID tableId, final DeckCardLists deckList) throws MageException, GameException { + public boolean submitDeck(final String sessionId, final UUID tableId, final DeckCardLists deckList) throws MageException { return executeWithResult("submitDeck", sessionId, new ActionWithBooleanResult() { @Override public Boolean execute() throws MageException { @@ -339,7 +340,7 @@ public class MageServerImpl implements MageServer { } @Override - public void updateDeck(final String sessionId, final UUID tableId, final DeckCardLists deckList) throws MageException, GameException { + public void updateDeck(final String sessionId, final UUID tableId, final DeckCardLists deckList) throws MageException { execute("updateDeck", sessionId, () -> { Optional session = SessionManager.instance.getSession(sessionId); if (!session.isPresent()) { diff --git a/Mage.Server/src/main/java/mage/server/Main.java b/Mage.Server/src/main/java/mage/server/Main.java index 53e15996977..877e0f8e09d 100644 --- a/Mage.Server/src/main/java/mage/server/Main.java +++ b/Mage.Server/src/main/java/mage/server/Main.java @@ -2,6 +2,7 @@ package mage.server; import mage.cards.ExpansionSet; import mage.cards.Sets; +import mage.cards.decks.DeckValidatorFactory; import mage.cards.repository.CardScanner; import mage.cards.repository.PluginClassloaderRegistery; import mage.cards.repository.RepositoryUtil; @@ -11,7 +12,6 @@ import mage.game.tournament.TournamentType; import mage.interfaces.MageServer; import mage.remote.Connection; import mage.server.draft.CubeFactory; -import mage.server.game.DeckValidatorFactory; import mage.server.game.GameFactory; import mage.server.game.PlayerFactory; import mage.server.record.UserStatsRepository; diff --git a/Mage.Server/src/main/java/mage/server/TableController.java b/Mage.Server/src/main/java/mage/server/TableController.java index 914bdf3a53c..d7edea75722 100644 --- a/Mage.Server/src/main/java/mage/server/TableController.java +++ b/Mage.Server/src/main/java/mage/server/TableController.java @@ -1,17 +1,9 @@ package mage.server; -import java.util.Locale; -import java.util.Map; -import java.util.Map.Entry; -import java.util.Optional; -import java.util.UUID; -import java.util.concurrent.ConcurrentHashMap; -import java.util.concurrent.ScheduledExecutorService; -import java.util.concurrent.ScheduledFuture; -import java.util.concurrent.TimeUnit; import mage.MageException; import mage.cards.decks.Deck; import mage.cards.decks.DeckCardLists; +import mage.cards.decks.DeckValidatorFactory; import mage.constants.RangeOfInfluence; import mage.constants.TableState; import mage.game.*; @@ -28,12 +20,10 @@ import mage.game.tournament.TournamentPlayer; import mage.players.Player; import mage.players.PlayerType; import mage.server.draft.DraftManager; -import mage.server.game.DeckValidatorFactory; import mage.server.game.GameFactory; import mage.server.game.GameManager; import mage.server.game.PlayerFactory; import mage.server.record.TableRecorderImpl; -import mage.server.tournament.TournamentController; import mage.server.tournament.TournamentFactory; import mage.server.tournament.TournamentManager; import mage.server.util.ConfigSettings; @@ -42,6 +32,16 @@ import mage.server.util.ThreadExecutor; import mage.view.ChatMessage; import org.apache.log4j.Logger; +import java.util.Locale; +import java.util.Map; +import java.util.Map.Entry; +import java.util.Optional; +import java.util.UUID; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.ScheduledExecutorService; +import java.util.concurrent.ScheduledFuture; +import java.util.concurrent.TimeUnit; + /** * @author BetaSteward_at_googlemail.com */ @@ -876,7 +876,7 @@ public class TableController { private void autoSideboard() { for (MatchPlayer player : match.getPlayers()) { if (!player.isDoneSideboarding()) { - match.submitDeck(player.getPlayer().getId(), player.generateDeck()); + match.submitDeck(player.getPlayer().getId(), player.generateDeck(table.getValidator())); } } } @@ -927,9 +927,9 @@ public class TableController { public boolean isTournamentStillValid() { if (table.getTournament() != null) { if (table.getState() != TableState.WAITING && table.getState() != TableState.READY_TO_START && table.getState() != TableState.STARTING) { - return TournamentManager.instance.getTournamentController(table.getTournament().getId()) - .map(tc -> tc.isTournamentStillValid(table.getState())) - .orElse(false); + return TournamentManager.instance.getTournamentController(table.getTournament().getId()) + .map(tc -> tc.isTournamentStillValid(table.getState())) + .orElse(false); } else { // check if table creator is still a valid user, if not removeUserFromAllTablesAndChat table diff --git a/Mage.Tests/src/test/java/org/mage/test/serverside/PlayGameTest.java b/Mage.Tests/src/test/java/org/mage/test/serverside/PlayGameTest.java index 5f498e437da..77f8e4aaad8 100644 --- a/Mage.Tests/src/test/java/org/mage/test/serverside/PlayGameTest.java +++ b/Mage.Tests/src/test/java/org/mage/test/serverside/PlayGameTest.java @@ -31,6 +31,7 @@ import java.util.Locale; public class PlayGameTest extends MageTestBase { private static final List colorChoices = new ArrayList<>(Arrays.asList("bu", "bg", "br", "bw", "ug", "ur", "uw", "gr", "gw", "rw", "bur", "buw", "bug", "brg", "brw", "bgw", "wur", "wug", "wrg", "rgu")); + private static final int DECK_SIZE = 40; @Ignore @Test @@ -42,8 +43,8 @@ public class PlayGameTest extends MageTestBase { // Deck deck = Deck.load(Sets.loadDeck("RB Aggro.dck")); Deck deck = generateRandomDeck(); - if (deck.getCards().size() < 40) { - throw new IllegalArgumentException("Couldn't load deck, deck size=" + deck.getCards().size()); + if (deck.getCards().size() < DECK_SIZE) { + throw new IllegalArgumentException("Couldn't load deck, deck size = " + deck.getCards().size() + ", but must be " + DECK_SIZE); } game.addPlayer(computerA, deck); game.loadCards(deck.getCards(), computerA.getId()); @@ -52,8 +53,8 @@ public class PlayGameTest extends MageTestBase { // Player playerB = createPlayer("ComputerB", "Computer - mad"); // Deck deck2 = Deck.load(Sets.loadDeck("RB Aggro.dck")); Deck deck2 = generateRandomDeck(); - if (deck2.getCards().size() < 40) { - throw new IllegalArgumentException("Couldn't load deck, deck size=" + deck2.getCards().size()); + if (deck2.getCards().size() < DECK_SIZE) { + throw new IllegalArgumentException("Couldn't load deck, deck size = " + deck2.getCards().size() + ", but must be " + DECK_SIZE); } game.addPlayer(computerB, deck2); game.loadCards(deck2.getCards(), computerB.getId()); @@ -89,6 +90,6 @@ public class PlayGameTest extends MageTestBase { allowedColors.add(ColoredManaSymbol.lookup(c)); } List cardPool = Sets.generateRandomCardPool(45, allowedColors); - return ComputerPlayer.buildDeck(cardPool, allowedColors); + return ComputerPlayer.buildDeck(DECK_SIZE, cardPool, allowedColors); } } diff --git a/Mage.Tests/src/test/java/org/mage/test/serverside/TestPlayRandomGame.java b/Mage.Tests/src/test/java/org/mage/test/serverside/TestPlayRandomGame.java index 5d30022f1e7..3d51dff3bb3 100644 --- a/Mage.Tests/src/test/java/org/mage/test/serverside/TestPlayRandomGame.java +++ b/Mage.Tests/src/test/java/org/mage/test/serverside/TestPlayRandomGame.java @@ -30,6 +30,7 @@ import java.util.Locale; public class TestPlayRandomGame extends MageTestBase { private static final List colorChoices = new ArrayList<>(Arrays.asList("bu", "bg", "br", "bw", "ug", "ur", "uw", "gr", "gw", "rw", "bur", "buw", "bug", "brg", "brw", "bgw", "wur", "wug", "wrg", "rgu")); + private static final int DECK_SIZE = 40; @Test @Ignore @@ -46,16 +47,16 @@ public class TestPlayRandomGame extends MageTestBase { Player computerA = createRandomPlayer("ComputerA"); Deck deck = generateRandomDeck(); - if (deck.getCards().size() < 40) { - throw new IllegalArgumentException("Couldn't load deck, deck size=" + deck.getCards().size()); + if (deck.getCards().size() < DECK_SIZE) { + throw new IllegalArgumentException("Couldn't load deck, deck size = " + deck.getCards().size() + ", but must be " + DECK_SIZE); } game.addPlayer(computerA, deck); game.loadCards(deck.getCards(), computerA.getId()); Player computerB = createRandomPlayer("ComputerB"); Deck deck2 = generateRandomDeck(); - if (deck2.getCards().size() < 40) { - throw new IllegalArgumentException("Couldn't load deck, deck size=" + deck2.getCards().size()); + if (deck2.getCards().size() < DECK_SIZE) { + throw new IllegalArgumentException("Couldn't load deck, deck size=" + deck2.getCards().size() + ", but must be " + DECK_SIZE); } game.addPlayer(computerB, deck2); game.loadCards(deck2.getCards(), computerB.getId()); @@ -80,6 +81,6 @@ public class TestPlayRandomGame extends MageTestBase { allowedColors.add(ColoredManaSymbol.lookup(c)); } List cardPool = Sets.generateRandomCardPool(45, allowedColors); - return ComputerPlayer.buildDeck(cardPool, allowedColors); + return ComputerPlayer.buildDeck(DECK_SIZE, cardPool, allowedColors); } } diff --git a/Mage.Tests/src/test/java/org/mage/test/utils/DeckTestUtils.java b/Mage.Tests/src/test/java/org/mage/test/utils/DeckTestUtils.java index 626f9f2edb4..0df089ff4f1 100644 --- a/Mage.Tests/src/test/java/org/mage/test/utils/DeckTestUtils.java +++ b/Mage.Tests/src/test/java/org/mage/test/utils/DeckTestUtils.java @@ -18,6 +18,8 @@ import java.util.List; */ public class DeckTestUtils { + private static final int DECK_SIZE = 40; + public static Deck buildRandomDeck(String colors, boolean onlyBasicLands) { return buildRandomDeck(colors, onlyBasicLands, ""); } @@ -41,7 +43,7 @@ public class DeckTestUtils { } List cardPool = Sets.generateRandomCardPool(45, allowedColors, onlyBasicLands, allowedList); - return ComputerPlayer.buildDeck(cardPool, allowedColors, onlyBasicLands); + return ComputerPlayer.buildDeck(DECK_SIZE, cardPool, allowedColors, onlyBasicLands); } public static DeckCardLists buildRandomDeckAndInitCards(String colors, boolean onlyBasicLands) { diff --git a/Mage/src/main/java/mage/cards/decks/Constructed.java b/Mage/src/main/java/mage/cards/decks/Constructed.java index 15a5b9bcb1b..aaa95e435bb 100644 --- a/Mage/src/main/java/mage/cards/decks/Constructed.java +++ b/Mage/src/main/java/mage/cards/decks/Constructed.java @@ -1,4 +1,3 @@ - package mage.cards.decks; import mage.cards.Card; @@ -41,12 +40,22 @@ public class Constructed extends DeckValidator { return setCodes; } + @Override + public int getDeckMinSize() { + return 60; + } + + @Override + public int getSideboardMinSize() { + return 0; + } + @Override public boolean validate(Deck deck) { boolean valid = true; //20091005 - 100.2a - if (deck.getCards().size() < 60) { - invalid.put("Deck", "Must contain at least 60 cards: has only " + deck.getCards().size() + " cards"); + if (deck.getCards().size() < getDeckMinSize()) { + invalid.put("Deck", "Must contain at least " + getDeckMinSize() + " cards: has only " + deck.getCards().size() + " cards"); valid = false; } //20130713 - 100.4a diff --git a/Mage/src/main/java/mage/cards/decks/DeckValidator.java b/Mage/src/main/java/mage/cards/decks/DeckValidator.java index d307890508d..506fd6310ba 100644 --- a/Mage/src/main/java/mage/cards/decks/DeckValidator.java +++ b/Mage/src/main/java/mage/cards/decks/DeckValidator.java @@ -1,14 +1,13 @@ - package mage.cards.decks; +import mage.cards.Card; + import java.io.Serializable; import java.util.Collection; import java.util.HashMap; import java.util.Map; -import mage.cards.Card; /** - * * @author BetaSteward_at_googlemail.com */ public abstract class DeckValidator implements Serializable { @@ -32,11 +31,10 @@ public abstract class DeckValidator implements Serializable { } protected void countCards(Map counts, Collection cards) { - for (Card card: cards) { + for (Card card : cards) { if (counts.containsKey(card.getName())) { counts.put(card.getName(), counts.get(card.getName()) + 1); - } - else { + } else { counts.put(card.getName(), 1); } } @@ -45,4 +43,8 @@ public abstract class DeckValidator implements Serializable { public int getEdhPowerLevel(Deck deck) { return 0; } + + public abstract int getDeckMinSize(); + + public abstract int getSideboardMinSize(); } diff --git a/Mage.Server/src/main/java/mage/server/game/DeckValidatorFactory.java b/Mage/src/main/java/mage/cards/decks/DeckValidatorFactory.java similarity index 86% rename from Mage.Server/src/main/java/mage/server/game/DeckValidatorFactory.java rename to Mage/src/main/java/mage/cards/decks/DeckValidatorFactory.java index bdaabc92a5d..b65ec5925bd 100644 --- a/Mage.Server/src/main/java/mage/server/game/DeckValidatorFactory.java +++ b/Mage/src/main/java/mage/cards/decks/DeckValidatorFactory.java @@ -1,8 +1,5 @@ +package mage.cards.decks; - -package mage.server.game; - -import mage.cards.decks.DeckValidator; import org.apache.log4j.Logger; import java.lang.reflect.Constructor; @@ -11,7 +8,6 @@ import java.util.Map; import java.util.Set; /** - * * @author BetaSteward_at_googlemail.com */ public enum DeckValidatorFactory { @@ -21,16 +17,12 @@ public enum DeckValidatorFactory { private final Map deckTypes = new LinkedHashMap<>(); - - - private DeckValidatorFactory() {} - public DeckValidator createDeckValidator(String deckType) { DeckValidator validator; try { Constructor con = deckTypes.get(deckType).getConstructor(); - validator = (DeckValidator)con.newInstance(); + validator = (DeckValidator) con.newInstance(); } catch (Exception ex) { logger.fatal("DeckValidatorFactory error", ex); return null; diff --git a/Mage/src/main/java/mage/game/match/MatchImpl.java b/Mage/src/main/java/mage/game/match/MatchImpl.java index ffeaabcc32a..668ef676705 100644 --- a/Mage/src/main/java/mage/game/match/MatchImpl.java +++ b/Mage/src/main/java/mage/game/match/MatchImpl.java @@ -389,7 +389,9 @@ public abstract class MatchImpl implements Match { // Check if the cards included in the deck are the same as in the original deck validDeck = (player.getDeck().getDeckCompleteHashCode() == deck.getDeckCompleteHashCode()); if (validDeck == false) { - deck.getCards().clear(); // Clear the deck so the player cheating looses the game + // clear the deck so the player cheating looses the game + deck.getCards().clear(); + deck.getSideboard().clear(); } player.updateDeck(deck); } diff --git a/Mage/src/main/java/mage/game/match/MatchPlayer.java b/Mage/src/main/java/mage/game/match/MatchPlayer.java index 5d1b9ca18e1..e7b876ceb64 100644 --- a/Mage/src/main/java/mage/game/match/MatchPlayer.java +++ b/Mage/src/main/java/mage/game/match/MatchPlayer.java @@ -1,13 +1,13 @@ - package mage.game.match; -import java.io.Serializable; import mage.cards.Card; import mage.cards.decks.Deck; +import mage.cards.decks.DeckValidator; import mage.players.Player; +import java.io.Serializable; + /** - * * @author BetaSteward_at_googlemail.com */ public class MatchPlayer implements Serializable { @@ -78,9 +78,9 @@ public class MatchPlayer implements Serializable { this.deck = deck; } - public Deck generateDeck() { - //TODO: improve this - while (deck.getCards().size() < 40 && !deck.getSideboard().isEmpty()) { + public Deck generateDeck(DeckValidator deckValidator) { + // auto complete deck + while (deck.getCards().size() < deckValidator.getDeckMinSize() && !deck.getSideboard().isEmpty()) { Card card = deck.getSideboard().iterator().next(); deck.getCards().add(card); deck.getSideboard().remove(card); diff --git a/Mage/src/main/java/mage/game/tournament/TournamentPlayer.java b/Mage/src/main/java/mage/game/tournament/TournamentPlayer.java index 6072015d4d9..18b063822b9 100644 --- a/Mage/src/main/java/mage/game/tournament/TournamentPlayer.java +++ b/Mage/src/main/java/mage/game/tournament/TournamentPlayer.java @@ -1,7 +1,5 @@ - package mage.game.tournament; -import java.util.Set; import mage.cards.decks.Deck; import mage.constants.TournamentPlayerState; import mage.game.result.ResultProtos.TourneyPlayerProto; @@ -10,8 +8,9 @@ import mage.players.Player; import mage.players.PlayerType; import mage.util.TournamentUtil; +import java.util.Set; + /** - * * @author BetaSteward_at_googlemail.com */ public class TournamentPlayer { @@ -93,7 +92,9 @@ public class TournamentPlayer { // Check if the cards included in the deck are the same as in the original deck boolean validDeck = (getDeck().getDeckCompleteHashCode() == deck.getDeckCompleteHashCode()); if (validDeck == false) { - deck.getCards().clear(); // Clear the deck so the player cheating looses the game + // Clear the deck so the player cheating looses the game + deck.getCards().clear(); + deck.getSideboard().clear(); } this.deck = deck; return validDeck; @@ -177,7 +178,6 @@ public class TournamentPlayer { /** * Free resources no longer needed if tournament has ended - * */ public void cleanUpOnTournamentEnd() { this.deck = null;