Xitax's deck convertor integrated into Forge - applies on load to decks where no card has explicitly defined set.

This commit is contained in:
Maxmtg
2014-01-25 19:10:26 +00:00
parent 11c205f0c9
commit 1986df1961
5 changed files with 106 additions and 44 deletions

View File

@@ -37,6 +37,7 @@ import com.google.common.collect.Lists;
import com.google.common.collect.Multimaps; import com.google.common.collect.Multimaps;
import forge.card.CardEdition.CardInSet; import forge.card.CardEdition.CardInSet;
import forge.card.CardEdition.Type;
import forge.item.PaperCard; import forge.item.PaperCard;
import forge.util.Aggregates; import forge.util.Aggregates;
import forge.util.CollectionSuppliers; import forge.util.CollectionSuppliers;
@@ -46,6 +47,8 @@ import forge.util.TextUtil;
public final class CardDb implements ICardDatabase { public final class CardDb implements ICardDatabase {
public final static String foilSuffix = "+"; public final static String foilSuffix = "+";
public final static char NameSetSeparator = '|';
// need this to obtain cardReference by name+set+artindex // need this to obtain cardReference by name+set+artindex
private final ListMultimap<String, PaperCard> allCardsByName = Multimaps.newListMultimap(new TreeMap<String,Collection<PaperCard>>(String.CASE_INSENSITIVE_ORDER), CollectionSuppliers.<PaperCard>arrayLists()); private final ListMultimap<String, PaperCard> allCardsByName = Multimaps.newListMultimap(new TreeMap<String,Collection<PaperCard>>(String.CASE_INSENSITIVE_ORDER), CollectionSuppliers.<PaperCard>arrayLists());
private final Map<String, PaperCard> uniqueCardsByName = new TreeMap<String, PaperCard>(String.CASE_INSENSITIVE_ORDER); private final Map<String, PaperCard> uniqueCardsByName = new TreeMap<String, PaperCard>(String.CASE_INSENSITIVE_ORDER);
@@ -58,7 +61,9 @@ public final class CardDb implements ICardDatabase {
public enum SetPreference { public enum SetPreference {
Latest, Latest,
LatestCoreExp,
Earliest, Earliest,
EarliestCoreExp,
Random Random
} }
@@ -81,17 +86,23 @@ public final class CardDb implements ICardDatabase {
if( isFoil ) if( isFoil )
name = name.substring(0, name.length() - foilSuffix.length()); name = name.substring(0, name.length() - foilSuffix.length());
String[] nameParts = TextUtil.split(name, '|'); String[] nameParts = TextUtil.split(name, NameSetSeparator);
int setPos = nameParts.length >= 2 && !StringUtils.isNumeric(nameParts[1]) ? 1 : -1; int setPos = nameParts.length >= 2 && !StringUtils.isNumeric(nameParts[1]) ? 1 : -1;
int artPos = nameParts.length >= 2 && StringUtils.isNumeric(nameParts[1]) ? 1 : nameParts.length >= 3 && StringUtils.isNumeric(nameParts[2]) ? 2 : -1; int artPos = nameParts.length >= 2 && StringUtils.isNumeric(nameParts[1]) ? 1 : nameParts.length >= 3 && StringUtils.isNumeric(nameParts[2]) ? 2 : -1;
String cardName = nameParts[0];
if( cardName.endsWith(foilSuffix)) {
cardName = cardName.substring(0, cardName.length() - foilSuffix.length());
isFoil = true;
}
int artIndex = artPos > 0 ? Integer.parseInt(nameParts[artPos]) : -1; int artIndex = artPos > 0 ? Integer.parseInt(nameParts[artPos]) : -1;
String setName = setPos > 0 ? nameParts[setPos] : null; String setName = setPos > 0 ? nameParts[setPos] : null;
if( "???".equals(setName) ) if( "???".equals(setName) )
setName = null; setName = null;
return new CardRequest(nameParts[0], setName, artIndex, isFoil); return new CardRequest(cardName, setName, artIndex, isFoil);
} }
} }
@@ -174,7 +185,6 @@ public final class CardDb implements ICardDatabase {
return tryGetCard(request); return tryGetCard(request);
} }
private PaperCard tryGetCard(CardRequest request) { private PaperCard tryGetCard(CardRequest request) {
Collection<PaperCard> cards = allCardsByName.get(request.cardName); Collection<PaperCard> cards = allCardsByName.get(request.cardName);
if ( null == cards ) return null; if ( null == cards ) return null;
@@ -211,20 +221,37 @@ public final class CardDb implements ICardDatabase {
@Override @Override
public PaperCard getCardFromEdition(final String cardName, final Date printedBefore, final SetPreference fromSet) { public PaperCard getCardFromEdition(final String cardName, final Date printedBefore, final SetPreference fromSet) {
return getCardFromEdition(cardName, null, fromSet, -1);
}
@Override
public PaperCard getCardFromEdition(final String cardName, final Date printedBefore, final SetPreference fromSet, int artIndex) {
List<PaperCard> cards = this.allCardsByName.get(cardName); List<PaperCard> cards = this.allCardsByName.get(cardName);
int sz = cards.size(); int sz = cards.size();
if( fromSet == SetPreference.Latest ) { if( fromSet == SetPreference.Earliest || fromSet == SetPreference.EarliestCoreExp) {
for(int i = 0 ; i < sz ; i++) for(int i = sz - 1 ; i >= 0 ; i--) {
if( printedBefore == null || editions.get(cards.get(i).getEdition()).getDate().after(printedBefore) ) PaperCard pc = cards.get(i);
return cards.get(i); CardEdition ed = editions.get(pc.getEdition());
if(fromSet == SetPreference.EarliestCoreExp && ed.getType() != Type.CORE && ed.getType() != Type.EXPANSION)
continue;
if((artIndex < 0 || pc.getArtIndex() == artIndex) && (printedBefore == null || ed.getDate().before(printedBefore)))
return pc;
}
return null; return null;
} else if( fromSet == SetPreference.Earliest || fromSet == null || fromSet == SetPreference.Random ) { } else if( fromSet == SetPreference.LatestCoreExp || fromSet == SetPreference.Latest || fromSet == null || fromSet == SetPreference.Random ) {
for(int i = sz - 1 ; i >= 0 ; i--) for(int i = 0 ; i < sz ; i++) {
if( printedBefore == null || editions.get(cards.get(i).getEdition()).getDate().after(printedBefore) ) { PaperCard pc = cards.get(i);
if( fromSet == SetPreference.Earliest ) CardEdition ed = editions.get(pc.getEdition());
return cards.get(i); if(fromSet == SetPreference.LatestCoreExp && ed.getType() != Type.CORE && ed.getType() != Type.EXPANSION)
return cards.get(MyRandom.getRandom().nextInt(i+1)); continue;
if((artIndex < 0 || pc.getArtIndex() == artIndex) && (printedBefore == null || ed.getDate().before(printedBefore))) {
if( fromSet == SetPreference.LatestCoreExp || fromSet == SetPreference.Latest )
return pc;
return cards.get(i + MyRandom.getRandom().nextInt(sz-i));
}
} }
return null; return null;
} }

View File

@@ -415,15 +415,21 @@ public final class CardEdition implements Comparable<CardEdition> { // immutable
public CardEdition getEarliestEditionWithAllCards(CardPool cards) { public CardEdition getEarliestEditionWithAllCards(CardPool cards) {
Set<String> minEditions = new HashSet<String>(); Set<String> minEditions = new HashSet<String>();
SetPreference strictness = SetPreference.EarliestCoreExp;
for(Entry<PaperCard, Integer> k : cards) { for(Entry<PaperCard, Integer> k : cards) {
PaperCard cp = StaticData.instance().getCommonCards().getCardFromEdition(k.getKey().getName(), SetPreference.Earliest); PaperCard cp = StaticData.instance().getCommonCards().getCardFromEdition(k.getKey().getName(), strictness);
if( cp == null && strictness == SetPreference.EarliestCoreExp) {
strictness = SetPreference.Earliest; // card is not found in core and expansions only (probably something CMD or C13)
cp = StaticData.instance().getCommonCards().getCardFromEdition(k.getKey().getName(), strictness);
}
if ( cp == null )
cp = k.getKey(); // it's unlikely, this code will ever run
minEditions.add(cp.getEdition()); minEditions.add(cp.getEdition());
} }
for(CardEdition ed : getOrderedEditions()) {
if( minEditions.contains(ed.getCode()) && ( ed.getType() == Type.CORE || ed.getType() == Type.EXPANSION ) )
return ed;
}
for(CardEdition ed : getOrderedEditions()) { for(CardEdition ed : getOrderedEditions()) {
if(minEditions.contains(ed.getCode())) if(minEditions.contains(ed.getCode()))
return ed; return ed;

View File

@@ -13,8 +13,9 @@ public interface ICardDatabase extends Iterable<PaperCard> {
PaperCard getCard(String cardName); PaperCard getCard(String cardName);
PaperCard getCard(String cardName, String edition); PaperCard getCard(String cardName, String edition);
PaperCard getCard(String cardName, String edition, int artIndex); PaperCard getCard(String cardName, String edition, int artIndex);
PaperCard getCardFromEdition(final String cardName, final SetPreference fromSet); PaperCard getCardFromEdition(String cardName, SetPreference fromSet);
PaperCard getCardFromEdition(final String cardName, final Date printedBefore, final SetPreference fromSet); PaperCard getCardFromEdition(String cardName, Date printedBefore, SetPreference fromSet);
PaperCard getCardFromEdition(String cardName, Date printedBefore, SetPreference fromSet, int artIndex);
PaperCard getFoiled(PaperCard cpi); PaperCard getFoiled(PaperCard cpi);
@@ -28,4 +29,5 @@ public interface ICardDatabase extends Iterable<PaperCard> {
List<PaperCard> getAllCards(Predicate<PaperCard> predicate); List<PaperCard> getAllCards(Predicate<PaperCard> predicate);
Predicate<? super PaperCard> wasPrintedInSets(List<String> allowedSetCodes); Predicate<? super PaperCard> wasPrintedInSets(List<String> allowedSetCodes);
} }

View File

@@ -21,8 +21,6 @@ import java.util.Iterator;
import java.util.Map.Entry; import java.util.Map.Entry;
import java.util.regex.Matcher; import java.util.regex.Matcher;
import java.util.regex.Pattern; import java.util.regex.Pattern;
import java.util.NoSuchElementException;
import org.apache.commons.lang3.StringUtils; import org.apache.commons.lang3.StringUtils;
import forge.StaticData; import forge.StaticData;
@@ -45,6 +43,10 @@ public class CardPool extends ItemPool<PaperCard> {
this.addAll(cards); this.addAll(cards);
} }
public void add(final String cardName, final int amount) {
this.add(cardName, null, -1, amount);
}
public void add(final String cardName, final String setCode) { public void add(final String cardName, final String setCode) {
this.add(cardName, setCode, -1, 1); this.add(cardName, setCode, -1, 1);
} }
@@ -61,7 +63,8 @@ public class CardPool extends ItemPool<PaperCard> {
isCommonCard = false; isCommonCard = false;
} }
int artCount = isCommonCard ? StaticData.instance().getCommonCards().getArtCount(cardName, setCode) : StaticData.instance().getVariantCards().getArtCount(cardName, setCode); int artCount = isCommonCard
? StaticData.instance().getCommonCards().getArtCount(cardName, setCode) : 1;
if ( cp != null) { if ( cp != null) {
if (artIndex >= 0 || artCount <= 1) { if (artIndex >= 0 || artCount <= 1) {
@@ -93,26 +96,6 @@ public class CardPool extends ItemPool<PaperCard> {
} }
} }
/**
* TODO: Write javadoc for this method.
*
* @param cardName the card name
*/
public void add(final String cardName, int cnt) {
// in order to account for art index randomization we have to add cards one by one instead of in a batch
// TODO: somehow optimize this algorithm?...
for (int i = 0; i < cnt; i++) {
PaperCard cp = StaticData.instance().getCommonCards().getCard(cardName);
if ( cp == null )
cp = StaticData.instance().getVariantCards().getCard(cardName);
if ( cp != null)
this.add(cp);
else
throw new NoSuchElementException(String.format("Card %s is not supported by Forge, as it's neither a known common card nor one of casual variants' card.", cardName));
}
}
/** /**
* returns n-th card from this DeckSection. LINEAR time. No fixed order between changes * returns n-th card from this DeckSection. LINEAR time. No fixed order between changes
* @param i * @param i

View File

@@ -19,7 +19,9 @@ package forge.deck;
import java.io.File; import java.io.File;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Calendar;
import java.util.Collections; import java.util.Collections;
import java.util.Date;
import java.util.EnumMap; import java.util.EnumMap;
import java.util.Iterator; import java.util.Iterator;
import java.util.List; import java.util.List;
@@ -36,8 +38,10 @@ import com.google.common.collect.Lists;
import forge.StaticData; import forge.StaticData;
import forge.card.CardDb; import forge.card.CardDb;
import forge.card.CardEdition;
import forge.card.ColorSet; import forge.card.ColorSet;
import forge.card.MagicColor; import forge.card.MagicColor;
import forge.card.CardDb.SetPreference;
import forge.deck.io.DeckFileHeader; import forge.deck.io.DeckFileHeader;
import forge.deck.io.DeckSerializer; import forge.deck.io.DeckSerializer;
import forge.item.PaperCard; import forge.item.PaperCard;
@@ -189,12 +193,18 @@ public class Deck extends DeckBase implements Iterable<Entry<DeckSection, CardPo
d.setComment(dh.getComment()); d.setComment(dh.getComment());
d.tags.addAll(dh.getTags()); d.tags.addAll(dh.getTags());
boolean hasExplicitlySpecifiedSet = false;
for (Entry<String, List<String>> s : sections.entrySet()) { for (Entry<String, List<String>> s : sections.entrySet()) {
DeckSection sec = DeckSection.smartValueOf(s.getKey()); DeckSection sec = DeckSection.smartValueOf(s.getKey());
if (sec == null) { if (sec == null) {
continue; continue;
} }
for(String k : s.getValue())
if ( k.indexOf(CardDb.NameSetSeparator) > 0 )
hasExplicitlySpecifiedSet = true;
CardPool pool = CardPool.fromCardList(s.getValue()); CardPool pool = CardPool.fromCardList(s.getValue());
// I used to store planes and schemes under sideboard header, so this will assign them to a correct section // I used to store planes and schemes under sideboard header, so this will assign them to a correct section
IPaperCard sample = pool.get(0); IPaperCard sample = pool.get(0);
@@ -207,9 +217,43 @@ public class Deck extends DeckBase implements Iterable<Entry<DeckSection, CardPo
d.parts.put(sec, pool); d.parts.put(sec, pool);
} }
if (!hasExplicitlySpecifiedSet) {
d.convertByXitaxMethod();
}
return d; return d;
} }
private void convertByXitaxMethod() {
CardEdition earliestSet = StaticData.instance().getEditions().getEarliestEditionWithAllCards(getAllCardsInASinglePool());
Calendar cal = Calendar.getInstance();
cal.setTime(earliestSet.getDate());
cal.add(Calendar.DATE, 1);
Date dayAfterNewestSetRelease = cal.getTime();
for(Entry<DeckSection, CardPool> p : parts.entrySet()) {
CardPool newPool = new CardPool();
for(Entry<PaperCard, Integer> cp : p.getValue()){
String cardName = cp.getKey().getName();
int artIndex = cp.getKey().getArtIndex();
PaperCard c = StaticData.instance().getCommonCards().getCardFromEdition(cardName, dayAfterNewestSetRelease, SetPreference.LatestCoreExp, artIndex);
if( null == c ) {
c = StaticData.instance().getCommonCards().getCardFromEdition(cardName, dayAfterNewestSetRelease, SetPreference.Latest, -1);
// this is to randomize art of all those cards
newPool.add(cardName, c.getEdition(), cp.getValue());
} else
newPool.add(c, cp.getValue());
}
parts.put(p.getKey(), newPool);
}
}
private static List<String> writeCardPool(final ItemPool<PaperCard> pool) { private static List<String> writeCardPool(final ItemPool<PaperCard> pool) {
List<Entry<PaperCard, Integer>> main2sort = Lists.newArrayList(pool); List<Entry<PaperCard, Integer>> main2sort = Lists.newArrayList(pool);
Collections.sort(main2sort, ItemPoolSorter.BY_NAME_THEN_SET); Collections.sort(main2sort, ItemPoolSorter.BY_NAME_THEN_SET);