Fuse Day, Scala & Battle Snake!

his Fuse Day, the Java group was concentrating on Akka for creating highly concurrent and scalable code. A multiplayer online game was selected as an interesting and fun mini-project for the day, and the Typesafe stack of the Play Framework, Akka and Scala/Java was the main focus of development. As I felt some people would be interested in the Scala side of things but have never tried it before, I suggested creating a sub-group that would only deal with Scala, and leave Akka for those more versed in the language or using Java instead.

In preparation for the Fuse Day, I conducted a preliminary crash course in Scala that consisted of three concentrated hours, where I gave a rough presentation of what Scala is, what the basic syntax looks like, and also a few tricks such as Stackable Modification Traits.

In preparation for the Fuse Day, The other group leaders and I tried to establish the API by which the different groups would communicate. This was especially important for the integration between the Java/Scala sub-groups, since we didn't want the Java sub-group to have to install Scala as part of their stack to get the whole thing to compile. Naturally, then, we ended up creating the API on the day itself.

The chosen multiplayer game was Battle Snake! - a classic snake game, where each player would have his own snake on the board, and would try to get the other players' snakes killed by making them bumping into its tail, the walls or other snakes. The rest of the game rules would be the same as the well-known game, we said, which later on spurred some debate on what those rules actually were.

To begin with, in an effort to spare the Java sub-group from the oh-so-terrible Scala dependancy, we set out to implement the model objects in Java, so we could then use them in our Scala code. This yielded a few classes such as Board, Snake, Fruit and Wall. Each of these were POJOs with your run of the mill fields, setters and getters, implementing an interface we called BoardElement. The Snake was comprised of a head and a tail, each of which was a Point, where the tail was comprised of BodyElements, each a single point on the board, pointing to the previous tail part. The Snake also held an enum value - Direction - which pointed to the direction in which the snake was advancing.

When starting to build the Scala code, it was immediately apparent to me that Java programmers tend to try to write Java using Scala. This leads to code that is much less concise and more messy than it had to have been, since Scala provides us with some interesting ways of changing the syntactic representation of our code without changing the semantics, but making the code more readable. Even things like unnecessary semicolons took a while to root out.

After a bit of code wrangling, we came up with a few cool things. Nested fors became a single for with multiple Ranges:

for (x <- 0 until boardWidth; y <- 0 until boardHeight) {


      board.put(new Point(0,y),wall)
      board.put(new Point(x,0),wall)
      board.put(new Point(boardWidth-1,y),wall)
      board.put(new Point(x,boardHeight-1),wall)
}

In this loop, the x and y variables are both initialized to the board height and width (the board is square), and wall points are created at the edges. The until keyword seen between the zero and the board width or height is not a keyword at all, but a function. Scala allows a function to be invoked in either form - a.func(b) or a func b. The latter provides a way to create natural looking DSLs without the noise of the supporting language. The until function creates a Range object with values ranging from the left operand to the right operand not inclusive.

When developing the snake advancement algorithm, it was necessary to move the head point to the next point on the board, in the direction pointed by the Direction enum value. This started out as some nasty code:

if (dir == Direction.UP) nextPoint = new Point(head.x, head.y - 1)
if (dir == 
Direction.LEFT) nextPoint = new Point(head.x - 1, head.y)
...

This quickly changed to use match instead:

dir match {

    case Direction.LEFT => new Point(point.getX - 1, point.getY)
    case Direction.RIGHT => new Point(point.getX + 1, point.getY)
    case Direction.UP => new Point(point.getX, point.getY - 1)
    case Direction.DOWN => new Point(point.getX, point.getY + 1)
    case _ => point
}

But still I thought the code could be a lot better. I decided that what I wanted to get to is to be able to write:

point = point + direction

This lead to a few more interesting Scala features. First, to be able to write point + direction, I would have to write a function named +. Scala provides a much more flexible function naming scheme than Java, to the point where method invocation looks like operator overloading. However, there is no operator overloading here, no special syntax, no special keywords like operator. Just plain old function definition. Defining the function + then, would look like this:

 def +(dir: Direction): Point = {


    dir match {
      case Direction.LEFT => new Point(point.getX - 1, point.getY)
      case Direction.RIGHT => new Point(point.getX + 1, point.getY)
      case Direction.UP => new Point(point.getX, point.getY - 1)
      case Direction.DOWN => new Point(point.getX, point.getY + 1)
      case _ => point
    }
}

Since Scala allows method invocations that have a single parameter to be formatted as a op b instead of a.op(b), our code would now look like we wanted it to. There's just one little problem. We can't add the plus method to the Point class, since it was defined in the Java code!
Scala comes to our rescue once again, with Implicit Conversions. This mechanism allows us to provide a conversion function from one object to another, if an operation is missing on the object on which the method is invoked. In other words, if a.b() doesn't exist, Scala will look for a conversion to some class C, where c.b() does exist, and will invoke it instead. We defined a class called PointOps (like Scala's StringOps) which now contains the plus function and the implicit conversion:

 class PointOps(val point: Point) {


  def +(dir: Direction): Point = {
    dir match {
      case Direction.LEFT => new Point(point.getX - 1, point.getY)
      case Direction.RIGHT => new Point(point.getX + 1, point.getY)
      case Direction.UP => new Point(point.getX, point.getY - 1)
      case Direction.DOWN => new Point(point.getX, point.getY + 1)
      case _ => point
    }
  }
}
 
object PointOps{
  implicit def pointToPointOps(value: Point): PointOps = new PointOps(value)
}

Towards the end of the Fuse Day, it was apparrent that the integration with the Akka sub-groups wouldn't happen, as we were running out of time. All in all, I believe that getting our hands dirty in some Scala code opened up some interesting prospects of its usage for most people. Personally, I'm going to delve further on into Scala and try to find out just how powerful this language is.

Thank you for your interest!

We will contact you as soon as possible.

Send us a message

Oops, something went wrong
Please try again or contact us by email at info@tikalk.com