Sunday, May 9, 2010

Implementing some cards

Okay, I think I've spent enough time on how abilities work in my problem, but it's definitely easier when viewing some real cards.

In reality, I haven't done much of the work yet that would make making cards interesting - no targeting, no damage, no destruction or sacrificing - it's essentially creating and spending mana right now.

Before I come to the interesting cards which can't be done yet, I'll show you what already works in this post. I have done a simple parser for cards. In fact, it's quite extensible and can be configured to plug-in different file formats. The only file format by now is a plain text format, for which in turn different line-parsers can be plugged in.

And now to the cards:

name    Forest
super   basic
type    land - forest

The basic land types have the mana producing ability implied, which are also parsed as any other mana ability. I'm not sure how this will work with adding and removing basic land types, but it's like that for now.

name    Graven Cairns
type    land
text    {T}: Add {1} to your mana pool.
text    {B/R}, {T}: Add {B}{B} to your mana pool.
text    {B/R}, {T}: Add {B}{R} to your mana pool.
text    {B/R}, {T}: Add {R}{R} to your mana pool.

Right now, there are only activated abilities. Costs and Effect are parsed separately, and every cost is parsed on its own. By now, any combination of mana costs and Tap or untap costs are working. The only Effect is "Add ... to your mana pool." Things like "{B}{B}, {B}{R} or {R}{R}" are not possible by now, neither are hybrid symbols (they only work for costs), so I write it as three abilities.

name    Dryad Arbor
color   green
type    land - forest
type    creature - dryad
pt      1/1
text    (Dryad Arbor isn't a spell, it's affected by summoning sickness, and it has "{T}: Add {G} to your mana pool.")
text    Dryad Arbor is green.

Here you can see that every type is specified on its own line only with its corresponding subtypes. The two "text" lines here are actually nonfunctional. The "Dryad Arbor is green." Ability is actually implemented by the "color" line, and the mana ability comes from the forest subtype.

Wednesday, May 5, 2010

Implementing activated abilities: Divide and conquer

Last time, I showed the technical concept behind abilities (and spells) in Laterna. Today, I want to explain the PlayInformation interface from another perspective.

I hope I have given a good impression of why I use the approach I do: Abilities using a function to create PlayInformation objects which do the work. But why is PlayInformation so "big"? Why does it do all the work from paying costs over targeting to dispatching the effect?

The reason is a simple one: Because it's easier this way. Imagine a "complex" ability: "{X}: ~ Deals X damage to target creature." What this means is that the variable X is mentioned in both cost and effect, as most of the time, and this gives two possibilities:
  • Make Cost and Effect both interfaces and define some kind of communication, likely using another object between them, or
  • only use that object from "in between" and make the communication between cost and effect an implementation detail.
The process of playing a spell/ability is a complex one, and putting it into a single class enables more compact code to be written for individual abilities.

Now there's only the question from last time left: How can I still define cost and effect separately, giving me the ability to reuse them?

Delegation is a key concept in OO programming: If a class gets too big, try to find some separated piece of work that it does, and transfer it to a new class. Then, let the original class use the new one. An example in LaternaMagica is the CardCharacteristics class: Cards have characteristics that can modified by various effects. But instead of implementing the characteristics in the MagicObject class, every MagicObject object has a CardCharacteristics object. That does this work.

In that case, it's defined in the interface. With PlayAbility, it isn't. It's an implementation detail of AbstractPlayInformation, which implements PlayInformation. The AbstractPlayInformation class allows you to combine multiple PlayInformation objects into a single, big PlayInformation that carries out your instructions in order.
If you have a cantrip spell, just add in a DrawCardInformation at the end!
If you have a complicated activated ability, implement the effect, but use standard cost Informations and combine them with the AbstractPlayInformation.

Oh, and don't forget to add an information that removes the spell/ability from the stack...

Saturday, May 1, 2010

Implementing activated abilities: Getting the effect to the game

There are two paragraphs in my previous post that I want to further examine:
  • ActivatedAbility has a method getPlayInformation() which takes an ActivateAction and returns a PlayInformation.
  • The PlayInformation is the real worker of abilities and implements modes, targeting, costs, effects etc. It depends on the game, so an activated ability can only create the PlayInformation if a game is provided.
First, let me show you the ActivatedAbility and PlayInformation interfaces, so you can see what I'm talking about:

public interface ActivatedAbility extends NonStaticAbility {
    public boolean isLegal(ActivateAction a);
  
    public PlayInformation getPlayInformation(ActivateAction a);
   
    //inherited from NonStaticAbility
    //public boolean isManaAbility();
}

public interface PlayInformation extends GameContent {
    /**
     * Returns the action that is used in playing.
     */
    public PlayAction getAction();
  
    /**
     * Returns the object that was played using this play information.
     */
    public MagicObject getObject();
  
    public void makeChoices();
  
    public void chooseTargets();
  
    public void distributeEffect();
  
    /**
     * This action is only defined for activated abilities and spells, but not for triggered abilities.
     */
    public GameAction getCost();
  
    public GameAction getEffect();
   
    //inherited from GameContent
    //public Game getGame();
}


As you can see, the Activated ability interface is pretty small; its job is primarily to create PlayInformation objects. PlayInformation does the whole work.

This means especially two things:
  • Although it would seem intuitive, to make a new activated ability, you don't implement ActivatedAbility but PlayInformation. This may be confusing for the first time, but you can get used to it. But:
  • You still have to implement the getPlayInformation() method to return your new PlayInformation. And this is what really bugged me. An ActivatedAbility class would usually exactly follow a template, and only replace the PlayInformation.
So I thought about what I could do to save me from creating all these redundant classes. The first step was to extract the job "create a PlayInformation for an ActivateAction" out of the ActivatedAbility class. As luck would have it, the Google Collect API, which I was already using, has the right interface for that: Function (simplified):

public interface Function<F, T> {
    T apply(F from);
}


Which led me to the ActivatedAbilityImpl class:

public class ActivatedAbilityImpl extends NonStaticAbilityImpl implements ActivatedAbility {
    private static final long                                           serialVersionUID = -8987886570576715112L;
   
    private Function<? super ActivateAction, ? extends PlayInformation> object;
    private Predicate<? super ActivateAction>                           legal;
   
    public ActivatedAbilityImpl(boolean manaAbility, Function<? super ActivateAction, ? extends PlayInformation> object, Predicate<? super ActivateAction> legal, String text) {
        super(manaAbility, text);
        this.object = object;
        this.legal = legal;
    }
   
    /**
     * Returns if casting the spell using the specified CastAction is legal.
     */
    @Override
    public boolean isLegal(ActivateAction a) {
        return legal.apply(a);
    }
   
   
    @Override
    public PlayInformation getPlayInformation(ActivateAction a) {
        return object.apply(a);
    }
}


(Predicate is also from Google Collect and represents a true/false decision about an object)

But that step doesn't really solve the problem. Now I don't have to implement ActivatedAbility, but instead Function. The real solution only came when diving deep into Java's pool of features: Reflection. Reflection means to analyze a program's parts, like, classes, methods, constructors and so on while it's running. So my idea was to make a Function which creates a new object of any class you want:

class B {
    public B(A a) {}
}

Function<A, B> f = new MyFunction<A, B>(A.class, B.class);
B b = f.apply(new A());


...and creating a new class has transformed into creating an object! However, there is still a problem: what if your PlayInformation needs configuration? Your PlayInformation might Implement the ability "<mana cost>: Tap target permanent." How do you set the mana cost? The ActivateAction, which is the function's input, can't provide it. What you need is a per-function configuration in addition to the per-apply parameter:

class B {
    public B(C c, A a) {}
}

C config = new C();
Function<A, B> f = new MyFunction<A, B, C>(C.class, config, A.class, B.class);
B b = f.apply(new A());
//b is equal to
//new B(config, new A());


And that's exactly how I ended up, and I'm quite satisfied with my work. You can look at the source code at FactoryFunction.java.

And the last note for today: PlayInformation has many things to do, among them providing the ability's (or spell's, PlayInformation is used for both) cost and effect. By Implementing both in the same class, you take yourself the opportunity to reuse costs in other abilities. Next time, I'll show you how to mix-and-match these.

Thursday, April 29, 2010

Cards - Two views on the same thing

I would really like to know if you can imagine of what two views I'm going to talk about. I guess it's more obvious for people who have thought about how to structure a magic application. If you like, leave a comment and state what's your background.

When you open a booster pack, how do you read cards? They have symbols and text, and of course you can read them and determine what they do. However, the card can't do anything, because you're not playing a game.
During a game, the card has a complex context that influences how you read it; For example, its color may have changed.

Humans can read a card outside the game and inside the game, but it's hard for a computer. The difference between these two views is very important and currently makes me some problems. A card outside the game (template), like the one from the booster, is a constant thing - it can't change between different copies. This means that multipe cards inside the game can share the same template, but those are then individuals. They have the same template, but that's it.
The same thought can be applied to abilities and spells, I think. Abilities and spells have another, even harder problem: Their effects. While cards just sit there, spells and abilities can directly influence the game, and what influence that is depends on how the spell/ability was played.

So what's the solution to the problem? Well, in a nutshell, the data structure for cards, spells and abilities is duplicated.

Outside of the game is CardTemplate and CardParts, inside the game is CardObject and CardCharacteristics. A CardCharacteristics is assigned to a CardObject is responsible for providing the characteristics, respecting effects and the layer system, but also taking into account the values "printed" on a CardParts object.

Outside the game is ActivatedAbility, inside the game is ActivateAction, PlayInformation and AbilityObject.
  • ActivatedAbility has a method getPlayInformation() which takes an ActivateAction and returns a PlayInformation.
  • The PlayInformation is the real worker of abilities and implements modes, targeting, costs, effects etc. It depends on the game, so an activated ability can only create the PlayInformation if a game is provided.
  • And to make things easier, the activate action has some additional infos like who played the ability and what card the ability is on (like I said, ActivatedAbility is outside the game, so it doesn't know which cards it is on. the ActivateAction knows).
All that happens under the surface. The ActivateAction retrieves the PlayInformation and does all the necessary things, like putting an AbilityObject onto the stack etc.

I hope that you had a chance to look into my program; I know that this is very hard to imagine without directly looking at the code, So I won't try to go into more detail unless you wish so ;)

Monday, April 26, 2010

Hardcoded vs Softcoded

From a user's perspective, a program's job is to do work, look good etc. If you want to look into a program, and very deep into it, you will notice that all a program does is to move data around. Data and code are two very important things in programming, because the code does the work, and only with data there is work.

But the borders can become unclear when you think of it. Data and code do both lie on your hard disk, or in memory when a program runs, so where's the difference? Well, code is data that represents some kind of work.

Magic is all about doing work. "You lose one life" is a piece of work. After the work is done, I might have lost the game. Still, I wouldn't like to have that effect around in my code - in my Java code, at least.

Hardcoding and softcoding is all about how work is represented.
Hardcoding essentially means "compiled". For example, the five colors and the card types are hardcoded into laterna - to change one, you need the source files and a Java compiler to generate a runnable program from it once again.
Softcoding, on the other hand, means "interpreted". "You lose one life", which might be a spell's effect, could be written in a text file. That file is read when the program is started, and will do its work, although it never was java code.

So softcoding is the better way to do work in all situations? Clearly no. Enabling something to be softcoded needs massive effort. Not only do you need to parse the file and get the important information from it, you also need to translate it into a form the program can handle. For Magic cards, this is very complex, since the work is done much later than the card is read, And a card might do different things everytime you use it. I'll talk about it in more detail the next time.

Monday, April 19, 2010

Spells

I fear that my blog evolves into a redundant commit log of my project, but I really try to write interesting and original.

First, let me say I'm steadily making progress. Now there's a mana pool and you can play mana abilities. Lands do untap and mana is removed properly. I have Llanowar Elves, my first nonland card, which you can play. It's put on the stack and then resolves. You don't pay costs for it yet...

And that's exactly my topic: What does it take to play a spell? There are several reasons why I started with lands, but the most important is that playing a land is a relatively simple thing: "To play a land, a player puts that land onto the battlefield from the zone it was in".

Playing a land is a single line in a Subpoint of the Subpoint 114.2a of "Special Actions" in the comprehensive rules. "Casting Spells" is Section 601, and 601.2 describes the steps necessary to do so, a to h, each one much longer than 114.2a.

The best known steps for playing spells are choosing targets and paying costs. Targets are a somewhat advanced, and I will rest a little before implementing them, but costs are a really essential part. The hard part is not costs per se, but paying them. Just for paying a mana cost, the player must choose how to pay for hybrid or variable symbols and then choose which mana to use.

Now that I know that playing spells works in general, I can try to fill in the details. When I have costs, and can therefore play simple spells rules-compliant, I might take a break to do some cards, improve the GUI, or implement combat... And swoosh! A game isn't that far away any more!

PS: There's one cost working already: The tap cost ;)

Sunday, April 11, 2010

Finally...

I'm glad to announce the first "playable" version of Laterna Magica. Features:
  • A rather simple GUI
  • Drawing a card during your draw step
  • Playing Lands
  • An opponent who does... nothing
Before I present you some screenshots, let me explain the "glue" I've talked about the last time, especially the controller.

The class Player in laterna magica is more or less a data structure and can only perform tasks that don't need decisions - like loosing life, drawing a card or discarding a card at random.
Discarding a chosen card is different, because it needs knowledge, which is something the Player class should not have. Different players make different decisions, and in different ways.

The solution is the Actor class. Whenever some decision is needed, like which card to discard, the actor is asked for that decision. The actor may implement an AI algorithm for choosing, it may get the choice over the network, or, most naturally, depend on user input from the GUI.

Although separating actor from player was a clear choice for me, I don't know how that class will look in the end. Magic is a game with tons of choices - there's not only "discard a card" but also "discard two cards", "discard a creature card", "discard a card of each color"... you know what I mean, this can quickly get messy.
For now, there's basically only "You have priority. What do you want to do?", so that problem is still far away.


And now screenies! When you start the program, you get a GUI with an empty board, like this:

But it doesn't stay for long, it will quickly populate your game with cards. You can watch how your library grows and you draw cards!
After passing priority twice, It will be your main, and you can play one of your (many) Plains:
Looks great? Look at that, during your next turn, you can do it again^^
What you have just seen demonstrates some important things:
  • Laterna Magica has many events. Playing a land doesn't explicitly remove it from the panel. Instead, the panel listens for cards entering/exiting the zone (and later also controller changes) to keep track of what cards are to be shown. When the land is played, the rules engine moves it, and the GUI listens to the rules engine. Similar things are true for the zone size labels, the life total labels and the turn progress label.
  • And because swing supports it, the game loop (passing priority back and forth, basically) can run in an extra thread. Whenever the player "freak" has priority, the GameLoop queries the Actor for what to do. That actor is a GuiActor and waits for the user to either click "Pass priority" or a Plains card. Therefore, the GUI thread is not blocked when the game loop is working.
  • The GUI has a utility for finding all the actions possible for clicking a card. Currently, there's only playing a land, but it will also check for playing spells or activated abilities, unmorphing etc. in the future. That Utility also checks if the action is legal (timing, only one land per turn etc.)
  • what aparently doesn't work is discarding excess cards at end of turn. While it's easy, I've chosen to show you what I have as soon as drawing and playing a land works.
  • If you would click yourself all the way through until a library is empty, you would notice that the game doesn't end with that. Although the state based action does exist, the loseGame() method of player is a No-Op.
okay, enough for now. Have fun playing some real games ;)