From b270e744ef6438c1d4bce9a7b13b94376384fc43 Mon Sep 17 00:00:00 2001 From: Maxmtg Date: Wed, 21 Sep 2011 04:00:53 +0000 Subject: [PATCH] DeckImport - wip --- src/main/java/forge/deck/DeckRecognizer.java | 63 ++++++++++++++- .../java/forge/gui/deckeditor/DeckImport.java | 80 +++++++++++++------ src/main/java/forge/item/CardDb.java | 46 +++++++---- 3 files changed, 149 insertions(+), 40 deletions(-) diff --git a/src/main/java/forge/deck/DeckRecognizer.java b/src/main/java/forge/deck/DeckRecognizer.java index fe29e30de42..4fc8ebefa58 100644 --- a/src/main/java/forge/deck/DeckRecognizer.java +++ b/src/main/java/forge/deck/DeckRecognizer.java @@ -1,7 +1,10 @@ package forge.deck; -import java.util.Map.Entry; +import java.util.regex.Matcher; +import java.util.regex.Pattern; +import org.apache.commons.lang3.StringUtils; +import forge.item.CardDb; import forge.item.CardPrinted; /** @@ -58,9 +61,63 @@ public class DeckRecognizer { public int getNumber() { return number; } } - public static Token recognizeLine(String line) +// Let's think about it numbers in the back later +// private static final Pattern searchNumbersInBack = Pattern.compile("(.*)[^A-Za-wyz]*\\s+([\\d]{1,2})"); + private static final Pattern searchNumbersInFront = Pattern.compile("([\\d]{1,2})[^A-Za-wyz]*\\s+(.*)"); + public static Token recognizeLine(String raw_line) { - return new Token(TokenType.Unknown, 0, line); + if (StringUtils.isBlank(raw_line)) { return new Token(TokenType.Comment, 0, raw_line); } + String line = raw_line.trim(); + + Token result = null; + Matcher foundNumbersInFront = searchNumbersInFront.matcher(line); + // Matcher foundNumbersInBack = searchNumbersInBack.matcher(line); + if (foundNumbersInFront.matches()) { + String cardName = foundNumbersInFront.group(2); + int amount = Integer.parseInt(foundNumbersInFront.group(1)); + result = recognizePossibleNameAndNumber(cardName, amount); + } /* else if (foundNumbersInBack.matches()) { + String cardName = foundNumbersInBack.group(1); + int amount = Integer.parseInt(foundNumbersInBack.group(2)); + return new Token(cardName, amount); + } */else { + if ( CardDb.instance().isCardSupported(line)) { + return new Token( CardDb.instance().getCard(line), 1); + } + result = recognizeNonCard(line, 1); + } + return result != null ? result : new Token(TokenType.Unknown, 0, line); + } + + private static Token recognizePossibleNameAndNumber(String name, int n) { + if ( CardDb.instance().isCardSupported(name)) + return new Token( CardDb.instance().getCard(name), n); + + Token known = recognizeNonCard(name, n); + return null == known ? new Token(name, n) : known; + } + + private static Token recognizeNonCard(String text, int n) { + if (isDecoration(text)) { return new Token(TokenType.Comment, n, text); } + if (isSectionName(text)) { return new Token(TokenType.SectionName, n, text); } + return null; + } + + private final static String[] knownComments = new String[] { + "lands", "creatures", "creature", "spells", "enchancements", "other spells", "artifacts", "cards" }; + private static boolean isDecoration(String line) { + for (String s : knownComments) { + if (line.equalsIgnoreCase(s)) { return true; } + } + return false; } + private static boolean isSectionName(String line) { + if (line.equalsIgnoreCase("sideboard")) { return true; } + if (line.equalsIgnoreCase("MAIN BOARD")) { return true; } + if (line.equalsIgnoreCase("MAIN")) { return true; } + return false; + } + + } diff --git a/src/main/java/forge/gui/deckeditor/DeckImport.java b/src/main/java/forge/gui/deckeditor/DeckImport.java index 8cdc30e5aae..ef6b11cf3ea 100644 --- a/src/main/java/forge/gui/deckeditor/DeckImport.java +++ b/src/main/java/forge/gui/deckeditor/DeckImport.java @@ -3,7 +3,6 @@ package forge.gui.deckeditor; import java.awt.Font; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; -import java.awt.event.WindowAdapter; import java.awt.event.WindowEvent; import java.util.ArrayList; import java.util.List; @@ -12,7 +11,7 @@ import javax.swing.BorderFactory; import javax.swing.JButton; import javax.swing.JDialog; import javax.swing.JEditorPane; -import javax.swing.JFrame; +import javax.swing.JLabel; import javax.swing.JOptionPane; import javax.swing.JScrollPane; import javax.swing.JTextArea; @@ -28,6 +27,7 @@ import net.miginfocom.swing.MigLayout; import forge.Singletons; import forge.deck.Deck; import forge.deck.DeckRecognizer; +import forge.deck.DeckRecognizer.TokenType; import forge.gui.GuiUtils; /** @@ -38,9 +38,30 @@ public class DeckImport extends JDialog { private static final long serialVersionUID = -5837776824284093004L; private JTextArea txtInput = new JTextArea(); - private JEditorPane htmlOutput = new JEditorPane("text/html", "

Expect result here

"); + private static final String stylesheet = ""; + private static final String htmlWelcomeText = ""+stylesheet+"

You'll see recognized cards here

" + + "
Legend
" + + "" + + "
Submit feedback to Max mtg on slightlymagic.net forum
" + + "
Post bug-reports to http://cardforge.org/bugz/
" + + ""; + + private JEditorPane htmlOutput = new JEditorPane("text/html", htmlWelcomeText); private JScrollPane scrollInput = new JScrollPane(txtInput); private JScrollPane scrollOutput = new JScrollPane(htmlOutput); + private JLabel summaryMain = new JLabel("Imported deck summary will appear here"); + private JLabel summarySide = new JLabel("This is second line"); private JButton cmdAccept = new JButton("Import Deck"); private JButton cmdCancel = new JButton("Cancel"); @@ -78,10 +99,14 @@ public class DeckImport extends JDialog { scrollOutput.setViewportBorder(BorderFactory.createLoweredBevelBorder()); getContentPane().setLayout(new MigLayout("fill")); - getContentPane().add(scrollInput, "cell 0 0, w 50%, growy, pushy"); + getContentPane().add(scrollInput, "cell 0 0, w 50%, sy 4, growy, pushy"); getContentPane().add(scrollOutput, "cell 1 0, w 50%, growy, pushy"); - getContentPane().add(cmdAccept, "cell 0 1, w 100, align r"); - getContentPane().add(cmdCancel, "cell 1 1, w 100, align l"); + + getContentPane().add(summaryMain, "cell 1 1, label"); + getContentPane().add(summarySide, "cell 1 2, label"); + + getContentPane().add(cmdAccept, "cell 1 3, split 2, w 100, align c"); + getContentPane().add(cmdCancel, "w 100"); cmdCancel.addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent e) { @@ -113,18 +138,9 @@ public class DeckImport extends JDialog { } } - private static String stylesheet = ""; + - private void displayTokens() - { + private void displayTokens() { StringBuilder sbOut = new StringBuilder(""); sbOut.append(stylesheet); for (DeckRecognizer.Token t : tokens) { @@ -134,13 +150,25 @@ public class DeckImport extends JDialog { htmlOutput.setText(sbOut.toString()); } - private Deck buildDeck() - { + private void updateSummaries() { + int[] cardsOk = new int[2]; + int[] cardsUnknown = new int[2]; + int idx = 0; + for (DeckRecognizer.Token t : tokens) { + if (t.getType() == TokenType.KnownCardWithNumber) { cardsOk[idx] += t.getNumber(); } + if (t.getType() == TokenType.UnknownCardWithNumber) { cardsUnknown[idx] += t.getNumber(); } + if (t.getType() == TokenType.SectionName && t.getText().toLowerCase().contains("side") ) { idx = 1; } + } + summaryMain.setText(String.format("Main: %d cards recognized, %d unknown cards", cardsOk[0], cardsUnknown[0])); + summarySide.setText(String.format("Sideboard: %d cards recognized, %d unknown cards", cardsOk[1], cardsUnknown[1])); + } + + private Deck buildDeck(){ return new Deck(); } protected class OnChangeTextUpdate implements DocumentListener { - private void onChange() { readInput(); displayTokens(); } + private void onChange() { readInput(); displayTokens(); updateSummaries(); } @Override public void insertUpdate(DocumentEvent e) { onChange(); } @Override public void removeUpdate(DocumentEvent e) { onChange(); } @Override public void changedUpdate(DocumentEvent e) { } // Happend only on ENTER pressed @@ -149,11 +177,17 @@ public class DeckImport extends JDialog { private String makeHtmlViewOfToken(DeckRecognizer.Token token) { switch(token.getType()) { + case KnownCardWithNumber: + return String.format("
%s * %s [%s]
", token.getNumber(), token.getCard().getName(), token.getCard().getSet()); + case UnknownCardWithNumber: + return String.format("
%s * %s
", token.getNumber(), token.getText()); + case SectionName: + return String.format("
%s
", token.getText()); case Unknown: - return String.format("
%s
", token.getText()); - default: - return String.format("
%s
", token.getType(), token.getText()); + case Comment: + return String.format("
%s
", token.getText()); } + return ""; } } diff --git a/src/main/java/forge/item/CardDb.java b/src/main/java/forge/item/CardDb.java index 33f3fed6fd4..488d2e440de 100644 --- a/src/main/java/forge/item/CardDb.java +++ b/src/main/java/forge/item/CardDb.java @@ -11,7 +11,7 @@ import java.util.Map.Entry; import net.slightlymagic.braids.util.lambda.Lambda1; import org.apache.commons.lang3.StringUtils; - +import org.apache.commons.lang3.tuple.ImmutablePair; import forge.Card; import forge.card.CardInSet; import forge.card.CardRules; @@ -102,24 +102,42 @@ public final class CardDb { uniqueCards.put(cardName, lastAdded); } - public boolean isCardSupported(final String cardName) { return uniqueCards.containsKey(cardName.toLowerCase()); } - + public boolean isCardSupported(final String cardName) { + ImmutablePair nameWithSet = splitCardName(cardName); + if ( nameWithSet.right == null ) { return uniqueCards.containsKey(nameWithSet.left.toLowerCase()); } + // Set exists? + Map cardsFromset = allCardsBySet.get(nameWithSet.right.toUpperCase()); + if (cardsFromset == null) return false; + // Card exists? + CardPrinted[] cardCopies = cardsFromset.get(nameWithSet.left.toLowerCase()); + return cardCopies != null && cardCopies.length > 0; + } + /** + * Splits cardname into Name and set whenever deck line reads as name|set + */ + private static ImmutablePair splitCardName(final String name) { + String cardName = name; // .trim() ? + int pipePos = cardName.indexOf('|'); + + if (pipePos >= 0) { + 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(cardName, setName); + } + } + return new ImmutablePair(cardName, null); + } + // Single fetch public CardPrinted getCard(final String name) { // Sometimes they read from decks things like "CardName|Set" - but we can handle it - int pipePos = name.indexOf('|'); - String cardName = name; - if (pipePos >= 0) { - cardName = name.substring(0, pipePos); - String setName = name.substring(pipePos + 1).trim(); - // only if set is not blank try to load it - if (StringUtils.isNotBlank(setName) && !"???".equals(setName)) { - return getCard(cardName, setName); - } - } + ImmutablePair nameWithSet = splitCardName(name); + if (nameWithSet.right != null) { return getCard(nameWithSet.left, nameWithSet.right); } // OK, plain name here - CardPrinted card = uniqueCards.get(cardName.toLowerCase()); + CardPrinted card = uniqueCards.get(nameWithSet.left.toLowerCase()); if (card != null) { return card; } throw new NoSuchElementException(String.format("Card '%s' not found in our database.", name)); }