# Learning F#: The Game of Life (Vol.2)

# Intro

I posted my thoughts several articles ago regarding my journey of learning F# via the implementation of The Game of Life. I had initially attempted (through my ignorance) Domain-Driven Design and quickly ran into some design issues. I received some feedback regarding my initial design on StackOverflow and decided to try an alternative design. Thus, I decided to use TDD.

One of the feedback items that I received was to consider using a grid instead of an array. But what really is a grid? As of right now, I would define a grid as a container of X,Y coordinates. Then I was confronted with the question, “how do I represent an x,y coordinate?”.

## Representing an X,Y Coordinate

**At first, I considered using a tuple:**

let cell = 0,0 let x,y = cell

However, in this domain a grid has cells which is really an identified part of the system. As a result, I decided that it would probably be best to define a cell instead.

**Thus, I defined a cell as the following:**

type Cell = { X:int; Y:int }

## What to do with a Cell?

Having a cell is great. However, a cell by itself is rendered useless. Hence, The Game of Life requires cells to live, die, and be resurrected from the dead based on the status of their neighbors.

## Defining a Cell’s Neighbor

Using a grid I can visually identify a cell’s neighbor. However, to do this programmatically, I relied on TDD.

**The following logic was generated via TDD:**

let isXNeighbor cell1 cell2 = if cell1.X >= 0 && cell2.X >= 0 then abs (cell1.X - cell2.X) = abs 1 || abs (cell1.X - cell2.X) = abs 0 else abs (cell2.X - cell1.X) = abs 1 || abs (cell2.X - cell1.X) = abs 0 let isYNeighbor cell1 cell2 = if cell1.Y >= 0 && cell2.Y >= 0 then abs (cell1.Y - cell2.Y) = abs 1 || abs (cell1.Y - cell2.Y) = abs 0 else abs (cell2.Y - cell1.Y) = abs 1 || abs (cell2.Y - cell1.Y) = abs 0 let isNeighbor cell1 cell2 = if cell1.X <> cell2.X && cell1.Y <> cell2.Y then let xAligned = isXNeighbor cell1 cell2 let yAligned = isYNeighbor cell1 cell2 xAligned && yAligned else false

**I then refactored that logic to the following:**

let isAbsNeighbor v1 v2 = abs (v1 - v2) = abs 1 || abs (v1 - v2) = abs 0 let IsValueNeighbor v1 v2 = if v1 >= 0 && v2 >= 0 then isAbsNeighbor v1 v2 else isAbsNeighbor v2 v1 let isNeighbor cell1 cell2 = if cell1.X <> cell2.X || cell1.Y <> cell2.Y then let xAligned = IsValueNeighbor cell1.X cell2.X let yAligned = IsValueNeighbor cell1.Y cell2.Y xAligned && yAligned else false

**The actual tests that flushed out the logic is the following:**

open FsUnit open NUnit.Framework [<Test>] let ``cells sharing x-coordinate are neighbors``() = // Setup let cell1 = { X=0; Y=0 } let cell2 = { X=0; Y=1 } // Verify cell1 |> isNeighbor cell2 |> should equal true [<Test>] let ``cells sharing y-coordinate are neighbors``() = // Setup let cell1 = { X=0; Y=1 } let cell2 = { X=1; Y=1 } cell1 |> isNeighbor cell2 |> should equal true [<Test>] let ``cell that's right 1 and down 1 is neighbor``() = // Setup let cell1 = { X=0; Y=0 } let cell2 = { X=1; Y=(-1) } // Verify cell1 |> isNeighbor cell2 |> should equal true [<Test>] let ``cell that's right 1 and down-0 is neighbor``() = // Setup let cell1 = { X=0; Y=0 } let cell2 = { X=1; Y=0 } // Verify cell1 |> isNeighbor cell2 |> should equal true [<Test>] let ``cell that's right 1 and up 1 is neighbor``() = // Setup let cell1 = { X=0; Y=0 } let cell2 = { X=1; Y=1 } // Verify cell1 |> isNeighbor cell2 |> should equal true [<Test>] let ``cell that's up 1 is neighbor``() = // Setup let cell1 = { X=0; Y=0 } let cell2 = { X=0; Y=1 } // Verify cell1 |> isNeighbor cell2 |> should equal true [<Test>] let ``cell that's down 1 is neighbor``() = // Setup let cell1 = { X=0; Y=0 } let cell2 = { X=0; Y=(-1) } // Verify cell1 |> isNeighbor cell2 |> should equal true [<Test>] let ``cell that's left 1 and up 1 is neighbor``() = // Setup let cell1 = { X=0; Y=0 } let cell2 = { X=(-1); Y=1 } // Verify cell1 |> isNeighbor cell2 |> should equal true [<Test>] let ``cell that's left 1 and down 1 is neighbor``() = // Setup let cell1 = { X=0; Y=0 } let cell2 = { X=(-1); Y=(-1) } // Verify cell1 |> isNeighbor cell2 |> should equal true [<Test>] let ``far away x-coordinates are not neighbors``() = // Setup let cell1 = { X=(-1); Y=0 } let cell2 = { X=(+1); Y=0 } // Verify cell1 |> isNeighbor cell2 |> should equal false [<Test>] let ``far away y-coordinates are not neighbors``() = // Setup let cell1 = { X=0; Y=(+1) } let cell2 = { X=0; Y=(-1) } // Verify cell1 |> isNeighbor cell2 |> should equal false [<Test>] let ``far away x,y-coordinates are not neighbors``() = // Setup let cell1 = { X=(+1); Y=(+1) } let cell2 = { X=(+1); Y=(-1) } // Verify cell1 |> isNeighbor cell2 |> should equal false [<Test>] let ``cells with same coordinates cannot be neighbors``() = // Setup let cell1 = { X=0; Y=0 } let cell2 = { X=0; Y=0 } // Verify cell1 |> isNeighbor cell2 |> should equal false

# Conclusion

In conclusion, I posted my thoughts several articles ago regarding my journey of learning F# via the implementation of The Game of Life. I had initially attempted (through my ignorance) Domain-Driven Design and quickly ran into some design issues. I received some feedback regarding my initial design on StackOverflow and decided to try an alternative design. Thus, I decided to use TDD. I’m still a novice to F#. Hence, I know that my implementation can be further refined. However, I do believe that I no expert starts as an expert. Thus, wish me luck!