Wednesday, December 30, 2009

How to Conquer the Complexity of Rules - Part 2

The idea of putting all of the rules into one large object, RulesEngine, is very versatile. To begin with I can code simple rules and then update them later as needed. This avoids the problem of overanalyzing the rules because you want to your program completely correct which usually results in "analysis paralysis". This approach doesn't work because the rules are too big and your brain is much too small.

While having one massive object is bad in some aspects, the positives include having all of the rules confined to one location. Internally I can restructure it as often as I need to because the external methods for RulesEngine won't change. Since RulesEngine implements every single rule, I should be able to easily implement new rules and to fix rules that I have misunderstood. I can write a very simple mana pool and then later make it more sophisticated.

The goal is to give RulesEngine all of the information and let it internally implement the rules. The hard point is giving RulesEngine "all of the information" because different Magic cards need to know different pieces of information. There will always be weird cards that require off-the-wall” information like Imperiosaur which has the static ability "Spend only mana produced by basic lands to play Imperiosaur". Or cards that require snow mana or cards that say something like "you can only use this mana to pay for artifacts".

Obviously implementing Magic isn't easy but by putting all of the rules together will make the coding as easy as possible.

Monday, December 28, 2009

How to Conquer the Complexity of Rules - Part 1

Programming Magic's tidal wave of rules is a huge challenge. I did my best with Forge version 1. I got the program "out the door" and working but it only implements a few of the rules. I'm slowly but thoroughly working on Forge version 2 and I'm trying to figure out how to program a few simple rules now and allow for more complex rules implementation later.

My idea is to put all of the rules into one large object which I call the RulesEngine. (An object is just code statements that are related.) You give all of the information to the RulesEngine and let it handle the rules internally. This way you are separating the rules from the rules implementation. In programming it is often useful to separate "tightly knit" systems like separating the user interface from the back-end business logic using the model, view, controller (MVC) pattern.

At the heart of Forge version 1 is the method nextPhase(), which advances the game to the next phase. (And although I know that there is technically a difference between phases and steps, I call everything a "phase".) I plan to use nextPhase() in Forge version 2 also. At first nextPhase() will just advance to the next phase but later on it could do anything number of things: empty the mana pool, move duplicate legendary and planeswalker cards to the graveyard, implement upkeep effects like Juzam Djinn, and check for other state effects.

The idea is to start with a "simple" implementation of Magic's rules and later on you can update your implementation as needed since all of the rules are in one place. Next time I examine more of the pros and cons of this idea.

Friday, December 25, 2009

10 Cards That You Didn’t Know Forge Had

Merry Christmas.

10 – The planeswalkers Ajani Vengeant and Jace Beleren. Ajani is a red-white powerhouse and Jace lets you draw cards or deck your opponent. (Yes, I cheated and mentioned two cards, so sue me :)

9 – Time Walk, yes you abuse the computer with this classic, and costly, card. (Funny note, at first Richard Garfield wrote this card to say “Your opponent losses his next turn”. One player came running up to Richard and said, “I just found this amazing card that lets you win the game” and Richard said, “What card is it?” The guy said, “It says your opponent loses the game.” The guy misunderstood the card to mean that your opponent loses the whole game.

8 – Akroma, Angel of Wrath, yes Forge implements this card 100%. At first Akroma just had flying and haste. As Forge progressed, Akroma slowly gained all of her abilities. Forge also has her red, Planar Chaos sister Akroma, Angel of Fury.

7 – Snow Mana, well you probably noticed this since there is a whole extra mana pool dedicated to snow mana but it is still cool. Be sure to check out snow mana cards like Boreal Griffin, Frost Raptor, Goblin Rimerunner, Phyrexian Snowcrusher, Rimebound Dead, Phyrexian Ironfoot.

6 – Door to Nothingness is a 5 mana artifact that lets you win the game for only WWUUBBRRGG. Johnnies, feel free to go nuts.

5 – Goblin Sharpshooter, is a great way to kill all of your opponents X/1 creatures in play. Works great against elves too!

4 – Equipment, make sure to add these to your favorite decks: No-Dachi (cost 2, equip 3, Equipped creature gets +2/+0 and has first strike) or Loxodon Warhammer (cost 3, equip 3, Equipped creature gets +3/+0 and has lifelink and trample.)

3 – Rukh Egg, an oldie but goodie. Break him out of his egg with Lightning Bolt.

2 – Sol Ring helps out any decks mana curve. For only a cost of 1, you get 2 more mana each turn.

1 – Darksteel Colossus – This is a huge trampling 11/11 creature. Since he is a little bit expensive, 11, feel free to cheat him into play using Elvish Pipe. Colossus can’t be put into the graveyard so you can’t Zombify him. Feel free to think of your own way to play this gigantic card.

That’s it. Merry Christmas.

Wednesday, December 23, 2009

Great Programming Books

I don’t write much about programming itself because….well….programming is as interesting as watching paint dry on the 4th of July. I have read one outstanding book on programming called Code Complete: A Practical Handbook of Software Construction by Steve McConnell. This book is better than all of the books that I bought for my computer college classes. (I majored in Information Science and minored in Computer Science, yeah go me!!)

Code Complete is very interesting even though it talks about computer programming. Specifically the book is aimed at “software construction” but a major part of software construction is computer programming. I re-read this book every year and it is just phenomenal. Amazon.com gives this book a 4.5 star rating with 149 customer reviews, which is a pretty strong recommendation. Feel free to buy the cheaper 1st edition since it has 99% the same stuff as the second edition. (I should know because I’ve practically memorized the 1st edition.)

It is really hard to describe “Joel on Software” written by Joel Spolsky. The book is just really, really good. The book is based on the author’s personal blog, http://www.joelonsoftware.com, but I find the book to be 100% more interesting and insightful than the blog. The book is hard to describe but it covers such computer science topics as “Why Anti-aliased text looks better”, “Network IO doesn’t work like local IO” and “Why there ain’t no such thing as plain text”. Overall the book isn’t technical but the author doesn’t mind diving in sometimes. The book is very humorous and I’ve found myself laughing out loud at it. (Warning your non-technical friends will not understand why the book is so funny.)

One really great essay from “Joel on Software” is the five worlds of computer programming. I’ll briefly go over the article but you can also read it here on his blog. The five worlds are shrinkwrap, internal, embedded, games and throwaway. Often an article or methodology will be talking about one world while the reader deals with a different world and then flame wars erupt. If a book is talking about shrinkwrap and you deal with open source, the book won’t make any sense to you. Each world is separate and doesn’t overlap.

Shrinkwrap – is used by zillions of customers, who often have alternatives. So the user interface needs to be easier than average to be successful. They spend half their time trying to make things even easier for Uncle Leo in Duluth.

Open Source – is often developed without anyone getting paid to develop it, so things that aren’t considered “fun” often don’t get done. (My comment – the user interface is often considered “not fun” and therefore never gets done. Most open source projects have horrible user interfaces that actually inflict pain on the user. And don’t get me started on command line interfaces that are as bad as the Sarlacc pit in Star Wars, i.e. very bad.)

Internal – only has to work in one situation on one company’s computers which makes it a lot easier to develop. You can make lots of assumptions about the environment under which it will run. You can require a particular version of Internet Explorer or Microsoft Office. Sadly lots of internal software sucks pretty badly even while accomplishing what it needs to accomplish. This can be depressing for young enthusiastic developers who need to be persuaded to stop when the software is “good enough.”

Embedded – is unique because it goes into a piece of hardware and in almost every case can never be updated. Even if it can technically be updated, it won’t be. Trust me, nobody downloads EPROM flash upgrades for their microwave ovens. This is a whole different world. The quality requirements are very high because there are no second chances. You may be dealing with a CPU that runs dramatically more slowly than the typical desktop processor, so developers may have to spend a lot of time optimizing and hand-tuning. Fast code is more important than elegant code. The input and output devices available to you will probably be limited.

Games – are unique. The economics of game development are hit-oriented. Some games are hits, many more games are failures, and if you want to make money on game software, you recognize this and make sure that you have a portfolio of games so that the blockbuster hit makes up for the losses on the failures. This is more like movies than software.

Throwaway – This category is included for completeness. This is code that you create temporarily solely for the purpose of obtaining something else, and you never need to use the code gain once you obtain that thing. For example, you might write a little shell script that massages an input file that you got into the format you need it for some other purpose, and this is a onetime operation. (My comment – throwaway code should always be saved for the future because you never know when you need to do “such and such” again. Usually if you need to do something once, you probably need to do it twice but you don’t realize it yet.)

Well after plagiarizing about 500 words you can tell that I really like the book. It is a very good non-technical book (only a few lines of code) that talks about technical subjects. Joel Spolsky wrote two very good books “Joel on Software” and “More Joel on Software”. He also edited the much worse “Best Software Writing I” which I mistakenly bought and it was a very BIG mistake. That book is horrible.

So in conclusion try to find “Code Complete” by Steve McConnell and if you want a good laugh or two read “Joel on Software” or “More Joel on Software” by Joel Spolsky.

Monday, December 21, 2009

Version 2 – A Fresh Beginning

I’m slowly working on Forge version 2. I’ve been sandbagging (i.e. goofing off) for probably a year or so but I’m making slow but steady progress. Like building a house, I’m starting at the foundation, phases. I’m making sure that you or the computer can play first, as well as implementing phase stops like Magic Online.

I have started version 2 multiple times and I have some very good code that I can use but basically I’m starting completely over. Starting over sounds very bad, even to me, but hopefully I can build something that is truly wonderful instead of a program that is held together with duck tape. Duck tape works but it often leads to weird, complicated problems in the future.

To put things into perspective, I probably have 30 lines of code and 10 or so methods. This is a small but promising start on such a big project. Currently Forge has more than 30,000 lines of code. I’m guessing that version 2 with 10 cards and an improved AI will have around 1,000 to 5,000 lines of code, I would like to predict when this will happen but I’ll leave the fortune-telling to gypsies and Las Vegas gamblers.

I consider Forge a complete success because it has more than 2,000 cards and is infinitely replayable. Forge is also a successful open-source project that continues to be updated even without my help. Forge is “computerized heaven” for casual players like myself.

Wednesday, December 16, 2009

The Rules Engine is a Pain in the Neck

We all know that Magic is a great game and one of the reasons why it is so great is because of the complicated (and sometime baffling) rules. And when I’m talking about the rules, I’m not talking about the wimpy basic rulebook that beginner’s use, I’m talking about the monstrous, sometimes incomprehensible comprehensive rulebook.

The comprehensive rulebook is great for answering specific small questions like what is a card’s type and supertype?

204.2a The card types are artifact, creature, enchantment, instant, land, plane, planeswalker, sorcery, tribal, and vanguard.

204.4a A card can also have one or more supertypes. These are printed directly before its card types. The supertypes are basic, legendary, snow, and world.

The comprehensive rules are individually numbered so you can quickly look up the rule again, or just reference it by writing 204.2a (if you have *cough* memorized it).

Obviously you have to know a little about Magic’s rules in order to program them. Some people don’t understand targeted and non-targeted spells and I understand their confusion but if you want to write a program that plays Magic, you have to know the rules as much as I can (without going crazy or getting “analysis paralysis”).

Targeted spells use the word “target” but it gets confusing when a spell affects multiple cards like Wrath of God. It seems like Wrath of God should target all creatures but it doesn’t. And Wrath of God will still destroy cards that have protection from white like Black Knight since protection only protects the creature from being targeted by a spell of that color.

Things get really tricky when you consider Pestilence AND a creature that has protection from black. Protection from black nullifies Pestilence and the creature will not receive any damage. Protection is also another thorny area and is widely misunderstood. Below is taken from this Saturday School article.

Protection from any quality means 4 things, abbreviated D-E-B-T: Damage from that quality is prevented, can’t be Enchanted by enchantments of that quality, can’t be Blocked by creatures of that quality, and can’t be Targeted by spells or effects of that quality. Commander Eesha can’t be blocked by a creature.

Forge supports regular "protection from color" as well as protection from enchantments (Azorius First-Wing), Dragons (Dragonstalker), Goblins (Warren-Scourge Elf), Demons (Baneslayer Angel), everything (Progenitus), artifacts (Nacatl Savage), and creatures (Beloved Chaplain).

My personal mistakes include thinking that Elvish Piper targeted a card in your hand AND that you have to choose the creature that you will put into play when you cast the ability. So I made two mistakes on one simple card. (By the way Elvish Piper is still a little broken because I never fixed it.)

Forge tries to implement as much as the rules as possible but originally Nightmare and Giant Growth didn’t work together. I know Giant Growth is supposed to pump up Nightmare but since creature's power and defense were simple numbers (int), a simple layer system had to be added. (Thanks to Dennis and Rob for the layer system.)

I used to think the hardest part of programming Magic was implementing the cards but I've learned that the rules engine itself is the most complicated part. If you rules engine is sophisticated enough with events and triggers, programming the cards shouldn't be much of a problem.

p.s. The picture for Garruk Wildspeaker is from from the Duel Decks: Garruk vs. Liliana set.

Monday, December 14, 2009

New Version

There is a new, hot-off-the-shelves, kick-your-brothers-butt, version of Forge with a whopping 200 new cards, which means that Forge now has colossal 2,331 cards. (P.S. I love the word whopping.) Probably the biggest change is that now there is a “Before Combat Begins” phase and an “After Attackers” phase, so you can milk those activated abilities and instants even more. I know people have been clamoring for more phases.

There are a ton of exciting new cards that you will you will want to get your hands on like the planeswalkers Ajani Vengeant and Jace Beleren, the insane-in-the-membrane Time Walk, and the put-any-artifact-into-play king Tinker (make sure to use a nice big fatty like Darksteel Colossus).

Other notable potables includes Academy Rector which lets you abuse enchantments, Umezawa's Jitte which is an insane piece of equipment, as well as the how-do-I-use-this-stupid-card Barren Glory (At the beginning of your upkeep, if you control no permanents other than Barren Glory and have no cards in hand, you win the game). Snow mana is now supported and there are also a ton of tiny fixes for individual cards.

The other big change is that Forge now uses a different deck system. Your old decks were all crammed into the file “all-decks2” but now each deck exists as a separate file. This version will import all of your old decks into the new deck system.

Other nice goodies include a deck editor that lets you easily hide colors and card types that you don’t want. You can see a nice screenshot of it here. (Thanks Nantuko!!)

This whole update was coded by the great guys on the forum: Dennis, Rob, Zerker, and Nantuko.

p.s. I added a text file that says that this is Forge version 11-25 because that was when it was released on the forums. On the forums you can cure world hunger, be the next president of the United States, or finish your homework. The forums are a great place to upload your favorite deck or download someone else's.

Download Forge

Wednesday, December 9, 2009

Shock and Royal Assassin – Part 3

Today I’m going to talk about Incantus and MagicWars. Both programs enforce the rules and allow you to play against other people over the Internet. Even though these two projects are completely separate, they encode Magic cards in a similar way. Each card is very short and is written in either Python or Java. Incantus was written in Python while MagicWars uses Java.

Incantus is the current king-of-the-hill when it comes to supporting the most cards. Incantus currently has more than 6,000 cards which is phenomenal. Of all of the freeware Magic programs, Incantus has the best user interface with all of the eye candy that you would ever want. Incantus has very readable, short card code that is written in Python. Currently the source code of Incantus is semi-private. It isn’t an open source project but you can get the source by reading through the Incantus forum.

MagicWars is newer than Incantus and has more than 550 cards including all 145 cards from Alara Reborn, go cascade!! MagicWars uses Groovy to encode Magic cards. The Groovy homepage says that it:

-- Builds upon the strengths of Java but has additional power features inspired by languages like Python, Ruby and Smalltalk.
-- Makes modern programming features available to Java developers with almost-zero learning curve.
--Supports Domain-Specific Languages and other compact syntax so your code becomes easy to read and maintain.

Groovy compiles to Java bytecode, so it can run anywhere that Java can. The MagicWars blog also says that “A Groovy Closure is like a ‘code block’ or a method pointer. It is a piece of code that is defined and then executed at a later point.” So Groovy is short like a domain specific language (see my previous article) and yet powerful enough to be a full-fledged language all by itself. Right now I don’t know anything about Groovy but it seem very interesting.

MagicWars also has a very nice blog that describes how it specifically uses Groovy. The blog encourages non-programmers to learn some syntax and to create their own favorite card.

Incantus:
Screenshot
Forum


MagicWars:
Screenshot - game in progress
Screenshot - deck editor

Download
Forum
Blog

Groovy

Incantus - Royal Assassin
name = 'Royal Assassin' 
cardnum = 0
expansion = ''
types = characteristic('Creature')
supertypes = no_characteristic()
subtypes = characteristic('Assassin', 'Human')
cost = '1BB'
color = characteristic('B')
power = 1
toughness = 1
text = ['T: Destroy target tapped creature.']

play_spell = play_permanent()

#################################

@activated(txt=text[0])
def ability():
def effects(controller, source):
cost = yield TapCost()
target = yield Target(isCreature.with_condition(lambda c: c.tapped))
target.destroy()
yield
return effects
abilities.add(ability)


Incantus - Shock
name = 'Shock'
cardnum = 0
expansion = ''
types = characteristic('Instant')
supertypes = no_characteristic()
subtypes = no_characteristic()
cost = 'R'
color = characteristic('R')
text = ['Shock deals 2 damage to target creature or player.']

#################################

@play_instant()
def effects(controller, source):
cost = yield source.cost
target = yield Target(isCreatureOrPlayer)
source.deal_damage(target, 2)
yield
play_spell = effects



MagicWars – Royal Assassin
name = "Royal Assassin"
types = ["Creature","Human","Assassin"]
manacost = "1 B B"
text = ["{T}: Destroy target tapped creature."]
power = 1
toughness = 1
prints = [
["M10", "R", 191318, 110],
["10E", "R", 129708, 174],
["9E", "R", 83235, 159],
["8E", "R", 45323, 159],
["4E", "R", 2124, 41]
]

script = '''\
addAbilityTap({
destroyTarget($target, $this)
}, "0")

setSpecificTarget("Select target
tapped creature to destroy.",
{
return $permanent.isCreature() &&
$permanent.isTapped()
})'


MagicWars - Shock
name = "Shock"
types = ["Instant"]
manacost = "R"
text = ["Shock deals 2 damage to target creature or player."]
prints = [
["10E", "C", 129732, 232],
["9E", "C", 83261, 220],
["ONS", "C", 39482, 227]
]

script = '''\
addSpell({
dealDamage($target, 2, $this);
})
setTarget("Creature|Player")
'''

Monday, December 7, 2009

Problem Domain Languages

It seems that I have gotten into a discussion of "problem domain languages" which is a language that only relates to a specific area such as controlling a robot. A problem domain language would let you move the robot and would consist of statements such as "go forward 3 feet" and "turn left".

Firemox, Wagic, and Forge have each created their own problem domain language for cards. The problem is "How to efficiently encode a Magic card into a computer programming language?" and the solution is to invent your own "little" computer language. Please note that problem domain languages are the opposite of general purpose languages such as C++ and Java.

All problem domain languages have approximately the same pros and cons. On the plus side the problem domain language will be more precise and shorter than a general purpose language. Problem domain languages can be parsed during runtime which promotes "late binding" and is more flexible than statically compiled code.

The negative side of problem domain languages is that they are hard to write because you have to take into consideration EVERYTHING that you want to do. If you make a mistake when you are creating your problem domain language, you might have to completely change your language and start again.

Creating a problem domain language is often very fun. You can use the Interpreter and Command software patterns to create a nice, little language for yourself. The easiest way is to make your own computer language is to create command objects that implement variable declarations, "if" and "for" statements. Now just put a few command objects together and *voila*, you have just invented your own (crappy) computer language.

Typically you would create a different command object for each part of the problem domain. The problem domain language for a robot would have a TurnLeftCommand and GoForwardCommand.

And what would this world be without Wikipedia? They have a pretty good explanation of problem domain languages here.

Thursday, December 3, 2009

Shock and Royal Assassin – Part 2

Today I'm going to examine how Firemox encodes Shock and Royal Assassin. Firemox allows you to play against other people on the Internet with rules enforcement. Firemox uses Java and currently has 6,041 cards.

Firemox uses XML to represent cards which is much better than using Java itself. On the plus side XML is usually shorter than Java and allows non-programmers to help. Using an "in-between" language like XML allows the programmer greater freedom when changing the code. For example, the damage code could be changed for all of the cards simultaneously because the damage code for each card is generated "on the fly" from the XML.

On the negative side, it hard to create XML code or any "do it yourself" language that is very flexible. The Firemox XML code below has a "colors" property which simply states the color of the card. Usually a card's color is determined by its mana cost but there are a few cards like Transguild Courier that are the exception.

I would hate to have to create an XML schema for Magic cards because it would be a very hard task. It would literally take weeks if not months. I'm sure that many hours of work was spent creating Firemox's XML language.

p.s. When I use the phrase "in-between" or "do it yourself" language, I'm talking about a problem domain language that only applies to a specific problem, like controlling a robot.

Firemox - Royal Assassin
<card> 
<rules-author-comment>By fabdouglas</rules-author-comment>

<init>
<registers>
<register index="colorless" value="1"/>
<register index="black" value="2"/>
<register index="power" value="1"/>
<register index="toughness" value="1"/>
</registers>

<colors>black</colors>
<idcards>creature </idcards>
<properties>assassin</properties>
</init>

<abilities>
<ability ref="cast-spell"/>
<activated-ability playable="instant" name="" zone="play">
<cost>
<action ref="T"/>
<action ref="target-creature">
<test>
<in-zone zone="playANDtapped"/>
</test>
</action>
</cost>

<effects>
<action ref="destroy"/>
</effects>
</activated-ability>
</abilities>


Firemox - Shock
<card>
<rules-author-comment>riclas</rules-author-comment>

<init>
<registers>
<register index='red' value='1'/>
</registers>
<colors>red </colors>
<idcards>instant </idcards>
</init>

<abilities>
<activated-ability playable='this' name='' zone='hand'>
<cost>
<pay-mana value='manacost'/>
<action ref='target-dealtable'/>
</cost>

<effects>
<assign-damage value='2' type='damage-normal'/>
<action ref='finish-spell'/>
</effects>
</activated-ability>
</abilities>

</card>