It is currently 13 Sep 2025, 08:32
   
Text Size

Issue 157: which classes do we need?

Post MTG Forge Related Programming Questions Here

Moderators: timmermac, Blacksmith, KrazyTheFox, Agetian, friarsol, CCGHQ Admins

Re: Issue 157: which classes do we need?

Postby friarsol » 27 Aug 2011, 18:01

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.
That's probably the better way to go. Then it'll be much easier to import outside Decks.
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?

Postby 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.
The Force will be with you, Always.
User avatar
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?

Postby 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.
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?

Postby Braids » 28 Aug 2011, 00:45

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.
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.
"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. ;)
User avatar
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?

Postby Braids » 28 Aug 2011, 00:47

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.
a good point, thank you.

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.
yes, but it seems that Max mtg is changing the contents of the deck files in the process.
"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. ;)
User avatar
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?

Postby Max mtg » 28 Aug 2011, 00:50

Braids wrote:
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.
yes, but it seems that Max mtg is changing the contents of the deck files in the process.
Nope, I'm just asking for an advice.
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

Braids wrote:
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.
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.
So the preloading happens now.
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?

Postby 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.
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?

Postby 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.
User avatar
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?

Postby Max mtg » 28 Aug 2011, 15:43

Rob 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.
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.


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?

Postby friarsol » 28 Aug 2011, 16:29

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 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?
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?

Postby 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.
The Force will be with you, Always.
User avatar
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?

Postby Max mtg » 28 Aug 2011, 17:30

Rob Cashwalker wrote:There's no reason I need to write this class for you, CardReader is very simple and straight-forward code.
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.


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?

Postby Braids » 28 Aug 2011, 18:10

Max mtg wrote:So the preloading happens now.
Would you like to have a look?
Code: Select all
package forge.card;
. . .
are you planning to write javadoc for those methods? i hope so. . .
"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. ;)
User avatar
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?

Postby Braids » 28 Aug 2011, 18:17

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.
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?
"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. ;)
User avatar
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?

Postby Braids » 28 Aug 2011, 18:20

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?
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.
"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. ;)
User avatar
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

PreviousNext

Return to Developer's Corner

Who is online

Users browsing this forum: No registered users and 35 guests

Main Menu

User Menu

Our Partners


Who is online

In total there are 35 users online :: 0 registered, 0 hidden and 35 guests (based on users active over the past 10 minutes)
Most users ever online was 7967 on 09 Sep 2025, 23:08

Users browsing this forum: No registered users and 35 guests

Login Form