Monday, June 9, 2008

Programming Hybrid Mana

I have talked about programming normal mana costs (2WW), but Shadowmoor features new, unusual costs like (2/B), you may pay 2 of any mana or B. Shadowmoor also brings back hybrid costs like (G/B), you may pay G or B. The reason I mention all of this, is because these new costs mean more programming (which isn’t necessarily a bad thing).

I have done some additional programming and the good news is that I can process all mana costs that Wizards has ever printed, except for the weird snow mana that Coldsnap introduced. I wanted to talk about the logic that my code uses.

Everything came together when I started thinking about dividing the mana cost into smaller parts. So “2WW” would have the parts: 2, W, W. Each individual part would know what kind of mana it needed. So the object ManaPart would have a only a few methods as shown below. The method needsMana() returns true if that mana is needed. The object ManaPart greatly simplifies the task of programming X and hybrid costs.

ManaPart
addMana(String mana)
needsMana(String) : boolean
isPaid() : boolean
toString() : String

But wait!! I haven’t shown you the magic yet. Each ManaPart object also has a method named correctManaPart(String part) that returns either true or false. This method answers the question “Does this object handle this kind of mana?” So the ManaPart that handles X costs always handles the X regardless of the rest of the cost. So I could easily handle snow mana, because it would involve just adding a new ManaPart.

I’m going to try to describe the pseudocode below. TotalManaCost is given a cost like 2WW creates the correct ManaPart for each part. In this example, the parts are “2”, “W”, and “W” so three ManaPart objects are created.
TotalManaCost.setCost(String cost):

#first divide “2 W W”, into 2, W, W
split cost into parts
for p in parts:
for m in (all manaParts):
if m.correctCost(p)
totalCost.add(create ManaPart(p))


method addMana(String mana):
#loop through to see which ManaPart needs mana
#manaPart is a list (array)
for z in manaPart:
if z.isNeeded(mana):
z.addMana(mana)
return
I know that reading the pseudo-code helps understand the overall process but seeing the actual code really helps. The method for addMana() was pasted from the actual source code.

Download Python Code – I’ll explain it in more detail in my next post.

4 comments:

Trick said...

This is really fascinating stuff, the idea of a computer reliably playing the entirety of Magic is something that has always piqued my interest. I remember the days of playing Shandalar :)

ecanimater@aol.com said...

Hmm... for the hybrid cards you could make invisible ability you can pay color2 instead of color1 when playing this card, and hybrid [2 or color], replace color2 with 2 colorless

A practical solution for snow land is make snow covered lands produce snow or lands type :)
however i dont know it making another color would make it real hard on you
dual lands can be made with the abilities
tap: manacolor 1
tap: manacolor 2

I know almost nothin about programming, but i'm another full of ideas :]. i dont mean to annoy you at all, but to help you create the next version of the game easier

Forge said...

Well I like excitement :)

Programming snow mana would be easy, I would use the letter S in the cost.

I could have gone the easy route and not programmed hybrid mana at all. I could have just let the user select which cost they would play. Like if the card cost (G/W) the user would select G or W and then tap the appriopriate land.

Forge said...

The computer AI is still pretty basic but it will slowly get better. (Not that the computer is learning, but I programming improvements as I see them.)