* Added a deck hash tag that's shown at the start of the game log to be able to identify a deck.

This commit is contained in:
LevelX2 2015-04-11 00:47:54 +02:00
parent 3bdf2a7957
commit 0fb7cf8317
7 changed files with 95 additions and 15 deletions

View file

@ -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;
/**

View file

@ -44,8 +44,8 @@ public class DeckBuilder {
deckSize = deckCardSize;
deck = new Deck();
final Collection<MageScoredCard> remainingCards = new ArrayList<MageScoredCard>();
Set<String> names = new HashSet<String>();
final Collection<MageScoredCard> remainingCards = new ArrayList<>();
Set<String> 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<ColoredManaSymbol> allowedColors, List<String> setsToUse, List<Card> landCardPool, RateCallback callback) {
// Calculate statistics per color.
final Map<String, Integer> colorCount = new HashMap<String, Integer>();
final Map<String, Integer> 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<String, Integer> colorSource = new HashMap<String, Integer>();
final Map<String, Integer> 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<ColoredManaSymbol> allowedColors) {
int converted = card.getManaCost().convertedManaCost();
final Map<String, Integer> singleCount = new HashMap<String, Integer>();
final Map<String, Integer> singleCount = new HashMap<>();
int maxSingleCount = 0;
int multicolor = 0;
Set<String> colors = new HashSet<String>();
Set<String> 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);

View file

@ -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<Card> cards = new LinkedHashSet<>();
private final Set<Card> 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<String> 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<String> 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<Card> getSideboard() {
return sideboard;
}
public long getDeckHashCode() {
return deckHashCode;
}
public void setDeckHashCode(long deckHashCode) {
this.deckHashCode = deckHashCode;
}
}

View file

@ -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("<br/>");
sb.append("DeckHash: ").append(mp.getDeck().getDeckHashCode()).append("<br/>");
}
if (getDraws() > 0) {
sb.append(" Draws: ").append(getDraws()).append("<br/>");

View file

@ -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;
}

View file

@ -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());
}

View file

@ -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;
}
}