Thursday, June 28, 2007

AI Good Enough?

I’m working on a new version of MTG Forge and I keep thinking about how to make the computer smarter, but I’m not sure if that is really relevant. My only thoughts are, “I wish I had more cards to play with.” I almost never think about what the computer is doing. So what is the computer isn’t that smart all the time, I am only looking for an opponent that is “good enough.” I tend to relate playing the computer like you would play with your kid brother. Your kid brother isn’t all that good at Magic, but he still can surprise you. I only expect the computer to play reasonably and to occasionally surprise me, which it does. J

So upon further reflection the AI will be the same, unless some easy method comes to me. I am all about easy coding, code it right the first time, but if it is really complicated, try to get by with simpler code, and optionally go back later to change it if I need to. In my games I don’t really care that the computer isn’t efficiently playing his cards, I’m only thinking about my strategy. My thinking and playing makes the game fun. The computer just acts like your kid brother except that he doesn’t mind losing, lol.

Although I will be programming the AI the same way, I should be able to make the computer play Instants at end of turn and hopefully program the computer to somehow respond to spells also, like bouncing a creature back to his hand. The computer should draw card at end of turn, and use burn effects at end of turn or during combat. I really would like the computer to play Giant Growth effects better also, and occasionally bluff so you don’t know if the computer really has Giant Growth in his hand or not.

Fun AI

The computer AI for MTG Forge is incredibly dumb. It just tries to play a card at random, pure and simple. But since you don’t know what card the computer is holding, the computer seems intelligent. Yesterday the computer did the absolutely best play; it played Wojek Embermage and then Hunted Troll on the next turn. Then it used Wojek’s ability to kill off the tokens that the Troll made. It was an amazing play from a computer that only plays random cards. If you didn’t know the computer was so dumb, you could mistake it for intelligent.

Granted sometimes it makes the worst play ever, usually involving Wrath of God. For example, the computer sometimes plays a creature and then Wrath, which is utterly stupid of course. Even most beginners don’t make a mistake like that, but the computer doesn’t learn like a beginner either. Most cards only do something bad for your opponent, and the computer seems very intelligent when playing with those kinds of cards, but the computer doesn’t seem so intelligent when playing cards that have a drawback.

2 Types of Programming

I think all computer programming can be divided up into two categories. One, code that is short but very tricky and two, code that is long and monotonous. Tricky code includes such things as sorting algorithms, where any small mistake in logic is a total disaster. SQL statements are notoriously tricky, sometimes you need a semicolon at the end and sometimes you don’t. One time I was helping a fellow programmer debug some networking code. He had mistakenly misread a variable read a lower case variable name “L” as a 1. It wasn’t a big mistake, but it still broke the functionality. Tricky code is harder to test because it was to work 100% correctly all of the time. For simple programs monotonous code tends to either run or not run, and that is all the error testing that it needed.

Monotonous code happens when you want to save a file to the hard drive. You know what you want to do, but there is a lot of error checking to be done. Is the hard drive full? Is the file name valid? How do you validate the file when you read it? Monotonous code wants to be lean and mean, but is bloated because of error checking or other requirements. Even though I say error checking “bloats” the code, error checking is very important. Another type of monotonous code is anything visual, like the user interface. Any decent visual interface (GUI) is at least 10,000 lines of code. I know all of those lines are needed, but the intent is just an interface, the product is tons of code that may or may not be manageable.

Monday, June 25, 2007

MTG Improvements

3 new articles today

I’m all for feedback, and I read all the e-mail I get. What are your thoughts about MTG Forge? Do you like the user interface, deck editor, and the computer AI? Do you play more constructed, sealed, or draft? Just click on the comments link at the bottom of this article to let your voice be heard.

Well I’m going to tell you my opinion. I’m not just the developer, I’m also an end user. I enjoy programs (games) that are easy to use and fun. I enjoy good surprises, like when the computer hits me with Hidetsugu's Second Rite which causes 10 damage only if you are at 10 life, it was a great way to lose. I think those kinds of surprise moments really make MTG Forge infinitely re-playable.

Personally, I used to play just sealed games with the “Generate Deck” option. I loved the surprises like getting 2 copies of the same rare in my deck or playing offbeat color combinations like white red or green blue. Recently I’ve done more drafts, about one a night, and I play all seven of the computer opponents. One time the computer had a pretty good red/green land destruction deck that really crippled me. Usually I don’t even experience a game loss, and very rarely I lose a whole match. This is a tidbit of inside info, when you are drafting instead of clicking the “Choose Button” card, you can just right click. By right clicking you are selecting the card that is currently highlighted.

I also really enjoy the deck editor. It took a lot of time to get the tables to show correctly on the screen and sort, I really wanted a sort feature. In case you don’t know, you can sort the cards by clicking on the column name. The deck editor looks a lot like Magic Online, and this is done on purpose. The deck editor is really easy to use, unlike other games. I think making your deck should be as fun as possible.

The suggestions that I’ve heard the most are making the user interface look more like Magic Online, cards pictures in play, stack lands, etc… and to program a whole set of real cards like 9th Edition or Ravnica. Of those two suggestions, the 2nd one is the most feasible. I really would love making MTG Forge more graphical like a video game, but I don’t have the knowledge to do that. Being able to play with a whole set would be cool because you could accurately draft and play block constructed.

I am currently trying to program the 10th edition core set. I am rebuilding MTG Forge from the ground up to make it better and more flexible, so currently it just cycles through the phases and I can play creatures. You can choose which phases stop, so you can play cards at the computer’s end of turn. Combat does not work, and all the old cards won’t work with the new version. I am going to start programming the white cards and many of white’s prevention effects have been eliminated, which makes it a little easier to program. Story Circle is still around, and I’m not sure how to currently program it, but I should be able to figure it out.

High Ground will be a pain to code, it is an enchantment that lets your creatures block 2 creatures. It does some seem useful for either block constructed or in limited games. Windborn Muse is a 2/3 with an ability like Ghostly Prison, that makes your opponent pay 2 for each attack. I think I can program it, but cards like that are prone to errors. Programming the computer AI for that card will be a pain also. Just the 10th edition white cards has first strike, double strike, and protection (yes, Paladin en-Vec seems to be back.)

Mobilization is back, it is an enchantment that gives all your soldiers vigilance and generates new soldier tokens for 2W. Thankfully, Mobilization won’t be hard to program. I have to program aura’s, and I think I can do it, but it will probably have some weird errors that I have to stamp out. Spirit Link is probably the most complicated aura, since it triggers on damage. Heart of Light is an odd aura that prevents all damage to and from the enchanted creature, so it becomes an all-star blocker? I’m not sure. So it prevents combat and regular damage, which might be tricky to program. OK, enough about all that, tell me your comments. --Forge

MTG Forge Overview

Trying to understand a whole programming project is difficult and almost impossible without copious amounts of documentation. I’m going to try to summarize the major classes MTG Forge uses. The Card class mimics the functions of a real card, and the Card class exists in your hand, in play, in the graveyard, and removed from the game. A Card can hold any number of SpellAbility objects. Each Card has at least one SpellAbility and if the Card has an ability like Elvish Piper, the Card will have two SpellAbilities added. One SpellAbility is the default summon creature spell and the other SpellAbility is the activated ability that lets you put a creature from your hand into play.

Every SpellAbility can have an optional mana cost, the only SpellAbilities that don’t have a mana cost are creatures that have tap abilities. Instants and Sorceries also use the SpellAbility class. SpellAbility has a resolve method that is called after it is popped off the stack. The CardFactory class makes new cards and copies existing ones. CardFactory also adds the SpellAbility objects to the Cards, and implements SpellAbility’s resolve method. The resolve method for Wrath of God would destroy everything.

The file “cards.txt” holds simple cards as well as all the text for Instants and Sorceries. This file saved time because I didn’t have to program simple creatures like Glory Seeker. This file also let me specify mana abilities, so creatures like Bird of Paradise are only implemented in cards.txt, no other code is needed. Flying, haste, fear, and vigilance are also supported by cards.txt Some users have added their own cards, which surprised me.

The class that runs everything is Gui_NewGame. It starts up the user interface and initializes everything. Every screen is a separate class and JFrame. These display classes all start with the abbreviation Gui and are only loosely tied together, they all read from Constant.Runtime in order to read which deck you and the computer are using.

I hate not throwing some code at you. J The code below constructs Serra Avenger. AllZone holds all of the zones, in play, graveyard, etc… and can be globally accessed. Global variables are generally bad, but they really helped get MTG Forge working. The computer can play regular creature cards like Serra Avenger using the code below, since it just pays the mana cost and the resolve method works the same for both the human and computer player.

The computer checks the canPlay and canPlayAI methods in SpellAbility to see if it is allowed to play that card. This specific card does not have a canPlayAI method, a card like Hex does, because it targets 6 creatures. The card below belongs in the human player’s deck, since he both controls and owns the card. If this card was going into the computer’s library, the computer would be listed as the owner and controller.


final Card card = new Card();
card.setName("Serra Avenger");
card.setManaCost("W W");

card.setAttack(3);
card.setDefense(3);

card.addKeyword("Flying");
card.addKeyword("Vigilance");

card.setOwner("Human");
card.setController("Human");

SpellAbility spell = new SpellAbility(SpellAbility.Spell, card)
{
public void resolve()
{
PlayerZone play = AllZone.getZone(Constant.Zone.Play, card.getController());
play.add(card);
}
public boolean canPlay()
{
//Serra Avenger cannot be played for the first three turns of the game
return 3 < AllZone.Phase.getTurn();
}
};
card.addSpellAbility(spell);

Design: Mouse Click

Without this next design concept I would have never been able to get MTG Forge off the ground. Processing user input, usually though the mouse, is critical but complicated. A mouse click can mean that I want to attack, block, play a card, use an ability, select targets for a card, or choose which land to tap. We all innately understand that a mouse click means different things at different times, but how do you program that?

I used the software pattern called State, it is mentioned in the original pattern book “Design Patterns” by Erich Gamma. I’m going to show you some pseudocode that looks similar to Java and then explain it afterwards.

interface Mouse
public void click(Card c);

class MouseState implements Mouse
private Mouse mouse;
public void setMouse(Mouse m) {mouse = m;}
public void click(Card c) {mouse.click(c);}

class MainMouse implements Mouse
public void click(Card c)
{
//If card in hand, try to pay for card
//If card in play, try to play ability
}

class AttackMouse implements Mouse
public void click(Card c) {//add creature to attackers}

class BlockMouse implements Mouse
public void click(Card c) {//add creature to blockers}

OK, we have an interface (or abstract class) that has one method, click(). MouseState just acts like a shell for the 3 other classes.

After this statement MouseState.setMouse(new MainMouse()), MouseState will act like it is a MainMouse object. If MouseState is passed an AttackMouse object, it will act like that object. Basically MouseState morphs into another object. So externally MouseState can act like multiple classes. The beauty of the State pattern is that MouseState doesn’t require a ton of IF statements. I can change the behavior of MouseState without changing the source code of MouseState, can you see the flexibility? The user interface only holds a reference to MouseState, and other classes change the behavior of MouseState as needed. MTG Forge uses Input instead of Mouse and InputControl instead of MouseState.

Friday, June 22, 2007

Design: AI – Part 2

There are two methods in the class SpellAbility that the computer AI uses. Those methods are canPlayAI() and chooseTargetAI() The canPlayAI() returns a boolean value and dictates whether the computer can play this card are not. Some cards like Remove Soul the computer cannot play; I could never get the logic to work correctly.

And currently the computer only plays cards during his turn. Serpent Warrior’s canPlayAI() method checks to see if the computer’s life is over 3, so the computer doesn’t kill himself. (Serpent Warrior causes its controller 3 damage when it comes into play.) Hex’s canPlayAI() checks to see if there are 6 enemy creatures in play. Remember that SpellAbility is used for Spells as wells as for Abilities, so Royal Assassin’s ability checks to see if there are any tapped enemy creatures.

The method chooseTargetAI() does what it says, it sets the target for the computer if the spell or ability has a target. Cards like Giant Growth and Shock need a target, while Counsel of the Soratami (2U, draw 2 cards) and Wrath of God do not have any targets.

Design: Magic Engine

The design for the next version of MTG Forge uses a concept that I call “Magic Engine.” A Magic Engine tightly implements all the functionality of a Magic game, like returning a creature from play to hand or drawing a card. Previously every card would handle these actions individually. If a card was bounced to your hand, the card would have to check if it was a token, now there will be a method in the Magic Engine called movePlayToHand(Card) that does all of the checks.

The idea is that if I want to program some really new card that the old engine cannot handle, I can just program a new engine with the new functionality. I should be able to construct cards separately from the engine, so that different engines could use the previous existing cards. CardFactory, the class that actually makes cards, basically just adds SpellAbilities to the cards. For more info on CardFactory and SpellAbility see the column Design: Card

Tuesday, June 19, 2007

History of Magic - Part 1


2 new posts today, make sure to read the comments in Design: Card for another post that contains alot of code.

This is Richard Garfield explaining how he created Magic: The Gathering, taken from the book the Game Design Workshop. I haven’t seen this anywhere else and I really enjoyed reading it.

The Creation of Magic: The Gathering
By Richard Garfield written in 1993

The ancestry of Magic
Games evolve. New ones take the most loved features of earlier games and add original characteristics. The creation of Magic: The Gathering is a case in point.

Though there are about a dozen games that have directly influenced Magic in one way or another, the game’s most influential ancestor is a game for which I have no end of respect: Cosmic Encounter, originally published by Eon Products and re-released by Mayfair Games. In this game, participants play alien races striving to conquer a piece of the universe. Players can attempt their conquest alone, or forge alliances with other aliens. There are nearly 50 alien races which can be played, each of which has a unique ability: the Amoeba, for example, has the power to Ooze, giving it unlimited token movement; the Sniveler has the power to Whine, allowing it to automatically catch up when behind. The best thing about Cosmic Encounter is precisely this limitless variety. I have played hundreds of times and still can be surprised at the interactions different combinations of aliens produce. Cosmic Encounter remains enjoyable because it is constantly new.

Cosmic Encounter proved to be an interesting complement to my own design ideas. I had been mulling over a longtime idea of mine: a game which used a deck of cards whose composition changed between rounds. During the course of the game, the players would add cards to and remove cards from the deck, so that when you played a new game it would have an entirely different card mix. I remembered playing marbles in elementary school, where each player had his own collection from which he would trade and compete. I was also curious about Strat-o-matic Baseball, in which participants draft, field, and compete their own teams of baseball players, whose abilities are based on real players’ previous year statistics. Intrigued by the structure of the game, I was irritated that the subject was one for which I had no patience.

These thoughts were the essence of what eventually became Magic. My experiences with Cosmic Encounter and other games inspired me to create a card game in 1982 call Five Magics. Five Magics was an attempt to distill the modularity of Cosmic Encounter down to just a card game. The nature of Cosmic Encounter seemed entirely appropriate for a magical card game – wild and not entirely predictable, but not completely unknown, like a set of forces you almost, but don’t quite, understand. Over the next few years, Five Magics went on to inspire entirely new magical card games among my friends.

Ten years later, I was still designing games, and Mike Davis and I had come up with a boardgame called RoboRally. Mike was acting as our agent, and among the companies he approached was a brand-new gaming company called Wizards of the Coast. Things seemed to be going well, so that August, Mike, and I made our way to Portland, Oregon to meet over pizza with Peter Adkison and James Hays of Wizards of the Coast.

Both Peter and James were very receptive to RoboRally, but informed me that they weren’t really in a position to come out with a boardgame right away. This wasn’t what I come out to hear, of course, but I didn’t want the trip to be a total waste. I asked Peter what he would be interested in. Peter replied that he really saw a need for a game that could be played quickly with minimal equipment, a game that would go over well at conventions. Could I do it?
Within a few days, the initial concept for a trading card game was born, based on another card game I had developed in 1985 called Safecracker. I hadn’t been one of my best games. But then I remembered Five Magics.

The first designs
I went back to graduates school at the University of Pennsylvania, and worked on the card game in whatever spare time I had. It wasn’t easy; there were three months of false starts on the project, there are so many aspects of card game design that have to be reconsidered when designing trading card games. First of all, you can’t have any bad cards – people wouldn’t play with them. In fact, you want to prevent too much range in the utility of cards because players will only play with the best – why make cards people won’t play with? Besides, homogeneity of card power is the only way to combat the “rich kid syndrome” that threatened the game concept from the starts. What was to keep someone from going out and getting ten decks and becoming uneatable?

It was a major design concern. I had numerous theories on how to prevent purchasing power from unbalancing the game, none of which were entirely valid but all of which had a grain of truth. The most compelling counter to this “buy-out-the-store” strategy was the ante. If we were playing for ante, the argument ran, and your deck was the distilled fruit of ten decks, when I did win, I would win a more valuable card. Also, if the game had enough skill, then the player purchasing their power would surely be easy prey for the players dueling and trading their way to a good deck. And of course there was the sentiment that buying a lot of poker chips doesn’t make you a winner. In the end, however, the “rich kid syndrome” became less of a concern. Magic is a fun game, and it doesn’t really matter how you get your deck. Playtesting showed that a deck that is too powerful defeats itself. On the one hand, people stopped playing against it for ante unless a handicap was invoked; on the other, it inspired them to assemble more effective decks in response.

The first Magic release was affectionately named Alpha. It consisted of 120 cards split randomly between two players. The two players would ante a card, fight a duel over the ante, and repeat until they got bored. They often took a long time to get bored; even then, Magic was a surprisingly addictive game. About ten o’clock one evening, Barry “Bit” Reich and I started a game in the University of Pennsylvania Astronomy lounge, a windowless, air-conditioned room. We played continuously until about 3:00 a.m.; – at least that’s what we thought, until we left the building and found the sun had risen.

I knew then that I had a game structure that could support the concept of individually owned and tailored decks. The game was quick, and while it had bluffing and strategy, it didn’t seem to get bogged down with too much calculation. The various combinations that came up were enjoyable and often surprising. At the same time, the variety of card combinations didn’t unbalance the game: when a person started to win, it didn’t turn into a landslide.

From alpha to gamma
Except for the card mix, little has changed about Magic since alpha. In alpha, walls could attack, and losing all your lands of a particular color destroyed the associated spells in play, but otherwise, the rules are much the same now as they were in the early stages of playtesting.
Moving from alpha to the beta version was like releasing a wild animal. The enjoyable game that was alpha now burst the confines of the duel to invade the lives of the participants. Players were free to trade cards between game and hunt down weaker players to challenge them to duels, while gamely facing or cravenly avoiding those who were more powerful. Reputations were forged – reputations built on anything from consistently strong play to a few lucky wins to good bluffing. The players didn’t know the card mix, so they learned to stay on their toes during duels. Even the most alert players would occasionally meet with nasty surprises. This constants discovery of unknown realms in an uncharted world gave the game a feeling of infinite size and possibility.

For the gamma version, new cards were added and many of the creature costs were increased. We also doubled the pool of playtesters, adding in a group with Strat-o-matic Baseball experience. We were particularly anxious to find out if Magic could be adapted for league play. Gamma was also the first version which was fully illustrated. Skaff Elias was my art director: he and others spends days poring over old graphic magazines, comic books, and game books searching for art for the cards.

These playtest decks were pretty attractive for crummy black-and-white cardstock photocopies. For the most part, the cards were illustrated with serious pictures, but there were a lot of humorous ones as well. Heal was illustrated by Skaff’s foot. Power Sink showed Calvin (of “Calvin and Hobbes”) in a toilet; after all, what is a toilet but a power sink? Berserk was John Travolta dancing in Saturday Night Fever. Righteousness pictured Captain Kirk, and Blessing showed Spock doing his “live long and prosper” gesture. An old comic book provided a Charles Atlas picture for Holy Strength, and a 98-poind weakling getting sand kicked in his face for Weakness. Instill Energy was Richard Simmons. The infamous Glasses of Urza were some X-ray glasses we found in a catalog. Ruthy Kantororvitz constructed a darling flame-belching baby for Firebreathing. I myself had the honor of being the Goblins. The pictures and additional players greatly added to the game atmosphere. It became clear that while the duels were for two players, the more players playing, the better the game was. In some sense, the individual duels were a part of a single, larger game.

Design: Card

This will be the first of a set of articles that I will write talking about how I designed MTG Forge. (Well 2nd article, the blogger really messes up Java code.) Magic focuses on cards, so I have a Card object. (I capitalize object names, it’s a Java thing.) Card objects are used everywhere that you would have a regular, cardboard card, in hand, in play, in your graveyard. Card objects hold values like card type (Creature, Sorcery), attack, defense, owner, and controller. Card objects don’t really do anything in and of themselves; they just hold a bunch of related values.

Another important class SpellAbility, implements the functionality of all spells and abilities. It has an abstract resolve() method that is overridden, so Wrath of God’s resolve() would destroy everything, got it?

In MTG Forge, Card objects have one or more SpellAbility objects. A generic creature like Eager Cadet, God bless his frail body, has only one SpellAbility. All creatures are spells, so all Card objects hold at least one SpellAbility. The class CardFactory constructs Cards by adding SpellAbilities, and also implementing the core functionality of the card by the resolve() method. (Resolve() is a method so it gets parenthesis. It is just hard to talk about code, without showing code.)

Ok review, Card objects exist in hand, play, grave, and removed from game. Each Card object has at least one SpellAbility. If a creature has an activated ability like Elvish Piper, the Card will have two SpellAbilities, one SpellAbility for the creature spell, and one for the ability. SpellAbility has an abstract resolve() method that implements the card function, it does the work of the card like destroying things or doing damage, etc..


//*************** START *********** START **************************
//note the mana cost was already set, so I can use the same resolve() for both cards
if(cardName.equals("Wrath of God") || cardName.equals("Damnation"))
{
final SpellAbility spell = new Spell(card)
{
public void resolve()
{
CardList all = new CardList();
all.addAll(AllZone.Human_Play.getCards());
all.addAll(AllZone.Computer_Play.getCards());

for(int i = 0; i < all.size(); i++)
{
Card c = all.get(i);
if(c.isCreature())
AllZone.GameAction.destroyNoRegeneration(c);
}
}//resolve()
public boolean canPlayAI()
{
return 0 < CardFactoryUtil.AI_getHumanCreature().size();
}
};//SpellAbility
card.clearSpellAbility();
card.addSpellAbility(spell);
}//*************** END ************ END **************************


//*************** START *********** START **************************
//note, the card object already has a standard summon creature SpellAbility added to it
if(cardName.equals("Thought Courier"))
{
//Ability_Tap is a subclass of SpellAbility
final Ability_Tap ability = new Ability_Tap(card)
{
public boolean canPlayAI() {return false;}
public void resolve()
{
AllZone.GameAction.drawCard(card.getController());
AllZone.InputControl.setInput(CardFactoryUtil.input_discard());
}
};//SpellAbility
card.addSpellAbility(ability);
ability.setDescription("tap: Draw a card, then discard a card.");
ability.setStackDescription("Thought Courier - draw a card, then discard a card.");
ability.setBeforePayMana(new Input_NoCost_TapAbility(ability));
}//*************** END ************ END **************************


Friday, June 15, 2007

Design: AI

I have gotten questions about how the computer AI is programmed. I presume that the AI seems believable and even smart sometimes. The AI is divided up into 2 parts: cards and combat. A different component handles each one.

The AI that plays cards is essentially very simple, it just randomly plays a card in his hand. Most cards have some AI code hardcoded into them. The computer will only play Wrath of God if you have a creature in play. Elvish Piper’s ability will choose the biggest creature in hand to put into play. The code in Giant Growth will only target a creature that will attack. The AI for each card is usually pretty simple, but combined together it makes the computer seem alive.

Some cards and abilities the computer cannot play because I wasn’t sure how to evaluate them. The computer cannot play Thought Courier’s draw a card, discard a card ability or Remove Soul, I couldn’t get the code to work correctly. Thankfully some cards like Pestilence the computer uses very efficiently.

Combat is divided up into attacking and blocking. Basically the computer trades creatures when attacking or blocking. (Trading means that both creatures die.) The computer will not block a non-flyer with a flyer, which is usually the correct thing to do. The AI combat routines sound simple but they were really hard to program. My mind felt twisted after I got done with them. It is really hard trying to handle all attacking and blocking situations. The object ComputerUtil_Attack2 is 125 lines and ComputerUtil_Block2 is 210 lines.

The code blocks creatures in this order.
-safe block: attacker dies, blocker lives
-shield block: attacker lives, blocker lives
-trade block: attacker dies, blocker dies
-chump block: attacker lives, blocker dies
-multiple blockers: attacker dies, some or all blockers die

Thursday, June 14, 2007

Programming Magic Cards is Hard

If you want to play Magic on the computer, you have to program cards. The central problem is how to encode Magic cards into a programming language. I have had e-mail asking, “How do you program Magic cards” and this article aims to answer that question. I wish I could say that my way is the easiest, best way to program Magic cards, but it is just a way.

The Magic Project lets you play against other human players over the Internet and enforces the rules unlike Apprentice. The Magic Project, sourceforge.net/projects/magic-project, uses XML for each card.

!-- {2}{b}{b} search your library for a card and put that card into your hand. then shuffle your library. -->
init>
registers>
register index="colorless" value="2"/>
register index="black" value="2"/>
/registers>
colors>black
idcards>sorcery
/init>
abilities>
activated-ability playable="this" name="" zone="hand">
cost>
pay-mana value="manacost"/>
/cost>
effects>
action ref="search-lib"/>
action ref="return-to-hand"/>
action ref="finish-spell"/>
/effects>
/activated-ability>
/abilities>
/card>

(Sorry the XML is butchered so badly.)

The Magic Project has 2,000+ cards programmed, which is a Herculean task in and of itself. The XML schema, mpvalidator.xsd, is 240kb, which is pretty long, but it has to allow for so many card variations and restrictions, like Terror that can only target non-black creatures.

My project MTG Forge, sourceforge.net/projects/mtgforge, just codes the cards into Java. MTG Forge currently has 365 cards. Let us look at Thought Courier, since he has a simple ability. The computer cannot play Thought Courier’s ability because it cannot evaluate cards, that is the meaning of “public boolean canPlayAI() {return false;}”

//*************** START *********** START **************************
if(cardName.equals("Thought Courier"))
{
final Ability_Tap ability = new Ability_Tap(card)
{
public boolean canPlayAI() {return false;}
public void resolve()
{
AllZone.GameAction.drawCard(card.getController());
AllZone.InputControl.setInput(CardFactoryUtil.input_discard());
}
};//SpellAbility
card.addSpellAbility(ability);
ability.setDescription("tap: Draw a card, then discard a card.");
ability.setStackDescription("Thought Courier - draw a card, then discard a card.");
ability.setBeforePayMana(new Input_NoCost_TapAbility(ability));
}//*************** END ************ END **************************

Demonic Tutor is a little bit longer, but is very straight forward. In case you don’t know, it lets you search your library for a card and then put it into your hand.

//*************** START *********** START **************************
if(cardName.equals("Demonic Tutor"))
{
final SpellAbility spell = new Spell(card)
{
public void resolve()
{
String player = card.getController();
if(player.equals(Constant.Player.Human))
humanResolve();
else
computerResolve();
}
public void humanResolve()
{
Object check = AllZone.Display.getChoiceOptional("Select card", AllZone.Human_Library.getCards());
if(check != null)
{
PlayerZone hand = AllZone.getZone(Constant.Zone.Hand, card.getController());
AllZone.GameAction.moveTo(hand, (Card)check);
}
AllZone.GameAction.shuffle(Constant.Player.Human);
}
public void computerResolve()
{
CardList list = new CardList();
Card[] library = AllZone.Computer_Library.getCards();

//gets cards that Computer has mana to play
for(int i = 0; i < library.length; i++)
if(ComputerUtil.canPayCost(library[i].getSpellAbility()[0])) list.add(library[i]);
//pick best creature
Card c = CardFactoryUtil.AI_getBestCreature(list);
if(c == null) c = library[0]; //System.out.println("comptuer picked - " +c); AllZone.Computer_Library.remove(c);
AllZone.Computer_Hand.add(c);
}

public boolean canPlay()
{ PlayerZone library = AllZone.getZone(Constant.Zone.Library, card.getController());
return library.getCards().length != 0; }

public boolean canPlayAI() {
CardList creature = new CardList();
creature.addAll(AllZone.Computer_Library.getCards());
creature = creature.getType("Creature");
return creature.size() != 0; }

MTG Forge there is a Card class that represents cards both in your hand and in play. Every Card object has one or more spells or abilities that are added to it. The class SpellAbility implements all spells and abilities. Every spell or ability has to implement a resolve() method in the SpellAbility class, resolve() does the main functionality of the card. Thought Courier’s ability is implemented in the resolve() method. The same goes for Demonic Tutor, the resolve() method lets you actually look through your library and choose a card. Since the computer can play cards, you will see that Demonic Tutor’s resolve() method does something different depending on if you or the computer played it. MTG Forge also reads cards from a file called “cards.txt” Cards with simple abilities like haste, fear, flying, vigilance, and mana abilities don’t have to be programmed, they are just added to the text file. No extra programming has to be done for cards like Llanowar Elves and Lightning Angel.

Llanowar Elves
G
Creature Elf Druid
no text
1/1
tap: add G

Lightning Angel
1 R W U
Creature Angel
no text
3/4
Flying
Vigilance
Haste

Friday, June 8, 2007

Split

Hi all, thanks for visiting this site. I've only been able to get around 10 hits a day and I want to improve that. I think the problem is the focus of this blog, people either care about Magic or Programming, not both. I plan to split this blog into two separate blogs that are more focused on that specific subject area. I welcome any comments on this subject, --Forge