Issue 157: which classes do we need?
Post MTG Forge Related Programming Questions Here
Moderators: timmermac, Blacksmith, KrazyTheFox, Agetian, friarsol, CCGHQ Admins
66 posts
• Page 3 of 5 • 1, 2, 3, 4, 5
Re: Issue 157: which classes do we need?
by friarsol » 27 Aug 2011, 18:01
That's probably the better way to go. Then it'll be much easier to import outside Decks.Braids wrote:instead of creating yet another decklist format, i think the mwDeck format would suit our needs.
edit: i'd be happy to create load/save code for this format.
- friarsol
- Global Moderator
- Posts: 7593
- Joined: 15 May 2010, 04:20
- Has thanked: 243 times
- Been thanked: 965 times
Re: Issue 157: which classes do we need?
by Rob Cashwalker » 27 Aug 2011, 23:43
Just be aware that if you change the deck formats AGAIN, then you have to add IMPORTERS and EXPORTERS in addition to the original deck importers, otherwise folks are going to be furious with their old decks being useless.
On the other hand, you can tweak the single-liner deck format to support all the information you need.
The point of this is not to change the deck file. The point is to make a lightweight card object that makes searching and sorting faster.
On the other hand, you can tweak the single-liner deck format to support all the information you need.
The point of this is not to change the deck file. The point is to make a lightweight card object that makes searching and sorting faster.
The Force will be with you, Always.
-
Rob Cashwalker - Programmer
- Posts: 2167
- Joined: 09 Sep 2008, 15:09
- Location: New York
- Has thanked: 5 times
- Been thanked: 40 times
Re: Issue 157: which classes do we need?
by Max mtg » 28 Aug 2011, 00:21
Agreed about that format, Braids suggested, though I didn't understand the whole regexp.
There's a wounderful "news" LazyCardFactory does not support iteration. At least Quest mode gets broken = will have to make my own generation.
There's a wounderful "news" LazyCardFactory does not support iteration. At least Quest mode gets broken = will have to make my own generation.
Single class for single responsibility.
- Max mtg
- Programmer
- Posts: 1997
- Joined: 02 Jul 2011, 14:26
- Has thanked: 173 times
- Been thanked: 334 times
Re: Issue 157: which classes do we need?
by Braids » 28 Aug 2011, 00:45
LazyCardFactory should be used to create #3-type cards, not #2. otherwise, there is no point in being lazy. we're supposed to preload all the #2-type cards.Max mtg wrote:There's a wounderful "news" LazyCardFactory does not support iteration. At least Quest mode gets broken = will have to make my own generation.
"That is the dumbest thing I've ever seen." --Rob Cashwalker, regarding Innistrad double-sided cards. One of the first times he and I have ever agreed on something. 

-
Braids - Programmer
- Posts: 556
- Joined: 22 Jun 2011, 00:39
- Location: Unknown. Hobby: Driving myself and others to constructive madness.
- Has thanked: 1 time
- Been thanked: 1 time
Re: Issue 157: which classes do we need?
by Braids » 28 Aug 2011, 00:47
a good point, thank you.Rob Cashwalker wrote:Just be aware that if you change the deck formats AGAIN, then you have to add IMPORTERS and EXPORTERS in addition to the original deck importers, otherwise folks are going to be furious with their old decks being useless.
yes, but it seems that Max mtg is changing the contents of the deck files in the process.Rob Cashwalker wrote:The point of this is not to change the deck file. The point is to make a lightweight card object that makes searching and sorting faster.
"That is the dumbest thing I've ever seen." --Rob Cashwalker, regarding Innistrad double-sided cards. One of the first times he and I have ever agreed on something. 

-
Braids - Programmer
- Posts: 556
- Joined: 22 Jun 2011, 00:39
- Location: Unknown. Hobby: Driving myself and others to constructive madness.
- Has thanked: 1 time
- Been thanked: 1 time
Re: Issue 157: which classes do we need?
by Max mtg » 28 Aug 2011, 00:50
Nope, I'm just asking for an advice.Braids wrote:yes, but it seems that Max mtg is changing the contents of the deck files in the process.Rob Cashwalker wrote:The point of this is not to change the deck file. The point is to make a lightweight card object that makes searching and sorting faster.
Changed for sure will be QuestData and the format its decks are stored (did you know that, now the whole cardpool is saved as sideboard!) but noone will see them outside of forge
So the preloading happens now.Braids wrote:LazyCardFactory should be used to create #3-type cards, not #2. otherwise, there is no point in being lazy. we're supposed to preload all the #2-type cards.Max mtg wrote:There's a wounderful "news" LazyCardFactory does not support iteration. At least Quest mode gets broken = will have to make my own generation.
Would you like to have a look?
- Code: Select all
package forge.card;
import java.util.ArrayList;
import java.util.Hashtable;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.NoSuchElementException;
import java.util.Properties;
import java.util.Map.Entry;
import org.apache.commons.lang3.StringUtils;
import forge.Card;
import forge.FileUtil;
import forge.properties.ForgeProps;
import forge.properties.NewConstants;
/**
* <p>CardOracleDatabase class.</p>
*
* @author Forge
* @version $Id: CardOracleDatabase.java 9708 2011-08-09 19:34:12Z jendave $
*/
public final class CardDb {
private static volatile CardDb onlyInstance = null; // 'volatile' keyword makes this working
public static CardDb instance() {
if (onlyInstance == null) {
synchronized (CardDb.class) {
if (onlyInstance == null) { // It's broken under 1.4 and below, on 1.5+ works again!
onlyInstance = new CardDb();
}
}
}
return onlyInstance;
}
// Here oracle cards
private final Map<String, CardRules> cards = new Hashtable<String, CardRules>();
// Here are refs, get them by name
private final Map<String, CardPrinted> uniqueCards = new Hashtable<String, CardPrinted>();
// need this to obtain cardReference by name+set+artindex
private final Map<String, Map<String, CardPrinted[]>> allCardsBySet = new Hashtable<String, Map<String, CardPrinted[]>>();
// this is the same list in flat storage
private final List<CardPrinted> allCardsFlat = new ArrayList<CardPrinted>();
private CardDb() {
List<String> mtgDataLines = FileUtil.readFile(ForgeProps.getFile(NewConstants.MTG_DATA));
MtgDataParser parser = new MtgDataParser(mtgDataLines);
while (parser.hasNext()) {
addNewCard(parser.next());
}
}
public void addNewCard(final CardRules card) {
if (null == card) { return; }
//System.out.println(card.getName());
String cardName = card.getName();
// 1. register among oracle uniques
cards.put(cardName, card);
// 2. fill refs into two lists: one with
CardPrinted lastAdded = null;
for (Entry<String, CardInSet> s : card.getSetsPrinted()) {
String set = s.getKey();
// get this set storage, if not found, create it!
Map<String, CardPrinted[]> setMap = allCardsBySet.get(set);
if (null == setMap) {
setMap = new Hashtable<String, CardPrinted[]>();
allCardsBySet.put(set, setMap);
}
int count = s.getValue().getCopiesCount();
CardPrinted[] cards = new CardPrinted[count];
setMap.put(cardName, cards);
for (int i = 0; i < count; i++) {
lastAdded = CardPrinted.build(card, set, s.getValue().getRarity(), i+1);
allCardsFlat.add(lastAdded);
cards[i] = lastAdded;
}
}
uniqueCards.put(cardName, lastAdded);
}
// 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('|');
if (pipePos >= 0) { return getCard(name.substring(0, pipePos), name.substring(pipePos+1)); }
// OK, plain name here
CardPrinted card = uniqueCards.get(name);
if (card != null) { return card; }
throw new NoSuchElementException(String.format("Card '%s' not found in our database.", name));
}
// Advanced fetch by name+set
public CardPrinted getCard(final String name, final String set) { return getCard(name, set, 1); }
public CardPrinted getCard(final String name, final String set, final int artIndex) {
// 1. get set
Map<String, CardPrinted[]> cardsFromset = allCardsBySet.get(set);
if (null == cardsFromset) {
String err = String.format("Asked for card '%s' from set '%s': that set was not found. :(", name, set);
throw new NoSuchElementException(err);
}
// 2. Find the card itself
CardPrinted[] cards = cardsFromset.get(name);
if (null == cards) {
String err = String.format("Asked for card '%s' from '%s': set found, but the card wasn't. :(", name, set);
throw new NoSuchElementException(err);
}
// 3. Get the proper copy
if (artIndex > 0 && artIndex <= cards.length) { return cards[artIndex-1]; }
String err = String.format("Asked for '%s' from '%s' #%d: db didn't find that copy. Note: artIndex is 1-based", name, set, artIndex);
throw new NoSuchElementException(err);
}
// Fetch from Forge's Card instance. Well, there should be no errors, but we'll still check
public CardPrinted getCard(final Card forgeCard) {
String name = forgeCard.getName();
String set = forgeCard.getCurSetCode();
if (StringUtils.isNotBlank(set)) { return getCard(name, set); }
return getCard(name);
}
// Multiple fetch
public List<CardPrinted> getCards(final List<String> names) {
List<CardPrinted> result = new ArrayList<CardPrinted>();
for (String name : names) { result.add(getCard(name)); }
return result;
}
// returns a list of all cards from their respective latest editions
public Iterable<CardPrinted> getAllUniqueCards() {
return uniqueCards.values();
}
public List<CardPrinted> getAllCards() { return allCardsFlat; }
}
Single class for single responsibility.
- Max mtg
- Programmer
- Posts: 1997
- Joined: 02 Jul 2011, 14:26
- Has thanked: 173 times
- Been thanked: 334 times
Re: Issue 157: which classes do we need?
by Max mtg » 28 Aug 2011, 02:07
Current state of classes commited in r9987.
This is an evaluation commit for you to see how it works. Instantiate CardDB singleton to get access to classes, use predicates to filter cards, see CardPool objects which are going to stand behind decks and deckeditors.
No other modules moving to this infrasructure were commited in this revision, so everything should be still working in the old way.
Now mtg-data.txt is used to fill up the database, but forge supports not every card from there.
We need a method to read data from cardname.txt files, that should be a class similiar to MtgDataParser but reading forge's native card records.
This is an evaluation commit for you to see how it works. Instantiate CardDB singleton to get access to classes, use predicates to filter cards, see CardPool objects which are going to stand behind decks and deckeditors.
No other modules moving to this infrasructure were commited in this revision, so everything should be still working in the old way.
Now mtg-data.txt is used to fill up the database, but forge supports not every card from there.
We need a method to read data from cardname.txt files, that should be a class similiar to MtgDataParser but reading forge's native card records.
Single class for single responsibility.
- Max mtg
- Programmer
- Posts: 1997
- Joined: 02 Jul 2011, 14:26
- Has thanked: 173 times
- Been thanked: 334 times
Re: Issue 157: which classes do we need?
by Rob Cashwalker » 28 Aug 2011, 15:13
Max, I'll say it for hopefully the last time - FORGET the mtg-data.txt. We do not want to distribute that file anyway, much less the extra processing to then read the cardname.txt files to figure out which card Forge supports. CardReader is the class that reads cardname.txt and it can VERY easily be tweaked to just populate string-only Card objects. Name it NewCardReader, CardReader2, whatever.
The Force will be with you, Always.
-
Rob Cashwalker - Programmer
- Posts: 2167
- Joined: 09 Sep 2008, 15:09
- Location: New York
- Has thanked: 5 times
- Been thanked: 40 times
Re: Issue 157: which classes do we need?
by Max mtg » 28 Aug 2011, 15:43
No chance, unless oracle text and correct data about sets is added into cardname.txtRob Cashwalker wrote:Max, I'll say it for hopefully the last time - FORGET the mtg-data.txt. We do not want to distribute that file anyway, much less the extra processing to then read the cardname.txt files to figure out which card Forge supports. CardReader is the class that reads cardname.txt and it can VERY easily be tweaked to just populate string-only Card objects. Name it NewCardReader, CardReader2, whatever.
There is no better source of data for the base by now.
It's not easy for me to crawl through all of that variable parsing found in CardReader
Would you please write that class? It should be an iterator of CardRules.
Single class for single responsibility.
- Max mtg
- Programmer
- Posts: 1997
- Joined: 02 Jul 2011, 14:26
- Has thanked: 173 times
- Been thanked: 334 times
Re: Issue 157: which classes do we need?
by friarsol » 28 Aug 2011, 16:29
I feel like I'm being ignored in this conversation. So I'm going to Bold and Caps to make myself as clear as I can. I ALREADY HAVE SCRIPTS TO ADD ORACLE TEXT TO CARDS.TXT FILES. THEY WERE WAITING UNTIL THIS DISCUSSION WAS RESOLVED BEFORE CHANGING ~9000 FILES. There is no reason to parse two different times.Max mtg wrote:No chance, unless oracle text and correct data about sets is added into cardname.txt
There is no better source of data for the base by now.
I'm not sure why you think the sets data in cards.txt is incorrect?
- friarsol
- Global Moderator
- Posts: 7593
- Joined: 15 May 2010, 04:20
- Has thanked: 243 times
- Been thanked: 965 times
Re: Issue 157: which classes do we need?
by Rob Cashwalker » 28 Aug 2011, 16:59
Sol, I know how you feel.
There's also no reason you have to crawl through any variable parsing. CardReader just reads each line and does something with it. Either it puts the data into the right place in the card object or it passed the ability to the AbilityFactory. All you have to change is the last part, to store the abilty text into the object. Then execute the AbilityFactory part later, when the ActiveCard object needs to be created while launching an actual game.
There's no reason I need to write this class for you, CardReader is very simple and straight-forward code.
There's also no reason you have to crawl through any variable parsing. CardReader just reads each line and does something with it. Either it puts the data into the right place in the card object or it passed the ability to the AbilityFactory. All you have to change is the last part, to store the abilty text into the object. Then execute the AbilityFactory part later, when the ActiveCard object needs to be created while launching an actual game.
There's no reason I need to write this class for you, CardReader is very simple and straight-forward code.
The Force will be with you, Always.
-
Rob Cashwalker - Programmer
- Posts: 2167
- Joined: 09 Sep 2008, 15:09
- Location: New York
- Has thanked: 5 times
- Been thanked: 40 times
Re: Issue 157: which classes do we need?
by Max mtg » 28 Aug 2011, 17:30
Not for me, but for the whole project. Hard is not the very class but the whole complexity of the job I initiated. It involves the WHOLE generation of boosters and decks, the deck editors, the model behid them, I won't be able to do everything alone.Rob Cashwalker wrote:There's no reason I need to write this class for you, CardReader is very simple and straight-forward code.
It's great Sol has everything ready, I didn't know it.
Sol, you should wait no longer. Since actual CardParser will ignore unknown lines, nothing is to break from your updating 9000 files.
The class able to parse these rules is to come for sure
Single class for single responsibility.
- Max mtg
- Programmer
- Posts: 1997
- Joined: 02 Jul 2011, 14:26
- Has thanked: 173 times
- Been thanked: 334 times
Re: Issue 157: which classes do we need?
by Braids » 28 Aug 2011, 18:10
are you planning to write javadoc for those methods? i hope so. . .Max mtg wrote:So the preloading happens now.
Would you like to have a look?
- Code: Select all
package forge.card;
. . .
"That is the dumbest thing I've ever seen." --Rob Cashwalker, regarding Innistrad double-sided cards. One of the first times he and I have ever agreed on something. 

-
Braids - Programmer
- Posts: 556
- Joined: 22 Jun 2011, 00:39
- Location: Unknown. Hobby: Driving myself and others to constructive madness.
- Has thanked: 1 time
- Been thanked: 1 time
Re: Issue 157: which classes do we need?
by Braids » 28 Aug 2011, 18:17
i can help you with the new CardReader. just tell me which class, and which fields you want me to fill in. am i correct you want to load all cards?Max mtg wrote:It's not easy for me to crawl through all of that variable parsing found in CardReader
Would you please write that class? It should be an iterator of CardRules.
"That is the dumbest thing I've ever seen." --Rob Cashwalker, regarding Innistrad double-sided cards. One of the first times he and I have ever agreed on something. 

-
Braids - Programmer
- Posts: 556
- Joined: 22 Jun 2011, 00:39
- Location: Unknown. Hobby: Driving myself and others to constructive madness.
- Has thanked: 1 time
- Been thanked: 1 time
Re: Issue 157: which classes do we need?
by Braids » 28 Aug 2011, 18:20
i thank the good friar for expressing himself. this information was not fresh in my mind in recent posts to this forum. i apologize if i ignored you, Sol. i know how frustrating that can be.friarsol wrote:I feel like I'm being ignored in this conversation. So I'm going to Bold and Caps to make myself as clear as I can. I ALREADY HAVE SCRIPTS TO ADD ORACLE TEXT TO CARDS.TXT FILES. THEY WERE WAITING UNTIL THIS DISCUSSION WAS RESOLVED BEFORE CHANGING ~9000 FILES. There is no reason to parse two different times.
I'm not sure why you think the sets data in cards.txt is incorrect?
"That is the dumbest thing I've ever seen." --Rob Cashwalker, regarding Innistrad double-sided cards. One of the first times he and I have ever agreed on something. 

-
Braids - Programmer
- Posts: 556
- Joined: 22 Jun 2011, 00:39
- Location: Unknown. Hobby: Driving myself and others to constructive madness.
- Has thanked: 1 time
- Been thanked: 1 time
66 posts
• Page 3 of 5 • 1, 2, 3, 4, 5
Who is online
Users browsing this forum: No registered users and 49 guests