From 0fb7cf8317c587ef7a2f173fd3de3ef7e6388994 Mon Sep 17 00:00:00 2001 From: LevelX2 Date: Sat, 11 Apr 2015 00:47:54 +0200 Subject: [PATCH] * Added a deck hash tag that's shown at the start of the game log to be able to identify a deck. --- Mage.Common/src/mage/utils/CardUtil.java | 2 +- Mage.Common/src/mage/utils/DeckBuilder.java | 18 ++++----- Mage/src/mage/cards/decks/Deck.java | 34 +++++++++++++++- Mage/src/mage/game/match/MatchImpl.java | 2 + Mage/src/mage/game/match/MatchPlayer.java | 1 + Mage/src/mage/players/PlayerImpl.java | 8 ++-- Mage/src/mage/util/DeckUtil.java | 45 +++++++++++++++++++++ 7 files changed, 95 insertions(+), 15 deletions(-) create mode 100644 Mage/src/mage/util/DeckUtil.java diff --git a/Mage.Common/src/mage/utils/CardUtil.java b/Mage.Common/src/mage/utils/CardUtil.java index 28a075b1d80..fb3331ed4be 100644 --- a/Mage.Common/src/mage/utils/CardUtil.java +++ b/Mage.Common/src/mage/utils/CardUtil.java @@ -1,8 +1,8 @@ package mage.utils; -import mage.constants.CardType; import mage.cards.Card; import mage.cards.MagePermanent; +import mage.constants.CardType; import mage.view.CardView; /** diff --git a/Mage.Common/src/mage/utils/DeckBuilder.java b/Mage.Common/src/mage/utils/DeckBuilder.java index 7ae206b9537..1cdde5cd6a6 100644 --- a/Mage.Common/src/mage/utils/DeckBuilder.java +++ b/Mage.Common/src/mage/utils/DeckBuilder.java @@ -44,8 +44,8 @@ public class DeckBuilder { deckSize = deckCardSize; deck = new Deck(); - final Collection remainingCards = new ArrayList(); - Set names = new HashSet(); + final Collection remainingCards = new ArrayList<>(); + Set names = new HashSet<>(); for (final Card card : spellCardPool) { if (names.contains(card.getName())) { continue; @@ -155,7 +155,7 @@ public class DeckBuilder { private static void addLandsToDeck(List allowedColors, List setsToUse, List landCardPool, RateCallback callback) { // Calculate statistics per color. - final Map colorCount = new HashMap(); + final Map colorCount = new HashMap<>(); for (final Card card : deck.getCards()) { for (String symbol : card.getManaCost().getSymbols()) { @@ -170,7 +170,7 @@ public class DeckBuilder { if (count > 0) { Integer typeCount = colorCount.get(symbol); if (typeCount == null) { - typeCount = new Integer(0); + typeCount = 0; } typeCount += 1; colorCount.put(symbol, typeCount); @@ -180,7 +180,7 @@ public class DeckBuilder { } // Add suitable non basic lands to deck in order of pack. - final Map colorSource = new HashMap(); + final Map colorSource = new HashMap<>(); for (final ColoredManaSymbol color : ColoredManaSymbol.values()) { colorSource.put(color.toString(), 0); } @@ -236,7 +236,7 @@ public class DeckBuilder { private static class MageScoredCard { private Card card; - private int score; + private final int score; private static final int SINGLE_PENALTY[] = {0, 1, 1, 3, 6, 9}; //private static final int DOUBLE_PENALTY[] = { 0, 0, 1, 2, 4, 6 }; @@ -266,10 +266,10 @@ public class DeckBuilder { private int getManaCostScore(Card card, List allowedColors) { int converted = card.getManaCost().convertedManaCost(); - final Map singleCount = new HashMap(); + final Map singleCount = new HashMap<>(); int maxSingleCount = 0; int multicolor = 0; - Set colors = new HashSet(); + Set colors = new HashSet<>(); for (String symbol : card.getManaCost().getSymbols()) { int count = 0; symbol = symbol.replace("{", "").replace("}", ""); @@ -289,7 +289,7 @@ public class DeckBuilder { } Integer typeCount = singleCount.get(symbol); if (typeCount == null) { - typeCount = new Integer(0); + typeCount = 0; } typeCount += 1; singleCount.put(symbol, typeCount); diff --git a/Mage/src/mage/cards/decks/Deck.java b/Mage/src/mage/cards/decks/Deck.java index f7655fd7953..74ea98b86f9 100644 --- a/Mage/src/mage/cards/decks/Deck.java +++ b/Mage/src/mage/cards/decks/Deck.java @@ -29,18 +29,25 @@ package mage.cards.decks; import java.io.Serializable; +import java.security.MessageDigest; +import java.security.NoSuchAlgorithmException; +import java.util.ArrayList; +import java.util.Collections; import java.util.LinkedHashSet; +import java.util.List; import java.util.Set; import mage.cards.Card; import mage.cards.repository.CardInfo; import mage.cards.repository.CardRepository; import mage.game.GameException; +import mage.util.DeckUtil; public class Deck implements Serializable { private String name; private final Set cards = new LinkedHashSet<>(); private final Set sideboard = new LinkedHashSet<>(); + private long deckHashCode = 0; public static Deck load(DeckCardLists deckCardLists) throws GameException { return Deck.load(deckCardLists, false); @@ -53,23 +60,39 @@ public class Deck implements Serializable { public static Deck load(DeckCardLists deckCardLists, boolean ignoreErrors, boolean mockCards) throws GameException { Deck deck = new Deck(); deck.setName(deckCardLists.getName()); + List deckCardNames = new ArrayList<>(); for (DeckCardInfo deckCardInfo: deckCardLists.getCards()) { Card card = createCard(deckCardInfo, mockCards); if (card != null) { deck.cards.add(card); + deckCardNames.add(card.getName()); } else if (!ignoreErrors) { throw createCardNotFoundGameException(deckCardInfo, deckCardLists.getName()); } } + List sbCardNames = new ArrayList<>(); for (DeckCardInfo deckCardInfo: deckCardLists.getSideboard()) { Card card = createCard(deckCardInfo, mockCards); if (card != null) { deck.sideboard.add(card); + sbCardNames.add(card.getName()); } else if (!ignoreErrors) { throw createCardNotFoundGameException(deckCardInfo, deckCardLists.getName()); } } - + Collections.sort(deckCardNames); + Collections.sort(sbCardNames); + String deckString = deckCardNames.toString() + sbCardNames.toString(); + deck.setDeckHashCode(DeckUtil.fixedHash(deckString)); +// try{ +// MessageDigest messageDigest = MessageDigest.getInstance("SHA-256"); +// messageDigest.update(deckString.getBytes()); +// String encryptedString = new String(messageDigest.digest()); +// deck.setDeckHashCode(encryptedString.hashCode()); +// } +// catch (NoSuchAlgorithmException e) { +// // nothing +// } return deck; } @@ -137,4 +160,13 @@ public class Deck implements Serializable { public Set getSideboard() { return sideboard; } + + public long getDeckHashCode() { + return deckHashCode; + } + + public void setDeckHashCode(long deckHashCode) { + this.deckHashCode = deckHashCode; + } + } diff --git a/Mage/src/mage/game/match/MatchImpl.java b/Mage/src/mage/game/match/MatchImpl.java index 118dea380fb..08077386748 100644 --- a/Mage/src/mage/game/match/MatchImpl.java +++ b/Mage/src/mage/game/match/MatchImpl.java @@ -400,6 +400,7 @@ public abstract class MatchImpl implements Match { if (player != null) { // make sure the deck name (needed for Tiny Leaders) won't get lost by sideboarding deck.setName(player.getDeck().getName()); + deck.setDeckHashCode(player.getDeck().getDeckHashCode()); player.submitDeck(deck); } synchronized (this) { @@ -425,6 +426,7 @@ public abstract class MatchImpl implements Match { sb.append(" QUITTED"); } sb.append("
"); + sb.append("DeckHash: ").append(mp.getDeck().getDeckHashCode()).append("
"); } if (getDraws() > 0) { sb.append(" Draws: ").append(getDraws()).append("
"); diff --git a/Mage/src/mage/game/match/MatchPlayer.java b/Mage/src/mage/game/match/MatchPlayer.java index c6adfc83edd..af956dcc747 100644 --- a/Mage/src/mage/game/match/MatchPlayer.java +++ b/Mage/src/mage/game/match/MatchPlayer.java @@ -90,6 +90,7 @@ public class MatchPlayer { if (this.deck != null) { // preserver deck name, important for Tiny Leaders format deck.setName(this.getDeck().getName()); + deck.setDeckHashCode(this.getDeck().getDeckHashCode()); } this.deck = deck; } diff --git a/Mage/src/mage/players/PlayerImpl.java b/Mage/src/mage/players/PlayerImpl.java index 3c14bb44e6c..d588c27cfb8 100644 --- a/Mage/src/mage/players/PlayerImpl.java +++ b/Mage/src/mage/players/PlayerImpl.java @@ -2783,13 +2783,13 @@ public abstract class PlayerImpl implements Player, Serializable { card = game.getCard(card.getId()); } if (!game.isSimulation()) { - StringBuilder sb = new StringBuilder(this.getName()).append(" puts ").append(withName ? card.getLogName() : "a face down card "); + StringBuilder sb = new StringBuilder(this.getName()).append(" puts ").append(withName ? card.getLogName() : "a face down card"); switch(fromZone) { case EXILED: - sb.append("from exile zone "); + sb.append(" from exile zone "); break; default: - sb.append(fromZone != null ? new StringBuilder("from ").append(fromZone.toString().toLowerCase(Locale.ENGLISH)).append(" ") : ""); + sb.append(fromZone != null ? new StringBuilder(" from ").append(fromZone.toString().toLowerCase(Locale.ENGLISH)).append(" ") : ""); break; } sb.append(card.getOwnerId().equals(this.getId()) ? "into his or her hand" : "into its owner's hand"); @@ -2927,7 +2927,7 @@ public abstract class PlayerImpl implements Player, Serializable { card = game.getCard(card.getId()); } game.informPlayers(new StringBuilder(this.getName()) - .append(" moves ").append(withName ? card.getLogName() : "a card face down ") + .append(" moves ").append(withName ? card.getLogName() : "a card face down").append(" ") .append(fromZone != null ? new StringBuilder("from ").append(fromZone.toString().toLowerCase(Locale.ENGLISH)).append(" ") : "") .append("to the exile zone").toString()); } diff --git a/Mage/src/mage/util/DeckUtil.java b/Mage/src/mage/util/DeckUtil.java new file mode 100644 index 00000000000..cf9b1ecb245 --- /dev/null +++ b/Mage/src/mage/util/DeckUtil.java @@ -0,0 +1,45 @@ +/* + * Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of BetaSteward_at_googlemail.com. + */ +package mage.util; + +/** + * + * @author LevelX2 + */ +public class DeckUtil { + + public static long fixedHash(String string) { + long h = 1125899906842597L; // prime + int len = string.length(); + + for (int i = 0; i < len; i++) { + h = 31 * h + string.charAt(i); + } + return h; + } +}