mirror of
https://github.com/Card-Forge/forge.git
synced 2025-11-19 20:28:00 +00:00
TEMP implementation of Smart Card Art Selection method
This commit is contained in:
@@ -21,8 +21,10 @@ import com.google.common.base.Function;
|
||||
import com.google.common.collect.Lists;
|
||||
import forge.StaticData;
|
||||
import forge.card.CardDb;
|
||||
import forge.card.CardEdition;
|
||||
import forge.item.IPaperCard;
|
||||
import forge.item.PaperCard;
|
||||
import org.apache.commons.lang3.tuple.Pair;
|
||||
|
||||
import java.util.*;
|
||||
import java.util.Map.Entry;
|
||||
@@ -220,71 +222,195 @@ public class Deck extends DeckBase implements Iterable<Entry<DeckSection, CardPo
|
||||
return;
|
||||
}
|
||||
|
||||
boolean hasExplicitlySpecifiedSet = false;
|
||||
boolean smartCardArtSelection = StaticData.instance().smartCardArtSelectionIsEnabled();
|
||||
boolean foundCardsWithUnspecifiedEditions = false;
|
||||
Map<DeckSection, ArrayList<String>> cardsWithNoEdition = null;
|
||||
if (smartCardArtSelection)
|
||||
cardsWithNoEdition = new EnumMap<>(DeckSection.class);
|
||||
|
||||
for (Entry<String, List<String>> s : deferredSections.entrySet()) {
|
||||
DeckSection sec = DeckSection.smartValueOf(s.getKey());
|
||||
if (sec == null) {
|
||||
if (sec == null)
|
||||
continue;
|
||||
}
|
||||
|
||||
final List<String> cardsInSection = s.getValue();
|
||||
for (String k : cardsInSection)
|
||||
if (k.indexOf(CardDb.NameSetSeparator) > 0)
|
||||
hasExplicitlySpecifiedSet = true;
|
||||
|
||||
if (smartCardArtSelection){
|
||||
List<Pair<String, Integer>> cardRequests = CardPool.processCardList(cardsInSection);
|
||||
ArrayList<String> cardNamesWithNoEdition = new ArrayList<>();
|
||||
for (Pair<String, Integer> pair : cardRequests) {
|
||||
String requestString = pair.getLeft();
|
||||
CardDb.CardRequest request = CardDb.CardRequest.fromString(requestString);
|
||||
if (request.edition == null) {
|
||||
foundCardsWithUnspecifiedEditions = true;
|
||||
cardNamesWithNoEdition.add(request.cardName);
|
||||
}
|
||||
}
|
||||
if (cardNamesWithNoEdition.size() > 0)
|
||||
cardsWithNoEdition.put(sec, cardNamesWithNoEdition);
|
||||
}
|
||||
|
||||
CardPool pool = CardPool.fromCardList(cardsInSection);
|
||||
// NOTE: @Leriomaggio -
|
||||
// this will need improvements with a validation schema for each section to avoid
|
||||
// accidental additions and/or sanitise the content of each section.
|
||||
|
||||
// I used to store planes and schemes under sideboard header, so this will assign them to a correct section
|
||||
IPaperCard sample = pool.get(0);
|
||||
if (sample != null && ( sample.getRules().getType().isPlane() || sample.getRules().getType().isPhenomenon())) {
|
||||
if (sample != null && ( sample.getRules().getType().isPlane() || sample.getRules().getType().isPhenomenon()))
|
||||
sec = DeckSection.Planes;
|
||||
}
|
||||
if (sample != null && sample.getRules().getType().isScheme()) {
|
||||
if (sample != null && sample.getRules().getType().isScheme())
|
||||
sec = DeckSection.Schemes;
|
||||
}
|
||||
putSection(sec, pool);
|
||||
}
|
||||
|
||||
deferredSections = null;
|
||||
if (!hasExplicitlySpecifiedSet) {
|
||||
convertByXitaxMethod();
|
||||
// deferredSections = null;
|
||||
if (smartCardArtSelection && foundCardsWithUnspecifiedEditions){
|
||||
/* Logic Explained:
|
||||
foundCardsWithUnspecifiedEditions = true:
|
||||
some cards have been retrieved according to Preferred Card Art Option
|
||||
that is, some sections to have a list of cards to match
|
||||
smartCardArtSelection = true
|
||||
Optimising Preferred Card Art Option is wanted
|
||||
*/
|
||||
updateCardArtSelectionInPools(cardsWithNoEdition);
|
||||
}
|
||||
}
|
||||
|
||||
private void convertByXitaxMethod() {
|
||||
Date dateWithAllCards = StaticData.instance().getEditions().getEarliestDateWithAllCards(getAllCardsInASinglePool());
|
||||
for(Entry<DeckSection, CardPool> p : parts.entrySet()) {
|
||||
if( p.getKey() == DeckSection.Planes || p.getKey() == DeckSection.Schemes || p.getKey() == DeckSection.Avatar)
|
||||
private void updateCardArtSelectionInPools(Map<DeckSection, ArrayList<String>> cardsWithNoEdition) {
|
||||
StaticData data = StaticData.instance();
|
||||
for(Entry<DeckSection, CardPool> part : parts.entrySet()) {
|
||||
DeckSection deckSection = part.getKey();
|
||||
if(deckSection == DeckSection.Planes || deckSection == DeckSection.Schemes || deckSection == DeckSection.Avatar)
|
||||
continue;
|
||||
|
||||
CardPool newPool = new CardPool();
|
||||
// == 0. First Off, check if there is anything at all to do for the current section
|
||||
ArrayList<String> cardNamesWithNoEditionInSection = cardsWithNoEdition.getOrDefault(deckSection, null);
|
||||
if (cardNamesWithNoEditionInSection == null || cardNamesWithNoEditionInSection.size() == 0)
|
||||
continue; // nothing to do here
|
||||
|
||||
for(Entry<PaperCard, Integer> cp : p.getValue()){
|
||||
// Otherwise, start by gathering existing pool
|
||||
CardPool pool = part.getValue();
|
||||
|
||||
// == 1. Gather Statistics per Edition
|
||||
Map<CardEdition, Integer> editionStatistics = new HashMap<>();
|
||||
for(Entry<PaperCard, Integer> cp : pool) {
|
||||
PaperCard card = cp.getKey();
|
||||
// Exclude basicLand from stats
|
||||
if (card.isVeryBasicLand())
|
||||
continue;
|
||||
int count = cp.getValue();
|
||||
CardEdition edition = data.getCardEdition(card.getEdition());
|
||||
int currentCount = editionStatistics.getOrDefault(edition, 0);
|
||||
currentCount += count;
|
||||
editionStatistics.put(edition, currentCount);
|
||||
}
|
||||
/* == 2. Get the REFERENCE EDITION:
|
||||
Note: This is the first, and the most crucial part of the procedure as future choices on card
|
||||
art will be made depending on this REFERENCE EDITION.
|
||||
|
||||
The Reference Edition is the Edition wrt. other arts will be retrieved, using
|
||||
a selection policy that complies with the CardArt Preference Specified in the Settings/DB.
|
||||
|
||||
In more details, the REFERENCE edition is the most recent edition among those having the highest
|
||||
number of cards in the pool//deck section - NOT including Basic Lands!
|
||||
*/
|
||||
|
||||
CardEdition referenceEdition = null;
|
||||
int maxCardOccurrence = 0;
|
||||
for(Entry<CardEdition, Integer> entry : editionStatistics.entrySet()) {
|
||||
Integer cardCount = entry.getValue();
|
||||
CardEdition ed = entry.getKey();
|
||||
if (referenceEdition == null || cardCount > maxCardOccurrence){
|
||||
maxCardOccurrence = cardCount;
|
||||
referenceEdition = ed;
|
||||
}
|
||||
else if (cardCount == maxCardOccurrence) {
|
||||
// Same Card Count, update referenceEdition is release date is more recent than current reference
|
||||
if (ed.getDate().compareTo(referenceEdition.getDate()) > 0)
|
||||
referenceEdition = ed;
|
||||
}
|
||||
}
|
||||
// == 3. Last step, update the pool!
|
||||
// Get Reference release date as two days AFTER the actual release date
|
||||
// of the reference date so that in case, the reference date will be counted in too!
|
||||
Calendar cal = Calendar.getInstance();
|
||||
cal.setTime(referenceEdition.getDate());
|
||||
cal.add(Calendar.DATE, 2);
|
||||
Date releaseDateReferenceEdition = cal.getTime();
|
||||
|
||||
CardPool newPool = new CardPool();
|
||||
for(Entry<PaperCard, Integer> cp : pool) {
|
||||
PaperCard card = cp.getKey();
|
||||
int count = cp.getValue();
|
||||
|
||||
PaperCard replacementCard;
|
||||
replacementCard = StaticData.instance().getAlternativeCardPrint(card, dateWithAllCards);
|
||||
|
||||
// Note @leriomaggio: The following logic is very obscure to me
|
||||
// Why looking for a replacement Card and then not using adding it to the pool?
|
||||
// Also, what does "having the same art index" say about the two cards?
|
||||
if (replacementCard.getArtIndex() == card.getArtIndex()) {
|
||||
if (card.hasImage())
|
||||
if (!cardNamesWithNoEditionInSection.contains(card.getName()))
|
||||
newPool.add(card, count); // Nothing to do
|
||||
else if (card.getEdition().equals(referenceEdition.getCode()))
|
||||
newPool.add(card, count); // Nothing to do either
|
||||
else {
|
||||
PaperCard alternativeArtCard = data.getAlternativeCardPrint(card, releaseDateReferenceEdition);
|
||||
if (alternativeArtCard == null) // no alternative found
|
||||
newPool.add(card, count);
|
||||
else{
|
||||
if (!alternativeArtCard.isVeryBasicLand()){
|
||||
if (!data.cardArtPreferenceIsLatest()) // if it's not Latest Art, No worries at all
|
||||
newPool.add(alternativeArtCard, count);
|
||||
// Is Latest
|
||||
CardEdition alternateCardEd = data.getCardEdition(alternativeArtCard.getEdition());
|
||||
if (referenceEdition.isModern() && alternateCardEd.isModern())
|
||||
newPool.add(alternativeArtCard, count); // keep the substitution
|
||||
else
|
||||
newPool.add(replacementCard, count);
|
||||
} else {
|
||||
if (card.hasImage())
|
||||
newPool.add(card.getName(), card.getEdition(), count); // this is to randomize art
|
||||
else
|
||||
newPool.add(replacementCard, count);
|
||||
newPool.add(card, count); // keep the original selection based on card art preference
|
||||
} else
|
||||
newPool.add(alternativeArtCard, count); // BasicLand - any sub will be great!
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
parts.put(p.getKey(), newPool);
|
||||
parts.put(deckSection, newPool);
|
||||
}
|
||||
}
|
||||
|
||||
// private void convertByXitaxMethod() {
|
||||
// Date dateWithAllCards = StaticData.instance().getEditions().getEarliestDateWithAllCards(getAllCardsInASinglePool());
|
||||
// for(Entry<DeckSection, CardPool> p : parts.entrySet()) {
|
||||
// if( p.getKey() == DeckSection.Planes || p.getKey() == DeckSection.Schemes || p.getKey() == DeckSection.Avatar)
|
||||
// continue;
|
||||
//
|
||||
// CardPool newPool = new CardPool();
|
||||
//
|
||||
// for(Entry<PaperCard, Integer> cp : p.getValue()) {
|
||||
// PaperCard card = cp.getKey();
|
||||
// int count = cp.getValue();
|
||||
//
|
||||
// PaperCard replacementCard;
|
||||
// replacementCard = StaticData.instance().getAlternativeCardPrint(card, dateWithAllCards);
|
||||
//
|
||||
// // Note @leriomaggio: The following logic is very obscure to me
|
||||
// // Why looking for a replacement Card and then not using adding it to the pool?
|
||||
// // Also, what does "having the same art index" say about the two cards?
|
||||
// if (replacementCard == null) {
|
||||
// newPool.add(card, count);
|
||||
// }
|
||||
// else {
|
||||
// if (replacementCard.getArtIndex() == card.getArtIndex()) {
|
||||
// if (card.hasImage())
|
||||
// newPool.add(card, count);
|
||||
// else
|
||||
// newPool.add(replacementCard, count);
|
||||
// } else {
|
||||
// if (card.hasImage())
|
||||
// newPool.add(card.getName(), card.getEdition(), count); // this is to randomize art
|
||||
// else
|
||||
// newPool.add(replacementCard, count);
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// parts.put(p.getKey(), newPool);
|
||||
// }
|
||||
// }
|
||||
|
||||
public static final Function<Deck, String> FN_NAME_SELECTOR = new Function<Deck, String>() {
|
||||
@Override
|
||||
public String apply(Deck arg1) {
|
||||
|
||||
Reference in New Issue
Block a user