forked from External/mage
* 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:
parent
3bdf2a7957
commit
0fb7cf8317
7 changed files with 95 additions and 15 deletions
|
|
@ -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;
|
||||
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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/>");
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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());
|
||||
}
|
||||
|
|
|
|||
45
Mage/src/mage/util/DeckUtil.java
Normal file
45
Mage/src/mage/util/DeckUtil.java
Normal 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;
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue