mirror of
https://github.com/Card-Forge/forge.git
synced 2025-11-20 20:58:03 +00:00
Moved cardDb and most of static data to core project. Had to rollback some incompatible changes. Sorry, drdev!
This commit is contained in:
@@ -19,7 +19,6 @@ package forge;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import com.google.common.collect.ImmutableList;
|
||||
|
||||
/**
|
||||
* <p>
|
||||
@@ -54,79 +53,6 @@ public final class Constant {
|
||||
public static final int HEIGHT = 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* The Interface Color.
|
||||
*/
|
||||
public static class Color {
|
||||
|
||||
/** The Black. */
|
||||
public static final String BLACK = "black";
|
||||
|
||||
/** The Blue. */
|
||||
public static final String BLUE = "blue";
|
||||
|
||||
/** The Green. */
|
||||
public static final String GREEN = "green";
|
||||
|
||||
/** The Red. */
|
||||
public static final String RED = "red";
|
||||
|
||||
/** The White. */
|
||||
public static final String WHITE = "white";
|
||||
|
||||
/** The Colorless. */
|
||||
public static final String COLORLESS = "colorless";
|
||||
// color order "wubrg"
|
||||
|
||||
/** The only colors. */
|
||||
public static final ImmutableList<String> ONLY_COLORS = ImmutableList.of(Color.WHITE, Color.BLUE, Color.BLACK, Color.RED, Color.GREEN);
|
||||
|
||||
/** The Snow. */
|
||||
public static final String SNOW = "snow";
|
||||
|
||||
/** The Basic lands. */
|
||||
public static final List<String> BASIC_LANDS = ImmutableList.of("Plains", "Island", "Swamp", "Mountain", "Forest");
|
||||
public static final List<String> SNOW_LANDS = ImmutableList.of("Snow-Covered Plains", "Snow-Covered Island", "Snow-Covered Swamp", "Snow-Covered Mountain", "Snow-Covered Forest");
|
||||
}
|
||||
|
||||
/**
|
||||
* The Interface CardTypes.
|
||||
*/
|
||||
public static class CardTypes {
|
||||
|
||||
/** The loaded. */
|
||||
public static final boolean[] LOADED = { false };
|
||||
|
||||
/** The card types. */
|
||||
public static final List<String> CARD_TYPES = new ArrayList<String>();
|
||||
|
||||
/** The super types. */
|
||||
public static final List<String> SUPER_TYPES = new ArrayList<String>();
|
||||
|
||||
/** The basic types. */
|
||||
public static final List<String> BASIC_TYPES = new ArrayList<String>();
|
||||
|
||||
/** The land types. */
|
||||
public static final List<String> LAND_TYPES = new ArrayList<String>();
|
||||
|
||||
/** The creature types. */
|
||||
public static final List<String> CREATURE_TYPES = new ArrayList<String>();
|
||||
|
||||
/** The instant types. */
|
||||
public static final List<String> INSTANT_TYPES = new ArrayList<String>();
|
||||
|
||||
/** The sorcery types. */
|
||||
public static final List<String> SORCERY_TYPES = new ArrayList<String>();
|
||||
|
||||
/** The enchantment types. */
|
||||
public static final List<String> ENCHANTMENT_TYPES = new ArrayList<String>();
|
||||
|
||||
/** The artifact types. */
|
||||
public static final List<String> ARTIFACT_TYPES = new ArrayList<String>();
|
||||
|
||||
/** The walker types. */
|
||||
public static final List<String> WALKER_TYPES = new ArrayList<String>();
|
||||
}
|
||||
|
||||
/**
|
||||
* The Interface Keywords.
|
||||
|
||||
9
forge-core/src/main/java/forge/ICardStorageReader.java
Normal file
9
forge-core/src/main/java/forge/ICardStorageReader.java
Normal file
@@ -0,0 +1,9 @@
|
||||
package forge;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import forge.card.CardRules;
|
||||
|
||||
public interface ICardStorageReader{
|
||||
List<CardRules> loadCards();
|
||||
}
|
||||
120
forge-core/src/main/java/forge/StaticData.java
Normal file
120
forge-core/src/main/java/forge/StaticData.java
Normal file
@@ -0,0 +1,120 @@
|
||||
package forge;
|
||||
|
||||
import java.io.File;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.TreeMap;
|
||||
|
||||
import forge.card.CardDb;
|
||||
import forge.card.CardEdition;
|
||||
import forge.card.CardRules;
|
||||
import forge.card.EditionCollection;
|
||||
import forge.card.FatPackTemplate;
|
||||
import forge.card.FormatCollection;
|
||||
import forge.card.PrintSheet;
|
||||
import forge.card.SealedProductTemplate;
|
||||
import forge.game.GameFormat;
|
||||
import forge.util.storage.IStorage;
|
||||
import forge.util.storage.StorageBase;
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* The class holding game invariants, such as cards, editions, game formats. All that data, which is not supposed to be changed by player
|
||||
*
|
||||
* @author Max
|
||||
*/
|
||||
public class StaticData {
|
||||
|
||||
private final CardDb commonCards;
|
||||
private final CardDb variantCards;
|
||||
private final EditionCollection editions;
|
||||
private final FormatCollection formats;
|
||||
private final IStorage<SealedProductTemplate> boosters;
|
||||
private final IStorage<SealedProductTemplate> specialBoosters;
|
||||
private final IStorage<SealedProductTemplate> tournaments;
|
||||
private final IStorage<FatPackTemplate> fatPacks;
|
||||
private final IStorage<PrintSheet> printSheets;
|
||||
|
||||
private static StaticData lastInstance = null;
|
||||
|
||||
|
||||
public StaticData(ICardStorageReader reader, String editionFolder, String blockDataFolder) {
|
||||
this.editions = new EditionCollection(new CardEdition.Reader(new File(editionFolder)));
|
||||
lastInstance = this;
|
||||
|
||||
final Map<String, CardRules> regularCards = new TreeMap<String, CardRules>(String.CASE_INSENSITIVE_ORDER);
|
||||
final Map<String, CardRules> variantsCards = new TreeMap<String, CardRules>(String.CASE_INSENSITIVE_ORDER);
|
||||
|
||||
synchronized (CardDb.class) {
|
||||
List<CardRules> rules = reader.loadCards();
|
||||
for (CardRules card : rules) {
|
||||
if (null == card) continue;
|
||||
|
||||
final String cardName = card.getName();
|
||||
if ( card.isVariant() )
|
||||
variantsCards.put(cardName, card);
|
||||
else
|
||||
regularCards.put(cardName, card);
|
||||
}
|
||||
|
||||
commonCards = new CardDb(regularCards, editions, false);
|
||||
variantCards = new CardDb(variantsCards, editions, false);
|
||||
}
|
||||
|
||||
|
||||
this.formats = new FormatCollection(new GameFormat.Reader(new File(blockDataFolder, "formats.txt")));
|
||||
this.boosters = new StorageBase<SealedProductTemplate>("Boosters", editions.getBoosterGenerator());
|
||||
this.specialBoosters = new StorageBase<SealedProductTemplate>("Special boosters", new SealedProductTemplate.Reader(new File(blockDataFolder, "boosters-special.txt")));
|
||||
this.tournaments = new StorageBase<SealedProductTemplate>("Starter sets", new SealedProductTemplate.Reader(new File(blockDataFolder, "starters.txt")));
|
||||
this.fatPacks = new StorageBase<FatPackTemplate>("Fat packs", new FatPackTemplate.Reader("res/blockdata/fatpacks.txt"));
|
||||
this.printSheets = new StorageBase<PrintSheet>("Special print runs", new PrintSheet.Reader(new File(blockDataFolder, "printsheets.txt")));
|
||||
}
|
||||
|
||||
public final static StaticData instance() {
|
||||
return lastInstance;
|
||||
}
|
||||
|
||||
|
||||
public final EditionCollection getEditions() {
|
||||
return this.editions;
|
||||
}
|
||||
|
||||
public final FormatCollection getFormats() {
|
||||
return this.formats;
|
||||
}
|
||||
|
||||
/** @return {@link forge.util.storage.IStorageView}<{@link forge.card.FatPackTemplate}> */
|
||||
public IStorage<FatPackTemplate> getFatPacks() {
|
||||
return fatPacks;
|
||||
}
|
||||
|
||||
/** @return {@link forge.util.storage.IStorageView}<{@link forge.card.BoosterTemplate}> */
|
||||
public final IStorage<SealedProductTemplate> getTournamentPacks() {
|
||||
return tournaments;
|
||||
}
|
||||
|
||||
/** @return {@link forge.util.storage.IStorageView}<{@link forge.card.BoosterTemplate}> */
|
||||
public final IStorage<SealedProductTemplate> getBoosters() {
|
||||
return boosters;
|
||||
}
|
||||
|
||||
public final IStorage<SealedProductTemplate> getSpecialBoosters() {
|
||||
return specialBoosters;
|
||||
}
|
||||
|
||||
public IStorage<PrintSheet> getPrintSheets() {
|
||||
return printSheets;
|
||||
}
|
||||
|
||||
|
||||
public CardDb getCommonCards() {
|
||||
return commonCards;
|
||||
}
|
||||
|
||||
|
||||
public CardDb getVariantCards() {
|
||||
return variantCards;
|
||||
}
|
||||
|
||||
}
|
||||
14
forge-core/src/main/java/forge/card/BoosterSlots.java
Normal file
14
forge-core/src/main/java/forge/card/BoosterSlots.java
Normal file
@@ -0,0 +1,14 @@
|
||||
package forge.card;
|
||||
|
||||
public class BoosterSlots {
|
||||
public static final String LAND = "Land";
|
||||
public static final String ANY = "Any";
|
||||
public static final String COMMON = "Common";
|
||||
public static final String UNCOMMON = "Uncommon";
|
||||
public static final String UNCOMMON_RARE = "UncommonRare";
|
||||
public static final String RARE = "Rare";
|
||||
public static final String RARE_MYTHIC = "RareMythic";
|
||||
public static final String MYTHIC = "Mythic";
|
||||
public static final String BASIC_LAND = "BasicLand";
|
||||
public static final String TIME_SHIFTED = "TimeShifted";
|
||||
}
|
||||
74
forge-core/src/main/java/forge/card/CardAiHints.java
Normal file
74
forge-core/src/main/java/forge/card/CardAiHints.java
Normal file
@@ -0,0 +1,74 @@
|
||||
package forge.card;
|
||||
|
||||
/**
|
||||
* TODO: Write javadoc for this type.
|
||||
*
|
||||
*/
|
||||
public class CardAiHints {
|
||||
|
||||
|
||||
private final boolean isRemovedFromAIDecks;
|
||||
private final boolean isRemovedFromRandomDecks;
|
||||
|
||||
private final DeckHints deckHints;
|
||||
private final DeckHints deckNeeds;
|
||||
|
||||
|
||||
public CardAiHints(boolean remAi, boolean remRandom, DeckHints dh, DeckHints dn) {
|
||||
isRemovedFromAIDecks = remAi;
|
||||
isRemovedFromRandomDecks = remRandom;
|
||||
deckHints = dh;
|
||||
deckNeeds = dn;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the rem ai decks.
|
||||
*
|
||||
* @return the rem ai decks
|
||||
*/
|
||||
public boolean getRemAIDecks() {
|
||||
return this.isRemovedFromAIDecks;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the rem random decks.
|
||||
*
|
||||
* @return the rem random decks
|
||||
*/
|
||||
public boolean getRemRandomDecks() {
|
||||
return this.isRemovedFromRandomDecks;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the deckHints
|
||||
*/
|
||||
public DeckHints getDeckHints() {
|
||||
return deckHints;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the deckHints
|
||||
*/
|
||||
public DeckHints getDeckNeeds() {
|
||||
return deckNeeds;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the ai status comparable.
|
||||
*
|
||||
* @return the ai status comparable
|
||||
*/
|
||||
public Integer getAiStatusComparable() {
|
||||
if (this.isRemovedFromAIDecks && this.isRemovedFromRandomDecks) {
|
||||
return Integer.valueOf(3);
|
||||
} else if (this.isRemovedFromAIDecks) {
|
||||
return Integer.valueOf(4);
|
||||
} else if (this.isRemovedFromRandomDecks) {
|
||||
return Integer.valueOf(2);
|
||||
} else {
|
||||
return Integer.valueOf(1);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
346
forge-core/src/main/java/forge/card/CardDb.java
Normal file
346
forge-core/src/main/java/forge/card/CardDb.java
Normal file
@@ -0,0 +1,346 @@
|
||||
/*
|
||||
* Forge: Play Magic: the Gathering.
|
||||
* Copyright (C) 2011 Forge Team
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package forge.card;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Map.Entry;
|
||||
import java.util.NoSuchElementException;
|
||||
import java.util.TreeMap;
|
||||
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.apache.commons.lang3.tuple.ImmutablePair;
|
||||
|
||||
import com.google.common.base.Predicate;
|
||||
import com.google.common.collect.Iterables;
|
||||
import com.google.common.collect.Lists;
|
||||
import com.google.common.collect.Multimap;
|
||||
import com.google.common.collect.Multimaps;
|
||||
|
||||
import forge.item.PaperCard;
|
||||
import forge.util.Aggregates;
|
||||
import forge.util.CollectionSuppliers;
|
||||
import forge.util.Lang;
|
||||
import forge.util.MyRandom;
|
||||
|
||||
public final class CardDb implements ICardDatabase {
|
||||
public final static String foilSuffix = "+";
|
||||
private final static int foilSuffixLength = foilSuffix.length();
|
||||
|
||||
// need this to obtain cardReference by name+set+artindex
|
||||
private final Multimap<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, CardRules> rulesByName;
|
||||
|
||||
private final List<PaperCard> allCards = new ArrayList<PaperCard>();
|
||||
private final List<PaperCard> roAllCards = Collections.unmodifiableList(allCards);
|
||||
private final Collection<PaperCard> roUniqueCards = Collections.unmodifiableCollection(uniqueCardsByName.values());
|
||||
private final EditionCollection editions;
|
||||
|
||||
|
||||
public CardDb(Map<String, CardRules> rules, EditionCollection editions0, boolean logMissingCards) {
|
||||
this.rulesByName = rules;
|
||||
this.editions = editions0;
|
||||
List<String> missingCards = new ArrayList<String>();
|
||||
for(CardEdition e : editions.getOrderedEditions()) {
|
||||
boolean worthLogging = logMissingCards && ( e.getType() == CardEdition.Type.CORE || e.getType() == CardEdition.Type.EXPANSION || e.getType() == CardEdition.Type.REPRINT );
|
||||
if(worthLogging)
|
||||
System.out.print(e.getName() + " (" + e.getCards().length + " cards)");
|
||||
String lastCardName = null;
|
||||
int artIdx = 0;
|
||||
for(CardEdition.CardInSet cis : e.getCards()) {
|
||||
if ( cis.name.equals(lastCardName) )
|
||||
artIdx++;
|
||||
else {
|
||||
artIdx = 0;
|
||||
lastCardName = cis.name;
|
||||
}
|
||||
CardRules cr = rulesByName.get(lastCardName);
|
||||
if( cr != null )
|
||||
addCard(new PaperCard(cr, e.getCode(), cis.rarity, artIdx));
|
||||
else if (worthLogging)
|
||||
missingCards.add(cis.name);
|
||||
}
|
||||
if(worthLogging) {
|
||||
if(missingCards.isEmpty())
|
||||
System.out.println(" ... 100% ");
|
||||
else {
|
||||
int missing = (e.getCards().length - missingCards.size()) * 10000 / e.getCards().length;
|
||||
System.out.printf(" ... %.2f%% (%s missing: %s )%n", missing * 0.01f, Lang.nounWithAmount(missingCards.size(), "card"), StringUtils.join(missingCards, " | ") );
|
||||
}
|
||||
missingCards.clear();
|
||||
}
|
||||
}
|
||||
|
||||
for(CardRules cr : rulesByName.values()) {
|
||||
if( !allCardsByName.containsKey(cr.getName()) )
|
||||
{
|
||||
System.err.println("The card " + cr.getName() + " was not assigned to any set. Adding it to UNKNOWN set... to fix see res/cardeditions/ folder. ");
|
||||
addCard(new PaperCard(cr, CardEdition.UNKNOWN.getCode(), CardRarity.Special, 0));
|
||||
}
|
||||
}
|
||||
|
||||
reIndex();
|
||||
}
|
||||
|
||||
private void addCard(PaperCard paperCard) {
|
||||
allCardsByName.put(paperCard.name, paperCard);
|
||||
}
|
||||
|
||||
private void reIndex() {
|
||||
uniqueCardsByName.clear();
|
||||
allCards.clear();
|
||||
for(Entry<String, Collection<PaperCard>> kv : allCardsByName.asMap().entrySet()) {
|
||||
uniqueCardsByName.put(kv.getKey(), Iterables.getFirst(kv.getValue(), null));
|
||||
allCards.addAll(kv.getValue());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Splits cardname into Name and set whenever deck line reads as name|set.
|
||||
*/
|
||||
private static ImmutablePair<String, String> splitCardName(final String name) {
|
||||
String cardName = name; // .trim() ?
|
||||
final int pipePos = cardName.indexOf('|');
|
||||
|
||||
if (pipePos >= 0) {
|
||||
final String setName = cardName.substring(pipePos + 1).trim();
|
||||
cardName = cardName.substring(0, pipePos);
|
||||
// only if set is not blank try to load it
|
||||
if (StringUtils.isNotBlank(setName) && !"???".equals(setName)) {
|
||||
return new ImmutablePair<String, String>(cardName, setName);
|
||||
}
|
||||
}
|
||||
return new ImmutablePair<String, String>(cardName, null);
|
||||
}
|
||||
|
||||
private boolean isFoil(final String cardName) {
|
||||
return cardName.toLowerCase().endsWith(CardDb.foilSuffix);
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes the foil suffix.
|
||||
*
|
||||
* @param cardName the card name
|
||||
* @return the string
|
||||
*/
|
||||
public String removeFoilSuffix(final String cardName) {
|
||||
return cardName.toLowerCase().endsWith(CardDb.foilSuffix) ? cardName.substring(0, cardName.length() - CardDb.foilSuffixLength) : cardName;
|
||||
}
|
||||
|
||||
@Override
|
||||
public PaperCard tryGetCard(final String cardName0) {
|
||||
return tryGetCard(cardName0, true);
|
||||
}
|
||||
|
||||
@Override
|
||||
public PaperCard tryGetCard(final String cardName0, boolean fromLastSet) {
|
||||
if (null == cardName0) {
|
||||
return null; // obviously
|
||||
}
|
||||
|
||||
final boolean isFoil = this.isFoil(cardName0);
|
||||
final String cardName = isFoil ? this.removeFoilSuffix(cardName0) : cardName0;
|
||||
|
||||
final ImmutablePair<String, String> nameWithSet = CardDb.splitCardName(cardName);
|
||||
|
||||
final PaperCard res = nameWithSet.right == null
|
||||
? ( fromLastSet ? this.uniqueCardsByName.get(nameWithSet.left) : Aggregates.random(this.allCardsByName.get(nameWithSet.left)) )
|
||||
: tryGetCard(nameWithSet.left, nameWithSet.right);
|
||||
return null != res && isFoil ? getFoiled(res) : res;
|
||||
}
|
||||
|
||||
@Override
|
||||
public PaperCard tryGetCardPrintedByDate(final String name0, final boolean fromLatestSet, final Date printedBefore) {
|
||||
final boolean isFoil = this.isFoil(name0);
|
||||
final String cardName = isFoil ? this.removeFoilSuffix(name0) : name0;
|
||||
final ImmutablePair<String, String> nameWithSet = CardDb.splitCardName(cardName);
|
||||
|
||||
PaperCard res = null;
|
||||
if (null != nameWithSet.right) // set explicitly requested, should return card from it and disregard the date
|
||||
res = tryGetCard(nameWithSet.left, nameWithSet.right);
|
||||
else {
|
||||
Collection<PaperCard> cards = this.allCardsByName.get(nameWithSet.left); // cards are sorted by datetime desc
|
||||
int idxRightSet = 0;
|
||||
for (PaperCard card : cards) {
|
||||
if (editions.get(card.getEdition()).getDate().after(printedBefore))
|
||||
idxRightSet++;
|
||||
else
|
||||
break;
|
||||
}
|
||||
res = fromLatestSet ? Iterables.get(cards, idxRightSet, null) : Aggregates.random(Iterables.skip(cards, idxRightSet));
|
||||
}
|
||||
|
||||
return null != res && isFoil ? getFoiled(res) : res;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public PaperCard tryGetCard(final String cardName, String setName) {
|
||||
return tryGetCard(cardName, setName, -1);
|
||||
}
|
||||
|
||||
@Override
|
||||
public PaperCard tryGetCard(final String cardName0, String setName, int index) {
|
||||
final boolean isFoil = this.isFoil(cardName0);
|
||||
final String cardName = isFoil ? this.removeFoilSuffix(cardName0) : cardName0;
|
||||
|
||||
Collection<PaperCard> cards = allCardsByName.get(cardName);
|
||||
if ( null == cards ) return null;
|
||||
|
||||
CardEdition edition = editions.get(setName);
|
||||
if ( null == edition )
|
||||
return tryGetCard(cardName, true); // set not found, try to get the same card from just any set.
|
||||
String effectiveSet = edition.getCode();
|
||||
|
||||
PaperCard result = null;
|
||||
if ( index < 0 ) { // this stands for 'random art'
|
||||
PaperCard[] candidates = new PaperCard[9]; // 9 cards with same name per set is a maximum of what has been printed (Arnchenemy)
|
||||
int cnt = 0;
|
||||
for( PaperCard pc : cards ) {
|
||||
if( pc.getEdition().equalsIgnoreCase(effectiveSet) )
|
||||
candidates[cnt++] = pc;
|
||||
}
|
||||
|
||||
if (cnt == 0 ) return null;
|
||||
result = cnt == 1 ? candidates[0] : candidates[MyRandom.getRandom().nextInt(cnt)];
|
||||
} else
|
||||
for( PaperCard pc : cards ) {
|
||||
if( pc.getEdition().equalsIgnoreCase(effectiveSet) && index == pc.getArtIndex() ) {
|
||||
result = pc;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if ( result == null ) return null;
|
||||
return isFoil ? getFoiled(result) : result;
|
||||
}
|
||||
|
||||
public PaperCard getFoiled(PaperCard card0) {
|
||||
// Here - I am still unsure if there should be a cache Card->Card from unfoiled to foiled, to avoid creation of N instances of single plains
|
||||
return new PaperCard(card0.getRules(), card0.getEdition(), card0.getRarity(), card0.getArtIndex(), true);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getPrintCount(String cardName, String edition) {
|
||||
int cnt = 0;
|
||||
for( PaperCard pc : allCardsByName.get(cardName) ) {
|
||||
if( pc.getEdition().equals(edition) )
|
||||
cnt++;
|
||||
}
|
||||
return cnt;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getMaxPrintCount(String cardName) {
|
||||
int max = -1;
|
||||
for( PaperCard pc : allCardsByName.get(cardName) ) {
|
||||
if ( max < pc.getArtIndex() )
|
||||
max = pc.getArtIndex();
|
||||
}
|
||||
return max + 1;
|
||||
}
|
||||
|
||||
// Single fetch
|
||||
@Override
|
||||
public PaperCard getCard(final String name) {
|
||||
return this.getCard(name, false);
|
||||
}
|
||||
|
||||
@Override
|
||||
public PaperCard getCard(final String name0, final boolean fromLatestSet) {
|
||||
// Sometimes they read from decks things like "CardName|Set" - but we
|
||||
// can handle it
|
||||
final PaperCard result = tryGetCard(name0, fromLatestSet);
|
||||
if (null == result) {
|
||||
throw new NoSuchElementException(String.format("Card '%s' not found in our database.", name0));
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public PaperCard getCardPrintedByDate(final String name0, final boolean fromLatestSet, Date printedBefore ) {
|
||||
// Sometimes they read from decks things like "CardName|Set" - but we
|
||||
// can handle it
|
||||
final PaperCard result = tryGetCard(name0, fromLatestSet);
|
||||
if (null == result) {
|
||||
throw new NoSuchElementException(String.format("Card '%s' released before %s not found in our database.", name0, printedBefore.toString()));
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
// Advanced fetch by name+set
|
||||
@Override
|
||||
public PaperCard getCard(final String name, final String set) {
|
||||
return this.getCard(name, set, -1);
|
||||
}
|
||||
|
||||
@Override
|
||||
public PaperCard getCard(final String name, final String set, final int artIndex) {
|
||||
|
||||
final PaperCard result = tryGetCard(name, set, artIndex);
|
||||
if (null == result) {
|
||||
final String message = String.format("Asked for '%s' from '%s' #%d: db didn't find that copy.", name, set, artIndex);
|
||||
throw new NoSuchElementException(message);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
// returns a list of all cards from their respective latest editions
|
||||
@Override
|
||||
public Collection<PaperCard> getUniqueCards() {
|
||||
return roUniqueCards;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<PaperCard> getAllCards() {
|
||||
return roAllCards;
|
||||
}
|
||||
|
||||
/** Returns a modifiable list of cards matching the given predicate */
|
||||
@Override
|
||||
public List<PaperCard> getAllCards(Predicate<PaperCard> predicate) {
|
||||
return Lists.newArrayList(Iterables.filter(this.roAllCards, predicate));
|
||||
}
|
||||
|
||||
public Predicate<? super PaperCard> wasPrintedInSets(List<String> setCodes) {
|
||||
return new PredicateExistsInSets(setCodes);
|
||||
}
|
||||
|
||||
private class PredicateExistsInSets implements Predicate<PaperCard> {
|
||||
private final List<String> sets;
|
||||
|
||||
public PredicateExistsInSets(final List<String> wantSets) {
|
||||
this.sets = wantSets; // maybe should make a copy here?
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean apply(final PaperCard subject) {
|
||||
Collection<PaperCard> cc = allCardsByName.get(subject.getName());
|
||||
for(PaperCard c : cc)
|
||||
if (sets.contains(c.getEdition()))
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
302
forge-core/src/main/java/forge/card/CardEdition.java
Normal file
302
forge-core/src/main/java/forge/card/CardEdition.java
Normal file
@@ -0,0 +1,302 @@
|
||||
/*
|
||||
* Forge: Play Magic: the Gathering.
|
||||
* Copyright (C) 2011 Forge Team
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package forge.card;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FilenameFilter;
|
||||
import java.text.ParseException;
|
||||
import java.text.SimpleDateFormat;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
import java.util.Map;
|
||||
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
|
||||
|
||||
import com.google.common.base.Function;
|
||||
import forge.util.FileSection;
|
||||
import forge.util.FileUtil;
|
||||
import forge.util.storage.StorageReaderFolder;
|
||||
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* CardSet class.
|
||||
* </p>
|
||||
*
|
||||
* @author Forge
|
||||
* @version $Id: CardSet.java 9708 2011-08-09 19:34:12Z jendave $
|
||||
*/
|
||||
public final class CardEdition implements Comparable<CardEdition> { // immutable
|
||||
public enum Type {
|
||||
UNKNOWN,
|
||||
|
||||
CORE,
|
||||
EXPANSION,
|
||||
|
||||
REPRINT,
|
||||
STARTER,
|
||||
|
||||
DUEL_DECKS,
|
||||
PREMIUM_DECK_SERIES,
|
||||
FROM_THE_VAULT,
|
||||
|
||||
OTHER,
|
||||
THIRDPARTY // custom sets
|
||||
}
|
||||
|
||||
public enum FoilType {
|
||||
NOT_SUPPORTED, // sets before Urza's Legacy
|
||||
OLD_STYLE, // sets between Urza's Legacy and 8th Edition
|
||||
MODERN // 8th Edition and newer
|
||||
}
|
||||
|
||||
public static class CardInSet {
|
||||
public final CardRarity rarity;
|
||||
public final String name;
|
||||
|
||||
public CardInSet(final String name, final CardRarity rarity) {
|
||||
this.rarity = rarity;
|
||||
this.name = name;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/** The Constant unknown. */
|
||||
private final static SimpleDateFormat formatter = new SimpleDateFormat("yyyy-MM-dd");
|
||||
|
||||
public static final CardEdition UNKNOWN = new CardEdition("1990-01-01", "??", "???", Type.UNKNOWN, "Undefined", FoilType.NOT_SUPPORTED, new CardInSet[]{});
|
||||
|
||||
private Date date;
|
||||
private String code2;
|
||||
private String code;
|
||||
private Type type;
|
||||
private String name;
|
||||
private String alias = null;
|
||||
private boolean whiteBorder = false;
|
||||
private FoilType foilType = FoilType.NOT_SUPPORTED;
|
||||
private int foilChanceInBooster = 0;
|
||||
private boolean foilAlwaysInCommonSlot = false;
|
||||
private final CardInSet[] cards;
|
||||
|
||||
|
||||
private int boosterArts = 1;
|
||||
private SealedProductTemplate boosterTpl = null;
|
||||
|
||||
private CardEdition(CardInSet[] cards) {
|
||||
this.cards = cards;
|
||||
}
|
||||
|
||||
/**
|
||||
* Instantiates a new card set.
|
||||
*
|
||||
* @param index indicates order of set release date
|
||||
* @param code2 the 2 (usually) letter code used for image filenames/URLs distributed by the HQ pics team that
|
||||
* use Magic Workstation-type edition codes. Older sets only had 2-letter codes, and some of the 3-letter
|
||||
* codes they use now aren't the same as the official list of 3-letter codes. When Forge downloads set-pics,
|
||||
* it uses the 3-letter codes for the folder no matter the age of the set.
|
||||
* @param code the MTG 3-letter set code
|
||||
* @param type the set type
|
||||
* @param name the name of the set
|
||||
* @param an optional secondary code alias for the set
|
||||
*/
|
||||
private CardEdition(String date, String code2, String code, Type type, String name, FoilType foil, CardInSet[] cards) {
|
||||
this(cards);
|
||||
this.code2 = code2;
|
||||
this.code = code;
|
||||
this.type = type;
|
||||
this.name = name;
|
||||
this.date = parseDate(date);
|
||||
this.foilType = foil;
|
||||
}
|
||||
|
||||
private static Date parseDate(String date) {
|
||||
if( date.length() <= 7 )
|
||||
date = date + "-01";
|
||||
try {
|
||||
return formatter.parse(date);
|
||||
} catch (ParseException e) {
|
||||
return new Date();
|
||||
}
|
||||
}
|
||||
|
||||
public Date getDate() { return date; }
|
||||
public String getCode2() { return code2; }
|
||||
public String getCode() { return code; }
|
||||
public Type getType() { return type; }
|
||||
public String getName() { return name; }
|
||||
public String getAlias() { return alias; }
|
||||
public FoilType getFoilType() { return foilType; }
|
||||
public int getFoilChanceInBooster() { return foilChanceInBooster; }
|
||||
public boolean getFoilAlwaysInCommonSlot() { return foilAlwaysInCommonSlot; }
|
||||
public CardInSet[] getCards() { return cards; }
|
||||
|
||||
/** The Constant fnGetName. */
|
||||
public static final Function<CardEdition, String> FN_GET_CODE = new Function<CardEdition, String>() {
|
||||
@Override
|
||||
public String apply(final CardEdition arg1) {
|
||||
return arg1.getCode();
|
||||
}
|
||||
};
|
||||
|
||||
@Override
|
||||
public int compareTo(final CardEdition o) {
|
||||
if (o == null) {
|
||||
return 1;
|
||||
}
|
||||
return date.compareTo(o.date);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return (this.code.hashCode() * 17) + this.name.hashCode();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(final Object obj) {
|
||||
if (this == obj) {
|
||||
return true;
|
||||
}
|
||||
if (obj == null) {
|
||||
return false;
|
||||
}
|
||||
if (this.getClass() != obj.getClass()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
final CardEdition other = (CardEdition) obj;
|
||||
return other.name.equals(this.name) && this.code.equals(other.code);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return this.name + " (set)";
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @return the whiteBorder
|
||||
*/
|
||||
public boolean isWhiteBorder() {
|
||||
return whiteBorder;
|
||||
}
|
||||
|
||||
public int getCntBoosterPictures() {
|
||||
return boosterArts;
|
||||
}
|
||||
|
||||
public SealedProductTemplate getBoosterTemplate() {
|
||||
return boosterTpl;
|
||||
}
|
||||
|
||||
public boolean hasBoosterTemplate() {
|
||||
return boosterTpl != null;
|
||||
}
|
||||
|
||||
public static class Reader extends StorageReaderFolder<CardEdition> {
|
||||
public Reader(File path) {
|
||||
super(path, CardEdition.FN_GET_CODE);
|
||||
}
|
||||
|
||||
public final static CardInSet[] arrCards = new CardInSet[] {};
|
||||
|
||||
@Override
|
||||
protected CardEdition read(File file) {
|
||||
final Map<String, List<String>> contents = FileSection.parseSections(FileUtil.readFile(file));
|
||||
|
||||
List<CardEdition.CardInSet> processedCards = new ArrayList<CardEdition.CardInSet>();
|
||||
for(String line : contents.get("cards")) {
|
||||
if (StringUtils.isBlank(line))
|
||||
continue;
|
||||
|
||||
// You may omit rarity for early development
|
||||
CardRarity r = CardRarity.smartValueOf(line.substring(0, 1));
|
||||
boolean hadRarity = r != CardRarity.Unknown && line.charAt(1) == ' ';
|
||||
String cardName = hadRarity ? line.substring(2) : line;
|
||||
CardInSet cis = new CardInSet(cardName, r);
|
||||
processedCards.add(cis);
|
||||
}
|
||||
|
||||
CardEdition res = new CardEdition(processedCards.toArray(arrCards));
|
||||
|
||||
|
||||
FileSection section = FileSection.parse(contents.get("metadata"), "=");
|
||||
res.name = section.get("name");
|
||||
res.date = parseDate(section.get("date"));
|
||||
res.code = section.get("code");
|
||||
res.code2 = section.get("code2");
|
||||
if( res.code2 == null )
|
||||
res.code2 = res.code;
|
||||
|
||||
res.boosterArts = section.getInt("BoosterCovers", 1);
|
||||
String boosterDesc = section.get("Booster");
|
||||
res.boosterTpl = boosterDesc == null ? null : new SealedProductTemplate(res.code, SealedProductTemplate.Reader.parseSlots(boosterDesc));
|
||||
|
||||
res.alias = section.get("alias");
|
||||
res.whiteBorder = "white".equalsIgnoreCase(section.get("border"));
|
||||
String type = section.get("type");
|
||||
Type enumType = Type.UNKNOWN;
|
||||
if (null != type && !type.isEmpty()) {
|
||||
try {
|
||||
enumType = Type.valueOf(type.toUpperCase(Locale.ENGLISH));
|
||||
} catch (IllegalArgumentException e) {
|
||||
// ignore; type will get UNKNOWN
|
||||
System.err.println(String.format("Ignoring unknown type in set definitions: name: %s; type: %s", res.name, type));
|
||||
}
|
||||
}
|
||||
res.type = enumType;
|
||||
|
||||
switch(section.get("foil", "newstyle").toLowerCase()) {
|
||||
case "notsupported":
|
||||
res.foilType = FoilType.NOT_SUPPORTED;
|
||||
break;
|
||||
case "oldstyle":
|
||||
case "classic":
|
||||
res.foilType = FoilType.OLD_STYLE;
|
||||
break;
|
||||
case "newstyle":
|
||||
case "modern":
|
||||
res.foilType = FoilType.MODERN;
|
||||
break;
|
||||
default:
|
||||
res.foilType = FoilType.NOT_SUPPORTED;
|
||||
break;
|
||||
}
|
||||
res.foilChanceInBooster = section.getInt("FoilChanceInBooster", 16);
|
||||
res.foilAlwaysInCommonSlot = section.getBoolean("FoilAlwaysInCommonSlot", false);
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected FilenameFilter getFileFilter() {
|
||||
return TXT_FILE_FILTER;
|
||||
}
|
||||
|
||||
|
||||
public static final FilenameFilter TXT_FILE_FILTER = new FilenameFilter() {
|
||||
@Override
|
||||
public boolean accept(final File dir, final String name) {
|
||||
return name.endsWith(".txt");
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
}
|
||||
222
forge-core/src/main/java/forge/card/CardRules.java
Normal file
222
forge-core/src/main/java/forge/card/CardRules.java
Normal file
@@ -0,0 +1,222 @@
|
||||
/*
|
||||
* Forge: Play Magic: the Gathering.
|
||||
* Copyright (C) 2011 Forge Team
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package forge.card;
|
||||
|
||||
import java.util.List;
|
||||
import forge.card.mana.ManaCost;
|
||||
|
||||
/**
|
||||
* A collection of methods containing full
|
||||
* meta and gameplay properties of a card.
|
||||
*
|
||||
* @author Forge
|
||||
* @version $Id: CardRules.java 9708 2011-08-09 19:34:12Z jendave $
|
||||
*/
|
||||
public final class CardRules implements ICardCharacteristics {
|
||||
private final CardSplitType splitType;
|
||||
private final ICardFace mainPart;
|
||||
private final ICardFace otherPart;
|
||||
//private final Map<String, CardInSet> setsPrinted = new TreeMap<String, CardInSet>(String.CASE_INSENSITIVE_ORDER);
|
||||
|
||||
private CardAiHints aiHints;
|
||||
|
||||
private ColorSet colorIdentity = null;
|
||||
|
||||
public CardRules(ICardFace[] faces, CardSplitType altMode, CardAiHints cah) {
|
||||
splitType = altMode;
|
||||
mainPart = faces[0];
|
||||
otherPart = faces[1];
|
||||
aiHints = cah;
|
||||
|
||||
//System.out.print(faces[0].getName());
|
||||
|
||||
// for (Entry<String, CardInSet> cs : sets.entrySet()) {
|
||||
// if( CardRulesReader.editions.get(cs.getKey()) != null )
|
||||
// setsPrinted.put(cs.getKey(), cs.getValue());
|
||||
// }
|
||||
//
|
||||
// if ( setsPrinted.isEmpty() ) {
|
||||
// System.err.println(getName() + " was not assigned any set.");
|
||||
// setsPrinted.put(CardEdition.UNKNOWN.getCode(), new CardInSet(CardRarity.Common, 1) );
|
||||
// }
|
||||
//
|
||||
//Calculate Color Identity
|
||||
byte colMask = calculateColorIdentity(mainPart);
|
||||
|
||||
if(otherPart != null)
|
||||
{
|
||||
colMask |= calculateColorIdentity(otherPart);
|
||||
}
|
||||
colorIdentity = ColorSet.fromMask(colMask);
|
||||
}
|
||||
|
||||
private byte calculateColorIdentity(ICardFace face)
|
||||
{
|
||||
byte res = face.getColor().getColor();
|
||||
boolean isReminder = false;
|
||||
boolean isSymbol = false;
|
||||
String oracleText = face.getOracleText();
|
||||
int len = oracleText.length();
|
||||
for(int i = 0; i < len; i++) {
|
||||
char c = oracleText.charAt(i); // This is to avoid needless allocations performed by toCharArray()
|
||||
switch(c) {
|
||||
case('('): isReminder = i > 0; break; // if oracle has only reminder, consider it valid rules (basic and true lands need this)
|
||||
case(')'): isReminder = false; break;
|
||||
case('{'): isSymbol = true; break;
|
||||
case('}'): isSymbol = false; break;
|
||||
default:
|
||||
if(isSymbol && !isReminder) {
|
||||
switch(c) {
|
||||
case('W'): res |= MagicColor.WHITE; break;
|
||||
case('U'): res |= MagicColor.BLUE; break;
|
||||
case('B'): res |= MagicColor.BLACK; break;
|
||||
case('R'): res |= MagicColor.RED; break;
|
||||
case('G'): res |= MagicColor.GREEN; break;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
public boolean isVariant() {
|
||||
CardType t = getType();
|
||||
return t.isVanguard() || t.isScheme() || t.isPlane() || t.isPhenomenon();
|
||||
}
|
||||
|
||||
public CardSplitType getSplitType() {
|
||||
return splitType;
|
||||
}
|
||||
|
||||
public ICardFace getMainPart() {
|
||||
return mainPart;
|
||||
}
|
||||
|
||||
public ICardFace getOtherPart() {
|
||||
return otherPart;
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
switch(splitType.getAggregationMethod()) {
|
||||
case AGGREGATE:
|
||||
return mainPart.getName() + " // " + otherPart.getName();
|
||||
default:
|
||||
return mainPart.getName();
|
||||
}
|
||||
}
|
||||
|
||||
public CardAiHints getAiHints() {
|
||||
return aiHints;
|
||||
}
|
||||
|
||||
@Override
|
||||
public CardType getType() {
|
||||
switch(splitType.getAggregationMethod()) {
|
||||
case AGGREGATE: // no cards currently have different types
|
||||
return CardType.combine(mainPart.getType(), otherPart.getType());
|
||||
default:
|
||||
return mainPart.getType();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public ManaCost getManaCost() {
|
||||
switch(splitType.getAggregationMethod()) {
|
||||
case AGGREGATE:
|
||||
return ManaCost.combine(mainPart.getManaCost(), otherPart.getManaCost());
|
||||
default:
|
||||
return mainPart.getManaCost();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public ColorSet getColor() {
|
||||
switch(splitType.getAggregationMethod()) {
|
||||
case AGGREGATE:
|
||||
return ColorSet.fromMask(mainPart.getColor().getColor() | otherPart.getColor().getColor());
|
||||
default:
|
||||
return mainPart.getColor();
|
||||
}
|
||||
}
|
||||
|
||||
@Override public int getIntPower() { return mainPart.getIntPower(); }
|
||||
@Override public int getIntToughness() { return mainPart.getIntToughness(); }
|
||||
@Override public String getPower() { return mainPart.getPower(); }
|
||||
@Override public String getToughness() { return mainPart.getToughness(); }
|
||||
@Override public int getInitialLoyalty() { return mainPart.getInitialLoyalty(); }
|
||||
|
||||
@Override
|
||||
public String getOracleText() {
|
||||
switch(splitType.getAggregationMethod()) {
|
||||
case AGGREGATE:
|
||||
return mainPart.getOracleText() + "\r\n\r\n" + otherPart.getOracleText();
|
||||
default:
|
||||
return mainPart.getOracleText();
|
||||
}
|
||||
}
|
||||
|
||||
// public Set<String> getSets() { return this.setsPrinted.keySet(); }
|
||||
// public CardInSet getEditionInfo(final String setCode) {
|
||||
// final CardInSet result = this.setsPrinted.get(setCode);
|
||||
// return result; // if returns null, String.format("Card '%s' was never printed in set '%s'", this.getName(), setCode);
|
||||
// }
|
||||
|
||||
// vanguard card fields, they don't use sides.
|
||||
private int deltaHand;
|
||||
private int deltaLife;
|
||||
|
||||
public int getHand() { return deltaHand; }
|
||||
public int getLife() { return deltaLife; }
|
||||
public void setVanguardProperties(String pt) {
|
||||
final int slashPos = pt == null ? -1 : pt.indexOf('/');
|
||||
if (slashPos == -1) {
|
||||
throw new RuntimeException(String.format("Vanguard '%s' has bad hand/life stats", this.getName()));
|
||||
}
|
||||
this.deltaHand = Integer.parseInt(pt.substring(0, slashPos).replace("+", ""));
|
||||
this.deltaLife = Integer.parseInt(pt.substring(slashPos+1).replace("+", ""));
|
||||
}
|
||||
|
||||
// Downloadable image
|
||||
private String dlUrl;
|
||||
private String dlUrlOtherSide;
|
||||
public String getPictureUrl(boolean backface ) { return backface ? dlUrlOtherSide : dlUrl; }
|
||||
public void setDlUrls(String[] dlUrls) { this.dlUrl = dlUrls[0]; this.dlUrlOtherSide = dlUrls[1]; }
|
||||
|
||||
public final List<String> getReplacements() {
|
||||
return null;
|
||||
}
|
||||
|
||||
public final List<String> getTriggers() {
|
||||
return null;
|
||||
}
|
||||
|
||||
public final List<String> getStaticAbilities() {
|
||||
return null;
|
||||
}
|
||||
|
||||
public final List<String> getAbilities() {
|
||||
return null;
|
||||
}
|
||||
|
||||
public ColorSet getColorIdentity() {
|
||||
return colorIdentity;
|
||||
|
||||
}
|
||||
}
|
||||
549
forge-core/src/main/java/forge/card/CardRulesPredicates.java
Normal file
549
forge-core/src/main/java/forge/card/CardRulesPredicates.java
Normal file
@@ -0,0 +1,549 @@
|
||||
package forge.card;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import com.google.common.base.Predicate;
|
||||
import com.google.common.base.Predicates;
|
||||
import com.google.common.collect.Iterables;
|
||||
import forge.util.ComparableOp;
|
||||
import forge.util.PredicateString;
|
||||
|
||||
/**
|
||||
* Filtering conditions specific for CardRules class, defined here along with
|
||||
* some presets.
|
||||
*/
|
||||
public final class CardRulesPredicates {
|
||||
|
||||
/** The Constant isKeptInAiDecks. */
|
||||
public static final Predicate<CardRules> IS_KEPT_IN_AI_DECKS = new Predicate<CardRules>() {
|
||||
@Override
|
||||
public boolean apply(final CardRules card) {
|
||||
return !card.getAiHints().getRemAIDecks();
|
||||
}
|
||||
};
|
||||
|
||||
/** The Constant isKeptInRandomDecks. */
|
||||
public static final Predicate<CardRules> IS_KEPT_IN_RANDOM_DECKS = new Predicate<CardRules>() {
|
||||
@Override
|
||||
public boolean apply(final CardRules card) {
|
||||
return !card.getAiHints().getRemRandomDecks();
|
||||
}
|
||||
};
|
||||
|
||||
// Static builder methods - they choose concrete implementation by
|
||||
// themselves
|
||||
/**
|
||||
* Cmc.
|
||||
*
|
||||
* @param op
|
||||
* the op
|
||||
* @param what
|
||||
* the what
|
||||
* @return the predicate
|
||||
*/
|
||||
public static Predicate<CardRules> cmc(final ComparableOp op, final int what) {
|
||||
return new LeafNumber(LeafNumber.CardField.CMC, op, what);
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param op
|
||||
* the op
|
||||
* @param what
|
||||
* the what
|
||||
* @return the predicate
|
||||
*/
|
||||
public static Predicate<CardRules> power(final ComparableOp op, final int what) {
|
||||
return new LeafNumber(LeafNumber.CardField.POWER, op, what);
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param op
|
||||
* the op
|
||||
* @param what
|
||||
* the what
|
||||
* @return the predicate
|
||||
*/
|
||||
public static Predicate<CardRules> toughness(final ComparableOp op, final int what) {
|
||||
return new LeafNumber(LeafNumber.CardField.TOUGHNESS, op, what);
|
||||
}
|
||||
|
||||
// P/T
|
||||
/**
|
||||
* Rules.
|
||||
*
|
||||
* @param op
|
||||
* the op
|
||||
* @param what
|
||||
* the what
|
||||
* @return the predicate
|
||||
*/
|
||||
public static Predicate<CardRules> rules(final PredicateString.StringOp op, final String what) {
|
||||
return new LeafString(LeafString.CardField.ORACLE_TEXT, op, what);
|
||||
}
|
||||
|
||||
/**
|
||||
* Name.
|
||||
*
|
||||
* @param op
|
||||
* the op
|
||||
* @param what
|
||||
* the what
|
||||
* @return the predicate
|
||||
*/
|
||||
public static Predicate<CardRules> name(final PredicateString.StringOp op, final String what) {
|
||||
return new LeafString(LeafString.CardField.NAME, op, what);
|
||||
}
|
||||
|
||||
/**
|
||||
* TODO: Write javadoc for this method.
|
||||
* @param transform
|
||||
* @return
|
||||
*/
|
||||
public static Predicate<CardRules> splitType(CardSplitType transform) {
|
||||
return new PredicateSplitType(transform);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sub type.
|
||||
*
|
||||
* @param what
|
||||
* the what
|
||||
* @return the predicate
|
||||
*/
|
||||
public static Predicate<CardRules> subType(final String what) {
|
||||
return new LeafString(LeafString.CardField.SUBTYPE, PredicateString.StringOp.CONTAINS, what);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sub type.
|
||||
*
|
||||
* @param op
|
||||
* the op
|
||||
* @param what
|
||||
* the what
|
||||
* @return the predicate
|
||||
*/
|
||||
public static Predicate<CardRules> subType(final PredicateString.StringOp op, final String what) {
|
||||
return new LeafString(LeafString.CardField.SUBTYPE, op, what);
|
||||
}
|
||||
|
||||
/**
|
||||
* Joined type.
|
||||
*
|
||||
* @param op
|
||||
* the op
|
||||
* @param what
|
||||
* the what
|
||||
* @return the predicate
|
||||
*/
|
||||
public static Predicate<CardRules> joinedType(final PredicateString.StringOp op, final String what) {
|
||||
return new LeafString(LeafString.CardField.JOINED_TYPE, op, what);
|
||||
}
|
||||
|
||||
/**
|
||||
* Has Keyword.
|
||||
*
|
||||
* @param keyword
|
||||
* the keyword
|
||||
* @return the predicate
|
||||
*/
|
||||
public static Predicate<CardRules> hasKeyword(final String keyword) {
|
||||
return new Predicate<CardRules>() {
|
||||
@Override
|
||||
public boolean apply(final CardRules card) {
|
||||
return Iterables.contains(card.getMainPart().getKeywords(), keyword);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Core type.
|
||||
*
|
||||
* @param isEqual
|
||||
* the is equal
|
||||
* @param what
|
||||
* the what
|
||||
* @return the predicate
|
||||
*/
|
||||
public static Predicate<CardRules> coreType(final boolean isEqual, final String what) {
|
||||
try {
|
||||
return CardRulesPredicates.coreType(isEqual, Enum.valueOf(CardCoreType.class, what));
|
||||
} catch (final Exception e) {
|
||||
return com.google.common.base.Predicates.alwaysFalse();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Core type.
|
||||
*
|
||||
* @param isEqual
|
||||
* the is equal
|
||||
* @param type
|
||||
* the type
|
||||
* @return the predicate
|
||||
*/
|
||||
public static Predicate<CardRules> coreType(final boolean isEqual, final CardCoreType type) {
|
||||
return new PredicateCoreType(type, isEqual);
|
||||
}
|
||||
|
||||
/**
|
||||
* Super type.
|
||||
*
|
||||
* @param isEqual
|
||||
* the is equal
|
||||
* @param what
|
||||
* the what
|
||||
* @return the predicate
|
||||
*/
|
||||
public static Predicate<CardRules> superType(final boolean isEqual, final String what) {
|
||||
try {
|
||||
return CardRulesPredicates.superType(isEqual, Enum.valueOf(CardSuperType.class, what));
|
||||
} catch (final Exception e) {
|
||||
return com.google.common.base.Predicates.alwaysFalse();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Super type.
|
||||
*
|
||||
* @param isEqual
|
||||
* the is equal
|
||||
* @param type
|
||||
* the type
|
||||
* @return the predicate
|
||||
*/
|
||||
public static Predicate<CardRules> superType(final boolean isEqual, final CardSuperType type) {
|
||||
return new PredicateSuperType(type, isEqual);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Checks for color.
|
||||
*
|
||||
* @param thatColor
|
||||
* the that color
|
||||
* @return the predicate
|
||||
*/
|
||||
public static Predicate<CardRules> hasColor(final byte thatColor) {
|
||||
return new LeafColor(LeafColor.ColorOperator.HasAllOf, thatColor);
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if is color.
|
||||
*
|
||||
* @param thatColor
|
||||
* the that color
|
||||
* @return the predicate
|
||||
*/
|
||||
public static Predicate<CardRules> isColor(final byte thatColor) {
|
||||
return new LeafColor(LeafColor.ColorOperator.HasAnyOf, thatColor);
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if is exactly that color.
|
||||
*
|
||||
* @param thatColor
|
||||
* color to check
|
||||
* @return the predicate
|
||||
*/
|
||||
public static Predicate<CardRules> isMonoColor(final byte thatColor) {
|
||||
return new LeafColor(LeafColor.ColorOperator.Equals, thatColor);
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks for cnt colors.
|
||||
*
|
||||
* @param cntColors
|
||||
* the cnt colors
|
||||
* @return the predicate
|
||||
*/
|
||||
public static Predicate<CardRules> hasCntColors(final byte cntColors) {
|
||||
return new LeafColor(LeafColor.ColorOperator.CountColors, cntColors);
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks for at least cnt colors.
|
||||
*
|
||||
* @param cntColors
|
||||
* the cnt colors
|
||||
* @return the predicate
|
||||
*/
|
||||
public static Predicate<CardRules> hasAtLeastCntColors(final byte cntColors) {
|
||||
return new LeafColor(LeafColor.ColorOperator.CountColorsGreaterOrEqual, cntColors);
|
||||
}
|
||||
|
||||
private static class LeafString extends PredicateString<CardRules> {
|
||||
public enum CardField {
|
||||
ORACLE_TEXT, NAME, SUBTYPE, JOINED_TYPE
|
||||
}
|
||||
|
||||
private final String operand;
|
||||
private final LeafString.CardField field;
|
||||
|
||||
@Override
|
||||
public boolean apply(final CardRules card) {
|
||||
boolean shouldContain;
|
||||
switch (this.field) {
|
||||
case NAME:
|
||||
return op(card.getName(), this.operand);
|
||||
case SUBTYPE:
|
||||
shouldContain = (this.getOperator() == StringOp.CONTAINS) || (this.getOperator() == StringOp.EQUALS);
|
||||
return shouldContain == card.getType().subTypeContains(this.operand);
|
||||
case ORACLE_TEXT:
|
||||
return op(card.getOracleText(), operand);
|
||||
case JOINED_TYPE:
|
||||
return op(card.getType().toString(), operand);
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
public LeafString(final LeafString.CardField field, final StringOp operator, final String operand) {
|
||||
super(operator);
|
||||
this.field = field;
|
||||
this.operand = operand;
|
||||
}
|
||||
}
|
||||
|
||||
private static class LeafColor implements Predicate<CardRules> {
|
||||
public enum ColorOperator {
|
||||
CountColors, CountColorsGreaterOrEqual, HasAnyOf, HasAllOf, Equals
|
||||
}
|
||||
|
||||
private final LeafColor.ColorOperator op;
|
||||
private final byte color;
|
||||
|
||||
public LeafColor(final LeafColor.ColorOperator operator, final byte thatColor) {
|
||||
this.op = operator;
|
||||
this.color = thatColor;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean apply(final CardRules subject) {
|
||||
if (null == subject) {
|
||||
return false;
|
||||
}
|
||||
switch (this.op) {
|
||||
case CountColors:
|
||||
return subject.getColor().countColors() == this.color;
|
||||
case CountColorsGreaterOrEqual:
|
||||
return subject.getColor().countColors() >= this.color;
|
||||
case Equals:
|
||||
return subject.getColor().isEqual(this.color);
|
||||
case HasAllOf:
|
||||
return subject.getColor().hasAllColors(this.color);
|
||||
case HasAnyOf:
|
||||
return subject.getColor().hasAnyColor(this.color);
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static class LeafNumber implements Predicate<CardRules> {
|
||||
public enum CardField {
|
||||
CMC, POWER, TOUGHNESS,
|
||||
}
|
||||
|
||||
private final LeafNumber.CardField field;
|
||||
private final ComparableOp operator;
|
||||
private final int operand;
|
||||
|
||||
public LeafNumber(final LeafNumber.CardField field, final ComparableOp op, final int what) {
|
||||
this.field = field;
|
||||
this.operand = what;
|
||||
this.operator = op;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean apply(final CardRules card) {
|
||||
int value;
|
||||
switch (this.field) {
|
||||
case CMC:
|
||||
return this.op(card.getManaCost().getCMC(), this.operand);
|
||||
case POWER:
|
||||
value = card.getIntPower();
|
||||
return value >= 0 ? this.op(value, this.operand) : false;
|
||||
case TOUGHNESS:
|
||||
value = card.getIntToughness();
|
||||
return value >= 0 ? this.op(value, this.operand) : false;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
private boolean op(final int op1, final int op2) {
|
||||
switch (this.operator) {
|
||||
case EQUALS:
|
||||
return op1 == op2;
|
||||
case GREATER_THAN:
|
||||
return op1 > op2;
|
||||
case GT_OR_EQUAL:
|
||||
return op1 >= op2;
|
||||
case LESS_THAN:
|
||||
return op1 < op2;
|
||||
case LT_OR_EQUAL:
|
||||
return op1 <= op2;
|
||||
case NOT_EQUALS:
|
||||
return op1 != op2;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static class PredicateCoreType implements Predicate<CardRules> {
|
||||
private final CardCoreType operand;
|
||||
private final boolean shouldBeEqual;
|
||||
|
||||
@Override
|
||||
public boolean apply(final CardRules card) {
|
||||
if (null == card) {
|
||||
return false;
|
||||
}
|
||||
return this.shouldBeEqual == card.getType().typeContains(this.operand);
|
||||
}
|
||||
|
||||
public PredicateCoreType(final CardCoreType type, final boolean wantEqual) {
|
||||
this.operand = type;
|
||||
this.shouldBeEqual = wantEqual;
|
||||
}
|
||||
}
|
||||
|
||||
private static class PredicateSuperType implements Predicate<CardRules> {
|
||||
private final CardSuperType operand;
|
||||
private final boolean shouldBeEqual;
|
||||
|
||||
@Override
|
||||
public boolean apply(final CardRules card) {
|
||||
return this.shouldBeEqual == card.getType().superTypeContains(this.operand);
|
||||
}
|
||||
|
||||
public PredicateSuperType(final CardSuperType type, final boolean wantEqual) {
|
||||
this.operand = type;
|
||||
this.shouldBeEqual = wantEqual;
|
||||
}
|
||||
}
|
||||
|
||||
private static class PredicateSplitType implements Predicate<CardRules> {
|
||||
private final CardSplitType cst;
|
||||
|
||||
public PredicateSplitType(final CardSplitType type) {
|
||||
cst = type;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean apply(final CardRules subject) {
|
||||
return subject.getSplitType() == cst;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* The Class Presets.
|
||||
*/
|
||||
public static class Presets {
|
||||
|
||||
/** The Constant isCreature. */
|
||||
public static final Predicate<CardRules> IS_CREATURE = CardRulesPredicates
|
||||
.coreType(true, CardCoreType.Creature);
|
||||
|
||||
public static final Predicate<CardRules> IS_LEGENDARY = CardRulesPredicates
|
||||
.superType(true, CardSuperType.Legendary);
|
||||
|
||||
/** The Constant isArtifact. */
|
||||
public static final Predicate<CardRules> IS_ARTIFACT = CardRulesPredicates
|
||||
.coreType(true, CardCoreType.Artifact);
|
||||
|
||||
/** The Constant isEquipment. */
|
||||
public static final Predicate<CardRules> IS_EQUIPMENT = CardRulesPredicates
|
||||
.subType("Equipment");
|
||||
|
||||
/** The Constant isLand. */
|
||||
public static final Predicate<CardRules> IS_LAND = CardRulesPredicates.coreType(true, CardCoreType.Land);
|
||||
|
||||
/** The Constant isBasicLand. */
|
||||
public static final Predicate<CardRules> IS_BASIC_LAND = new Predicate<CardRules>() {
|
||||
@Override
|
||||
public boolean apply(final CardRules subject) {
|
||||
return subject.getType().isBasicLand();
|
||||
}
|
||||
};
|
||||
|
||||
/** The Constant isNonBasicLand. */
|
||||
public static final Predicate<CardRules> IS_NONBASIC_LAND = new Predicate<CardRules>() {
|
||||
@Override
|
||||
public boolean apply(final CardRules subject) {
|
||||
return subject.getType().isLand() && !subject.getType().isBasicLand();
|
||||
}
|
||||
};
|
||||
|
||||
/** The Constant isPlaneswalker. */
|
||||
public static final Predicate<CardRules> IS_PLANESWALKER = CardRulesPredicates.coreType(true,
|
||||
CardCoreType.Planeswalker);
|
||||
|
||||
/** The Constant isInstant. */
|
||||
public static final Predicate<CardRules> IS_INSTANT = CardRulesPredicates.coreType(true, CardCoreType.Instant);
|
||||
|
||||
/** The Constant isSorcery. */
|
||||
public static final Predicate<CardRules> IS_SORCERY = CardRulesPredicates.coreType(true, CardCoreType.Sorcery);
|
||||
|
||||
/** The Constant isEnchantment. */
|
||||
public static final Predicate<CardRules> IS_ENCHANTMENT = CardRulesPredicates.coreType(true, CardCoreType.Enchantment);
|
||||
|
||||
public static final Predicate<CardRules> IS_PLANE = CardRulesPredicates.coreType(true, CardCoreType.Plane);
|
||||
public static final Predicate<CardRules> IS_PHENOMENON = CardRulesPredicates.coreType(true, CardCoreType.Phenomenon);
|
||||
public static final Predicate<CardRules> IS_PLANE_OR_PHENOMENON = Predicates.or(IS_PLANE, IS_PHENOMENON);
|
||||
public static final Predicate<CardRules> IS_SCHEME = CardRulesPredicates.coreType(true, CardCoreType.Scheme);
|
||||
public static final Predicate<CardRules> IS_VANGUARD = CardRulesPredicates.coreType(true, CardCoreType.Vanguard);
|
||||
|
||||
/** The Constant isNonLand. */
|
||||
public static final Predicate<CardRules> IS_NON_LAND = CardRulesPredicates.coreType(false, CardCoreType.Land);
|
||||
|
||||
/** The Constant isNonCreatureSpell. */
|
||||
public static final Predicate<CardRules> IS_NON_CREATURE_SPELL = Predicates.not(Predicates.or(
|
||||
Presets.IS_CREATURE, Presets.IS_LAND));
|
||||
|
||||
/** The Constant IS_NONCREATURE_SPELL_FOR_GENERATOR. **/
|
||||
@SuppressWarnings("unchecked")
|
||||
public static final Predicate<CardRules> IS_NONCREATURE_SPELL_FOR_GENERATOR = com.google.common.base.Predicates
|
||||
.or(Presets.IS_SORCERY, Presets.IS_INSTANT, Presets.IS_PLANESWALKER, Presets.IS_ENCHANTMENT,
|
||||
Predicates.and(Presets.IS_ARTIFACT, Predicates.not(Presets.IS_CREATURE)));
|
||||
|
||||
/** The Constant isWhite. */
|
||||
public static final Predicate<CardRules> IS_WHITE = CardRulesPredicates.isColor(MagicColor.WHITE);
|
||||
|
||||
/** The Constant isBlue. */
|
||||
public static final Predicate<CardRules> IS_BLUE = CardRulesPredicates.isColor(MagicColor.BLUE);
|
||||
|
||||
/** The Constant isBlack. */
|
||||
public static final Predicate<CardRules> IS_BLACK = CardRulesPredicates.isColor(MagicColor.BLACK);
|
||||
|
||||
/** The Constant isRed. */
|
||||
public static final Predicate<CardRules> IS_RED = CardRulesPredicates.isColor(MagicColor.RED);
|
||||
|
||||
/** The Constant isGreen. */
|
||||
public static final Predicate<CardRules> IS_GREEN = CardRulesPredicates.isColor(MagicColor.GREEN);
|
||||
|
||||
/** The Constant isColorless. */
|
||||
public static final Predicate<CardRules> IS_COLORLESS = CardRulesPredicates.hasCntColors((byte) 0);
|
||||
|
||||
/** The Constant isMulticolor. */
|
||||
public static final Predicate<CardRules> IS_MULTICOLOR = CardRulesPredicates.hasAtLeastCntColors((byte) 2);
|
||||
|
||||
public static final Predicate<CardRules> IS_MONOCOLOR = CardRulesPredicates.hasCntColors((byte) 1);
|
||||
|
||||
/** The Constant colors. */
|
||||
public static final List<Predicate<CardRules>> COLORS = new ArrayList<Predicate<CardRules>>();
|
||||
static {
|
||||
Presets.COLORS.add(Presets.IS_WHITE);
|
||||
Presets.COLORS.add(Presets.IS_BLUE);
|
||||
Presets.COLORS.add(Presets.IS_BLACK);
|
||||
Presets.COLORS.add(Presets.IS_RED);
|
||||
Presets.COLORS.add(Presets.IS_GREEN);
|
||||
Presets.COLORS.add(Presets.IS_COLORLESS);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -24,8 +24,6 @@ import java.util.List;
|
||||
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
|
||||
import forge.Constant;
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* Immutable Card type. Can be build only from parsing a string.
|
||||
@@ -236,6 +234,47 @@ public final class CardType implements Comparable<CardType> {
|
||||
return this.coreType.contains(CardCoreType.Phenomenon);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* The Interface CardTypes.
|
||||
*/
|
||||
public static class Constant {
|
||||
|
||||
/** The loaded. */
|
||||
public static final boolean[] LOADED = { false };
|
||||
|
||||
/** The card types. */
|
||||
public static final List<String> CARD_TYPES = new ArrayList<String>();
|
||||
|
||||
/** The super types. */
|
||||
public static final List<String> SUPER_TYPES = new ArrayList<String>();
|
||||
|
||||
/** The basic types. */
|
||||
public static final List<String> BASIC_TYPES = new ArrayList<String>();
|
||||
|
||||
/** The land types. */
|
||||
public static final List<String> LAND_TYPES = new ArrayList<String>();
|
||||
|
||||
/** The creature types. */
|
||||
public static final List<String> CREATURE_TYPES = new ArrayList<String>();
|
||||
|
||||
/** The instant types. */
|
||||
public static final List<String> INSTANT_TYPES = new ArrayList<String>();
|
||||
|
||||
/** The sorcery types. */
|
||||
public static final List<String> SORCERY_TYPES = new ArrayList<String>();
|
||||
|
||||
/** The enchantment types. */
|
||||
public static final List<String> ENCHANTMENT_TYPES = new ArrayList<String>();
|
||||
|
||||
/** The artifact types. */
|
||||
public static final List<String> ARTIFACT_TYPES = new ArrayList<String>();
|
||||
|
||||
/** The walker types. */
|
||||
public static final List<String> WALKER_TYPES = new ArrayList<String>();
|
||||
}
|
||||
|
||||
///////// Utility methods
|
||||
public static boolean isACardType(final String cardType) {
|
||||
return CardType.getAllCardTypes().contains(cardType);
|
||||
@@ -245,7 +284,7 @@ public final class CardType implements Comparable<CardType> {
|
||||
final ArrayList<String> types = new ArrayList<String>();
|
||||
|
||||
// types.addAll(getCardTypes());
|
||||
types.addAll(Constant.CardTypes.CARD_TYPES);
|
||||
types.addAll(Constant.CARD_TYPES);
|
||||
|
||||
// not currently used by Forge
|
||||
types.add("Plane");
|
||||
@@ -258,7 +297,7 @@ public final class CardType implements Comparable<CardType> {
|
||||
public static ArrayList<String> getBasicTypes() {
|
||||
final ArrayList<String> types = new ArrayList<String>();
|
||||
|
||||
types.addAll(Constant.CardTypes.BASIC_TYPES);
|
||||
types.addAll(Constant.BASIC_TYPES);
|
||||
|
||||
return types;
|
||||
}
|
||||
@@ -266,8 +305,8 @@ public final class CardType implements Comparable<CardType> {
|
||||
public static ArrayList<String> getLandTypes() {
|
||||
final ArrayList<String> types = new ArrayList<String>();
|
||||
|
||||
types.addAll(Constant.CardTypes.BASIC_TYPES);
|
||||
types.addAll(Constant.CardTypes.LAND_TYPES);
|
||||
types.addAll(Constant.BASIC_TYPES);
|
||||
types.addAll(Constant.LAND_TYPES);
|
||||
|
||||
return types;
|
||||
}
|
||||
@@ -275,13 +314,13 @@ public final class CardType implements Comparable<CardType> {
|
||||
public static ArrayList<String> getCreatureTypes() {
|
||||
final ArrayList<String> types = new ArrayList<String>();
|
||||
|
||||
types.addAll(Constant.CardTypes.CREATURE_TYPES);
|
||||
types.addAll(Constant.CREATURE_TYPES);
|
||||
|
||||
return types;
|
||||
}
|
||||
|
||||
public static boolean isASuperType(final String cardType) {
|
||||
return (Constant.CardTypes.SUPER_TYPES.contains(cardType));
|
||||
return (Constant.SUPER_TYPES.contains(cardType));
|
||||
}
|
||||
|
||||
public static boolean isASubType(final String cardType) {
|
||||
@@ -289,18 +328,18 @@ public final class CardType implements Comparable<CardType> {
|
||||
}
|
||||
|
||||
public static boolean isACreatureType(final String cardType) {
|
||||
return (Constant.CardTypes.CREATURE_TYPES.contains(cardType));
|
||||
return (Constant.CREATURE_TYPES.contains(cardType));
|
||||
}
|
||||
|
||||
public static boolean isALandType(final String cardType) {
|
||||
return (Constant.CardTypes.LAND_TYPES.contains(cardType));
|
||||
return (Constant.LAND_TYPES.contains(cardType));
|
||||
}
|
||||
|
||||
public static boolean isAPlaneswalkerType(final String cardType) {
|
||||
return (Constant.CardTypes.WALKER_TYPES.contains(cardType));
|
||||
return (Constant.WALKER_TYPES.contains(cardType));
|
||||
}
|
||||
|
||||
public static boolean isABasicLandType(final String cardType) {
|
||||
return (Constant.CardTypes.BASIC_TYPES.contains(cardType));
|
||||
return (Constant.BASIC_TYPES.contains(cardType));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -17,7 +17,6 @@
|
||||
*/
|
||||
package forge.card;
|
||||
|
||||
import forge.Constant;
|
||||
import forge.card.mana.ManaCost;
|
||||
import forge.util.BinaryUtil;
|
||||
|
||||
@@ -253,7 +252,7 @@ public final class ColorSet implements Comparable<ColorSet> {
|
||||
return "n/a";
|
||||
}
|
||||
String toReturn = MagicColor.toLongString(myColor);
|
||||
if (toReturn == Constant.Color.COLORLESS && myColor != 0) {
|
||||
if (toReturn == MagicColor.Constant.COLORLESS && myColor != 0) {
|
||||
return "multi";
|
||||
}
|
||||
return toReturn;
|
||||
|
||||
128
forge-core/src/main/java/forge/card/DeckHints.java
Normal file
128
forge-core/src/main/java/forge/card/DeckHints.java
Normal file
@@ -0,0 +1,128 @@
|
||||
package forge.card;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
|
||||
import com.google.common.base.Function;
|
||||
import com.google.common.base.Predicate;
|
||||
import com.google.common.base.Predicates;
|
||||
import com.google.common.collect.Iterables;
|
||||
import com.google.common.collect.Lists;
|
||||
|
||||
import forge.item.PaperCard;
|
||||
import forge.util.PredicateString.StringOp;
|
||||
|
||||
/**
|
||||
* DeckHints provides the ability for a Card to "want" another Card or type of
|
||||
* Cards in its random deck.
|
||||
*
|
||||
*/
|
||||
public class DeckHints {
|
||||
|
||||
/**
|
||||
* Enum of types of DeckHints.
|
||||
*/
|
||||
public enum Type {
|
||||
|
||||
/** The Color. */
|
||||
COLOR,
|
||||
/** The Keyword. */
|
||||
KEYWORD,
|
||||
/** The Name. */
|
||||
NAME,
|
||||
/** The Type. */
|
||||
TYPE,
|
||||
/** The None. */
|
||||
NONE
|
||||
}
|
||||
|
||||
private Type type = Type.NONE;
|
||||
private String filterParam = null;
|
||||
|
||||
/**
|
||||
* Construct a DeckHints from the SVar string.
|
||||
*
|
||||
* @param wants
|
||||
* SVar for DeckHints
|
||||
*/
|
||||
public DeckHints(String wants) {
|
||||
String[] pieces = wants.split("\\$");
|
||||
if (pieces.length == 2) {
|
||||
try {
|
||||
Type typeValue = Type.valueOf(pieces[0].toUpperCase());
|
||||
for (Type t : Type.values()) {
|
||||
if (typeValue == t) {
|
||||
type = t;
|
||||
break;
|
||||
}
|
||||
}
|
||||
} catch (IllegalArgumentException e) {
|
||||
// type will remain NONE
|
||||
}
|
||||
|
||||
filterParam = pieces[1];
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the type
|
||||
*/
|
||||
public Type getType() {
|
||||
return type;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a list of Cards from the given List<Card> that match this
|
||||
* DeckHints. I.e., other cards that this Card needs in its deck.
|
||||
*
|
||||
* @param cardList
|
||||
* list of cards to be filtered
|
||||
* @return List<Card> of Cards that match this DeckHints.
|
||||
*/
|
||||
public List<PaperCard> filter(Iterable<PaperCard> cardList) {
|
||||
List<PaperCard> ret;
|
||||
switch (type) {
|
||||
case TYPE:
|
||||
ret = new ArrayList<PaperCard>();
|
||||
String[] types = filterParam.split("\\|");
|
||||
for (String type : types) {
|
||||
addMatchingItems(ret, cardList, CardRulesPredicates.subType(type), PaperCard.FN_GET_RULES);
|
||||
}
|
||||
break;
|
||||
case COLOR:
|
||||
ret = new ArrayList<PaperCard>();
|
||||
String[] colors = filterParam.split("\\|");
|
||||
for (String color : colors) {
|
||||
ColorSet cc = ColorSet.fromNames(color);
|
||||
addMatchingItems(ret, cardList, CardRulesPredicates.isColor(cc.getColor()), PaperCard.FN_GET_RULES);
|
||||
}
|
||||
break;
|
||||
case KEYWORD:
|
||||
ret = new ArrayList<PaperCard>();
|
||||
String[] keywords = filterParam.split("\\|");
|
||||
for (String keyword : keywords) {
|
||||
addMatchingItems(ret, cardList, CardRulesPredicates.hasKeyword(keyword), PaperCard.FN_GET_RULES);
|
||||
}
|
||||
break;
|
||||
case NAME:
|
||||
ret = new ArrayList<PaperCard>();
|
||||
String[] names = filterParam.split("\\|");
|
||||
for (String name : names) {
|
||||
addMatchingItems(ret, cardList, CardRulesPredicates.name(StringOp.EQUALS, name), PaperCard.FN_GET_RULES);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
ret = Lists.newArrayList(cardList);
|
||||
break;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
private static <T, U> void addMatchingItems(Collection<? super T> dest, Iterable<? extends T> source, Predicate<U> predicate, Function<T, U> fn) {
|
||||
for (T item : Iterables.filter(source, Predicates.compose(predicate, fn))) {
|
||||
dest.add(item);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
128
forge-core/src/main/java/forge/card/EditionCollection.java
Normal file
128
forge-core/src/main/java/forge/card/EditionCollection.java
Normal file
@@ -0,0 +1,128 @@
|
||||
/*
|
||||
* Forge: Play Magic: the Gathering.
|
||||
* Copyright (C) 2011 Forge Team
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package forge.card;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.TreeMap;
|
||||
|
||||
import com.google.common.base.Function;
|
||||
import com.google.common.collect.Lists;
|
||||
|
||||
import forge.util.IItemReader;
|
||||
import forge.util.storage.StorageBase;
|
||||
import forge.util.storage.StorageReaderBase;
|
||||
|
||||
public final class EditionCollection extends StorageBase<CardEdition> {
|
||||
|
||||
private final Map<String, CardEdition> aliasToEdition = new TreeMap<String, CardEdition>(String.CASE_INSENSITIVE_ORDER);
|
||||
|
||||
public EditionCollection(IItemReader<CardEdition> reader) {
|
||||
super("Card editions", reader);
|
||||
|
||||
for (CardEdition ee : this) {
|
||||
String alias = ee.getAlias();
|
||||
if (null != alias) {
|
||||
aliasToEdition.put(alias, ee);
|
||||
}
|
||||
aliasToEdition.put(ee.getCode2(), ee);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a sets by code. It will search first by three letter codes, then by aliases and two-letter codes.
|
||||
*
|
||||
* @param code
|
||||
* the code
|
||||
* @return the sets the by code
|
||||
*/
|
||||
@Override
|
||||
public CardEdition get(final String code) {
|
||||
CardEdition baseResult = super.get(code);
|
||||
return baseResult == null ? aliasToEdition.get(code) : baseResult;
|
||||
}
|
||||
|
||||
|
||||
public Iterable<CardEdition> getOrderedEditions() {
|
||||
List<CardEdition> res = Lists.newArrayList(this);
|
||||
Collections.sort(res);
|
||||
Collections.reverse(res);
|
||||
return res;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the sets by code or throw.
|
||||
*
|
||||
* @param code
|
||||
* the code
|
||||
* @return the sets the by code or throw
|
||||
*/
|
||||
public CardEdition getEditionByCodeOrThrow(final String code) {
|
||||
final CardEdition set = this.get(code);
|
||||
if (null == set) {
|
||||
throw new RuntimeException(String.format("Edition with code '%s' not found", code));
|
||||
}
|
||||
return set;
|
||||
}
|
||||
|
||||
// used by image generating code
|
||||
/**
|
||||
* Gets the code2 by code.
|
||||
*
|
||||
* @param code
|
||||
* the code
|
||||
* @return the code2 by code
|
||||
*/
|
||||
public String getCode2ByCode(final String code) {
|
||||
final CardEdition set = this.get(code);
|
||||
return set == null ? "" : set.getCode2();
|
||||
}
|
||||
|
||||
public final Function<String, CardEdition> FN_EDITION_BY_CODE = new Function<String, CardEdition>() {
|
||||
@Override
|
||||
public CardEdition apply(String code) {
|
||||
return EditionCollection.this.get(code);
|
||||
};
|
||||
};
|
||||
|
||||
/**
|
||||
* TODO: Write javadoc for this method.
|
||||
* @return
|
||||
*/
|
||||
public IItemReader<SealedProductTemplate> getBoosterGenerator() {
|
||||
// TODO Auto-generated method stub
|
||||
return new StorageReaderBase<SealedProductTemplate>(null) {
|
||||
|
||||
@Override
|
||||
public Map<String, SealedProductTemplate> readAll() {
|
||||
Map<String, SealedProductTemplate> map = new TreeMap<String, SealedProductTemplate>(String.CASE_INSENSITIVE_ORDER);
|
||||
for(CardEdition ce : EditionCollection.this) {
|
||||
map.put(ce.getCode(), ce.getBoosterTemplate());
|
||||
}
|
||||
return map;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getItemKey(SealedProductTemplate item) {
|
||||
return item.getEdition();
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
75
forge-core/src/main/java/forge/card/FatPackTemplate.java
Normal file
75
forge-core/src/main/java/forge/card/FatPackTemplate.java
Normal file
@@ -0,0 +1,75 @@
|
||||
package forge.card;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import org.apache.commons.lang3.tuple.ImmutablePair;
|
||||
import org.apache.commons.lang3.tuple.Pair;
|
||||
|
||||
import forge.util.TextUtil;
|
||||
import forge.util.storage.StorageReaderFile;
|
||||
|
||||
/**
|
||||
* TODO: Write javadoc for this type.
|
||||
*
|
||||
*/
|
||||
public class FatPackTemplate extends SealedProductTemplate {
|
||||
private final int cntBoosters;
|
||||
|
||||
|
||||
public int getCntBoosters() { return cntBoosters; }
|
||||
|
||||
private FatPackTemplate(String edition, int boosters, Iterable<Pair<String, Integer>> itrSlots)
|
||||
{
|
||||
super(edition, itrSlots);
|
||||
cntBoosters = boosters;
|
||||
}
|
||||
|
||||
public static final class Reader extends StorageReaderFile<FatPackTemplate> {
|
||||
public Reader(String pathname) {
|
||||
super(pathname, FatPackTemplate.FN_GET_NAME);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected FatPackTemplate read(String line, int i) {
|
||||
String[] headAndData = TextUtil.split(line, ':', 2);
|
||||
final String edition = headAndData[0];
|
||||
final String[] data = TextUtil.splitWithParenthesis(headAndData[1], ',');
|
||||
int nBoosters = 6;
|
||||
|
||||
List<Pair<String, Integer>> slots = new ArrayList<Pair<String,Integer>>();
|
||||
for(String slotDesc : data) {
|
||||
String[] kv = TextUtil.split(slotDesc, ' ', 2);
|
||||
if (kv[1].startsWith("Booster"))
|
||||
nBoosters = Integer.parseInt(kv[0]);
|
||||
else
|
||||
slots.add(ImmutablePair.of(kv[1], Integer.parseInt(kv[0])));
|
||||
}
|
||||
|
||||
return new FatPackTemplate(edition, nBoosters, slots);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
if (0 >= cntBoosters) {
|
||||
return "no cards";
|
||||
}
|
||||
|
||||
StringBuilder s = new StringBuilder();
|
||||
for(Pair<String, Integer> p : slots) {
|
||||
s.append(p.getRight()).append(" ").append(p.getLeft()).append(", ");
|
||||
}
|
||||
// trim the last comma and space
|
||||
if( s.length() > 0 )
|
||||
s.replace(s.length() - 2, s.length(), "");
|
||||
|
||||
if (0 < cntBoosters) {
|
||||
if( s.length() > 0 )
|
||||
s.append(" and ");
|
||||
|
||||
s.append(cntBoosters).append(" booster packs ");
|
||||
}
|
||||
return s.toString();
|
||||
}
|
||||
}
|
||||
79
forge-core/src/main/java/forge/card/FormatCollection.java
Normal file
79
forge-core/src/main/java/forge/card/FormatCollection.java
Normal file
@@ -0,0 +1,79 @@
|
||||
/*
|
||||
* Forge: Play Magic: the Gathering.
|
||||
* Copyright (C) 2011 Forge Team
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package forge.card;
|
||||
|
||||
import forge.game.GameFormat;
|
||||
import forge.util.storage.StorageReaderBase;
|
||||
import forge.util.storage.StorageBase;
|
||||
|
||||
/**
|
||||
* The Class FormatUtils.
|
||||
*/
|
||||
public final class FormatCollection extends StorageBase<GameFormat> {
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* TODO: Write javadoc for Constructor.
|
||||
* @param io
|
||||
*/
|
||||
public FormatCollection(StorageReaderBase<GameFormat> reader) {
|
||||
super("Format collections", reader);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the standard.
|
||||
*
|
||||
* @return the standard
|
||||
*/
|
||||
public GameFormat getStandard() {
|
||||
return this.map.get("Standard");
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the extended.
|
||||
*
|
||||
* @return the extended
|
||||
*/
|
||||
public GameFormat getExtended() {
|
||||
return this.map.get("Extended");
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the modern.
|
||||
*
|
||||
* @return the modern
|
||||
*/
|
||||
public GameFormat getModern() {
|
||||
return this.map.get("Modern");
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a specified format.
|
||||
* @return the requested format
|
||||
*/
|
||||
public GameFormat getFormat(String format) {
|
||||
return this.map.get(format);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* TODO: Write javadoc for this type.
|
||||
*
|
||||
*/
|
||||
34
forge-core/src/main/java/forge/card/ICardDatabase.java
Normal file
34
forge-core/src/main/java/forge/card/ICardDatabase.java
Normal file
@@ -0,0 +1,34 @@
|
||||
package forge.card;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
|
||||
import com.google.common.base.Predicate;
|
||||
|
||||
import forge.item.PaperCard;
|
||||
|
||||
public interface ICardDatabase {
|
||||
PaperCard tryGetCard(String cardName);
|
||||
PaperCard tryGetCard(String cardName, boolean fromLastSet);
|
||||
PaperCard tryGetCard(String cardName, String edition);
|
||||
PaperCard tryGetCard(String cardName, String edition, int artIndex);
|
||||
PaperCard tryGetCardPrintedByDate(String name0, boolean fromLatestSet, Date printedBefore);
|
||||
|
||||
PaperCard getCard(String cardName);
|
||||
PaperCard getCard(String cardName, boolean fromLastSet);
|
||||
PaperCard getCard(String cardName, String edition);
|
||||
PaperCard getCard(String cardName, String edition, int artIndex);
|
||||
PaperCard getCardPrintedByDate(String name0, boolean fromLatestSet, Date printedBefore);
|
||||
|
||||
PaperCard getFoiled(PaperCard cpi);
|
||||
|
||||
int getPrintCount(String cardName, String edition);
|
||||
int getMaxPrintCount(String cardName);
|
||||
|
||||
Collection<PaperCard> getUniqueCards();
|
||||
List<PaperCard> getAllCards();
|
||||
List<PaperCard> getAllCards(Predicate<PaperCard> predicate);
|
||||
|
||||
Predicate<? super PaperCard> wasPrintedInSets(List<String> allowedSetCodes);
|
||||
}
|
||||
16
forge-core/src/main/java/forge/card/IUnOpenedProduct.java
Normal file
16
forge-core/src/main/java/forge/card/IUnOpenedProduct.java
Normal file
@@ -0,0 +1,16 @@
|
||||
package forge.card;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import com.google.common.base.Supplier;
|
||||
|
||||
import forge.item.PaperCard;
|
||||
|
||||
/**
|
||||
* TODO: Write javadoc for this type.
|
||||
*
|
||||
*/
|
||||
|
||||
public interface IUnOpenedProduct extends Supplier<List<PaperCard>> {
|
||||
public List<PaperCard> get();
|
||||
}
|
||||
@@ -1,6 +1,8 @@
|
||||
package forge.card;
|
||||
|
||||
import forge.Constant;
|
||||
import java.util.List;
|
||||
|
||||
import com.google.common.collect.ImmutableList;
|
||||
|
||||
/**
|
||||
* Holds byte values for each color magic has.
|
||||
@@ -22,31 +24,31 @@ public class MagicColor {
|
||||
|
||||
public static byte fromName(String s) {
|
||||
if( s == null ) return 0;
|
||||
if (s.equalsIgnoreCase(Constant.Color.WHITE) || s.equalsIgnoreCase("w")) {
|
||||
if (s.equalsIgnoreCase(Constant.WHITE) || s.equalsIgnoreCase("w")) {
|
||||
return MagicColor.WHITE;
|
||||
}
|
||||
if (s.equalsIgnoreCase(Constant.Color.BLUE) || s.equalsIgnoreCase("u")) {
|
||||
if (s.equalsIgnoreCase(Constant.BLUE) || s.equalsIgnoreCase("u")) {
|
||||
return MagicColor.BLUE;
|
||||
}
|
||||
if (s.equalsIgnoreCase(Constant.Color.BLACK) || s.equalsIgnoreCase("b")) {
|
||||
if (s.equalsIgnoreCase(Constant.BLACK) || s.equalsIgnoreCase("b")) {
|
||||
return MagicColor.BLACK;
|
||||
}
|
||||
if (s.equalsIgnoreCase(Constant.Color.RED) || s.equalsIgnoreCase("r")) {
|
||||
if (s.equalsIgnoreCase(Constant.RED) || s.equalsIgnoreCase("r")) {
|
||||
return MagicColor.RED;
|
||||
}
|
||||
if (s.equalsIgnoreCase(Constant.Color.GREEN) || s.equalsIgnoreCase("g")) {
|
||||
if (s.equalsIgnoreCase(Constant.GREEN) || s.equalsIgnoreCase("g")) {
|
||||
return MagicColor.GREEN;
|
||||
}
|
||||
return 0; // colorless
|
||||
}
|
||||
|
||||
public static String toShortString(String color) {
|
||||
if (color.equalsIgnoreCase(Constant.Color.SNOW)) return "S"; // compatibility
|
||||
if (color.equalsIgnoreCase(Constant.SNOW)) return "S"; // compatibility
|
||||
return toShortString(fromName(color));
|
||||
}
|
||||
|
||||
public static String toLongString(String color) {
|
||||
if (color.equalsIgnoreCase("s")) return Constant.Color.SNOW; // compatibility
|
||||
if (color.equalsIgnoreCase("s")) return Constant.SNOW; // compatibility
|
||||
return toLongString(fromName(color));
|
||||
}
|
||||
|
||||
@@ -63,12 +65,47 @@ public class MagicColor {
|
||||
|
||||
public static String toLongString(byte color) {
|
||||
switch(color){
|
||||
case GREEN: return Constant.Color.GREEN ;
|
||||
case RED: return Constant.Color.RED;
|
||||
case BLUE: return Constant.Color.BLUE;
|
||||
case BLACK: return Constant.Color.BLACK;
|
||||
case WHITE: return Constant.Color.WHITE;
|
||||
default: return Constant.Color.COLORLESS;
|
||||
case GREEN: return Constant.GREEN ;
|
||||
case RED: return Constant.RED;
|
||||
case BLUE: return Constant.BLUE;
|
||||
case BLACK: return Constant.BLACK;
|
||||
case WHITE: return Constant.WHITE;
|
||||
default: return Constant.COLORLESS;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* The Interface Color.
|
||||
*/
|
||||
public static class Constant {
|
||||
|
||||
/** The Black. */
|
||||
public static final String BLACK = "black";
|
||||
|
||||
/** The Blue. */
|
||||
public static final String BLUE = "blue";
|
||||
|
||||
/** The Green. */
|
||||
public static final String GREEN = "green";
|
||||
|
||||
/** The Red. */
|
||||
public static final String RED = "red";
|
||||
|
||||
/** The White. */
|
||||
public static final String WHITE = "white";
|
||||
|
||||
/** The Colorless. */
|
||||
public static final String COLORLESS = "colorless";
|
||||
// color order "wubrg"
|
||||
|
||||
/** The only colors. */
|
||||
public static final ImmutableList<String> ONLY_COLORS = ImmutableList.of(WHITE, BLUE, BLACK, RED, GREEN);
|
||||
|
||||
/** The Snow. */
|
||||
public static final String SNOW = "snow";
|
||||
|
||||
/** The Basic lands. */
|
||||
public static final List<String> BASIC_LANDS = ImmutableList.of("Plains", "Island", "Swamp", "Mountain", "Forest");
|
||||
public static final List<String> SNOW_LANDS = ImmutableList.of("Snow-Covered Plains", "Snow-Covered Island", "Snow-Covered Swamp", "Snow-Covered Mountain", "Snow-Covered Forest");
|
||||
}
|
||||
}
|
||||
|
||||
131
forge-core/src/main/java/forge/card/PrintSheet.java
Normal file
131
forge-core/src/main/java/forge/card/PrintSheet.java
Normal file
@@ -0,0 +1,131 @@
|
||||
package forge.card;
|
||||
|
||||
import java.io.File;
|
||||
import java.util.List;
|
||||
import java.util.Map.Entry;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
|
||||
import com.google.common.base.Function;
|
||||
|
||||
import forge.util.ItemPool;
|
||||
import forge.deck.CardPool;
|
||||
import forge.item.PaperCard;
|
||||
import forge.util.MyRandom;
|
||||
import forge.util.storage.StorageReaderFileSections;
|
||||
|
||||
|
||||
/**
|
||||
* TODO: Write javadoc for this type.
|
||||
*
|
||||
*/
|
||||
public class PrintSheet {
|
||||
public static final Function<PrintSheet, String> FN_GET_KEY = new Function<PrintSheet, String>() {
|
||||
@Override public final String apply(PrintSheet sheet) { return sheet.name; }
|
||||
};
|
||||
|
||||
|
||||
private final ItemPool<PaperCard> cardsWithWeights;
|
||||
|
||||
|
||||
private final String name;
|
||||
public PrintSheet(String name0) {
|
||||
this(name0, null);
|
||||
}
|
||||
|
||||
public PrintSheet(String name0, ItemPool<PaperCard> pool) {
|
||||
name = name0;
|
||||
cardsWithWeights = pool != null ? pool : new ItemPool<PaperCard>(PaperCard.class);
|
||||
}
|
||||
|
||||
public void add(PaperCard card) {
|
||||
add(card,1);
|
||||
}
|
||||
|
||||
public void add(PaperCard card, int weight) {
|
||||
cardsWithWeights.add(card, weight);
|
||||
}
|
||||
|
||||
public void addAll(Iterable<PaperCard> cards) {
|
||||
addAll(cards, 1);
|
||||
}
|
||||
|
||||
public void addAll(Iterable<PaperCard> cards, int weight) {
|
||||
for(PaperCard card : cards)
|
||||
cardsWithWeights.add(card, weight);
|
||||
}
|
||||
|
||||
/** Cuts cards out of a sheet - they won't be printed again.
|
||||
* Please use mutable sheets for cubes only.*/
|
||||
public void removeAll(Iterable<PaperCard> cards) {
|
||||
for(PaperCard card : cards)
|
||||
cardsWithWeights.remove(card);
|
||||
}
|
||||
|
||||
private PaperCard fetchRoulette(int start, int roulette, Collection<PaperCard> toSkip) {
|
||||
int sum = start;
|
||||
boolean isSecondRun = start > 0;
|
||||
for(Entry<PaperCard, Integer> cc : cardsWithWeights ) {
|
||||
sum += cc.getValue().intValue();
|
||||
if( sum > roulette ) {
|
||||
if( toSkip != null && toSkip.contains(cc.getKey()))
|
||||
continue;
|
||||
return cc.getKey();
|
||||
}
|
||||
}
|
||||
if( isSecondRun )
|
||||
throw new IllegalStateException("Print sheet does not have enough unique cards");
|
||||
|
||||
return fetchRoulette(sum + 1, roulette, toSkip); // start over from beginning, in case last cards were to skip
|
||||
}
|
||||
|
||||
public List<PaperCard> random(int number, boolean wantUnique) {
|
||||
List<PaperCard> result = new ArrayList<PaperCard>();
|
||||
|
||||
int totalWeight = cardsWithWeights.countAll();
|
||||
if( totalWeight == 0) {
|
||||
System.err.println("No cards were found on sheet " + name);
|
||||
return result;
|
||||
}
|
||||
|
||||
// If they ask for 40 unique basic lands (to make a fatpack) out of 20 distinct possible, add the whole print run N times.
|
||||
int uniqueCards = cardsWithWeights.countDistinct();
|
||||
while ( number >= uniqueCards ) {
|
||||
for(Entry<PaperCard, Integer> kv : cardsWithWeights) {
|
||||
result.add(kv.getKey());
|
||||
}
|
||||
number -= uniqueCards;
|
||||
}
|
||||
|
||||
List<PaperCard> uniques = wantUnique ? new ArrayList<PaperCard>() : null;
|
||||
for(int iC = 0; iC < number; iC++) {
|
||||
int index = MyRandom.getRandom().nextInt(totalWeight);
|
||||
PaperCard toAdd = fetchRoulette(0, index, wantUnique ? uniques : null);
|
||||
result.add(toAdd);
|
||||
if( wantUnique )
|
||||
uniques.add(toAdd);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
public boolean isEmpty() {
|
||||
return cardsWithWeights.isEmpty();
|
||||
}
|
||||
|
||||
public Iterable<PaperCard> toFlatList() {
|
||||
return cardsWithWeights.toFlatList();
|
||||
}
|
||||
|
||||
public static class Reader extends StorageReaderFileSections<PrintSheet> {
|
||||
public Reader(File file) {
|
||||
super(file, PrintSheet.FN_GET_KEY);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected PrintSheet read(String title, Iterable<String> body, int idx) {
|
||||
return new PrintSheet(title, CardPool.fromCardList(body));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
128
forge-core/src/main/java/forge/card/SealedProductTemplate.java
Normal file
128
forge-core/src/main/java/forge/card/SealedProductTemplate.java
Normal file
@@ -0,0 +1,128 @@
|
||||
/*
|
||||
* Forge: Play Magic: the Gathering.
|
||||
* Copyright (C) 2011 Forge Team
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package forge.card;
|
||||
|
||||
import java.io.File;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import org.apache.commons.lang3.tuple.ImmutablePair;
|
||||
import org.apache.commons.lang3.tuple.Pair;
|
||||
|
||||
import com.google.common.base.Function;
|
||||
import com.google.common.collect.Lists;
|
||||
|
||||
import forge.util.TextUtil;
|
||||
import forge.util.storage.StorageReaderFile;
|
||||
|
||||
|
||||
public class SealedProductTemplate {
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
public final static SealedProductTemplate genericBooster = new SealedProductTemplate(null, Lists.newArrayList(
|
||||
Pair.of(BoosterSlots.COMMON, 10), Pair.of(BoosterSlots.UNCOMMON, 3),
|
||||
Pair.of(BoosterSlots.RARE_MYTHIC, 1), Pair.of(BoosterSlots.BASIC_LAND, 1)
|
||||
));
|
||||
|
||||
|
||||
protected final List<Pair<String, Integer>> slots;
|
||||
protected final String name;
|
||||
|
||||
|
||||
public final List<Pair<String, Integer>> getSlots() {
|
||||
return slots;
|
||||
}
|
||||
|
||||
public final String getEdition() {
|
||||
return name;
|
||||
}
|
||||
public SealedProductTemplate(Iterable<Pair<String, Integer>> itrSlots)
|
||||
{
|
||||
this(null, itrSlots);
|
||||
}
|
||||
|
||||
public SealedProductTemplate(String name0, Iterable<Pair<String, Integer>> itrSlots)
|
||||
{
|
||||
slots = Lists.newArrayList(itrSlots);
|
||||
name = name0;
|
||||
}
|
||||
|
||||
public SealedProductTemplate(String code, String boosterDesc) {
|
||||
this(code, Reader.parseSlots(boosterDesc));
|
||||
}
|
||||
|
||||
public int getNumberOfCardsExpected() {
|
||||
int sum = 0;
|
||||
for(Pair<String, Integer> p : slots) {
|
||||
sum += p.getRight().intValue();
|
||||
}
|
||||
return sum;
|
||||
}
|
||||
|
||||
public static final Function<? super SealedProductTemplate, String> FN_GET_NAME = new Function<SealedProductTemplate, String>() {
|
||||
@Override
|
||||
public String apply(SealedProductTemplate arg1) {
|
||||
return arg1.name;
|
||||
}
|
||||
};
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
StringBuilder s = new StringBuilder();
|
||||
|
||||
|
||||
s.append("consisting of ");
|
||||
for(Pair<String, Integer> p : slots) {
|
||||
s.append(p.getRight()).append(" ").append(p.getLeft()).append(", ");
|
||||
}
|
||||
|
||||
// trim the last comma and space
|
||||
s.replace(s.length() - 2, s.length(), "");
|
||||
|
||||
// put an 'and' before the previous comma
|
||||
int lastCommaIdx = s.lastIndexOf(",");
|
||||
if (0 < lastCommaIdx) {
|
||||
s.replace(lastCommaIdx+1, lastCommaIdx+1, " and");
|
||||
}
|
||||
|
||||
return s.toString();
|
||||
}
|
||||
|
||||
public final static class Reader extends StorageReaderFile<SealedProductTemplate> {
|
||||
public Reader(File file) {
|
||||
super(file, SealedProductTemplate.FN_GET_NAME);
|
||||
}
|
||||
|
||||
public static List<Pair<String, Integer>> parseSlots(String data) {
|
||||
final String[] dataz = TextUtil.splitWithParenthesis(data, ',');
|
||||
List<Pair<String, Integer>> slots = new ArrayList<Pair<String,Integer>>();
|
||||
for(String slotDesc : dataz) {
|
||||
String[] kv = TextUtil.splitWithParenthesis(slotDesc, ' ', 2);
|
||||
slots.add(ImmutablePair.of(kv[1], Integer.parseInt(kv[0])));
|
||||
}
|
||||
return slots;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected SealedProductTemplate read(String line, int i) {
|
||||
String[] headAndData = TextUtil.split(line, ':', 2);
|
||||
return new SealedProductTemplate(headAndData[0], parseSlots(headAndData[1]));
|
||||
}
|
||||
}
|
||||
}
|
||||
171
forge-core/src/main/java/forge/deck/CardPool.java
Normal file
171
forge-core/src/main/java/forge/deck/CardPool.java
Normal file
@@ -0,0 +1,171 @@
|
||||
/*
|
||||
* Forge: Play Magic: the Gathering.
|
||||
* Copyright (C) 2011 Forge Team
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package forge.deck;
|
||||
|
||||
import java.util.Iterator;
|
||||
import java.util.Map.Entry;
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
import java.util.NoSuchElementException;
|
||||
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
|
||||
import forge.StaticData;
|
||||
import forge.item.PaperCard;
|
||||
import forge.util.ItemPool;
|
||||
|
||||
/**
|
||||
* Deck section.
|
||||
*
|
||||
*/
|
||||
public class CardPool extends ItemPool<PaperCard> {
|
||||
|
||||
/**
|
||||
* Instantiates a new deck section.
|
||||
*/
|
||||
public CardPool() {
|
||||
super(PaperCard.class);
|
||||
}
|
||||
|
||||
/**
|
||||
* Instantiates a new deck section.
|
||||
*
|
||||
* @param cards the cards
|
||||
*/
|
||||
public CardPool(final Iterable<Entry<PaperCard, Integer>> cards) {
|
||||
this();
|
||||
this.addAll(cards);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Adds the.
|
||||
*
|
||||
* @param cardName
|
||||
* the card name
|
||||
* @param setCode
|
||||
* the set code
|
||||
*/
|
||||
public void add(final String cardName, final String setCode) {
|
||||
this.add(cardName, setCode, 1);
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds the.
|
||||
*
|
||||
* @param cardName the card name
|
||||
* @param setCode the set code
|
||||
* @param amount the amount
|
||||
*/
|
||||
public void add(final String cardName, final String setCode, final int amount) {
|
||||
PaperCard cp = StaticData.instance().getCommonCards().tryGetCard(cardName, setCode);
|
||||
if ( cp == null )
|
||||
cp = StaticData.instance().getVariantCards().tryGetCard(cardName, setCode);
|
||||
|
||||
if ( cp != null)
|
||||
this.add(cp, amount);
|
||||
else
|
||||
throw new RuntimeException(String.format("Card %s from %s is not supported by Forge, as it's neither a known common card nor one of casual variants' card.", cardName, setCode ));
|
||||
}
|
||||
|
||||
/**
|
||||
* Add all from a List of CardPrinted.
|
||||
*
|
||||
* @param list
|
||||
* CardPrinteds to add
|
||||
*/
|
||||
public void add(final Iterable<PaperCard> list) {
|
||||
for (PaperCard cp : list) {
|
||||
this.add(cp);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* TODO: Write javadoc for this method.
|
||||
*
|
||||
* @param cardName the card name
|
||||
*/
|
||||
public void add(final String cardName, int cnt) {
|
||||
PaperCard cp = StaticData.instance().getCommonCards().tryGetCard(cardName);
|
||||
if ( cp == null )
|
||||
cp = StaticData.instance().getVariantCards().tryGetCard(cardName);
|
||||
|
||||
if ( cp != null)
|
||||
this.add(cp, cnt);
|
||||
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
|
||||
* @param i
|
||||
* @return
|
||||
*/
|
||||
public PaperCard get(int n) {
|
||||
for(Entry<PaperCard, Integer> e : this)
|
||||
{
|
||||
n -= e.getValue();
|
||||
if ( n <= 0 ) return e.getKey();
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
if (this.isEmpty()) return "[]";
|
||||
|
||||
boolean isFirst = true;
|
||||
StringBuilder sb = new StringBuilder();
|
||||
sb.append('[');
|
||||
for (Entry<PaperCard, Integer> e : this) {
|
||||
if ( isFirst ) isFirst = false;
|
||||
else sb.append(", ");
|
||||
|
||||
sb.append(e.getValue()).append(" x ").append(e.getKey().getName());
|
||||
}
|
||||
return sb.append(']').toString();
|
||||
}
|
||||
|
||||
|
||||
public static CardPool fromCardList(final Iterable<String> lines) {
|
||||
CardPool pool = new CardPool();
|
||||
final Pattern p = Pattern.compile("((\\d+)\\s+)?(.*?)");
|
||||
|
||||
if (lines == null) {
|
||||
return pool;
|
||||
}
|
||||
|
||||
final Iterator<String> lineIterator = lines.iterator();
|
||||
while (lineIterator.hasNext()) {
|
||||
final String line = lineIterator.next();
|
||||
if (line.startsWith(";") || line.startsWith("#")) { continue; } // that is a comment or not-yet-supported card
|
||||
|
||||
final Matcher m = p.matcher(line.trim());
|
||||
m.matches();
|
||||
final String sCnt = m.group(2);
|
||||
final String cardName = m.group(3);
|
||||
if (StringUtils.isBlank(cardName)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
final int count = sCnt == null ? 1 : Integer.parseInt(sCnt);
|
||||
pool.add(cardName, count);
|
||||
}
|
||||
return pool;
|
||||
}
|
||||
}
|
||||
8
forge-core/src/main/java/forge/deck/package-info.java
Normal file
8
forge-core/src/main/java/forge/deck/package-info.java
Normal file
@@ -0,0 +1,8 @@
|
||||
/**
|
||||
*
|
||||
*/
|
||||
/**
|
||||
* @author Max
|
||||
*
|
||||
*/
|
||||
package forge.deck;
|
||||
215
forge-core/src/main/java/forge/game/GameFormat.java
Normal file
215
forge-core/src/main/java/forge/game/GameFormat.java
Normal file
@@ -0,0 +1,215 @@
|
||||
/*
|
||||
* Forge: Play Magic: the Gathering.
|
||||
* Copyright (C) 2011 Forge Team
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package forge.game;
|
||||
|
||||
import java.io.File;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
import com.google.common.base.Function;
|
||||
import com.google.common.base.Predicate;
|
||||
import com.google.common.base.Predicates;
|
||||
import com.google.common.collect.Lists;
|
||||
|
||||
import forge.StaticData;
|
||||
import forge.item.PaperCard;
|
||||
import forge.item.IPaperCard;
|
||||
import forge.util.FileSection;
|
||||
import forge.util.storage.StorageReaderFileSections;
|
||||
|
||||
|
||||
/**
|
||||
* TODO: Write javadoc for this type.
|
||||
*
|
||||
*/
|
||||
public class GameFormat implements Comparable<GameFormat> {
|
||||
|
||||
private final String name;
|
||||
// contains allowed sets, when empty allows all sets
|
||||
protected final List<String> allowedSetCodes;
|
||||
protected final List<String> bannedCardNames;
|
||||
|
||||
protected final transient List<String> allowedSetCodes_ro;
|
||||
protected final transient List<String> bannedCardNames_ro;
|
||||
|
||||
protected final transient Predicate<PaperCard> filterRules;
|
||||
protected final transient Predicate<PaperCard> filterPrinted;
|
||||
|
||||
private final int index;
|
||||
|
||||
/**
|
||||
* Instantiates a new game format.
|
||||
*
|
||||
* @param fName
|
||||
* the f name
|
||||
* @param sets
|
||||
* the sets
|
||||
* @param bannedCards
|
||||
* the banned cards
|
||||
*/
|
||||
public GameFormat(final String fName, final Iterable<String> sets, final List<String> bannedCards) {
|
||||
this(fName, sets, bannedCards, 0);
|
||||
}
|
||||
|
||||
public GameFormat(final String fName, final Iterable<String> sets, final List<String> bannedCards, int compareIdx) {
|
||||
this.index = compareIdx;
|
||||
this.name = fName;
|
||||
this.allowedSetCodes = sets == null ? new ArrayList<String>() : Lists.newArrayList(sets);
|
||||
this.bannedCardNames = bannedCards == null ? new ArrayList<String>() : Lists.newArrayList(bannedCards);
|
||||
|
||||
this.allowedSetCodes_ro = Collections.unmodifiableList(allowedSetCodes);
|
||||
this.bannedCardNames_ro = Collections.unmodifiableList(bannedCardNames);
|
||||
|
||||
this.filterRules = this.buildFilterRules();
|
||||
this.filterPrinted = this.buildFilterPrinted();
|
||||
}
|
||||
|
||||
private Predicate<PaperCard> buildFilterPrinted() {
|
||||
final Predicate<PaperCard> banNames = Predicates.not(IPaperCard.Predicates.names(this.bannedCardNames));
|
||||
if (this.allowedSetCodes == null || this.allowedSetCodes.isEmpty()) {
|
||||
return banNames;
|
||||
}
|
||||
return Predicates.and(banNames, IPaperCard.Predicates.printedInSets(this.allowedSetCodes, true));
|
||||
}
|
||||
|
||||
private Predicate<PaperCard> buildFilterRules() {
|
||||
final Predicate<PaperCard> banNames = Predicates.not(IPaperCard.Predicates.names(this.bannedCardNames));
|
||||
if (this.allowedSetCodes == null || this.allowedSetCodes.isEmpty()) {
|
||||
return banNames;
|
||||
}
|
||||
return Predicates.and(banNames, StaticData.instance().getCommonCards().wasPrintedInSets(this.allowedSetCodes));
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the name.
|
||||
*
|
||||
* @return the name
|
||||
*/
|
||||
public String getName() {
|
||||
return this.name;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the set list (for GameFormatQuest).
|
||||
*
|
||||
* @return list of allowed set codes
|
||||
*/
|
||||
public List<String> getAllowedSetCodes() {
|
||||
return this.allowedSetCodes_ro;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the banned cards (for GameFormatQuest).
|
||||
*
|
||||
* @return list of banned card names
|
||||
*/
|
||||
public List<String> getBannedCardNames() {
|
||||
return this.bannedCardNames_ro;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the filter rules.
|
||||
*
|
||||
* @return the filter rules
|
||||
*/
|
||||
public Predicate<PaperCard> getFilterRules() {
|
||||
return this.filterRules;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the filter printed.
|
||||
*
|
||||
* @return the filter printed
|
||||
*/
|
||||
public Predicate<PaperCard> getFilterPrinted() {
|
||||
return this.filterPrinted;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if is sets the legal.
|
||||
*
|
||||
* @param setCode
|
||||
* the set code
|
||||
* @return true, if is sets the legal
|
||||
*/
|
||||
public boolean isSetLegal(final String setCode) {
|
||||
return this.allowedSetCodes.isEmpty() || this.allowedSetCodes.contains(setCode);
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
*
|
||||
* @see java.lang.Object#toString()
|
||||
*/
|
||||
@Override
|
||||
public String toString() {
|
||||
return this.name + " (format)";
|
||||
}
|
||||
|
||||
public static final Function<GameFormat, String> FN_GET_NAME = new Function<GameFormat, String>() {
|
||||
@Override
|
||||
public String apply(GameFormat arg1) {
|
||||
return arg1.getName();
|
||||
}
|
||||
};
|
||||
|
||||
/* (non-Javadoc)
|
||||
* just used for ordering -- comparing the name is sufficient
|
||||
* @see java.lang.Comparable#compareTo(java.lang.Object)
|
||||
*/
|
||||
@Override
|
||||
public int compareTo(GameFormat other) {
|
||||
if (null == other) {
|
||||
return 1;
|
||||
}
|
||||
return index - other.index;
|
||||
}
|
||||
|
||||
public int getIndex() {
|
||||
return index;
|
||||
}
|
||||
|
||||
/**
|
||||
* Instantiates a new format utils.
|
||||
*/
|
||||
public static class Reader extends StorageReaderFileSections<GameFormat> {
|
||||
public Reader(File file0) {
|
||||
super(file0, GameFormat.FN_GET_NAME);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected GameFormat read(String title, Iterable<String> body, int idx) {
|
||||
List<String> sets = null; // default: all sets allowed
|
||||
List<String> bannedCards = null; // default: nothing banned
|
||||
|
||||
FileSection section = FileSection.parse(body, ":");
|
||||
String strSets = section.get("sets");
|
||||
if ( null != strSets ) {
|
||||
sets = Arrays.asList(strSets.split(", "));
|
||||
}
|
||||
String strCars = section.get("banned");
|
||||
if ( strCars != null ) {
|
||||
bannedCards = Arrays.asList(strCars.split("; "));
|
||||
}
|
||||
|
||||
return new GameFormat(title, sets, bannedCards, 1 + idx);
|
||||
}
|
||||
}
|
||||
}
|
||||
8
forge-core/src/main/java/forge/game/package-info.java
Normal file
8
forge-core/src/main/java/forge/game/package-info.java
Normal file
@@ -0,0 +1,8 @@
|
||||
/**
|
||||
*
|
||||
*/
|
||||
/**
|
||||
* @author Max
|
||||
*
|
||||
*/
|
||||
package forge.game;
|
||||
163
forge-core/src/main/java/forge/item/IPaperCard.java
Normal file
163
forge-core/src/main/java/forge/item/IPaperCard.java
Normal file
@@ -0,0 +1,163 @@
|
||||
package forge.item;
|
||||
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
|
||||
import com.google.common.base.Predicate;
|
||||
import com.google.common.collect.Lists;
|
||||
|
||||
//import forge.Card;
|
||||
import forge.card.CardRarity;
|
||||
import forge.card.CardRules;
|
||||
import forge.util.PredicateString;
|
||||
|
||||
public interface IPaperCard extends InventoryItem {
|
||||
|
||||
/**
|
||||
* Number of filters based on CardPrinted values.
|
||||
*/
|
||||
public abstract static class Predicates {
|
||||
|
||||
public static Predicate<PaperCard> rarity(final boolean isEqual, final CardRarity value) {
|
||||
return new PredicateRarity(value, isEqual);
|
||||
}
|
||||
public static Predicate<PaperCard> printedInSets(final String[] sets) {
|
||||
return printedInSets(Lists.newArrayList(sets), true);
|
||||
}
|
||||
|
||||
public static Predicate<PaperCard> printedInSets(final List<String> value, final boolean shouldContain) {
|
||||
if ((value == null) || value.isEmpty()) {
|
||||
return com.google.common.base.Predicates.alwaysTrue();
|
||||
}
|
||||
return new PredicateSets(value, shouldContain);
|
||||
}
|
||||
|
||||
public static Predicate<PaperCard> printedInSet(final String value) {
|
||||
if (StringUtils.isEmpty(value)) {
|
||||
return com.google.common.base.Predicates.alwaysTrue();
|
||||
}
|
||||
return new PredicateSets(Lists.newArrayList(value), true);
|
||||
}
|
||||
|
||||
public static Predicate<PaperCard> name(final String what) {
|
||||
return new PredicateName(PredicateString.StringOp.EQUALS_IC, what);
|
||||
}
|
||||
|
||||
public static Predicate<PaperCard> name(final PredicateString.StringOp op, final String what) {
|
||||
return new PredicateName(op, what);
|
||||
}
|
||||
|
||||
public static Predicate<PaperCard> names(final List<String> what) {
|
||||
return new PredicateNames(what);
|
||||
}
|
||||
|
||||
private static class PredicateRarity implements Predicate<PaperCard> {
|
||||
private final CardRarity operand;
|
||||
private final boolean shouldBeEqual;
|
||||
|
||||
@Override
|
||||
public boolean apply(final PaperCard card) {
|
||||
return (card.getRarity() == this.operand) == this.shouldBeEqual;
|
||||
}
|
||||
|
||||
public PredicateRarity(final CardRarity type, final boolean wantEqual) {
|
||||
this.operand = type;
|
||||
this.shouldBeEqual = wantEqual;
|
||||
}
|
||||
}
|
||||
|
||||
private static class PredicateSets implements Predicate<PaperCard> {
|
||||
private final Set<String> sets;
|
||||
private final boolean mustContain;
|
||||
|
||||
@Override
|
||||
public boolean apply(final PaperCard card) {
|
||||
return this.sets.contains(card.getEdition()) == this.mustContain;
|
||||
}
|
||||
|
||||
public PredicateSets(final List<String> wantSets, final boolean shouldContain) {
|
||||
this.sets = new HashSet<String>(wantSets);
|
||||
this.mustContain = shouldContain;
|
||||
}
|
||||
}
|
||||
|
||||
private static class PredicateName extends PredicateString<PaperCard> {
|
||||
private final String operand;
|
||||
|
||||
@Override
|
||||
public boolean apply(final PaperCard card) {
|
||||
return this.op(card.getName(), this.operand);
|
||||
}
|
||||
|
||||
public PredicateName(final PredicateString.StringOp operator, final String operand) {
|
||||
super(operator);
|
||||
this.operand = operand;
|
||||
}
|
||||
}
|
||||
|
||||
private static class PredicateNames extends PredicateString<PaperCard> {
|
||||
private final List<String> operand;
|
||||
|
||||
@Override
|
||||
public boolean apply(final PaperCard card) {
|
||||
final String cardName = card.getName();
|
||||
for (final String element : this.operand) {
|
||||
if (this.op(cardName, element)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public PredicateNames(final List<String> operand) {
|
||||
super(StringOp.EQUALS);
|
||||
this.operand = operand;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Pre-built predicates are stored here to allow their re-usage and
|
||||
* easier access from code.
|
||||
*/
|
||||
public abstract static class Presets {
|
||||
// Think twice before using these, since rarity is a prop of printed
|
||||
// card.
|
||||
/** The Constant isCommon. */
|
||||
public static final Predicate<PaperCard> IS_COMMON = Predicates.rarity(true, CardRarity.Common);
|
||||
|
||||
/** The Constant isUncommon. */
|
||||
public static final Predicate<PaperCard> IS_UNCOMMON = Predicates.rarity(true, CardRarity.Uncommon);
|
||||
|
||||
/** The Constant isRare. */
|
||||
public static final Predicate<PaperCard> IS_RARE = Predicates.rarity(true, CardRarity.Rare);
|
||||
|
||||
/** The Constant isMythicRare. */
|
||||
public static final Predicate<PaperCard> IS_MYTHIC_RARE = Predicates.rarity(true, CardRarity.MythicRare);
|
||||
|
||||
/** The Constant isRareOrMythic. */
|
||||
public static final Predicate<PaperCard> IS_RARE_OR_MYTHIC = com.google.common.base.Predicates.or(Presets.IS_RARE,
|
||||
Presets.IS_MYTHIC_RARE);
|
||||
|
||||
/** The Constant isSpecial. */
|
||||
public static final Predicate<PaperCard> IS_SPECIAL = Predicates.rarity(true, CardRarity.Special);
|
||||
|
||||
/** The Constant exceptLands. */
|
||||
public static final Predicate<PaperCard> IS_BASIC_LAND = Predicates.rarity(true, CardRarity.BasicLand);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public abstract String getName();
|
||||
public abstract String getEdition();
|
||||
public abstract int getArtIndex();
|
||||
public abstract boolean isFoil();
|
||||
public abstract boolean isToken();
|
||||
public abstract CardRules getRules();
|
||||
public abstract CardRarity getRarity();
|
||||
|
||||
public abstract String getItemType();
|
||||
|
||||
}
|
||||
34
forge-core/src/main/java/forge/item/InventoryItem.java
Normal file
34
forge-core/src/main/java/forge/item/InventoryItem.java
Normal file
@@ -0,0 +1,34 @@
|
||||
/*
|
||||
* Forge: Play Magic: the Gathering.
|
||||
* Copyright (C) 2011 Forge Team
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package forge.item;
|
||||
|
||||
import forge.util.IHasName;
|
||||
|
||||
/**
|
||||
* Interface to define a player's inventory may hold. Should include
|
||||
* CardPrinted, Booster, Pets, Plants... etc
|
||||
*/
|
||||
public interface InventoryItem extends IHasName
|
||||
{
|
||||
/**
|
||||
* Return type as a string.
|
||||
*
|
||||
* @return the type
|
||||
*/
|
||||
String getItemType();
|
||||
}
|
||||
@@ -0,0 +1,31 @@
|
||||
/*
|
||||
* Forge: Play Magic: the Gathering.
|
||||
* Copyright (C) 2011 Forge Team
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package forge.item;
|
||||
|
||||
/**
|
||||
* Interface to define a player's inventory may hold. Should include
|
||||
* CardPrinted, Booster, Pets, Plants... etc
|
||||
*/
|
||||
public interface InventoryItemFromSet extends InventoryItem {
|
||||
/**
|
||||
* An item belonging to a set should return its set as well.
|
||||
*
|
||||
* @return the sets the
|
||||
*/
|
||||
String getEdition();
|
||||
}
|
||||
196
forge-core/src/main/java/forge/item/PaperCard.java
Normal file
196
forge-core/src/main/java/forge/item/PaperCard.java
Normal file
@@ -0,0 +1,196 @@
|
||||
/*
|
||||
* Forge: Play Magic: the Gathering.
|
||||
* Copyright (C) 2011 Forge Team
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package forge.item;
|
||||
|
||||
import com.google.common.base.Function;
|
||||
|
||||
import forge.card.CardRarity;
|
||||
import forge.card.CardRules;
|
||||
|
||||
|
||||
/**
|
||||
* A viciously lightweight version of a card, for instances
|
||||
* where a full set of meta and rules is not needed.
|
||||
* <br><br>
|
||||
* The full set of rules is in the CardRules class.
|
||||
*
|
||||
* @author Forge
|
||||
* @version $Id: CardReference.java 9708 2011-08-09 19:34:12Z jendave $
|
||||
*/
|
||||
public final class PaperCard implements Comparable<IPaperCard>, InventoryItemFromSet, IPaperCard {
|
||||
// Reference to rules
|
||||
private final transient CardRules card;
|
||||
|
||||
// These fields are kinda PK for PrintedCard
|
||||
public final String name;
|
||||
public final String edition;
|
||||
public final int artIndex;
|
||||
public final boolean foil;
|
||||
|
||||
// Calculated fields are below:
|
||||
private final transient CardRarity rarity; // rarity is given in ctor when set is assigned
|
||||
|
||||
@Override
|
||||
public String getName() {
|
||||
return this.name;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getEdition() {
|
||||
return this.edition;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getArtIndex() {
|
||||
return this.artIndex;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isFoil() {
|
||||
return this.foil;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isToken() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public CardRules getRules() {
|
||||
return this.card;
|
||||
}
|
||||
|
||||
@Override
|
||||
public CardRarity getRarity() {
|
||||
return this.rarity;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
// @Override
|
||||
// public String getImageKey() {
|
||||
// return getImageLocator(getImageName(), getArtIndex(), true, false);
|
||||
// }
|
||||
|
||||
|
||||
@Override
|
||||
public String getItemType() {
|
||||
return "Card";
|
||||
}
|
||||
|
||||
/**
|
||||
* Lambda to get rules for selects from list of printed cards.
|
||||
*/
|
||||
public static final Function<PaperCard, CardRules> FN_GET_RULES = new Function<PaperCard, CardRules>() {
|
||||
@Override
|
||||
public CardRules apply(final PaperCard from) {
|
||||
return from.card;
|
||||
}
|
||||
};
|
||||
public static final Function<PaperCard, String> FN_GET_NAME = new Function<PaperCard, String>() {
|
||||
@Override
|
||||
public String apply(final PaperCard from) {
|
||||
return from.getName();
|
||||
}
|
||||
};
|
||||
|
||||
public PaperCard(final CardRules c, final String edition0, final CardRarity rare, final int index) {
|
||||
this(c, edition0, rare, index, false);
|
||||
}
|
||||
|
||||
public PaperCard(final CardRules c, final String edition0, final CardRarity rare, final int index, final boolean foil) {
|
||||
if ( edition0 == null || c == null || rare == null )
|
||||
throw new IllegalArgumentException("Cannot create card without rules, edition or rarity");
|
||||
this.card = c;
|
||||
this.name = c.getName();
|
||||
this.edition = edition0;
|
||||
this.artIndex = index;
|
||||
this.foil = foil;
|
||||
this.rarity = rare;
|
||||
}
|
||||
|
||||
// Want this class to be a key for HashTable
|
||||
@Override
|
||||
public boolean equals(final Object obj) {
|
||||
if (this == obj) {
|
||||
return true;
|
||||
}
|
||||
if (obj == null) {
|
||||
return false;
|
||||
}
|
||||
if (this.getClass() != obj.getClass()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
final PaperCard other = (PaperCard) obj;
|
||||
if (!this.name.equals(other.name)) {
|
||||
return false;
|
||||
}
|
||||
if (!this.edition.equals(other.edition)) {
|
||||
return false;
|
||||
}
|
||||
if ((other.foil != this.foil) || (other.artIndex != this.artIndex)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
*
|
||||
* @see java.lang.Object#hashCode()
|
||||
*/
|
||||
@Override
|
||||
public int hashCode() {
|
||||
final int code = (this.name.hashCode() * 11) + (this.edition.hashCode() * 59) + (this.artIndex * 2);
|
||||
if (this.foil) {
|
||||
return code + 1;
|
||||
}
|
||||
return code;
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
*
|
||||
* @see java.lang.Object#toString()
|
||||
*/
|
||||
@Override
|
||||
public String toString() {
|
||||
return this.name;
|
||||
// cannot still decide, if this "name|set" format is needed anymore
|
||||
// return String.format("%s|%s", name, cardSet);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
*
|
||||
* @see java.lang.Comparable#compareTo(java.lang.Object)
|
||||
*/
|
||||
@Override
|
||||
public int compareTo(final IPaperCard o) {
|
||||
final int nameCmp = this.getName().compareToIgnoreCase(o.getName());
|
||||
if (0 != nameCmp) {
|
||||
return nameCmp;
|
||||
}
|
||||
// TODO compare sets properly
|
||||
return this.edition.compareTo(o.getEdition());
|
||||
}
|
||||
}
|
||||
64
forge-core/src/main/java/forge/item/PaperToken.java
Normal file
64
forge-core/src/main/java/forge/item/PaperToken.java
Normal file
@@ -0,0 +1,64 @@
|
||||
package forge.item;
|
||||
|
||||
import java.util.Locale;
|
||||
|
||||
import forge.card.CardEdition;
|
||||
import forge.card.CardRarity;
|
||||
import forge.card.CardRules;
|
||||
|
||||
|
||||
public class PaperToken implements InventoryItemFromSet, IPaperCard {
|
||||
private String name;
|
||||
private CardEdition edition;
|
||||
private String imageFileName;
|
||||
private CardRules card;
|
||||
|
||||
// takes a string of the form "<colors> <power> <toughness> <name>" such as: "B 0 0 Germ"
|
||||
public static String makeTokenFileName(String in) {
|
||||
StringBuffer out = new StringBuffer();
|
||||
char c;
|
||||
for (int i = 0; i < in.length(); i++) {
|
||||
c = in.charAt(i);
|
||||
if ((c == ' ') || (c == '-') || (c == '_')) {
|
||||
out.append('_');
|
||||
} else if (Character.isLetterOrDigit(c)) {
|
||||
out.append(c);
|
||||
}
|
||||
}
|
||||
return out.toString().toLowerCase(Locale.ENGLISH);
|
||||
}
|
||||
|
||||
public static String makeTokenFileName(String colors, int power, int toughness, String name) {
|
||||
return makeTokenFileName(colors, String.valueOf(power), String.valueOf(toughness), name);
|
||||
}
|
||||
|
||||
public static String makeTokenFileName(String colors, String power, String toughness, String name) {
|
||||
StringBuilder fileName = new StringBuilder();
|
||||
fileName.append(colors).append('_').append(power).append('_').append(toughness).append('_').append(name);
|
||||
return makeTokenFileName(fileName.toString());
|
||||
}
|
||||
|
||||
public PaperToken(final CardRules c, CardEdition edition0, final String imageFileName) {
|
||||
this.card = c;
|
||||
this.name = c.getName();
|
||||
this.edition = edition0;
|
||||
this.imageFileName = String.format("%s%s", null == edition || CardEdition.UNKNOWN == edition ? "" : edition.getCode(), imageFileName);
|
||||
}
|
||||
|
||||
@Override public String getName() { return name; }
|
||||
|
||||
@Override public String getEdition() { return edition.getCode(); }
|
||||
|
||||
@Override public int getArtIndex() { return 0; } // This might change however
|
||||
@Override public boolean isFoil() { return false; }
|
||||
@Override public CardRules getRules() { return card; }
|
||||
|
||||
@Override public CardRarity getRarity() { return CardRarity.Common; } // They don't have rarity though!
|
||||
|
||||
// Unfortunately this is a property of token, cannot move it outside of class
|
||||
public String getImageFilename() { return imageFileName; }
|
||||
|
||||
@Override public String getItemType() { return "Token"; }
|
||||
|
||||
@Override public boolean isToken() { return true; }
|
||||
}
|
||||
8
forge-core/src/main/java/forge/item/package-info.java
Normal file
8
forge-core/src/main/java/forge/item/package-info.java
Normal file
@@ -0,0 +1,8 @@
|
||||
/**
|
||||
*
|
||||
*/
|
||||
/**
|
||||
* @author Max
|
||||
*
|
||||
*/
|
||||
package forge.item;
|
||||
174
forge-core/src/main/java/forge/util/Aggregates.java
Normal file
174
forge-core/src/main/java/forge/util/Aggregates.java
Normal file
@@ -0,0 +1,174 @@
|
||||
package forge.util;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.Hashtable;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Map.Entry;
|
||||
import java.util.Random;
|
||||
|
||||
import com.google.common.base.Function;
|
||||
|
||||
/**
|
||||
* TODO: Write javadoc for this type.
|
||||
*
|
||||
*/
|
||||
public class Aggregates {
|
||||
|
||||
// Returns the value matching predicate conditions with the maximum value of whatever valueAccessor returns.
|
||||
public static final <T> Integer max(final Iterable<T> source, final Function<T, Integer> valueAccessor) {
|
||||
if (source == null) { return null; }
|
||||
int max = Integer.MIN_VALUE;
|
||||
for (final T c : source) {
|
||||
int value = valueAccessor.apply(c);
|
||||
if (value > max) {
|
||||
max = value;
|
||||
}
|
||||
}
|
||||
return max;
|
||||
}
|
||||
|
||||
public static final <T> Integer min(final Iterable<T> source, final Function<T, Integer> valueAccessor) {
|
||||
if (source == null) { return null; }
|
||||
int max = Integer.MAX_VALUE;
|
||||
for (final T c : source) {
|
||||
int value = valueAccessor.apply(c);
|
||||
if (value < max) {
|
||||
max = value;
|
||||
}
|
||||
}
|
||||
return max;
|
||||
}
|
||||
|
||||
|
||||
public static final <T> T itemWithMax(final Iterable<T> source, final Function<T, Integer> valueAccessor) {
|
||||
if (source == null) { return null; }
|
||||
int max = Integer.MIN_VALUE;
|
||||
T result = null;
|
||||
for (final T c : source) {
|
||||
int value = valueAccessor.apply(c);
|
||||
if (value > max) {
|
||||
max = value;
|
||||
result = c;
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
public static final <T> int sum(final Iterable<T> source, final Function<T, Integer> valueAccessor) {
|
||||
int result = 0;
|
||||
if (source != null) {
|
||||
for (final T c : source) {
|
||||
result += valueAccessor.apply(c);
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
// Random - algorithm adapted from Braid's GeneratorFunctions
|
||||
/**
|
||||
* Random.
|
||||
*
|
||||
* @param source
|
||||
* the source
|
||||
* @return the t
|
||||
*/
|
||||
public static final <T> T random(final Iterable<T> source) {
|
||||
if( null == source )
|
||||
return null;
|
||||
Random rnd = MyRandom.getRandom();
|
||||
if ( source instanceof List<?> )
|
||||
{
|
||||
List<T> src = (List<T>)source;
|
||||
int len = src.size();
|
||||
switch(len) {
|
||||
case 0: return null;
|
||||
case 1: return src.get(0);
|
||||
default: return src.get(rnd.nextInt(len));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
int n = 0;
|
||||
T candidate = null;
|
||||
for (final T item : source) {
|
||||
if ((rnd.nextDouble() * ++n) < 1) {
|
||||
candidate = item;
|
||||
}
|
||||
}
|
||||
return candidate;
|
||||
}
|
||||
|
||||
// Get several random values
|
||||
// should improve to make 1 pass over source and track N candidates at once
|
||||
public static final <T> List<T> random(final Iterable<T> source, final int count) {
|
||||
final List<T> result = new ArrayList<T>();
|
||||
for (int i = 0; i < count; ++i) {
|
||||
final T toAdd = Aggregates.random(source);
|
||||
if (toAdd == null) {
|
||||
break;
|
||||
}
|
||||
result.add(toAdd);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
public static final <K, U> Iterable<U> uniqueByLast(final Iterable<U> source, final Function<U, K> fnUniqueKey) { // this might be exotic
|
||||
final Map<K, U> uniques = new Hashtable<K, U>();
|
||||
for (final U c : source) {
|
||||
uniques.put(fnUniqueKey.apply(c), c);
|
||||
}
|
||||
return uniques.values();
|
||||
}
|
||||
|
||||
|
||||
public static <T> T itemWithMin(final Iterable<T> source, final Function<T, Integer> valueAccessor) {
|
||||
if (source == null) { return null; }
|
||||
int max = Integer.MAX_VALUE;
|
||||
T result = null;
|
||||
for (final T c : source) {
|
||||
int value = valueAccessor.apply(c);
|
||||
if (value < max) {
|
||||
max = value;
|
||||
result = c;
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
public static <TItem, TField> TItem firstFieldEquals(List<TItem> source, Function<TItem, TField> valueAccessor, TField valueEquals) {
|
||||
if (source == null) { return null; }
|
||||
if (valueEquals == null) {
|
||||
for (final TItem c : source) {
|
||||
if (null == valueAccessor.apply(c)) {
|
||||
return c;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
for (final TItem c : source) {
|
||||
if (valueEquals.equals(valueAccessor.apply(c))) {
|
||||
return c;
|
||||
}
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
public static <T, U> Iterable<Entry<U, Integer>> groupSumBy(Iterable<Entry<T, Integer>> source, Function<T, U> fnGetField) {
|
||||
Map<U, Integer> result = new HashMap<U, Integer>();
|
||||
for(Entry<T, Integer> kv : source) {
|
||||
U k = fnGetField.apply(kv.getKey());
|
||||
Integer v = kv.getValue();
|
||||
Integer sum = result.get(k);
|
||||
int n = v == null ? 0 : v.intValue();
|
||||
int s = sum == null ? 0 : sum.intValue();
|
||||
result.put(k, Integer.valueOf(s + n));
|
||||
}
|
||||
return result.entrySet();
|
||||
}
|
||||
|
||||
}
|
||||
42
forge-core/src/main/java/forge/util/CollectionSuppliers.java
Normal file
42
forge-core/src/main/java/forge/util/CollectionSuppliers.java
Normal file
@@ -0,0 +1,42 @@
|
||||
package forge.util;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashSet;
|
||||
import java.util.TreeSet;
|
||||
|
||||
import com.google.common.base.Supplier;
|
||||
|
||||
/**
|
||||
* TODO: Write javadoc for this type.
|
||||
*
|
||||
*/
|
||||
public abstract class CollectionSuppliers {
|
||||
|
||||
|
||||
public static <T> Supplier<ArrayList<T>> arrayLists() {
|
||||
return new Supplier<ArrayList<T>>() {
|
||||
@Override
|
||||
public ArrayList<T> get() {
|
||||
return new ArrayList<T>();
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
public static <T> Supplier<HashSet<T>> hashSets() {
|
||||
return new Supplier<HashSet<T>>() {
|
||||
@Override
|
||||
public HashSet<T> get() {
|
||||
return new HashSet<T>();
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
public static <T extends Comparable<T>> Supplier<TreeSet<T>> treeSets() {
|
||||
return new Supplier<TreeSet<T>>() {
|
||||
@Override
|
||||
public TreeSet<T> get() {
|
||||
return new TreeSet<T>();
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
34
forge-core/src/main/java/forge/util/ComparableOp.java
Normal file
34
forge-core/src/main/java/forge/util/ComparableOp.java
Normal file
@@ -0,0 +1,34 @@
|
||||
/*
|
||||
* Forge: Play Magic: the Gathering.
|
||||
* Copyright (C) 2011 MaxMtg
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package forge.util;
|
||||
|
||||
/**
|
||||
* Possible operators for comparables.
|
||||
*
|
||||
* @author Max
|
||||
*
|
||||
*/
|
||||
public enum ComparableOp {
|
||||
|
||||
EQUALS,
|
||||
NOT_EQUALS,
|
||||
GREATER_THAN,
|
||||
LESS_THAN,
|
||||
GT_OR_EQUAL,
|
||||
LT_OR_EQUAL
|
||||
}
|
||||
216
forge-core/src/main/java/forge/util/FileSection.java
Normal file
216
forge-core/src/main/java/forge/util/FileSection.java
Normal file
@@ -0,0 +1,216 @@
|
||||
/*
|
||||
* Forge: Play Magic: the Gathering.
|
||||
* Copyright (C) 2011 Forge Team
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package forge.util;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.TreeMap;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
/**
|
||||
* TODO: Write javadoc for this type.
|
||||
*
|
||||
*/
|
||||
public class FileSection {
|
||||
|
||||
/** The lines. */
|
||||
private final Map<String, String> lines;
|
||||
|
||||
/**
|
||||
* Gets the lines.
|
||||
*
|
||||
* @return the lines
|
||||
*/
|
||||
protected final Map<String, String> getLines() {
|
||||
return this.lines;
|
||||
}
|
||||
|
||||
/**
|
||||
* Instantiates a new file section.
|
||||
*/
|
||||
protected FileSection() {
|
||||
this(new TreeMap<String, String>(String.CASE_INSENSITIVE_ORDER));
|
||||
}
|
||||
|
||||
protected FileSection(Map<String, String> lines0) {
|
||||
lines = lines0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Parses the.
|
||||
*
|
||||
* @param line the line
|
||||
* @param kvSeparator the kv separator
|
||||
* @param pairSeparator the pair separator
|
||||
* @return the file section
|
||||
*/
|
||||
public static FileSection parse(final String line, final String kvSeparator, final String pairSeparator) {
|
||||
Map<String, String> map = parseToMap(line, kvSeparator, pairSeparator);
|
||||
return new FileSection(map);
|
||||
}
|
||||
|
||||
public static Map<String, String> parseToMap(final String line, final String kvSeparator, final String pairSeparator) {
|
||||
final String[] pairs = line.split(Pattern.quote(pairSeparator));
|
||||
final Pattern splitter = Pattern.compile(Pattern.quote(kvSeparator));
|
||||
Map<String, String> result = new TreeMap<String, String>(String.CASE_INSENSITIVE_ORDER);
|
||||
|
||||
for (final String dd : pairs) {
|
||||
final String[] v = splitter.split(dd, 2);
|
||||
result.put(v[0].trim(), v.length > 1 ? v[1].trim() : "");
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Parses the.
|
||||
*
|
||||
* @param lines the lines
|
||||
* @param kvSeparator the kv separator
|
||||
* @return the file section
|
||||
*/
|
||||
public static FileSection parse(final Iterable<String> lines, final String kvSeparator) {
|
||||
final FileSection result = new FileSection();
|
||||
final Pattern splitter = Pattern.compile(Pattern.quote(kvSeparator));
|
||||
for (final String dd : lines) {
|
||||
final String[] v = splitter.split(dd, 2);
|
||||
result.lines.put(v[0].trim(), v.length > 1 ? v[1].trim() : "");
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the.
|
||||
*
|
||||
* @param fieldName the field name
|
||||
* @return the string
|
||||
*/
|
||||
public String get(final String fieldName) {
|
||||
return this.lines.get(fieldName);
|
||||
}
|
||||
|
||||
public String get(final String fieldName, final String defaultValue) {
|
||||
return lines.containsKey(fieldName) ? this.lines.get(fieldName) : defaultValue;
|
||||
}
|
||||
|
||||
public boolean contains(String keyName) {
|
||||
return lines.containsKey(keyName);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the int.
|
||||
*
|
||||
* @param fieldName the field name
|
||||
* @return the int
|
||||
*/
|
||||
public int getInt(final String fieldName) {
|
||||
return this.getInt(fieldName, 0);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the int.
|
||||
*
|
||||
* @param fieldName the field name
|
||||
* @param defaultValue the default value
|
||||
* @return the int
|
||||
*/
|
||||
public int getInt(final String fieldName, final int defaultValue) {
|
||||
try {
|
||||
return Integer.parseInt(this.get(fieldName));
|
||||
} catch (final NumberFormatException ex) {
|
||||
return defaultValue;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the boolean.
|
||||
*
|
||||
* @param fieldName the field name
|
||||
* @return the boolean
|
||||
*/
|
||||
public boolean getBoolean(final String fieldName) {
|
||||
return this.getBoolean(fieldName, false);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the boolean.
|
||||
*
|
||||
* @param fieldName the field name
|
||||
* @param defaultValue the default value
|
||||
* @return the boolean
|
||||
*/
|
||||
public boolean getBoolean(final String fieldName, final boolean defaultValue) {
|
||||
final String s = this.get(fieldName);
|
||||
if (s == null) {
|
||||
return defaultValue;
|
||||
}
|
||||
return "true".equalsIgnoreCase(s);
|
||||
}
|
||||
|
||||
/**
|
||||
* Parses the sections.
|
||||
*
|
||||
* @param source
|
||||
* the source
|
||||
* @return the map
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
public static Map<String, List<String>> parseSections(final List<String> source) {
|
||||
final Map<String, List<String>> result = new TreeMap<String, List<String>>(String.CASE_INSENSITIVE_ORDER);
|
||||
String currentSection = "";
|
||||
List<String> currentList = null;
|
||||
|
||||
for (final String s : source) {
|
||||
final String st = s.trim();
|
||||
if (st.length() == 0) {
|
||||
continue;
|
||||
}
|
||||
if (st.startsWith("[") && st.endsWith("]")) {
|
||||
if ((currentList != null) && (currentList.size() > 0)) {
|
||||
final Object oldVal = result.get(currentSection);
|
||||
if ((oldVal != null) && (oldVal instanceof List<?>)) {
|
||||
currentList.addAll((List<String>) oldVal);
|
||||
}
|
||||
result.put(currentSection, currentList);
|
||||
}
|
||||
|
||||
final String newSection = st.substring(1, st.length() - 1);
|
||||
currentSection = newSection;
|
||||
currentList = null;
|
||||
} else {
|
||||
if (currentList == null) {
|
||||
currentList = new ArrayList<String>();
|
||||
}
|
||||
currentList.add(st);
|
||||
}
|
||||
}
|
||||
|
||||
// save final block
|
||||
if ((currentList != null) && (currentList.size() > 0)) {
|
||||
final Object oldVal = result.get(currentSection);
|
||||
if ((oldVal != null) && (oldVal instanceof List<?>)) {
|
||||
currentList.addAll((List<String>) oldVal);
|
||||
}
|
||||
result.put(currentSection, currentList);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
}
|
||||
36
forge-core/src/main/java/forge/util/FileSectionManual.java
Normal file
36
forge-core/src/main/java/forge/util/FileSectionManual.java
Normal file
@@ -0,0 +1,36 @@
|
||||
/*
|
||||
* Forge: Play Magic: the Gathering.
|
||||
* Copyright (C) 2011 Forge Team
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package forge.util;
|
||||
|
||||
/**
|
||||
* TODO: Write javadoc for this type.
|
||||
*
|
||||
*/
|
||||
public class FileSectionManual extends FileSection {
|
||||
|
||||
/**
|
||||
* Put.
|
||||
*
|
||||
* @param key the key
|
||||
* @param value the value
|
||||
*/
|
||||
public void put(final String key, final String value) {
|
||||
this.getLines().put(key, value);
|
||||
}
|
||||
|
||||
}
|
||||
210
forge-core/src/main/java/forge/util/FileUtil.java
Normal file
210
forge-core/src/main/java/forge/util/FileUtil.java
Normal file
@@ -0,0 +1,210 @@
|
||||
/*
|
||||
* Forge: Play Magic: the Gathering.
|
||||
* Copyright (C) 2011 Forge Team
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package forge.util;
|
||||
|
||||
import java.io.BufferedReader;
|
||||
import java.io.File;
|
||||
import java.io.FileReader;
|
||||
import java.io.IOException;
|
||||
import java.io.PrintWriter;
|
||||
import java.io.Reader;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.apache.commons.lang3.tuple.Pair;
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* FileUtil class.
|
||||
* </p>
|
||||
*
|
||||
* @author Forge
|
||||
* @version $Id$
|
||||
*/
|
||||
public final class FileUtil {
|
||||
|
||||
private FileUtil() {
|
||||
throw new AssertionError();
|
||||
}
|
||||
|
||||
/**
|
||||
* Takes two paths and combines them into a valid path string
|
||||
* for the current OS.
|
||||
* <p>
|
||||
* Similar to the Path.Combine() function in .Net.
|
||||
*/
|
||||
public static String pathCombine (String path1, String path2) {
|
||||
File file1 = new File(path1);
|
||||
File file2 = new File(file1, path2);
|
||||
return file2.getPath();
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* doesFileExist.
|
||||
* </p>
|
||||
*
|
||||
* @param filename
|
||||
* a {@link java.lang.String} object.
|
||||
* @return a boolean.
|
||||
*/
|
||||
public static boolean doesFileExist(final String filename) {
|
||||
final File f = new File(filename);
|
||||
return f.exists();
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* writeFile.
|
||||
* </p>
|
||||
*
|
||||
* @param filename
|
||||
* a {@link java.lang.String} object.
|
||||
* @param data
|
||||
* a {@link java.util.List} object.
|
||||
*/
|
||||
public static void writeFile(final String filename, final List<String> data) {
|
||||
FileUtil.writeFile(new File(filename), data);
|
||||
}
|
||||
|
||||
// writes each element of ArrayList on a separate line
|
||||
// this is used to write a file of Strings
|
||||
// this will create a new file if needed
|
||||
// if filename already exists, it is deleted
|
||||
/**
|
||||
* <p>
|
||||
* writeFile.
|
||||
* </p>
|
||||
*
|
||||
* @param file
|
||||
* a {@link java.io.File} object.
|
||||
* @param data
|
||||
* a {@link java.util.List} object.
|
||||
*/
|
||||
public static void writeFile(File file, Collection<?> data) {
|
||||
try {
|
||||
PrintWriter p = new PrintWriter(file);
|
||||
for (Object o : data) {
|
||||
p.println(o);
|
||||
}
|
||||
p.close();
|
||||
} catch (final Exception ex) {
|
||||
throw new RuntimeException("FileUtil : writeFile() error, problem writing file - " + file + " : " + ex);
|
||||
}
|
||||
} // writeAllDecks()
|
||||
|
||||
public static String readFileToString(String filename) {
|
||||
StringBuilder s = new StringBuilder();
|
||||
for (String line : readFile(filename)) {
|
||||
s.append(line).append('\n');
|
||||
}
|
||||
return s.toString();
|
||||
}
|
||||
|
||||
public static List<String> readFile(final String filename) {
|
||||
return FileUtil.readFile(new File(filename));
|
||||
}
|
||||
|
||||
// reads line by line and adds each line to the ArrayList
|
||||
// this will return blank lines as well
|
||||
// if filename not found, returns an empty ArrayList
|
||||
/**
|
||||
* <p>
|
||||
* readFile.
|
||||
* </p>
|
||||
*
|
||||
* @param file
|
||||
* a {@link java.io.File} object.
|
||||
* @return a {@link java.util.ArrayList} object.
|
||||
*/
|
||||
public static List<String> readFile(final File file) {
|
||||
try {
|
||||
if ((file == null) || !file.exists()) {
|
||||
return new ArrayList<String>();
|
||||
}
|
||||
return FileUtil.readAllLines(new FileReader(file), false);
|
||||
} catch (final Exception ex) {
|
||||
throw new RuntimeException("FileUtil : readFile() error, " + ex);
|
||||
}
|
||||
} // readFile()
|
||||
|
||||
/**
|
||||
* Read all lines.
|
||||
*
|
||||
* @param reader the reader
|
||||
* @return the list
|
||||
*/
|
||||
public static List<String> readAllLines(final Reader reader) {
|
||||
return FileUtil.readAllLines(reader, false);
|
||||
}
|
||||
|
||||
/**
|
||||
* Reads all lines from given reader to a list of strings.
|
||||
*
|
||||
* @param reader is a reader (e.g. FileReader, InputStreamReader)
|
||||
* @param mayTrim defines whether to trim lines.
|
||||
* @return list of strings
|
||||
*/
|
||||
public static List<String> readAllLines(final Reader reader, final boolean mayTrim) {
|
||||
final ArrayList<String> list = new ArrayList<String>();
|
||||
try {
|
||||
final BufferedReader in = new BufferedReader(reader);
|
||||
String line;
|
||||
while ((line = in.readLine()) != null) {
|
||||
if (mayTrim) {
|
||||
line = line.trim();
|
||||
}
|
||||
list.add(line);
|
||||
}
|
||||
in.close();
|
||||
} catch (final IOException ex) {
|
||||
throw new RuntimeException("FileUtil : readAllLines() error, " + ex);
|
||||
}
|
||||
return list;
|
||||
}
|
||||
|
||||
// returns a list of <name, url> pairs. if the name is not in the file, it is synthesized from the url
|
||||
public static List<Pair<String, String>> readNameUrlFile(String nameUrlFile) {
|
||||
Pattern lineSplitter = Pattern.compile(Pattern.quote(" "));
|
||||
Pattern replacer = Pattern.compile(Pattern.quote("%20"));
|
||||
|
||||
List<Pair<String, String>> list = new ArrayList<Pair<String, String>>();
|
||||
|
||||
for (String line : readFile(nameUrlFile)) {
|
||||
if (StringUtils.isBlank(line) || line.startsWith("#")) {
|
||||
continue;
|
||||
}
|
||||
|
||||
String[] parts = lineSplitter.split(line, 2);
|
||||
if (2 == parts.length) {
|
||||
list.add(Pair.of(replacer.matcher(parts[0]).replaceAll(" "), parts[1]));
|
||||
} else {
|
||||
// figure out the filename from the URL
|
||||
Pattern pathSplitter = Pattern.compile(Pattern.quote("/"));
|
||||
String[] pathParts = pathSplitter.split(parts[0]);
|
||||
String last = pathParts[pathParts.length - 1];
|
||||
list.add(Pair.of(replacer.matcher(last).replaceAll(" "), parts[0]));
|
||||
}
|
||||
}
|
||||
|
||||
return list;
|
||||
}
|
||||
}
|
||||
9
forge-core/src/main/java/forge/util/IHasName.java
Normal file
9
forge-core/src/main/java/forge/util/IHasName.java
Normal file
@@ -0,0 +1,9 @@
|
||||
package forge.util;
|
||||
|
||||
/**
|
||||
* TODO: Write javadoc for this type.
|
||||
*
|
||||
*/
|
||||
public interface IHasName {
|
||||
String getName();
|
||||
}
|
||||
49
forge-core/src/main/java/forge/util/IItemReader.java
Normal file
49
forge-core/src/main/java/forge/util/IItemReader.java
Normal file
@@ -0,0 +1,49 @@
|
||||
/*
|
||||
* Forge: Play Magic: the Gathering.
|
||||
* Copyright (C) 2011 Forge Team
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package forge.util;
|
||||
|
||||
import java.io.File;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* The Interface IItemReader.
|
||||
*
|
||||
* @param <T> the generic type
|
||||
*/
|
||||
public interface IItemReader<T> {
|
||||
|
||||
/**
|
||||
* Read all.
|
||||
*
|
||||
* @return the map
|
||||
*/
|
||||
Map<String, T> readAll();
|
||||
// T read(File file);
|
||||
|
||||
/**
|
||||
* Gets the item key.
|
||||
*
|
||||
* @param item the item
|
||||
* @return the item key
|
||||
*/
|
||||
String getItemKey(T item);
|
||||
|
||||
Iterable<File> getSubFolders();
|
||||
|
||||
IItemReader<T> getReaderForFolder(File subfolder);
|
||||
}
|
||||
45
forge-core/src/main/java/forge/util/IItemSerializer.java
Normal file
45
forge-core/src/main/java/forge/util/IItemSerializer.java
Normal file
@@ -0,0 +1,45 @@
|
||||
/*
|
||||
* Forge: Play Magic: the Gathering.
|
||||
* Copyright (C) 2011 Forge Team
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package forge.util;
|
||||
|
||||
import java.io.File;
|
||||
|
||||
/**
|
||||
* TODO: Write javadoc for this type.
|
||||
*
|
||||
* @param <T> the generic type
|
||||
*/
|
||||
public interface IItemSerializer<T> extends IItemReader<T> {
|
||||
|
||||
/**
|
||||
* Save.
|
||||
*
|
||||
* @param unit the unit
|
||||
*/
|
||||
void save(T unit);
|
||||
|
||||
/**
|
||||
* Erase.
|
||||
*
|
||||
* @param unit the unit
|
||||
*/
|
||||
void erase(T unit);
|
||||
|
||||
|
||||
File getDirectory();
|
||||
}
|
||||
229
forge-core/src/main/java/forge/util/ItemPool.java
Normal file
229
forge-core/src/main/java/forge/util/ItemPool.java
Normal file
@@ -0,0 +1,229 @@
|
||||
/*
|
||||
* Forge: Play Magic: the Gathering.
|
||||
* Copyright (C) 2011 Forge Team
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package forge.util;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.Map.Entry;
|
||||
|
||||
import forge.item.InventoryItem;
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* ItemPool class.
|
||||
* </p>
|
||||
* Represents a list of items with amount of each
|
||||
*
|
||||
* @param <T>
|
||||
* an Object
|
||||
*/
|
||||
public class ItemPool<T extends InventoryItem> extends ItemPoolView<T> {
|
||||
|
||||
|
||||
|
||||
// Constructors here
|
||||
/**
|
||||
*
|
||||
* ItemPool Constructor.
|
||||
*
|
||||
* @param cls
|
||||
* a T
|
||||
*/
|
||||
public ItemPool(final Class<T> cls) {
|
||||
super(cls);
|
||||
}
|
||||
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
public static <Tin extends InventoryItem, Tout extends InventoryItem> ItemPool<Tout> createFrom(final ItemPoolView<Tin> from, final Class<Tout> clsHint) {
|
||||
final ItemPool<Tout> result = new ItemPool<Tout>(clsHint);
|
||||
if (from != null) {
|
||||
for (final Entry<Tin, Integer> e : from) {
|
||||
final Tin srcKey = e.getKey();
|
||||
if (clsHint.isInstance(srcKey)) {
|
||||
result.put((Tout) srcKey, e.getValue());
|
||||
}
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
public static <Tin extends InventoryItem, Tout extends InventoryItem> ItemPool<Tout> createFrom(final Iterable<Tin> from, final Class<Tout> clsHint) {
|
||||
final ItemPool<Tout> result = new ItemPool<Tout>(clsHint);
|
||||
if (from != null) {
|
||||
for (final Tin srcKey : from) {
|
||||
if (clsHint.isInstance(srcKey)) {
|
||||
result.put((Tout) srcKey, Integer.valueOf(1));
|
||||
}
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
// get
|
||||
/**
|
||||
*
|
||||
* Get item view.
|
||||
*
|
||||
* @return a ItemPoolView
|
||||
*/
|
||||
public ItemPoolView<T> getView() {
|
||||
return new ItemPoolView<T>(Collections.unmodifiableMap(this.getItems()), this.getMyClass());
|
||||
}
|
||||
|
||||
// Items manipulation
|
||||
/**
|
||||
*
|
||||
* Add a single item.
|
||||
*
|
||||
* @param item
|
||||
* a T
|
||||
*/
|
||||
public void add(final T item) {
|
||||
this.add(item, 1);
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* Add multiple items.
|
||||
*
|
||||
* @param item
|
||||
* a T
|
||||
* @param amount
|
||||
* a int
|
||||
*/
|
||||
public void add(final T item, final int amount) {
|
||||
if (amount <= 0) {
|
||||
return;
|
||||
}
|
||||
this.getItems().put(item, Integer.valueOf(this.count(item) + amount));
|
||||
this.isListInSync = false;
|
||||
}
|
||||
|
||||
private void put(final T item, final int amount) {
|
||||
this.getItems().put(item, amount);
|
||||
this.isListInSync = false;
|
||||
}
|
||||
|
||||
/**
|
||||
* addAllFlat.
|
||||
*
|
||||
* @param <U>
|
||||
* a InventoryItem
|
||||
* @param items
|
||||
* a Iterable<U>
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
public <U extends InventoryItem> void addAllFlat(final Iterable<U> items) {
|
||||
for (final U cr : items) {
|
||||
if (this.getMyClass().isInstance(cr)) {
|
||||
this.add((T) cr);
|
||||
}
|
||||
}
|
||||
this.isListInSync = false;
|
||||
}
|
||||
|
||||
/**
|
||||
* addAll.
|
||||
*
|
||||
* @param <U>
|
||||
* an InventoryItem
|
||||
* @param map
|
||||
* a Iterable<Entry<U, Integer>>
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
public <U extends InventoryItem> void addAll(final Iterable<Entry<U, Integer>> map) {
|
||||
Class<T> myClass = this.getMyClass();
|
||||
for (final Entry<U, Integer> e : map) {
|
||||
if (myClass.isInstance(e.getKey())) {
|
||||
this.add((T) e.getKey(), e.getValue());
|
||||
}
|
||||
}
|
||||
this.isListInSync = false;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* Remove.
|
||||
*
|
||||
* @param item
|
||||
* a T
|
||||
*/
|
||||
public boolean remove(final T item) {
|
||||
return this.remove(item, 1);
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* Remove.
|
||||
*
|
||||
* @param item
|
||||
* a T
|
||||
* @param amount
|
||||
* a int
|
||||
*/
|
||||
public boolean remove(final T item, final int amount) {
|
||||
final int count = this.count(item);
|
||||
if ((count == 0) || (amount <= 0)) {
|
||||
return false;
|
||||
}
|
||||
if (count <= amount) {
|
||||
this.getItems().remove(item);
|
||||
} else {
|
||||
this.getItems().put(item, count - amount);
|
||||
}
|
||||
this.isListInSync = false;
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* RemoveAll.
|
||||
*
|
||||
* @param map
|
||||
* a T
|
||||
*/
|
||||
public void removeAll(final Iterable<Entry<T, Integer>> map) {
|
||||
for (final Entry<T, Integer> e : map) {
|
||||
this.remove(e.getKey(), e.getValue());
|
||||
}
|
||||
// need not set out-of-sync: either remove did set, or nothing was removed
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* TODO: Write javadoc for this method.
|
||||
* @param flat Iterable<T>
|
||||
*/
|
||||
public void removeAllFlat(final Iterable<T> flat) {
|
||||
for (final T e : flat) {
|
||||
this.remove(e);
|
||||
}
|
||||
// need not set out-of-sync: either remove did set, or nothing was removed
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* Clear.
|
||||
*/
|
||||
public void clear() {
|
||||
this.getItems().clear();
|
||||
this.isListInSync = false;
|
||||
}
|
||||
}
|
||||
87
forge-core/src/main/java/forge/util/ItemPoolSorter.java
Normal file
87
forge-core/src/main/java/forge/util/ItemPoolSorter.java
Normal file
@@ -0,0 +1,87 @@
|
||||
/*
|
||||
* Forge: Play Magic: the Gathering.
|
||||
* Copyright (C) 2011 Forge Team
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package forge.util;
|
||||
|
||||
import java.util.Comparator;
|
||||
import java.util.Map.Entry;
|
||||
|
||||
import com.google.common.base.Function;
|
||||
|
||||
import forge.item.PaperCard;
|
||||
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* TableSorter class.
|
||||
* </p>
|
||||
*
|
||||
* @param <T>
|
||||
* the generic type
|
||||
* @author Forge
|
||||
* @version $Id: TableSorter.java 21966 2013-06-05 06:58:32Z Max mtg $
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
// Comparable needs <type>
|
||||
public class ItemPoolSorter<T> implements Comparator<Entry<T, Integer>> {
|
||||
private final boolean ascending;
|
||||
private final Function<Entry<T, Integer>, Comparable<?>> field;
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* Constructor for TableSorter.
|
||||
* </p>
|
||||
*
|
||||
* @param field
|
||||
* the field
|
||||
* @param inAscending
|
||||
* a boolean.
|
||||
*/
|
||||
public ItemPoolSorter(final Function<Entry<T, Integer>, Comparable<?>> field, final boolean inAscending) {
|
||||
this.field = field;
|
||||
this.ascending = inAscending;
|
||||
}
|
||||
|
||||
/** The Constant byNameThenSet. */
|
||||
public static final ItemPoolSorter<PaperCard> BY_NAME_THEN_SET = new ItemPoolSorter<PaperCard>(
|
||||
new Function<Entry<PaperCard, Integer>, Comparable<?>>() {
|
||||
@Override
|
||||
public Comparable<?> apply(final Entry<PaperCard, Integer> from) {
|
||||
return from.getKey();
|
||||
}
|
||||
}, true);
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
*
|
||||
* @see java.util.Comparator#compare(java.lang.Object, java.lang.Object)
|
||||
*/
|
||||
@SuppressWarnings("rawtypes")
|
||||
@Override
|
||||
public final int compare(final Entry<T, Integer> arg0, final Entry<T, Integer> arg1) {
|
||||
final Comparable obj1 = this.field.apply(arg0);
|
||||
final Comparable obj2 = this.field.apply(arg1);
|
||||
if (obj1 == null) {
|
||||
return -1;
|
||||
}
|
||||
if (obj2 == null) {
|
||||
return 1;
|
||||
}
|
||||
//System.out.println(String.format("%s vs %s _______ %s vs %s", arg0, arg1, obj1, obj2));
|
||||
return this.ascending ? obj1.compareTo(obj2) : obj2.compareTo(obj1);
|
||||
}
|
||||
}
|
||||
256
forge-core/src/main/java/forge/util/ItemPoolView.java
Normal file
256
forge-core/src/main/java/forge/util/ItemPoolView.java
Normal file
@@ -0,0 +1,256 @@
|
||||
/*
|
||||
* Forge: Play Magic: the Gathering.
|
||||
* Copyright (C) 2011 Forge Team
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package forge.util;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Hashtable;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Map.Entry;
|
||||
|
||||
import com.google.common.base.Function;
|
||||
import com.google.common.base.Predicate;
|
||||
|
||||
import forge.item.InventoryItem;
|
||||
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* ItemPoolView class.
|
||||
* </p>
|
||||
*
|
||||
* @param <T>
|
||||
* an InventoryItem
|
||||
* @author Forge
|
||||
* @version $Id: ItemPoolView.java 9708 2011-08-09 19:34:12Z jendave $
|
||||
*/
|
||||
public class ItemPoolView<T extends InventoryItem> implements Iterable<Entry<T, Integer>> {
|
||||
|
||||
/** The fn to printed. */
|
||||
public final transient Function<Entry<T, Integer>, T> FN_GET_KEY = new Function<Entry<T, Integer>, T>() {
|
||||
@Override
|
||||
public T apply(final Entry<T, Integer> from) {
|
||||
return from.getKey();
|
||||
}
|
||||
};
|
||||
|
||||
/** The fn to item name. */
|
||||
public final transient Function<Entry<T, Integer>, String> FN_GET_NAME = new Function<Entry<T, Integer>, String>() {
|
||||
@Override
|
||||
public String apply(final Entry<T, Integer> from) {
|
||||
return from.getKey().getName();
|
||||
}
|
||||
};
|
||||
|
||||
/** The fn to count. */
|
||||
public final transient Function<Entry<T, Integer>, Integer> FN_GET_COUNT = new Function<Entry<T, Integer>, Integer>() {
|
||||
@Override
|
||||
public Integer apply(final Entry<T, Integer> from) {
|
||||
return from.getValue();
|
||||
}
|
||||
};
|
||||
|
||||
// Constructors
|
||||
public ItemPoolView(final Class<T> cls) {
|
||||
this(new Hashtable<T, Integer>(), cls);
|
||||
}
|
||||
|
||||
public ItemPoolView(final Map<T, Integer> inMap, final Class<T> cls) {
|
||||
this.items = inMap;
|
||||
this.myClass = cls;
|
||||
}
|
||||
|
||||
// Data members
|
||||
/** The items. */
|
||||
private final Map<T, Integer> items;
|
||||
|
||||
/** The my class. */
|
||||
private final Class<T> myClass; // class does not keep this in runtime by
|
||||
// itself
|
||||
|
||||
// same thing as above, it was copied to provide sorting (needed by table
|
||||
// views in deck editors)
|
||||
/** The items ordered. */
|
||||
private final transient List<Entry<T, Integer>> itemsOrdered = new ArrayList<Map.Entry<T, Integer>>();
|
||||
|
||||
/** Whether list is in sync. */
|
||||
protected transient boolean isListInSync = false;
|
||||
|
||||
/**
|
||||
* iterator.
|
||||
*
|
||||
* @return Iterator<Entry<T, Integer>>
|
||||
*/
|
||||
@Override
|
||||
public final Iterator<Entry<T, Integer>> iterator() {
|
||||
return this.items.entrySet().iterator();
|
||||
}
|
||||
|
||||
// Items read only operations
|
||||
/**
|
||||
*
|
||||
* contains.
|
||||
*
|
||||
* @param item
|
||||
* a T
|
||||
* @return boolean
|
||||
*/
|
||||
public final boolean contains(final T item) {
|
||||
if (this.items == null) {
|
||||
return false;
|
||||
}
|
||||
return this.items.containsKey(item);
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* count.
|
||||
*
|
||||
* @param item
|
||||
* a T
|
||||
* @return int
|
||||
*/
|
||||
public final int count(final T item) {
|
||||
if (this.items == null) {
|
||||
return 0;
|
||||
}
|
||||
final Integer boxed = this.items.get(item);
|
||||
return boxed == null ? 0 : boxed.intValue();
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* countAll.
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
public final int countAll() {
|
||||
return countAll(null, myClass);
|
||||
}
|
||||
|
||||
public final int countAll(Predicate<T> condition) {
|
||||
return countAll(condition, myClass);
|
||||
}
|
||||
|
||||
public final <U extends InventoryItem> int countAll(Predicate<U> condition, Class<U> cls) {
|
||||
int result = 0;
|
||||
if (this.items != null) {
|
||||
final boolean isSameClass = cls == myClass;
|
||||
for (final Entry<T, Integer> kv : this) {
|
||||
final T key = kv.getKey();
|
||||
@SuppressWarnings("unchecked")
|
||||
final U castKey = isSameClass || cls.isInstance(key) ? (U)key : null;
|
||||
if (null == condition || castKey != null && condition.apply(castKey))
|
||||
result += kv.getValue();
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* countDistinct.
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
public final int countDistinct() {
|
||||
return this.items.size();
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* isEmpty.
|
||||
*
|
||||
* @return boolean
|
||||
*/
|
||||
public final boolean isEmpty() {
|
||||
return (this.items == null) || this.items.isEmpty();
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* getOrderedList.
|
||||
*
|
||||
* @return List<Entry<T, Integer>>
|
||||
*/
|
||||
public final List<Entry<T, Integer>> getOrderedList() {
|
||||
if (!this.isListInSync) {
|
||||
this.rebuildOrderedList();
|
||||
}
|
||||
return this.itemsOrdered;
|
||||
}
|
||||
|
||||
private void rebuildOrderedList() {
|
||||
this.itemsOrdered.clear();
|
||||
if (this.items != null) {
|
||||
for (final Entry<T, Integer> e : this.items.entrySet()) {
|
||||
this.itemsOrdered.add(e);
|
||||
}
|
||||
}
|
||||
this.isListInSync = true;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* toFlatList.
|
||||
*
|
||||
* @return List<T>
|
||||
*/
|
||||
public final List<T> toFlatList() {
|
||||
final List<T> result = new ArrayList<T>();
|
||||
for (final Entry<T, Integer> e : this) {
|
||||
for (int i = 0; i < e.getValue(); i++) {
|
||||
result.add(e.getKey());
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the items.
|
||||
*
|
||||
* @return the items
|
||||
*/
|
||||
protected Map<T, Integer> getItems() {
|
||||
return this.items;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the my class.
|
||||
*
|
||||
* @return the myClass
|
||||
*/
|
||||
public Class<T> getMyClass() {
|
||||
return this.myClass;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* To item list string.
|
||||
*
|
||||
* @return the iterable
|
||||
*/
|
||||
public Iterable<String> toItemListString() {
|
||||
final List<String> list = new ArrayList<String>();
|
||||
for (final Entry<T, Integer> e : this.items.entrySet()) {
|
||||
list.add(String.format("%d x %s", e.getValue(), e.getKey().getName()));
|
||||
}
|
||||
return list;
|
||||
}
|
||||
}
|
||||
134
forge-core/src/main/java/forge/util/Lang.java
Normal file
134
forge-core/src/main/java/forge/util/Lang.java
Normal file
@@ -0,0 +1,134 @@
|
||||
package forge.util;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
|
||||
import com.google.common.base.Function;
|
||||
import com.google.common.collect.Iterables;
|
||||
import com.google.common.collect.Lists;
|
||||
|
||||
/**
|
||||
* TODO: Write javadoc for this type.
|
||||
*
|
||||
*/
|
||||
public class Lang {
|
||||
|
||||
/**
|
||||
* TODO: Write javadoc for this method.
|
||||
* @param position
|
||||
* @return
|
||||
*/
|
||||
public static String getOrdinal(int position) {
|
||||
String[] sufixes = new String[] { "th", "st", "nd", "rd", "th", "th", "th", "th", "th", "th" };
|
||||
switch (position % 100) {
|
||||
case 11:
|
||||
case 12:
|
||||
case 13:
|
||||
return position + "th";
|
||||
default:
|
||||
return position + sufixes[position % 10];
|
||||
}
|
||||
}
|
||||
|
||||
public static <T> String joinHomogenous(String s1, String s2) {
|
||||
boolean has1 = StringUtils.isNotBlank(s1);
|
||||
boolean has2 = StringUtils.isNotBlank(s2);
|
||||
return has1 ? (has2 ? s1 + " and " + s2 : s1) : (has2 ? s2 : "");
|
||||
}
|
||||
|
||||
public static <T> String joinHomogenous(Iterable<T> objects) { return joinHomogenous(Lists.newArrayList(objects)); }
|
||||
public static <T> String joinHomogenous(Collection<T> objects) { return joinHomogenous(objects, null, "and"); }
|
||||
public static <T> String joinHomogenous(Collection<T> objects, Function<T, String> accessor) {
|
||||
return joinHomogenous(objects, accessor, "and");
|
||||
}
|
||||
public static <T> String joinHomogenous(Collection<T> objects, Function<T, String> accessor, String lastUnion) {
|
||||
int remaining = objects.size();
|
||||
StringBuilder sb = new StringBuilder();
|
||||
for(T obj : objects) {
|
||||
remaining--;
|
||||
if( accessor != null )
|
||||
sb.append(accessor.apply(obj));
|
||||
else
|
||||
sb.append(obj);
|
||||
if( remaining > 1 ) sb.append(", ");
|
||||
if( remaining == 1 ) sb.append(" ").append(lastUnion).append(" ");
|
||||
}
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
|
||||
public static <T> String joinVerb(List<T> subjects, String verb) {
|
||||
return subjects.size() > 1 || !subjectIsSingle3rdPerson(Iterables.getFirst(subjects, "it").toString()) ? verb : verbs3rdPersonSingular(verb);
|
||||
}
|
||||
|
||||
public static String joinVerb(String subject, String verb) {
|
||||
return !Lang.subjectIsSingle3rdPerson(subject) ? verb : verbs3rdPersonSingular(verb);
|
||||
}
|
||||
|
||||
public static boolean subjectIsSingle3rdPerson(String subject) {
|
||||
// Will be most simple
|
||||
return !"You".equalsIgnoreCase(subject);
|
||||
}
|
||||
|
||||
public static String verbs3rdPersonSingular(String verb) {
|
||||
// English is simple - just add (s) for multiple objects.
|
||||
return verb + "s";
|
||||
}
|
||||
|
||||
public static String getPlural(String noun) {
|
||||
return noun + ( noun.endsWith("s") || noun.endsWith("x") ? "es" : "s");
|
||||
}
|
||||
|
||||
public static <T> String nounWithAmount(int cnt, String noun) {
|
||||
String countedForm = cnt <= 1 ? noun : getPlural(noun);
|
||||
final String strCount;
|
||||
if( cnt == 1 )
|
||||
strCount = startsWithVowel(noun) ? "an " : "a ";
|
||||
else
|
||||
strCount = String.valueOf(cnt) + " ";
|
||||
return strCount + countedForm;
|
||||
}
|
||||
|
||||
public static <T> String nounWithNumeral(int cnt, String noun) {
|
||||
String countedForm = cnt <= 1 ? noun : getPlural(noun);
|
||||
return getNumeral(cnt) + " " + countedForm;
|
||||
}
|
||||
|
||||
public static String getPossesive(String name) {
|
||||
if ("You".equalsIgnoreCase(name)) return name + "r"; // to get "your"
|
||||
return name.endsWith("s") ? name + "'" : name + "'s";
|
||||
}
|
||||
|
||||
public static boolean startsWithVowel(String word) {
|
||||
return isVowel(word.trim().charAt(0));
|
||||
}
|
||||
|
||||
private static final char[] vowels = { 'a', 'i', 'e', 'o', 'u' };
|
||||
public static boolean isVowel(char letter) {
|
||||
char l = Character.toLowerCase(letter);
|
||||
for(char c : vowels)
|
||||
if ( c == l ) return true;
|
||||
return false;
|
||||
|
||||
}
|
||||
|
||||
public final static String[] numbers0 = new String[] {
|
||||
"zero", "one", "two", "three", "four", "five", "six", "seven", "eight", "nine",
|
||||
"ten", "eleven", "twelve", "thirteen", "fourteen", "fifteen", "sixteen", "seventeen", "eightteen", "nineteen" };
|
||||
public final static String[] numbers20 = new String[] {"twenty", "thirty", "fourty", "fifty", "sixty", "seventy", "eighty", "ninety" };
|
||||
|
||||
public static String getNumeral(int n) {
|
||||
String prefix = n < 0 ? "minus " : "";
|
||||
n = Math.abs(n);
|
||||
if ( n >= 0 && n < 20 )
|
||||
return prefix + numbers0[n];
|
||||
if ( n < 100 ) {
|
||||
int n1 = n % 10;
|
||||
String ones = n1 == 0 ? "" : numbers0[n1];
|
||||
return prefix + numbers20[(n / 10) - 2] + " " + ones;
|
||||
}
|
||||
return Integer.toString(n);
|
||||
}
|
||||
}
|
||||
58
forge-core/src/main/java/forge/util/MyRandom.java
Normal file
58
forge-core/src/main/java/forge/util/MyRandom.java
Normal file
@@ -0,0 +1,58 @@
|
||||
/*
|
||||
* Forge: Play Magic: the Gathering.
|
||||
* Copyright (C) 2011 Forge Team
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package forge.util;
|
||||
|
||||
import java.security.SecureRandom;
|
||||
import java.util.Random;
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* MyRandom class.<br>
|
||||
* Preferably all Random numbers should be retrieved using this wrapper class
|
||||
* </p>
|
||||
*
|
||||
* @author Forge
|
||||
* @version $Id$
|
||||
*/
|
||||
public class MyRandom {
|
||||
/** Constant <code>random</code>. */
|
||||
private static Random random = new SecureRandom();
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* percentTrue.<br>
|
||||
* If percent is like 30, then 30% of the time it will be true.
|
||||
* </p>
|
||||
*
|
||||
* @param percent
|
||||
* a int.
|
||||
* @return a boolean.
|
||||
*/
|
||||
public static boolean percentTrue(final int percent) {
|
||||
return percent > MyRandom.getRandom().nextInt(100);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the random.
|
||||
*
|
||||
* @return the random
|
||||
*/
|
||||
public static Random getRandom() {
|
||||
return MyRandom.random;
|
||||
}
|
||||
}
|
||||
112
forge-core/src/main/java/forge/util/PredicateString.java
Normal file
112
forge-core/src/main/java/forge/util/PredicateString.java
Normal file
@@ -0,0 +1,112 @@
|
||||
/*
|
||||
* Forge: Play Magic: the Gathering.
|
||||
* Copyright (C) 2011 MaxMtg
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package forge.util;
|
||||
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
|
||||
import com.google.common.base.Predicate;
|
||||
|
||||
/**
|
||||
* Special predicate class to perform string operations.
|
||||
*
|
||||
* @param <T>
|
||||
* the generic type
|
||||
*/
|
||||
public abstract class PredicateString<T> implements Predicate<T> {
|
||||
/** Possible operators for string operands. */
|
||||
public enum StringOp {
|
||||
/** The CONTAINS. */
|
||||
CONTAINS,
|
||||
/** The CONTAINS ignore case. */
|
||||
CONTAINS_IC,
|
||||
/** The EQUALS. */
|
||||
EQUALS,
|
||||
/** The EQUALS. */
|
||||
EQUALS_IC
|
||||
}
|
||||
|
||||
/** The operator. */
|
||||
private final StringOp operator;
|
||||
|
||||
/**
|
||||
* Op.
|
||||
*
|
||||
* @param op1
|
||||
* the op1
|
||||
* @param op2
|
||||
* the op2
|
||||
* @return true, if successful
|
||||
*/
|
||||
protected final boolean op(final String op1, final String op2) {
|
||||
switch (this.getOperator()) {
|
||||
case CONTAINS_IC:
|
||||
return StringUtils.containsIgnoreCase(op1, op2);
|
||||
case CONTAINS:
|
||||
return StringUtils.contains(op1, op2);
|
||||
case EQUALS:
|
||||
return op1.equals(op2);
|
||||
case EQUALS_IC:
|
||||
return op1.equalsIgnoreCase(op2);
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Instantiates a new predicate string.
|
||||
*
|
||||
* @param operator
|
||||
* the operator
|
||||
*/
|
||||
public PredicateString(final StringOp operator) {
|
||||
this.operator = operator;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the operator
|
||||
*/
|
||||
public StringOp getOperator() {
|
||||
return operator;
|
||||
}
|
||||
|
||||
public static PredicateString<String> contains(final String what) {
|
||||
return new PredicateString<String>(StringOp.CONTAINS) {
|
||||
@Override
|
||||
public boolean apply(String subject) {
|
||||
return op(subject, what);
|
||||
}
|
||||
};
|
||||
}
|
||||
public static PredicateString<String> containsIgnoreCase(final String what) {
|
||||
return new PredicateString<String>(StringOp.CONTAINS_IC) {
|
||||
@Override
|
||||
public boolean apply(String subject) {
|
||||
return op(subject, what);
|
||||
}
|
||||
};
|
||||
}
|
||||
public static PredicateString<String> equals(final String what) {
|
||||
return new PredicateString<String>(StringOp.EQUALS) {
|
||||
@Override
|
||||
public boolean apply(String subject) {
|
||||
return op(subject, what);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
}
|
||||
122
forge-core/src/main/java/forge/util/TextUtil.java
Normal file
122
forge-core/src/main/java/forge/util/TextUtil.java
Normal file
@@ -0,0 +1,122 @@
|
||||
package forge.util;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
import java.util.Map;
|
||||
import java.util.Map.Entry;
|
||||
|
||||
import org.apache.commons.lang3.ArrayUtils;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
|
||||
import forge.item.PaperCard;
|
||||
|
||||
/**
|
||||
* TODO: Write javadoc for this type.
|
||||
*
|
||||
*/
|
||||
public class TextUtil {
|
||||
|
||||
/**
|
||||
* Safely converts an object to a String.
|
||||
*
|
||||
* @param obj
|
||||
* to convert; may be null
|
||||
*
|
||||
* @return "null" if obj is null, obj.toString() otherwise
|
||||
*/
|
||||
public static String safeToString(final Object obj) {
|
||||
return obj == null ? "null" : obj.toString();
|
||||
}
|
||||
|
||||
public static String mapToString(Map<String, ?> map) {
|
||||
StringBuilder mapAsString = new StringBuilder();
|
||||
boolean isFirst = true;
|
||||
for (Entry<String, ?> p : map.entrySet()) {
|
||||
if (isFirst) {
|
||||
isFirst = false;
|
||||
} else {
|
||||
mapAsString.append("; ");
|
||||
}
|
||||
mapAsString.append(p.getKey() + " => " + (p.getValue() == null ? "(null)" : p.getValue().toString()));
|
||||
}
|
||||
return mapAsString.toString();
|
||||
}
|
||||
|
||||
public static String[] split(CharSequence input, char delimiter) {
|
||||
return splitWithParenthesis(input, delimiter, Integer.MAX_VALUE, '\0', '\0', true);
|
||||
}
|
||||
|
||||
public static String[] split(CharSequence input, char delimiter, int limit) {
|
||||
return splitWithParenthesis(input, delimiter, limit, '\0', '\0', true);
|
||||
}
|
||||
public static String[] splitWithParenthesis(CharSequence input, char delimiter) {
|
||||
return splitWithParenthesis(input, delimiter, Integer.MAX_VALUE, '(', ')', true);
|
||||
}
|
||||
|
||||
public static String[] splitWithParenthesis(CharSequence input, char delimiter, char openPar, char closePar) {
|
||||
return splitWithParenthesis(input, delimiter, Integer.MAX_VALUE, openPar, closePar, true);
|
||||
}
|
||||
|
||||
public static String[] splitWithParenthesis(CharSequence input, char delimiter, int limit) {
|
||||
return splitWithParenthesis(input, delimiter, limit, '(', ')', true);
|
||||
}
|
||||
|
||||
public static String[] splitWithParenthesis(CharSequence input, char delimiter, char openPar, char closePar, int limit) {
|
||||
return splitWithParenthesis(input, delimiter, limit, openPar, closePar, true);
|
||||
}
|
||||
|
||||
/**
|
||||
* Split string separated by a single char delimiter, can take parenthesis in account
|
||||
* It's faster than String.split, and allows parenthesis
|
||||
*/
|
||||
public static String[] splitWithParenthesis(CharSequence input, char delimiter, int maxEntries, char openPar, char closePar, boolean skipEmpty) {
|
||||
List<String> result = new ArrayList<String>();
|
||||
// Assume that when equal non-zero parenthesis are passed, they need to be discarded
|
||||
boolean trimParenthesis = openPar == closePar && openPar > 0;
|
||||
int nPar = 0;
|
||||
int len = input.length();
|
||||
int start = 0;
|
||||
int idx = 1;
|
||||
for (int iC = 0; iC < len; iC++ ) {
|
||||
char c = input.charAt(iC);
|
||||
if( closePar > 0 && c == closePar && nPar > 0 ) { nPar--; }
|
||||
else if( openPar > 0 && c == openPar ) nPar++;
|
||||
|
||||
if( c == delimiter && nPar == 0 && idx < maxEntries) {
|
||||
if( iC > start || !skipEmpty ) {
|
||||
result.add(input.subSequence(start, iC).toString());
|
||||
idx++;
|
||||
}
|
||||
start = iC + 1;
|
||||
}
|
||||
}
|
||||
|
||||
if( len > start || !skipEmpty )
|
||||
result.add(input.subSequence(start, len).toString());
|
||||
|
||||
String[] toReturn = result.toArray(ArrayUtils.EMPTY_STRING_ARRAY);
|
||||
return trimParenthesis ? StringUtils.stripAll(toReturn, String.valueOf(openPar)) : toReturn;
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts an enum value to a printable label but upcasing the first letter
|
||||
* and lcasing all subsequent letters
|
||||
*/
|
||||
public static String enumToLabel(Enum<?> val) {
|
||||
return val.toString().substring(0, 1).toUpperCase(Locale.ENGLISH) +
|
||||
val.toString().substring(1).toLowerCase(Locale.ENGLISH);
|
||||
}
|
||||
|
||||
public static String buildFourColumnList(String firstLine, Iterable<PaperCard> cAnteRemoved) {
|
||||
StringBuilder sb = new StringBuilder(firstLine);
|
||||
int i = 0;
|
||||
for(PaperCard cp: cAnteRemoved) {
|
||||
if ( i != 0 ) sb.append(", ");
|
||||
if ( i % 4 == 0 ) sb.append("\n");
|
||||
sb.append(cp);
|
||||
i++;
|
||||
}
|
||||
return sb.toString();
|
||||
}
|
||||
}
|
||||
49
forge-core/src/main/java/forge/util/storage/IStorage.java
Normal file
49
forge-core/src/main/java/forge/util/storage/IStorage.java
Normal file
@@ -0,0 +1,49 @@
|
||||
/*
|
||||
* Forge: Play Magic: the Gathering.
|
||||
* Copyright (C) 2011 Forge Team
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package forge.util.storage;
|
||||
|
||||
import java.util.Collection;
|
||||
|
||||
import com.google.common.base.Predicate;
|
||||
|
||||
import forge.util.IHasName;
|
||||
|
||||
/**
|
||||
* TODO: Write javadoc for this type.
|
||||
*
|
||||
* @param <T> the generic type
|
||||
*/
|
||||
public interface IStorage<T> extends Iterable<T>, IHasName {
|
||||
|
||||
T get(final String name);
|
||||
|
||||
T find(final Predicate<T> condition);
|
||||
// todo: find(final Predicate<T> condition, boolean recursive).
|
||||
|
||||
Collection<String> getItemNames();
|
||||
|
||||
boolean contains(final String name);
|
||||
|
||||
int size();
|
||||
|
||||
void add(final T deck);
|
||||
|
||||
void delete(final String deckName);
|
||||
|
||||
IStorage<IStorage<T>> getFolders();
|
||||
}
|
||||
115
forge-core/src/main/java/forge/util/storage/StorageBase.java
Normal file
115
forge-core/src/main/java/forge/util/storage/StorageBase.java
Normal file
@@ -0,0 +1,115 @@
|
||||
/*
|
||||
* Forge: Play Magic: the Gathering.
|
||||
* Copyright (C) 2011 Forge Team
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package forge.util.storage;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.HashMap;
|
||||
import java.util.Iterator;
|
||||
import java.util.Map;
|
||||
|
||||
import com.google.common.base.Predicate;
|
||||
import com.google.common.collect.Iterables;
|
||||
|
||||
import forge.util.IItemReader;
|
||||
|
||||
//reads and writeDeck Deck objects
|
||||
/**
|
||||
* <p>
|
||||
* DeckManager class.
|
||||
* </p>
|
||||
*
|
||||
* @param <T> the generic type
|
||||
* @author Forge
|
||||
* @version $Id: DeckManager.java 13590 2012-01-27 20:46:27Z Max mtg $
|
||||
*/
|
||||
public class StorageBase<T> implements IStorage<T> {
|
||||
protected final Map<String, T> map;
|
||||
|
||||
public final static StorageBase<?> emptyMap = new StorageBase<Object>("Empty", new HashMap<String, Object>());
|
||||
public final String name;
|
||||
|
||||
public StorageBase(final String name, final IItemReader<T> io) {
|
||||
this.name = name;
|
||||
this.map = io.readAll();
|
||||
}
|
||||
|
||||
public StorageBase(final String name, final Map<String, T> inMap) {
|
||||
this.name = name;
|
||||
this.map = inMap;
|
||||
}
|
||||
|
||||
@Override
|
||||
public T get(final String name) {
|
||||
return this.map.get(name);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public final Collection<String> getItemNames() {
|
||||
return new ArrayList<String>(this.map.keySet());
|
||||
}
|
||||
|
||||
@Override
|
||||
public Iterator<T> iterator() {
|
||||
return this.map.values().iterator();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean contains(String name) {
|
||||
return name == null ? false : this.map.containsKey(name);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int size() {
|
||||
return this.map.size();
|
||||
}
|
||||
|
||||
@Override
|
||||
public T find(Predicate<T> condition) {
|
||||
return Iterables.tryFind(map.values(), condition).orNull();
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void add(T deck) {
|
||||
throw new UnsupportedOperationException("This is a read-only storage");
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void delete(String deckName) {
|
||||
throw new UnsupportedOperationException("This is a read-only storage");
|
||||
}
|
||||
|
||||
// we don't have nested folders unless that's overridden in a derived class
|
||||
@SuppressWarnings("unchecked")
|
||||
@Override
|
||||
public IStorage<IStorage<T>> getFolders() {
|
||||
return (IStorage<IStorage<T>>) emptyMap;
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see forge.util.IHasName#getName()
|
||||
*/
|
||||
@Override
|
||||
public String getName() {
|
||||
// TODO Auto-generated method stub
|
||||
return name;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
package forge.util.storage;
|
||||
|
||||
import java.io.File;
|
||||
|
||||
import com.google.common.base.Function;
|
||||
import com.google.common.collect.ImmutableList;
|
||||
|
||||
import forge.util.IItemReader;
|
||||
|
||||
public abstract class StorageReaderBase<T> implements IItemReader<T> {
|
||||
|
||||
protected final Function<? super T, String> keySelector;
|
||||
public StorageReaderBase(final Function<? super T, String> keySelector0) {
|
||||
keySelector = keySelector0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Iterable<File> getSubFolders() {
|
||||
// TODO Auto-generated method stub
|
||||
return ImmutableList.of();
|
||||
}
|
||||
|
||||
@Override
|
||||
public IItemReader<T> getReaderForFolder(File subfolder) {
|
||||
throw new UnsupportedOperationException("This reader is not supposed to have nested folders");
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,119 @@
|
||||
/*
|
||||
* Forge: Play Magic: the Gathering.
|
||||
* Copyright (C) 2011 Nate
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package forge.util.storage;
|
||||
|
||||
import java.io.File;
|
||||
import java.util.Map;
|
||||
import java.util.TreeMap;
|
||||
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
|
||||
import com.google.common.base.Function;
|
||||
|
||||
import forge.util.FileUtil;
|
||||
|
||||
/**
|
||||
* This class treats every line of a given file as a source for a named object.
|
||||
*
|
||||
* @param <T>
|
||||
* the generic type
|
||||
*/
|
||||
public abstract class StorageReaderFile<T> extends StorageReaderBase<T> {
|
||||
|
||||
private final File file;
|
||||
|
||||
|
||||
/**
|
||||
* Instantiates a new storage reader file.
|
||||
*
|
||||
* @param pathname the pathname
|
||||
* @param keySelector0 the key selector0
|
||||
*/
|
||||
public StorageReaderFile(final String pathname, final Function<? super T, String> keySelector0) {
|
||||
this(new File(pathname), keySelector0);
|
||||
}
|
||||
|
||||
/**
|
||||
* Instantiates a new storage reader file.
|
||||
*
|
||||
* @param file0 the file0
|
||||
* @param keySelector0 the key selector0
|
||||
*/
|
||||
public StorageReaderFile(final File file0, final Function<? super T, String> keySelector0) {
|
||||
super(keySelector0);
|
||||
this.file = file0;
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see forge.util.IItemReader#readAll()
|
||||
*/
|
||||
@Override
|
||||
public Map<String, T> readAll() {
|
||||
final Map<String, T> result = new TreeMap<String, T>();
|
||||
|
||||
int idx = 0;
|
||||
for (final String s : FileUtil.readFile(this.file)) {
|
||||
if (!this.lineContainsObject(s)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
final T item = this.read(s, idx);
|
||||
if (null == item) {
|
||||
final String msg = "An object stored in " + this.file.getPath() + " failed to load.\nPlease submit this as a bug with the mentioned file attached.";
|
||||
throw new RuntimeException(msg);
|
||||
}
|
||||
|
||||
idx++;
|
||||
String newKey = keySelector.apply(item);
|
||||
if( result.containsKey(newKey))
|
||||
System.err.println("StorageReader: Overwriting an object with key " + newKey);
|
||||
|
||||
result.put(newKey, item);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* TODO: Write javadoc for this method.
|
||||
*
|
||||
* @param line
|
||||
* the line
|
||||
* @return the t
|
||||
*/
|
||||
protected abstract T read(String line, int idx);
|
||||
|
||||
/**
|
||||
* Line contains object.
|
||||
*
|
||||
* @param line
|
||||
* the line
|
||||
* @return true, if successful
|
||||
*/
|
||||
protected boolean lineContainsObject(final String line) {
|
||||
return !StringUtils.isBlank(line) && !line.trim().startsWith("#");
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see forge.util.IItemReader#getItemKey(java.lang.Object)
|
||||
*/
|
||||
@Override
|
||||
public String getItemKey(final T item) {
|
||||
return this.keySelector.apply(item);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,136 @@
|
||||
/*
|
||||
* Forge: Play Magic: the Gathering.
|
||||
* Copyright (C) 2011 Nate
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package forge.util.storage;
|
||||
|
||||
import java.io.File;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.TreeMap;
|
||||
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
|
||||
import com.google.common.base.Function;
|
||||
|
||||
import forge.util.FileUtil;
|
||||
|
||||
/**
|
||||
* This class treats every line of a given file as a source for a named object.
|
||||
*
|
||||
* @param <T>
|
||||
* the generic type
|
||||
*/
|
||||
public abstract class StorageReaderFileSections<T> extends StorageReaderBase<T> {
|
||||
|
||||
private final File file;
|
||||
|
||||
public StorageReaderFileSections(final String pathname, final Function<? super T, String> keySelector0) {
|
||||
this(new File(pathname), keySelector0);
|
||||
}
|
||||
|
||||
public StorageReaderFileSections(final File file0, final Function<? super T, String> keySelector0) {
|
||||
super(keySelector0);
|
||||
this.file = file0;
|
||||
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see forge.util.IItemReader#readAll()
|
||||
*/
|
||||
@Override
|
||||
public Map<String, T> readAll() {
|
||||
final Map<String, T> result = new TreeMap<String, T>();
|
||||
|
||||
int idx = 0;
|
||||
Iterable<String> file = FileUtil.readFile(this.file);
|
||||
|
||||
List<String> accumulator = new ArrayList<String>();
|
||||
String header = null;
|
||||
|
||||
for (final String s : file) {
|
||||
if (!this.lineContainsObject(s)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if(s.charAt(0) == '[') {
|
||||
if( header != null ) {
|
||||
// read previously collected item
|
||||
T item = readItem(header, accumulator, idx);
|
||||
if( item != null ) {
|
||||
result.put(this.keySelector.apply(item), item);
|
||||
idx++;
|
||||
}
|
||||
}
|
||||
|
||||
header = StringUtils.strip(s, "[] ");
|
||||
accumulator.clear();
|
||||
} else
|
||||
accumulator.add(s);
|
||||
}
|
||||
|
||||
// store the last item
|
||||
if ( !accumulator.isEmpty() ) {
|
||||
T item = readItem(header, accumulator, idx);
|
||||
if( item != null ) {
|
||||
String newKey = keySelector.apply(item);
|
||||
if( result.containsKey(newKey))
|
||||
System.err.println("StorageReader: Overwriting an object with key " + newKey);
|
||||
|
||||
result.put(newKey, item);
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
private final T readItem(String header, Iterable<String> accumulator, int idx) {
|
||||
final T item = this.read(header, accumulator, idx);
|
||||
if (null != item) return item;
|
||||
|
||||
final String msg = "An object stored in " + this.file.getPath() + " failed to load.\nPlease submit this as a bug with the mentioned file attached.";
|
||||
throw new RuntimeException(msg);
|
||||
}
|
||||
|
||||
/**
|
||||
* TODO: Write javadoc for this method.
|
||||
*
|
||||
* @param line
|
||||
* the line
|
||||
* @return the t
|
||||
*/
|
||||
protected abstract T read(String title, Iterable<String> body, int idx);
|
||||
|
||||
/**
|
||||
* Line contains object.
|
||||
*
|
||||
* @param line
|
||||
* the line
|
||||
* @return true, if successful
|
||||
*/
|
||||
protected boolean lineContainsObject(final String line) {
|
||||
return !StringUtils.isBlank(line) && !line.trim().startsWith("#");
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see forge.util.IItemReader#getItemKey(java.lang.Object)
|
||||
*/
|
||||
@Override
|
||||
public String getItemKey(final T item) {
|
||||
return this.keySelector.apply(item);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,142 @@
|
||||
/*
|
||||
* Forge: Play Magic: the Gathering.
|
||||
* Copyright (C) 2011 Nate
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package forge.util.storage;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileFilter;
|
||||
import java.io.FilenameFilter;
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.NoSuchElementException;
|
||||
import java.util.TreeMap;
|
||||
|
||||
import com.google.common.base.Function;
|
||||
|
||||
/**
|
||||
* This class treats every file in the given folder as a source for a named
|
||||
* object. The descendant should implement read method to deserialize a single
|
||||
* item. So that readAll will return a map of Name => Object as read from disk
|
||||
*
|
||||
* @param <T> the generic type
|
||||
*/
|
||||
public abstract class StorageReaderFolder<T> extends StorageReaderBase<T> {
|
||||
|
||||
/**
|
||||
* @return the directory
|
||||
*/
|
||||
public File getDirectory() {
|
||||
return directory;
|
||||
}
|
||||
|
||||
|
||||
protected final File directory;
|
||||
|
||||
/**
|
||||
* Instantiates a new storage reader folder.
|
||||
*
|
||||
* @param deckDir0 the deck dir0
|
||||
*/
|
||||
public StorageReaderFolder(final File deckDir0, Function<? super T, String> keySelector0) {
|
||||
super(keySelector0);
|
||||
|
||||
this.directory = deckDir0;
|
||||
|
||||
if (this.directory == null) {
|
||||
throw new IllegalArgumentException("No directory specified");
|
||||
}
|
||||
try {
|
||||
if (this.directory.isFile()) {
|
||||
throw new IOException("Not a directory");
|
||||
} else {
|
||||
this.directory.mkdirs();
|
||||
if (!this.directory.isDirectory()) {
|
||||
throw new IOException("Directory can't be created");
|
||||
}
|
||||
}
|
||||
} catch (final IOException ex) {
|
||||
throw new RuntimeException("StorageReaderFolder.ctor() error, " + ex.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
public final List<String> objectsThatFailedToLoad = new ArrayList<String>();
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see forge.util.IItemReader#readAll()
|
||||
*/
|
||||
@Override
|
||||
public Map<String, T> readAll() {
|
||||
final Map<String, T> result = new TreeMap<String, T>();
|
||||
|
||||
final File[] files = this.directory.listFiles(this.getFileFilter());
|
||||
for (final File file : files) {
|
||||
try {
|
||||
final T newDeck = this.read(file);
|
||||
if (null == newDeck) {
|
||||
final String msg = "An object stored in " + file.getPath() + " failed to load.\nPlease submit this as a bug with the mentioned file/directory attached.";
|
||||
throw new RuntimeException(msg);
|
||||
}
|
||||
String newKey = keySelector.apply(newDeck);
|
||||
if( result.containsKey(newKey))
|
||||
System.err.println("StorageReader: Overwriting an object with key " + newKey);
|
||||
|
||||
result.put(newKey, newDeck);
|
||||
} catch (final NoSuchElementException ex) {
|
||||
final String message = String.format("%s failed to load because ---- %s", file.getName(), ex.getMessage());
|
||||
objectsThatFailedToLoad.add(message);
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Read the object from file.
|
||||
*
|
||||
* @param file the file
|
||||
* @return the object deserialized by inherited class
|
||||
*/
|
||||
protected abstract T read(File file);
|
||||
|
||||
/**
|
||||
* TODO: Write javadoc for this method.
|
||||
*
|
||||
* @return FilenameFilter to pick only relevant objects for deserialization
|
||||
*/
|
||||
protected abstract FilenameFilter getFileFilter();
|
||||
|
||||
@Override
|
||||
public String getItemKey(T item) {
|
||||
return keySelector.apply(item);
|
||||
}
|
||||
|
||||
|
||||
// methods handling nested folders are provided. It's up to consumer whether to use these or not.
|
||||
@Override
|
||||
public Iterable<File> getSubFolders() {
|
||||
File[] list = this.directory.listFiles(new FileFilter() {
|
||||
|
||||
@Override
|
||||
public boolean accept(File file) {
|
||||
return file.isDirectory() && !file.isHidden();
|
||||
}
|
||||
});
|
||||
return Arrays.asList(list);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
/**
|
||||
*
|
||||
*/
|
||||
/**
|
||||
* @author Max
|
||||
*
|
||||
*/
|
||||
package forge.util.storage;
|
||||
Reference in New Issue
Block a user