Monday, September 20, 2010

Delaying Laterna Magica: Graduation Project

School has totally got me now. We spent last week in Carinthia and focused completely on the project. It was a great experience and we laid much of the foundation work. Today, we got even more long-term assignments, and my impression is that the difference to our graduation project is not the amount of work, but that the teachers don't give us as much time...

Okay, enough of that. What I really want to tell today is two things. Bad news are always first, so let's get it out of the way: I won't have much (if any) time to work on Laterna Magica in the near future.
And the reason is already the good news: I have a veeery interesting graduation project together with 3 colleagues: We're building and programming a robot to attend a robot competition in the USA.

Okay, to make my excitement clear, let's break this down:
We're building a robot
I think this is pretty clear. The competition consists of a few challenges, and the robot has to reflect these hardware-wise to show optimal performance. The challenges are presented at the end of October; an employee of the competiton's organization visits us personally, because we'd be the first team from Europe to attend.
We're programming a robot
This is probably the most interesting part of it. Our project is sponsored by TU Wien, Vienna's technical university, and our job is not just to program the robot, but to do so using a rule- and agent-based artificial intelligence.
  • Rule-based is basically a programming approach such as imperative or functional. It means to define a program in terms of condition-reaction pairs. It is supported by a framework which checks the conditions and execites the appropriate actions. While this might not seem spectacular, think about it: have you ever written or seen a program using this approach? Note that this is not another name for an event system; events also result in a reaction, but they only allow for reactions on one-time events (if some event happens), not to states (if some condition holds).
    Rule-based systems are good for modelling intelligent behavior. A human reacts to events because of the state-changes they cause, not the events themselves: If a window falls open, you close it because it's cold or loud outside, not because the window has opened.
  • Agent is just another word for actor. Remember how I wrote about the downloader; it's essentially the same. The only difference is that all this is now integrated into a rule system, which also changes the way how the agents exchange messages. Besides that, the concept of parallel processing stays. In our case, the focus lies on the independence of the actors to cooperatively reach a solution for a problem, and not on simpler multithreading by getting away from traditional synchronization.
  • Artificial intelligence always sounds good, but what does it really mean? Our parent project at TU Wien has a very specific goal: To build cooperative robots capable of disassembling Lego models. We won't get anywhere near disassembly, but the cooperation is still there, just in the software though. In the end, an artificial intelligence is always task-oriented, and the border where intelligence begins is not well-defined. The question is very interesting, but more philosiphical than technical, so maybe in a later post.
...to attend a robot competition in the USA
This is a goal we all really want to reach, but if we do will depend on how we perform. Our project is definitely complex, so if it doesn't work out too well, we won't go. I'm positive about it, though.
The competition we would attend is BotBall, organized by the KISS Institute of Practical Robotics, and we have the honor to be invited directly to the final "Global Conference of Educational Robotics", without attending any of the qualification tournaments. (I hope you can read from all this how proud I am^^)

So the last point to check for today is: This is definitely good news for me, but how is it for you? Well, I'll write about it, of course. Some things might be off-topic in terms of Magic, but artificial intelligence is definitely in, right? Be sure to check back in a few weeks, there are definitely interesting things to come!

Wednesday, September 8, 2010

Static and triggered abilities

Laterna Magica already supports some core functionalities of Magic, but there's still much left. I don't talk about discard and such things; these are effects that just need to be coded, and then they will be there; just a new flavor of an existing thing. I also don't talk about very complicated effects. All cards currently supported in Laterna Magica use the original oracle wording (with the exception that "draw three cards" must be changed into "draw 3 cards"), which won't be possible for all abilities, but such abilities are still not what I'm talking about.

I'm thinking about really new features, like static and triggered abilities, the ability to target, or text changing effects.
Text changing effects are just very hard; they kind of break my concept of "one template, many instances" for abilities: The printed wording can be shared between cards, just its interpretation, the rules meaning, is card-specific.
Targets are currently not my goal; I don't really want to do much UI at the moment, and this in inevitable with giving the player yet another possibility to make a choice.

That neatly leaves behind the two thing I already stated in the title, and they have one thing in common which currently gives me a headache: Scope of influence.

The scope of an ability means in what places and at what times it works. For spells and activated abilities it's comparable to legality, but the big difference is that the user initiates those abilities; static and triggered abilities are around at all times.

There are two ways to handle the situation:
  • keep all abilities at all times and ask them if they should apply on every single occasion
  • let the abilities themselves handle it; registering and unregistering using some events
I don't know why, but my initial though was to use the second. Both have good and bad points of course: The first can result in a performance problem, the second might break in strange corner cases.
A more obvious, but still realistic example is controller changes: Imagine you get control of a Glorious Anthem, but it still pumps your opponent's creatures.
But even the first approach has similar issues, namely abilities that didn't exist at the beginning of the game, for example on tokens or from Auras. If you register all abilities at the beginning of the game, those would be ignored.

If you expected a definitive solution here, I'm sorry. I don't have one. There's no right way to do anything, just several ways with different consequences.

Monday, September 6, 2010

Update

I was kindly brought to a windows incompatibility in my program, so I fixed this. Along with it came an update of the installation, which should make it much easier to update to future versions.

You can see the result here.

Saturday, September 4, 2010

First release!

This is only a short post, but one that makes me proud nonetheless.

This is the day where I put the first release version online. Don't expect too much; the basic rules including combat works, but there are currently nearly only vanilla creatures. Anyway, if you want to try it, or at least see what's there exactly, go to the forums and download it.

Tuesday, August 31, 2010

When you feel plainly dumb...

There are time when you work on a problem and nothing seems to help. You have checked everything, yet nothing works. And then you see the obvious answer. I had such a problem today. Until now, Laterna Magica only allowed you to pay costs in advance, first adding all the mana to the pool, then activating an ability or (more likely in LM) casting a spell.

The rules allow it, however, to play mana abilities while playing spells/abilities. So I wrote the code: A piece in the cost to ask the player for input, a piece in the player to handle the GUI. and it didn't work. Clicking on a card was just not recognized.

I first thought it could be that my legality checking code was not working while a spell is being cast, but I couldn't find any line in the code that even bothered about that. Next, I suspected that the asynchronous communication between game and GUI didn't work, and enabled a few debug statements, which in turn made clear that everything went like desired. So I thought to myself: where could I easily check if the action was successfully processed? Well, in the cost, where the player was asked in the first place.

But I never got to writing a debug statement; the bug was clear and simple: While I retrieved the activate action, I didn't execute it. These are the times when you feel plainly dumb...

Saturday, August 28, 2010

New Downloader

Besides working on combat, I played a little more with Jetlang and created a downloader, which works asynchronously and can inform interested listeners over PropertyChangeEvents.
Jetlang's concurrency approach is centered around the actors (who performs a task/where is it performed) and the tasks instead of around the data. Normal multithreading requires you to synchronize on the data you share, while an Actor framework doesn't share data but pass it around, so that only one thread "has" it at a time.
This makes it easier to code, because it is how humans think: You don't worry that two people will write on the same piece of paper at the same time; you wait until the piece of paper is passed to you. That said, it still needs a lot of thinking: Who are the people in your program, what's the piece of paper, and when should you pass it around?

Btw, I made a little comparison between the new downloader and the one used by forge (admittedly, in which I also had a great part).

Program           After 2 minutes  For 1500 images
Laterna Magica    1500 images       2:00 minutes
Forge              200 images      10:00 minutes

I looked at the code for Forge and checked if it is roughly comparable to mine, and it was; otherwise I wouldn't have posted this. I changed two things, however: I increased the buffer size to 8 kB to match Laterna Magica, and I removed a print statement. These are pretty slow and shouldn't be there when measuring time.

Laterna Magica's downloader uses 10 threads, which means that 10 pictures are downloaded at the same time. Even though it might seem at first that it shouldn't make much of a difference, because the total bandwidth stays the same, the numbers clearly say that download speed is five times better. The reason for that is the reduced overhead. Every picture needs the following steps to be done:
  1. Connect to the server
  2. Request the image
  3. Receive the data, store it into a file
The time is lost between step 2 and 3. The first two steps has you upload data (the request), the third has you download data. Between that is only waiting. When using only a single thread, this waiting directly influences the download speed, because nothing else happens in that time. Using multiple threads, waiting only blocks one of the threads, leaving 9 downloads running in the meantime.

Besides downloading card pictures, I adapted Laterna Editor to use the new downloader, which also shown its flexibility: Laterna Editor downloads HTML pages from Gatherer, but doesn't save them to files. Instead, it further processes them to compact card descriptions for Laterna Magica. While it took a little work, the downloader is not limited to Files but can download to any location, such as a string buffer in memory.

The card downloader from Laterna Editor also shows how the task-centric approach helps with programming. This picture pretty much describes how the download process works:


Both Source and Destination are classes implemented by CardDownloader, but implement interfaces specified by Downloader. The source checks if the URL is a search or a single card, and also handles the automatic redirect if Gatherer only finds a single card for a search. The destination saves the HTML page to a string and waits for the download to finish, by registering a property change listener to the download job. If the download was successful, it sends the page to the search- or card processor, depending on the source. If it wasn't, it just discards the downloaded page.
The search processor finds additional result pages (every page has at most 100 cards in the compact view, which is used by the downloader) and of course the individual cards. The download of those is again done by the same process. The search processor simply posts the DownloadJob to the downloader and that's it.
The card processor finds the individual fields like name and mana cost, and stores them into a card. Once that's done, it posts the card to a Channel where the Gui can find it and in turn show the editor.

Monday, August 23, 2010

Combat and concurrency

It was on July 15th when I titled a blog post "Combat in sight?", but now it really is. Today, I committed a version to my project where players can attack and thus deal damage. Blocking is not possible yet, but that's more a matter of work and not of thinking. Players still can't loose the game, but that's another story...

Now, for those of you not familiar with "concurrency" in programming, it means when multiple parts of a program run at the same time, "competing for the computer's resources" like CPU or RAM. Concurrency is hard for three reasons:
  • you have to control what happens when, because the classical "everything happens in a fixed sequence" is not true
  • speaking of "competing for resources", when two concurrent threads of execution access the same data, they can overwrite each other, messing things up
  • for this reason, locks and synchronizing have come up, which grant exclusive access to a resource to a single thread. This also means that threads have to wait for resources until they aren't locked any more. In the worst case, two threads can wait for each other.
Laterna Magica uses an approach that has two main threads; one for the game, and one for the user interface. While the UI thread is mandated by Java, I could have implemented LM to run on the same thread. The main reason I did not was to make LM independent of the GUI, meaning that the program can use different UIs and even run without a User Interface, say in a Computer-vs-Computer simulation or on a server (while the latter needs more preparation, I believe it will be possible someday).

So there are two threads, which means every GUI interaction means synchronization. The first GUI interaction implemented was playing cards and activating abilities. The code to enable that was pretty wordy and hardly extensible:


private boolean    ready;
private PlayAction a;

public GuiActor(Player player) {
    super(player);
} 
 
public synchronized void putAction(PlayAction a) {
    ready = true;
    this.a = a;
    notifyAll();
}

public synchronized PlayAction getAction() {
    ready = false;
    while(!ready)
        try {
            wait();
        } catch(InterruptedException ex) {
            ex.printStackTrace();
        }
    return a;
}

On the surface, it doesn't look that bad, but it has several issues:
  • It is low-level: It handles all the synchronization stuff itself, as seen by boolean ready, notifyAll(), synchronized, while(!ready) ... This is all stuff that has to be repeated for every sort of user input: declare attacker, blocker, ...
  • It moves control away from the actor: putAction takes a PlayAction, which is the result of e.g. clicking on a card. How that click is associated to the PlayAction is not controlled by the actor which violates atomicity
    • Translating click to PlayAction is specific to playing spells and not compatible with e.g. declaring attackers. This means that the translation, which is not atomic, has to be performed for every type of input
  • Missing Encapsulation: The interpretation as a PlayAction is only valid when the player has priority, and this fact is not represented here: There is no representation of the fact whether the Actor is waiting for a PlayAction or for declaring an attacker
On the opposite, here is the new variant:

public class GuiMagicActor extends AbstractMagicActor {
    public final GuiChannels    channels = new GuiChannels();
   

    private static T getValue(Fiber f, Channel ch, GuiActor a) {
        a.start();
        log.debug("Waiting for result...");
        T result = Parallel.getValue(f, ch);
        log.debug("received!");
        a.dispose();
        return result;
    }
   
    public PlayAction getAction() {
        return getValue(channels.fiber, channels.actions, new ActionActor(this));
    }

    
    ...
}

This new version is based on the Jetlang concurrency framework, which works using channels and callbacks: Messages published to a channel are - asynchronously - forwarded to registered callbacks, which may then in turn publish new messages. The Parallel.getValue() method is used to get a value back from the channel synchonously, and the ActionActor encapsulates the state, in this case choosing a PlayAction to perform:

public class GuiChannels {
    /**
     * Channel for receiving {@link PlayAction}s to execute when the player has priority
     */
    public final Channel  actions      = new MemoryChannel();
   
    /**
     * Channel for publishing {@link MagicObject}s when the user clicks on them
     */
    public final Channel objects      = new MemoryChannel();
   
    /**
     * Channel for publishing {@link Player}s when the user clicks on them
     */
    public final Channel      players      = new MemoryChannel();
   
    /**
     * Channel for publishing when the user clicks "pass priority"
     */
    public final Channel        passPriority = new MemoryChannel();
   
    public final Fiber                fiber;
   
    public GuiChannels() {
        PoolFiberFactory f = new PoolFiberFactory(Executors.newCachedThreadPool());
        fiber = start(f.create());
    }
   
    private Fiber start(Fiber f) {
        f.start();
        return f;
    }
}


public class ActionActor extends GuiActor {
    public ActionActor(GuiMagicActor actor) {
        super(actor);
    }
   
    @Override
    public void start() {
        disposables.add(actor.channels.objects.subscribe(actor.channels.fiber, new CardCallback()));
        disposables.add(actor.channels.passPriority.subscribe(actor.channels.fiber, new PassPriorityCallback()));
    }
   
    private class CardCallback implements Callback {
        @Override
        public void onMessage(MagicObject c) {
            log.debug("Received: " + c);
            PlayAction a = GuiUtil.getActionOptional(actor.getPlayer(), c);
            if(a != null) actor.channels.actions.publish(a);
        }
    }
   
    private class PassPriorityCallback implements Callback {
        @Override
        public void onMessage(Void v) {
            log.debug("Received pass priority");
            actor.channels.actions.publish(null);
        }
    }
}
 

The ActionActor receives Messages through the objects and passPriority channels and reacts specific to its task.

Hope you liked it!