Global Day of CodeRetreat

Most of the team went along to the Perth Global Day of CodeRetreat at the Thoughtworks office on Saturday; I’d been interested in going to one for a while, so when a local event popped up, I was there. Most of the pairs were split 50/50 on Java/C# — conservative bunch we are in Perth — although there were some JavaScript pairs and I participated in an Objective-C one (with limited success).

Overall I found the experience quite worthwhile, but I did find it frustrating to attack the same problem (Conway’s Game of Life) over and over, and never finish it. So I went home and finished my last attempt.

This implementation adheres to most of the constraints we attempted at various stages during our event:

  • No control of flow statements (no if, else, switch, do, while, loop, for, foreach etc)
  • No Cell class
  • Infinite Grid
  • Methods no longer than 3 lines of code

It consists of one class and one struct, first a helper Point struct:

public struct Point
{
    public int X { get; private set; }
    public int Y { get; private set; }

    public Point(int x, int y) : this()
    {
        X = x;
        Y = y;
    }

    public override bool Equals(object obj)
    {
        return X == ((Point)obj).X && Y == ((Point)obj).Y;
    }

    public static bool operator == (Point p1, Point p2)
    {
        return p1.Equals(p2);
    }

    public static bool operator != (Point p1, Point p2)
    {
        return !p1.Equals(p2);
    }

    public override int  GetHashCode()
    {
        return X.GetHashCode() & Y.GetHashCode();
    }

    public IEnumerable<Point> AdjacentPoints
    {
        get
        {
            return new List<Point> { new Point(X - 1, Y - 1),
                new Point(X - 1, Y),
                new Point(X - 1, Y + 1),
                new Point(X, Y - 1),
                new Point(X, Y + 1),
                new Point(X + 1, Y - 1),
                new Point(X + 1, Y),
                new Point(X + 1, Y + 1) };
        }
    }
}

and then the main ‘World’ class:

public class World
{
    private List<Point> liveCells;

    public World(List<Point> liveCells)
    {
        this.liveCells = new List<Point>(liveCells);
    }

    public int LiveCellCount { 
        get { return liveCells.Count(); } 
    }

    public void Tick()
    {
       liveCells = liveCells.Where(p => NumberOfLiveNeighbours(p) == 2 || NumberOfLiveNeighbours(p) == 3) // stay alive
           .Union(AdjacentDeadCells.Where(p => NumberOfLiveNeighbours(p) == 3)) // become alive
           .ToList();
    }

    private int NumberOfLiveNeighbours(Point point)
    {
        return liveCells.Intersect(point.AdjacentPoints).Count();
    }

    private IEnumerable<Point> AdjacentDeadCells
    {
        get 
        {
            return liveCells.SelectMany(p => p.AdjacentPoints).Except(liveCells).Distinct();
        }
    }
}

This is cheating slightly as the framework LINQ queries are probably implemented as foreaches, but technically I haven’t used any control of flow. The code is also not as easily testable as some of the iterations I went through during the CodeRetreat, but there is significantly less of it. I think there can be scenarios where attempting to modularise something can introduce too many interfaces to keep the code tight & concise.