Saturday, May 12, 2007

MTG Forge Architecture

I am intending this for both programmers and non-programmers, so some of this will be review. Program architecture describes how you divide things up into classes, like a paragraph in a novel, and how all the classes (paragraphs) work together. The architecture was very homegrown; I basically programmed it and saw if it works. Finally the architecture was stable enough to implement Magic cards. I programmed using Java 1.2 with no packages.

The goal of any programmer is to program real-world objects. If I was building a program that simulated a car, I would program a tire class. A non-programmer would understand most of the tire class code, because it relates to a real-world object. Every program includes many classes that don’t relate to real-world objects, but are required in order to make the program work.

So MTG Forge has a Card class as well as a SpellAbility class, that implements the functionality of all spells and abilities. A Card class has at least 1 SpellAbility class, because every card is at least a spell, lands are the exception I guess. Lands are just put into play and not actually played. If a card like Elvish Piper has an activated ability, the associated Card has a SpellAbility added that does the Piper’s ability.

Every SpellAbility has an abstract resolve() method that every Magic card and ability overrides. The SpellAbility that implements the Elvish Piper ability lets you put a creature card from your hand into play, all that code goes into resolve() method. All of the zones like cards in play, graveyard, hand, are global variables, so the resolve() method has access to them. Even though MTG Forge only has about 118 classes, it has at least 400+ anonymous (unnamed) classes. Every card and ability is implemented using an anonymous class. I just as easily could have used a regular, named class for each card, and I plan to do that in version 2.

Global variables are generally bad, but they are a trade-off. You can potentially have huge problems because you cannot track down that specific line of code that changes a global variable. Non-global variables have less code that modifies them, so if you have a problem you don’t have to look through your whole program.


Unknown said...


It's me again: the time-traveler! One of the reasons I resolved to read your entire blog is because you started to write two years ago, and I wanted to see the transformation of a novice programmer into something greater.

Another part was that I, too, will soon try my hand at implementing magic: the gathering. We all should, I think!

The first step I took though, was to implement a simpler card game using object-oriented programming and with MTG in mind. I implemented Big Two, a poker-like game. Essentially I broke things down into three classes: zone, player, and card. Of course, those three branch off into many different subclasses (for instance one subclass of Zone is the Deck, another is the Hand; one subclass of Card is PokerCard). Then there are two unrelated classes that deal with the GUI and run the game.

I know that when I write MTG I will need many more classes and subclasses, but I hope to make everything extend from those three core classes. I'm thinking, though, that I will need a new class to cover one of the elements of the game I had been completely negligent of in my initial plan: that class will be "Rule"!


Julio Rodrigues said...

Hello, I know im leaving a comment in a very old post.

Me and some friends made a card-table game in paper. Now Im researching how I could make it on PC online. Im finding this blog (and the source code of course) very very useful.

Im a computer science student and I think this project will really make me a better programmer. Thank you so much!