Monday, November 17, 2008

Programming CardArray

Let me state the obvious, Magic is a game that involves cards, so almost every aspect of MTG Forge involves moving or counting cards, thus the “CardArray” object was created. (CardArray is an array that holds Card objects. Also remember that an object is just group of related code.) To begin with CardArray was very simple but as time went on more and more methods were added to it. (An object is a collection of many methods.)

CardArray does many things like it can return all cards that are creatures or lands. CardArray even has a filter option that lets you specify any type of criteria. The computer AI for Shock uses the filter option to burn 2/2 or 3/1 flyers.

The filter option is used for many different types of cards. Nevinyrral's Disk uses filter to first create a CardArray of only artifacts, creatures, and enchantments and then loops through that CardArray destroying everything. Needle Storm uses the filter to only damage creatures with flying. Anytime a card interacts with multiple other cards, CardArray is used. All zones, like your library and graveyard, are basically just CardArray objects.

And although CardArray is a simple chunk of code, it is very important. Since CardArray does one thing well, it holds cards, you can use it absolutely everywhere since it is very versatile.

MTG Forge doesn’t have an object named CardArray, instead it is called CardList since it is basically just a fancy ArrayList. I used the name CardArray since most programmers know what the word “array” means.


Anonymous said...

In Incantus, our Zones are a lot like your CardLists. They have an internal list, but when you use the "get()" method, they apply a filter to the list to get only the kinds of cards you want. For example, Wrath of God checks "play.get(isCreature)" and Demigod of Revenge checks "graveyard.get(isCard.with_condition(lambda c: == 'Demigod of Revenge'))".

Well, actually, Wrath of God checks ", all=True)", but that's just because Incantus doesn't like referring to Keeper (the instance of the GameKeeper we use) inside of a card, and Demigod of Revenge checks "controller.graveyard.get(...)" so that it knows which graveyard to look in, but these are minor details.

Anonymous said...

That's funny, I have what I call "targeters" for that same purpose: retrieving a list of "valid" cards. I also use them to choose targets, as a matter of fact (the only difference being that when actually used to choose a target, there are extra checks for "protection from...")