Yesterday was the Global Day of CodeRetreat. Software engineers around the globe met together to learn from each other.

CR2012 1

There were several sessions where people were pair-programming Conway’s Game of Life.

CR2012 2

Each session you had to choose a new partner, so that both of you can learn something new.

CR2012 3

During the first session my partner and I decided to implement the Game in Java, mainly because it was the language she was most comfortable with. We implemented the procedural solution using two-dimensional array and nested loops. At that moment that was the only solution I could think of. The main challenge was to cover all edge cases and fix all ArrayIndexOutOfBoundsExceptions. Java is fairly verbose language, and with nested loops and if-else statements the final solution was pretty hard to read. You can see here how it might look like.

First session was a warmup, during which most people realized that programming arrays is a tedious work. For the second session my new partner suggested an object-oriented approach, where you would operate on Cell objects that would encapsulate coordinates on the grid. In this case you move the game logic from the grid to the cell, making it easier to calculate a new state. This was my first acquaintance with C#. Interesting language — basically, Java with lambdas. Here is an example of C# implementation. Our solution was very similar.

While the first session’s data structure was array of booleans, on the second session it was replaced by a list of objects. The next step would be to relax the data structure even further. We decided to experiment with un-ordered set of coordinate pairs. For language we chose Clojure. Although we didn’t finish the implementation, by the end of the session we had a clear picture how to solve the problem in functional style.

On the fourth session the facilitators put an interesting constraint: the coding must be done in absolute silence. That was the most amazing experience of the day. Before we started I thought we couldn’t accomplish much without talking. As it turned out, we could. The key of effective silent coding is to use the tools which both partners are familiar with. In our case we both were advanced users of Vim, and we knew Lisp languages. Our Clojure implementation was based on map/filter/reduce approach and spanned 20 lines of code. After the session Leo showed me Christophe Grand’s 7-line solution based on list comprehensions. It is so wonderful that I want to post it here

life.clj
(defn neighbours [[x y]]
(for [dx [-1 0 1] dy (if (zero? dx) [-1 1] [-1 0 1])]
[(+ dx x) (+ dy y)]))
(defn step [cells]
(set (for [[loc n] (frequencies (mapcat neighbours cells))
:when (or (= n 3) (and (= n 2) (cells loc)))]
loc)))

For the last session we chose Erlang. Because we already knew how to implement the functional solution, that was just an exercise of translating Clojure code into Erlang. Unfortunately we didn’t find an equivalent of frequencies function in the standard library, so we implemented it ourselves. Other than that, the Erlang code is almost identical to Clojure.

life.erl
neighbours({X, Y}) ->
[{X + DX, Y + DY} || DX <- [-1, 0, 1], DY <- [-1, 0, 1], {DX, DY} =/= {0, 0}].
step(Cells) ->
Nbs = lists:flatmap(fun neighbours/1, sets:to_list(Cells)),
NewCells = [C || {C, N} <- dict:to_list(frequencies(Nbs)),
(N == 3) orelse ((N == 2) andalso sets:is_element(C, Cells))],
sets:from_list(NewCells).
frequencies(List) -> frequencies(List, dict:new()).
frequencies([], Acc) -> Acc;
frequencies([X|Xs], Acc) -> frequencies(Xs, dict:update_counter(X, 1, Acc)).

Summary

During this day I learnt a lot: new language, new abstractions, new techniques, new ways of communication, new ideas. I met bunch of smart people. I was so overwhelmed with all this cool stuff that I had to write this blog post to offload it from my head.

If you are a programmer and you’ve never been to CodeRetreat, I strongly encourage you to do it next year. It’s an exciting experience.

I want to thank all the people who organized and participated in this event.

Photo Credits

  • Michael DiBernardo [1]
  • Kunal Gupta [2]
  • Carlo Barrettara [3]