Sunday, October 23, 2011

A "snaky" tribute to Stuart in Scala with Akka

Hello again.

Today a little bit of Scala. My Clojure current algorithm not being complete, I found myself with the same recurring dilemma. What am I going to talk about? This is a commitment in trying to understand, then expose a little subject, whatever it is, so to learn how to transfer ideas.

The subject came to me while reading Stuart Halloway book, programming Clojure. Nice book, full of interesting exercises. One of the exercises aims to picture some very amusing use of STM (aka Software Transactional Memory) in the form of a simple Snake game.
A very entertaining part and potentially a nice code kata. One must steer a moving snake in a rectangular area. Some Apple(s) is(are) dispatched in the game area while the snake is rambling. The purpose is to catch apples in order to make the snake grow. One can control the snake using the arrow keys. Once the snake has grown enough you win. But beware the head of the snake must never hit the snakes body .
Simple.
Although I do not play game, programming Stuart Halloway example was quite fun and the game may be in implementing the solution. Stuart Halloway presents a nice simple architecture separating the purely functional aspect from the mutable state and the GUI.
The mutable part of the game can evolve in three ways

A game can be reset to its initial state.

Every turn, the snake updates its position. If it eats an apple, a new apple

is placed.

A snake can turn.

My (small !!) Scala brain started yelling : "God, You can do that in Scala" with actors. The game state can be managed by some actor that can reinforce the serialisation of the change. My Scala mind tortures me enough, so I do not want to upset her....but let spice the idea with some Akka.

Having not found a pet project yet in Scala and no Scala Master for guidance, this is the only opportunity I have to bring Akka into the game (may I say). Naturally, I would not recommand using Akka in order to program a little game, the Scala genuine actors being self sufficient in order to manage this kind of implementation.
In the large set of Akka modules we can also find a STM module, and I will not resist in using it.
Before starting, I provide here the sbtbuild.scala project content, sbt being a nice tool, not always very easy to start with:

Why not following Stuart Halloway path in reusing idioms from the language? Scala being a multi-paradigm language, we could use actors of course, and object oriented approach, colored by some functional treatment into the pattern matching implemented in the actors' bodies .

I wanted the stuff to be simple. The approach can be resumed by the following scheme:

The global state lays into an Entities Actor in charge of handling all events incoming from the graphic interface. I voluntarily split the Game board (a swing panel) from the entities actor using a second actor called a board driver.The board driver plays the part of a single access point to the game board, both sending and receiving events in coordination with the entities actor.
The entities actor will send notification concerning the model update to the board driver while the board driver will send direction update notifications and refresh notifications.
Basically, a timer will issue the periodic update to the board driver that will convert it into some actor message.
No big stuff.

Like Stuart Halloway we need useful tools in order to help us swapping from the model world to the screen world. First of all, the Game world must be described by abstractions like positions , dimensions etc... For the sake of simplicity, I introduced the following tool class:

where a position into our small universe can be pointed out by a WorldLocation.
The randomLocation method provides us a simple mean to pop an apple in a different location on need. The + operation has been implemented in order to provide more fluent expressions during WorldLocation manipulations. winLength defines the size a snake must grow up to in order for the player to win the game Describing a small universe serves no purpose unitl we convert our desription into a screen world language.

Here comes the GraphConverters object, very helpful when dealing with transformations from model to screen:

A scale factor of value 10 will provide a visible graphical panel surface delimited by a 750 * 1000 rectangle. The diplayPointFrom method takes in charge the basic conversion processe from the game World to the screen World, so it will be reused from the converted methods in charge of handling simple coordinates or list of coordinates.

Nice. The game started. We need a entities actor managing our entities. The entities are classified in two sub classes definitions: a snake and an apple. So two object abstractions:

I found case classes to be natural implementations of board entities
Some of you, dear pals, are going to yell at me. Yes, the Snake entity is a real object, taking in charge its own growth, like a real adult snake, being capable of changing its direction on demand etc...Or does it. As a matter of fact snake instances are immutable, so real "value objects". Every object invocation consists in a pure read access, like head position or leads to the creation of a new snake like moved, grown or go. Can it be more functional ? The location of the methods into the snake definition serves a modular purpose only.
Precisely the methods purpose:

method

purpose

go

change direction

moved

change snake position

grown

grow snake

ahead

provides next location of head

head

location of head

We have our two objects.

Good, we need an actor behavior to manage the transformations induced by the incoming events. An akka actor receives its event notifications via the ...receive method:

If the snake eats the apple, in essence , if the the snake head meets the apple location, then a new apple is re-created and the snake grown.
If coincidentally the snake head location meets the snake body, the game is lost, so restarted after notifying the main game board (Game.displayMessage)

If hopefully the size of the snake is enough the game is won, so restarted after notifying the main game board (Game.displayMessage)

...else we move the snake in its current direction.

So suitable is pattern matching dealing with our update !!

The Updated message, wraps around locations only and not entities that do belong to the model world.
And that's all. Our model is safe, thanks to a containing actor:

We provided a companion object to the actor in order to simplify both creation and start of the actor. A reset action is fired while instantiating the actor.
The second part concerns the board and its driver.

There, we fall into Scala Swing. The Game extends the standard SimpleSwingApplication while gathering the three elements:

Call me a nit-picker if you want, but I did not want the display to know about the driver, although they do lay into the same Game class (making my own bakery of doom ?). So notification of key pressure is blindly fired through a function closing onto the driver.

The board by itself (not my favorite part), embeds some DSL's from the the Scala Swing layers:

As of Scala Swing the listenTo(keys) and reactions += {...} expressions elegantly set the environment as key event listener. We just added the constructor handle method to the list of reactions to be fired on key press event reception.

The apply method provides us with an idiomatic way to drive the panel repaint from the board driver. The apply methods receives ScreenLocation infornation immediately converted into a closure that will be invoked during the next paint action, issued from the repaint invocation. As a matter of fact I don't like the idea of storing a reference to the closure on a variable, although the driver board is an actor so serialises its incoming events treatment.

The board driver implementation remains very simple as a single entry point. Its purpose being only the translation of timer/user inputs into actor messages and actor messages into actions onto the main board:

As in all actors, the main purpose is implemented into its receive method.
An incoming Updated message implies the invocation of the board after conversion of WorldLocation abstractions into ScreenLocation abstraction.
The reception of a KeyPressed message will fire an update order to the entities model and finally a show message will display the dialog box.

The periodic timer is started into the Game definition. Here it is at the bottom of the whole Game class definition:

One minute pals. Didn't I promise for a STM implementation ? Well, the Game, its board and board drivers remaining almost unchanged, the stuff that do really changes is the Entities class. No more actor involved in this template.

The global state of game, consisting in a snake and an apple will be updated atomically in one transaction. The code will look familiar to Clojure developers. And it is, quoting Jonas Boner, "Refs (transactional references) are mutable references to values and through the STM allow the safe sharing of mutable data. Refs separate identity from value."

A transaction is delimited using the atomic keyword. The snake and apple definitions remaining the same, the snake and apple object "values" will be identified by two immutable reference fields:

The updatePositions method implementation makes use of the atomic keyword, using then the get/set methods of references in order to modify the references value. Invoked from the Game, the updateSnakeDirection method uses the alternate alter method which accepts a function that takes the old value while creating a new value of the same type, still in the scope of a transaction.

We used a closure for the purpose of our implementation. The reset method is made private as being exclusively invoked from an atomic scope.
Coming back to the Game class, we provide a version very close to the previous one:

Okay the game's very simple, the boundary positions are not controlled, but the kata is worth while. Thank you Stuart Halloway. Must go to fix my next blog code...in Clojure this time. Very strange bug indeed.