mirror of
https://github.com/Card-Forge/forge.git
synced 2025-11-19 12:18:00 +00:00
DeckImport - wip
This commit is contained in:
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
@@ -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", "<html><style>.rose { color:#ebaeba; }</style><h3 class=\"rose\">Expect result here</h3></html>");
|
||||
private static final String stylesheet = "<style>" +
|
||||
"body, h1, h2, h3, h4, h5, h6, table, tr, td, p {margin: 1px; padding: 0; font-weight: normal; font-style: normal; text-decoration: none; font-family: Arial; font-size: 10px;} " +
|
||||
//"h1 {border-bottom: solid 1px black; color: blue; font-size: 12px; margin: 3px 0 9px 0; } " +
|
||||
".comment {color: #666666;} " +
|
||||
".knowncard {color: #009900;} " +
|
||||
".unknowncard {color: #990000;} " +
|
||||
".section {font-weight: bold; margin: 6px 0; text-decoration: underline; } " +
|
||||
"</style>";
|
||||
private static final String htmlWelcomeText = "<html>"+stylesheet+"<h3>You'll see recognized cards here</h3>" +
|
||||
"<div class='section'>Legend</div>" +
|
||||
"<ul>" +
|
||||
"<li class='knowncard'>Recognized cards will be shown in green. These cards will be auto-imported into a new deck<BR></li>" +
|
||||
"<li class='unknowncard'>Lines which seem to see cards but could not be recognized, are shown in red<BR></li>" +
|
||||
"<li class='comment'>Lines that appear unsignificant will be shown in gray<BR><BR></li>" +
|
||||
"</ul>" +
|
||||
"<div class='comment'>Submit feedback to Max mtg on slightlymagic.net forum</div>" +
|
||||
"<div class='comment'>Post bug-reports to http://cardforge.org/bugz/</div>" +
|
||||
"</html>";
|
||||
|
||||
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 = "<style>" +
|
||||
"body, h1, h2, h3, h4, h5, h6, table, tr, td, p {margin: 0; padding: 0; font-weight: normal; font-style: normal; text-decoration: none; font-family: Arial; font-size: 10px;} " +
|
||||
//"h1 {border-bottom: solid 1px black; color: blue; font-size: 12px; margin: 3px 0 9px 0; } " +
|
||||
".unknown {color: #660000;} " +
|
||||
".comment {color: #006666;} " +
|
||||
".KnownCardWithNumber {color: #009900;} " +
|
||||
".UnknownCardWithNumber {color: #000099;} " +
|
||||
".SectionName {font-weight: bold;} " +
|
||||
"</style>";
|
||||
|
||||
private void displayTokens()
|
||||
{
|
||||
|
||||
private void displayTokens() {
|
||||
StringBuilder sbOut = new StringBuilder("<html>");
|
||||
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("<div class='knowncard'>%s * %s [%s]</div>", token.getNumber(), token.getCard().getName(), token.getCard().getSet());
|
||||
case UnknownCardWithNumber:
|
||||
return String.format("<div class='unknowncard'>%s * %s</div>", token.getNumber(), token.getText());
|
||||
case SectionName:
|
||||
return String.format("<div class='section'>%s</div>", token.getText());
|
||||
case Unknown:
|
||||
return String.format("<div class='unknown'>%s</div>", token.getText());
|
||||
default:
|
||||
return String.format("<div class='%s'>%s</div>", token.getType(), token.getText());
|
||||
case Comment:
|
||||
return String.format("<div class='comment'>%s</div>", token.getText());
|
||||
}
|
||||
return "";
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -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<String, String> nameWithSet = splitCardName(cardName);
|
||||
if ( nameWithSet.right == null ) { return uniqueCards.containsKey(nameWithSet.left.toLowerCase()); }
|
||||
// Set exists?
|
||||
Map<String, CardPrinted[]> 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<String, String> 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<String, String>(cardName, setName);
|
||||
}
|
||||
}
|
||||
return new ImmutablePair<String, String>(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<String, String> 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));
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user