From dabb40714ecfbe88a8241c8c562849a1244695df Mon Sep 17 00:00:00 2001 From: leriomaggio Date: Tue, 7 Sep 2021 00:24:35 +0100 Subject: [PATCH] Updated translations and added new DeckStats classes to automate stats report generation with less duplications. Signed-off-by: leriomaggio --- .../forge/screens/deckeditor/DeckImport.java | 239 ++++++++++++------ forge-gui/res/languages/en-US.properties | 17 +- 2 files changed, 179 insertions(+), 77 deletions(-) diff --git a/forge-gui-desktop/src/main/java/forge/screens/deckeditor/DeckImport.java b/forge-gui-desktop/src/main/java/forge/screens/deckeditor/DeckImport.java index 53a91b8b5a3..aa1d6d21c7c 100644 --- a/forge-gui-desktop/src/main/java/forge/screens/deckeditor/DeckImport.java +++ b/forge-gui-desktop/src/main/java/forge/screens/deckeditor/DeckImport.java @@ -21,9 +21,8 @@ import java.awt.*; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.awt.event.WindowEvent; -import java.util.HashMap; +import java.util.*; import java.util.List; -import java.util.Map; import javax.swing.BorderFactory; import javax.swing.event.DocumentEvent; @@ -31,7 +30,9 @@ import javax.swing.event.DocumentListener; import forge.StaticData; import forge.card.CardEdition; +import forge.card.CardRarity; import forge.card.CardType; +import forge.card.ColorSet; import forge.deck.*; import forge.deck.DeckRecognizer.TokenType; import forge.game.GameFormat; @@ -48,6 +49,7 @@ import forge.toolbox.FSkin; import forge.toolbox.FTextArea; import forge.util.Localizer; import forge.view.FDialog; +import org.apache.commons.math3.stat.inference.BinomialTest; /** * @@ -363,16 +365,18 @@ public class DeckImport ex + "text-decoration: none; font-family: Arial; font-size: 10px; " + "color: white; background-color: #ffffff; color: #000000;} " + " h3 {font-size: 13px; margin: 2px 0; padding: 0px 5px; } " - + " h5 {font-size: 11px; padding: 2px 20px; margin: 3px 0;} " - + " span {display: block !important; } " - + " div {margin: 0 !important; text-align: justify; padding 2px 10px; } " - + " p {margin: 2px; text-align: justify; padding: 2px 5px;} " + + " h4 {font-size: 10px; padding: 1px 20px; margin: 3px 0 0 0;} " + + " div {margin: 0; ext-align: justify; padding 1px 10px;}" + + " p {margin: 2px; text-align: justify; padding: 1px 5px;} " + ".unknowncard {color: #666666;} " + ".knowncard {color: #009900;} " + ".illegalcard {color: #990000;} " + ".invalidcard {color: #000099;} " + ".section {font-weight: 700; background-color: #DDDDDD; color: #000000 } " + + ".mana {font-weight: 700; background-color: #c7bcba; color: #ffffff } " + + ".rarity {font-weight: 700; background-color: #df8030; color: #ffffff } " + ".edition {font-weight: 700; background-color: #5a8276; color: #ffffff } " - + ".editioncode {font-weight: 700; color: #5a8276;} " + + ".editioncode {font-weight: 700; color: #5a8276; font-style: normal !important;} " + ".cardtype {font-weight: 700; background-color: #FFCC66; color: #000000} " + + ".decksection {padding-left: 20px; font-weight: 700;}" + " ul li {padding: 5px 1px 1px 1px !important; margin: 0 1px !important} " + ""; @@ -386,22 +390,28 @@ public class DeckImport ex if (hasOnlyComment(tokens)) { String statsSummaryList = String.format( - "
  • %s
  • %s
  • %s
  • %s
", + "
  • %s
  • %s
  • %s
  • %s
  • %s
  • %s
", Localizer.getInstance().getMessage("lblStatsSummaryCount"), Localizer.getInstance().getMessage("lblStatsSummarySection"), Localizer.getInstance().getMessage("lblStatsSummaryCardType"), - Localizer.getInstance().getMessage("lblStatsSummaryCardSet")); + Localizer.getInstance().getMessage("lblStatsSummaryCardSet"), + Localizer.getInstance().getMessage("lblStatsSummaryRarity"), + Localizer.getInstance().getMessage("lblStatsSummaryCMC") + ); this.decklistStats.setText(String.format(summaryMsgTemplate, head, Localizer.getInstance().getMessage("lblSummaryHeadMsg", deckListName), String.format("

%s

", Localizer.getInstance().getMessage("lblImportedDeckSummary", statsSummaryList)))); } else { - Map deckSectionsStats = new HashMap<>(); + Map deckSectionsStats = new TreeMap<>(String.CASE_INSENSITIVE_ORDER); deckSectionsStats.put(DeckSection.Main.name(), 0); String currentKeySection = DeckSection.Main.name(); - Map cardTypeStats = new HashMap<>(); - Map editionsStats = new HashMap<>(); + + DeckStats cardTypeStats = new CardTypeDeckStats(Localizer.getInstance().getMessage("lblSummaryCardTypeStats"), "cardtype"); + DeckStats editionsStats = new EditionDeckStats(Localizer.getInstance().getMessage("lblSummaryEditionStats"), "edition"); + DeckStats manaStats = new DeckStats(Localizer.getInstance().getMessage("lblSummaryManaStats"), "mana"); + DeckStats rarityStats = new RarityDeckStats(Localizer.getInstance().getMessage("lblSummaryRarityStats"), "rarity"); for (final DeckRecognizer.Token t : tokens) { if (t.getType() == TokenType.UNKNOWN_CARD_REQUEST) @@ -410,8 +420,10 @@ public class DeckImport ex illegalCardsCount += t.getNumber(); else if (t.getType() == TokenType.INVALID_CARD_REQUEST) invalidCardsCount += t.getNumber(); - else if (t.getType() == TokenType.DECK_SECTION_NAME) - currentKeySection = t.getText(); + else if (t.getType() == TokenType.DECK_SECTION_NAME) { + if (!t.getText().equalsIgnoreCase(currentKeySection)) + currentKeySection = t.getText(); + } else if (t.getType() == TokenType.DECK_NAME) deckListName = String.format("\"%s\"", t.getText()); else if (t.getType() == TokenType.LEGAL_CARD_REQUEST) { @@ -425,24 +437,31 @@ public class DeckImport ex // update card edition stats String setCode = t.getCard().getEdition(); - int setCount = editionsStats.getOrDefault(setCode, 0); - setCount += tokenNumber; - editionsStats.put(setCode, setCount); - + editionsStats.add(currentKeySection, setCode, tokenNumber); // update card type stats for (CardType.CoreType coreType : t.getCard().getRules().getType().getCoreTypes()) { String coreTypeName = coreType.name(); - int cTypeCount = cardTypeStats.getOrDefault(coreTypeName, 0); - cTypeCount += tokenNumber; - cardTypeStats.put(coreTypeName, cTypeCount); + cardTypeStats.add(currentKeySection, coreTypeName, tokenNumber); + } + // update rarity stats + if (!t.getCard().isVeryBasicLand()) + rarityStats.add(currentKeySection, t.getCard().getRarity().name(), tokenNumber); + // update colour stats + if (!t.getCard().getRules().getType().isLand()) { + String manaCost = String.format("CMC %d", t.getCard().getRules().getManaCost().getCMC()); + manaStats.add(currentKeySection, manaCost, tokenNumber); } - } } - String deckListSummaryHtml = createSummaryStats(unknownCardsCount, illegalCardsCount, - legalCardsCount, invalidCardsCount, deckSectionsStats, editionsStats, - cardTypeStats); + String cardStatsReport = createCardsStatsReport(unknownCardsCount, illegalCardsCount, + invalidCardsCount, + legalCardsCount, deckSectionsStats); + + String deckListSummaryHtml = String.format("

%s

%s %s %s %s %s", + Localizer.getInstance().getMessage("lblSummaryDeckStats"), cardStatsReport, + editionsStats.toHTML(), cardTypeStats.toHTML(), rarityStats.toHTML(), manaStats.toHTML()); + this.decklistStats.setText(String.format(summaryMsgTemplate, head, Localizer.getInstance().getMessage("lblSummaryHeadMsg", deckListName), deckListSummaryHtml)); @@ -450,50 +469,6 @@ public class DeckImport ex cmdAccept.setEnabled(legalCardsCount > 0); } - private String createSummaryStats(int unknownCardsCount, int illegalCardsCount, - int legalCardsCount, int invalidCardsCount, - Map deckSectionsStats, - Map editionsStats, - Map cardTypeStats) { - String cardStatsReport = createCardsStatsReport(unknownCardsCount, illegalCardsCount, - invalidCardsCount, - legalCardsCount, deckSectionsStats); - String editionsReport = createEditionsStatsReport(editionsStats); - String cardTypesReport = createCardTypeStatsReport(cardTypeStats); - - return String.format("
%s
%s" + - "
%s
%s"+ - "
%s
%s", - Localizer.getInstance().getMessage("lblSummaryDeckStats"), cardStatsReport, - Localizer.getInstance().getMessage("lblSummaryCardTypeStats"), cardTypesReport, - Localizer.getInstance().getMessage("lblSummaryEditionStats"), editionsReport); - } - - private String createEditionsStatsReport(Map editionsStats) { - StringBuilder editionsReport = new StringBuilder(); - for (String setCode : editionsStats.keySet()){ - CardEdition edition = StaticData.instance().getCardEdition(setCode); - if (edition == null) - edition = CardEdition.UNKNOWN; - - String tag = String.format("
[%s] %s : %d", setCode, edition.getName(), - editionsStats.get(setCode)); - editionsReport.append(tag); - } - return editionsReport.toString(); - } - - private String createCardTypeStatsReport(Map cardTypesStats) { - StringBuilder cardTypesReport = new StringBuilder(""); - for (String typeLabel : cardTypesStats.keySet()){ - String typeLocalLab = Localizer.getInstance().getMessage(String.format("lbl%s", typeLabel)); - String tag = String.format("
%s : %d
", typeLocalLab, - cardTypesStats.get(typeLabel)); - cardTypesReport.append(tag); - } - return cardTypesReport.toString(); - } - private String createCardsStatsReport(int unknownCardsCount, int illegalCardsCount, int invalidCardsCount, int legalCardsCount, Map deckSectionsStats) { StringBuilder sb = new StringBuilder(); @@ -523,8 +498,9 @@ public class DeckImport ex for (String sectionName : deckSectionsStats.keySet()){ String sectionNameLabel = Localizer.getInstance().getMessage(String.format("lbl%s", sectionName)); String tag = String.format("
%s : %d
", - Localizer.getInstance().getMessage("lblDeckSectionStats", sectionNameLabel), - deckSectionsStats.get(sectionName)); + Localizer.getInstance().getMessage("lblDeckSectionStats", + String.format("%s", sectionNameLabel)), + deckSectionsStats.get(sectionName)); deckSectionsReport.append(tag); } return deckSectionsReport.toString(); @@ -572,3 +548,124 @@ public class DeckImport ex } } } + +class DeckStats { + + protected Map> deckSectionMap; + protected String label; + protected String cssClass; + + public DeckStats(final String name, final String cssClass0){ + this.deckSectionMap = new TreeMap<>(String.CASE_INSENSITIVE_ORDER); + this.label = name; + this.cssClass = cssClass0; + } + + public void add(String sectionName, String key, int amount){ + Map sectionMap = getOrInitStatMap(sectionName); + int currentCount = sectionMap.getOrDefault(key, 0); + currentCount += amount; + sectionMap.put(key, currentCount); + deckSectionMap.put(sectionName, sectionMap); + } + + protected Map getOrInitStatMap(String sectionName){ + return this.deckSectionMap.getOrDefault(sectionName, new TreeMap<>(String.CASE_INSENSITIVE_ORDER)); + } + + public String toHTML(){ + StringBuilder report = new StringBuilder(""); + report.append(String.format("

%s

", this.cssClass, this.label)); + for (String deckSection: this.deckSectionMap.keySet()) { + Map sectionStat = this.deckSectionMap.get(deckSection); + report.append(String.format("
%s
", deckSection)); + int itemCounter = 0; + for (String propertyLabel : sectionStat.keySet()) { + int count = sectionStat.getOrDefault(propertyLabel, 0); + if (count == 0) + continue; + String tag = this.propertyTag(propertyLabel, count); + report.append(tag); + itemCounter += 1; + if (itemCounter == 3) { + report.append("
"); + itemCounter = 0; // reset + } + } + } + return report.toString(); + } + + protected String propertyTag(String propertyLabel, int count){ + return String.format("%s : %d<;  ", propertyLabel, count); + } +} + +class EditionDeckStats extends DeckStats { + + public EditionDeckStats(final String name, final String cssClass0) { + super(name, cssClass0); + } + + @Override + public String toHTML(){ + StringBuilder report = new StringBuilder(""); + report.append(String.format("

%s

", this.cssClass, this.label)); + for (String deckSection: this.deckSectionMap.keySet()) { + Map sectionStat = this.deckSectionMap.get(deckSection); + report.append(String.format("
%s
", deckSection)); + for (String propertyLabel : sectionStat.keySet()) { + int count = sectionStat.getOrDefault(propertyLabel, 0); + if (count == 0) + continue; + String tag = this.propertyTag(propertyLabel, count); + report.append(tag); + } + } + return report.toString(); + } + + @Override + protected String propertyTag(String setCode, int count){ + CardEdition edition = StaticData.instance().getCardEdition(setCode); + if (edition == null) + edition = CardEdition.UNKNOWN; + return String.format("
[%s] %s : %d
", + setCode, edition.getName(), count); + } +} + +class CardTypeDeckStats extends DeckStats { + public CardTypeDeckStats(final String name, final String cssClass0) { + super(name, cssClass0); + } + + @Override + protected String propertyTag(String typeLabel, int count){ + String typeLocalLab = Localizer.getInstance().getMessage(String.format("lbl%s", typeLabel)); + return String.format("%s : %d;  ", typeLocalLab, count); + } +} + +class RarityDeckStats extends DeckStats { + + public RarityDeckStats(final String name, final String cssClass0) { + super(name, cssClass0); + } + + @Override + protected Map getOrInitStatMap(String sectionName){ + Map statMap = this.deckSectionMap.getOrDefault(sectionName, null); + if (statMap == null){ + Map defaultRarityMap = new LinkedHashMap<>(); // I want card rarity to be shown in this exact order! + defaultRarityMap.put(CardRarity.Common.name(), 0); + defaultRarityMap.put(CardRarity.Uncommon.name(), 0); + defaultRarityMap.put(CardRarity.Rare.name(), 0); + defaultRarityMap.put(CardRarity.MythicRare.name(), 0); + defaultRarityMap.put(CardRarity.Special.name(), 0); + return defaultRarityMap; + } + return statMap; + } + +} diff --git a/forge-gui/res/languages/en-US.properties b/forge-gui/res/languages/en-US.properties index 43e9fb0afdf..37aab2eaba8 100644 --- a/forge-gui/res/languages/en-US.properties +++ b/forge-gui/res/languages/en-US.properties @@ -2614,11 +2614,14 @@ lblTargetingArcsAlwaysOn=Targeting arcs: Always on #ListCardArea.java lblDone=Done #DeckImport.java -lblImportedDeckSummary=In this panel, the main Statistics about the Decklist will be automatically reported. These include: {0}. -lblStatsSummaryCount=Statistics on recognized cards -lblStatsSummarySection=The number of cards in each Deck Section (default: "Main") +lblImportedDeckSummary=In this panel, the main Statistics about the Decklist will be automatically reported, \ + organised by Deck Section. These include: {0}. +lblStatsSummaryCount=Overview of Card Matching during the import +lblStatsSummarySection=Total number of cards in each Deck Section (default: "Main") lblStatsSummaryCardType=The number of cards per (Core) Card Type -lblStatsSummaryCardSet=Statistics on the number of cards per single M:TG Edition +lblStatsSummaryCardSet=Total number of cards per single M:TG Edition +lblStatsSummaryRarity=Statitics on Card Rarity +lblStatsSummaryCMC=Converted Mana costs of cards in each Deck Section lblDeckImporter=Deck Importer for the Game lblPasteTypeDecklist=Paste or Type your Card List lblReplaceDeck=Replace Current Deck @@ -2629,8 +2632,10 @@ lblExpectRecognizedLines=Recognized Decklist lblSummaryStats=Decklist Summary lblSummaryHeadMsg=Summary Statistics for {0} lblSummaryDeckStats=Deck Statistics -lblSummaryCardTypeStats=Card Types Statistics -lblSummaryEditionStats=Card Editions Statistics +lblSummaryCardTypeStats=Card Types +lblSummaryEditionStats=Card Editions +lblSummaryManaStats=Converted Mana Costs +lblSummaryRarityStats=Rarity lblDeckSectionStats=Cards in {0} lblLegalCardsCount=Matched Cards lblIllegalCardsCount=Illegal Cards