# Intro

I have been crafting the logic required for the Game of Life. In the last article, I documented how I struggled with life cycles. However, I made some progress recently.

## Tests

As I discussed in past articles, I wanted to learn how to implement this system via TDD.

The following tests have been implemented:

```[<Test>]
let ``Any live cell with fewer than two live neighbors dies, as if caused by under-population``() =
// Setup
let rowCount = 3
let grid = rowCount |> createGrid
|> setCell { X=2; Y=2; State=Alive }
|> setReaction (2,2)
// Verify
grid |> getStatus (2,2) |> should equal Dead

[<Test>]
let ``Any live cell with two or three live neighbours lives on to the next generation``() =
// Setup
let rowCount = 3
let grid = rowCount |> createGrid
|> setCell { X=1; Y=2; State=Alive }
|> setCell { X=2; Y=2; State=Alive }
|> setCell { X=3; Y=2; State=Alive }
|> setReaction (2,2)
// Verify
grid |> getStatus (2,2) |> should equal Alive

[<Test>]
let ``Any live cell with more than three live neighbours dies, as if by over-population``() =
// Setup
let rowCount = 3
let grid = rowCount |> createGrid
|> setCell { X=1; Y=2; State=Alive }
|> setCell { X=2; Y=2; State=Alive }
|> setCell { X=3; Y=2; State=Alive }
|> setCell { X=3; Y=3; State=Alive }
|> setCell { X=2; Y=1; State=Alive }
|> setReaction (2,2)
// Verify
grid |> getStatus (2,2) |> should equal Dead

[<Test>]
let ``Any dead cell with exactly three live neighbours becomes a live cell, as if by reproduction``() =
// Setup
let rowCount = 3
let grid = rowCount |> createGrid
|> setCell { X=1; Y=2; State=Alive }
|> setCell { X=2; Y=2; State=Dead }
|> setCell { X=3; Y=2; State=Alive }
|> setCell { X=3; Y=3; State=Alive }
|> setReaction (2,2)
// Verify
grid |> getStatus (2,2) |> should equal Alive
```

## Business Logic

I wrote some additional business logic to capture a cell’s neighbors. In addition, I also wrote code to capture a cell’s response to its neighbors.

### Neighbors

Each grid block is comprised of nine cells. Thus, I decided to name a cell based on its relative relationship to the original cell that’s being targeted for a response.

Thus, I implemented the following function to get neighboring coordinates:

```let getNeighbors (coordinate:int*int) =

let x,y = coordinate
let west = x-1, y
let northWest = x-1, y+1
let north = x, y+1
let northEast = x+1, y+1
let east = x+1, y
let southEast = x+1, y-1
let south = x, y-1
let southWest = x-1, y-1

[west; northWest; north; northEast; east; southEast; south; southWest]
```

### Response

The Game of Life requires that a cell responds to its neighbors based on the state of its neighbors.

The following code was implemented to reflect a cell’s responde to its neighbors:

```let setReaction coordinate grid:Map<(int * int), Cell> =

let x,y = coordinate
let count = coordinate |> getNeighbors
|> List.filter (fun coordinate -> grid |> getStatus coordinate = Alive)
|> List.length
match count with
| count when count < 2               ||  count > 3 -> grid |> setCell { X=x; Y=y; State=Dead }
| 3                    -> match grid.TryFind coordinate with
| Some cell -> if cell.State = Dead then
grid |> setCell { cell with State=Alive }
else grid
| None      -> failwith "Cell doesn't exists"
| _ -> grid
```

The full logic is as follows:

```type State = Alive | Dead
type Cell = { X:int; Y:int; State:State }

type Response = | Die
| Survive
| Resurect

let isNeighbor cell1 cell2 =

let isAbsNeighbor v1 v2 =
match abs (v1 - v2) with
| 0 | 1 -> true
| _     -> false

let isValueNeighbor v1 v2 =
match v1 >= 0
&&  v2 >= 0 with
| true  -> isAbsNeighbor v1 v2
| _     -> isAbsNeighbor v2 v1

match cell1.X <> cell2.X
||  cell1.Y <> cell2.Y with
| true ->   isValueNeighbor cell1.X cell2.X
&& isValueNeighbor cell1.Y cell2.Y
| _    -> false

let createGrid rowCount =

[for x in 1..rowCount do
for y in 1..rowCount do
yield { X=x; Y=y; State=Dead }
]|> List.map (fun c -> (c.X, c.Y), { X=c.X; Y=c.Y; State=Dead })
|> Map.ofList

let setCell cell (grid:Map<(int * int), Cell>) =

grid |> Map.map (fun k v -> match k with
| c when c = (cell.X, cell.Y) -> { v with State=cell.State }
| _ -> v)

let getStatus coordinate (grid:Map<(int * int), Cell>) =

match grid.TryFind coordinate with
| Some cell -> cell.State
| None      -> Dead

let getNeighbors (coordinate:int*int) =

let x,y = coordinate
let west = x-1, y
let northWest = x-1, y+1
let north = x, y+1
let northEast = x+1, y+1
let east = x+1, y
let southEast = x+1, y-1
let south = x, y-1
let southWest = x-1, y-1

[west; northWest; north; northEast; east; southEast; south; southWest]

let setReaction coordinate grid:Map<(int * int), Cell> =

let x,y = coordinate
let count = coordinate |> getNeighbors
|> List.filter (fun coordinate -> grid |> getStatus coordinate = Alive)
|> List.length
match count with
| count when count < 2               ||  count > 3 -> grid |> setCell { X=x; Y=y; State=Dead }
| 3                    -> match grid.TryFind coordinate with
| Some cell -> if cell.State = Dead then
grid |> setCell { cell with State=Alive }
else grid
| None      -> failwith "Cell doesn't exists"
| _ -> grid
```

The full tests is as follows:

```[<Test>]
let ``cells sharing x-coordinate are neighbors``() =
// Setup
let cell1 = { X=0; Y=0; State=Dead }
let cell2 = { X=0; Y=1 ; State=Dead }

// Verify
cell1 |> isNeighbor cell2
|> should equal true

[<Test>]
let ``cells sharing y-coordinate are neighbors``() =
// Setup
let cell1 = { X=0; Y=1; State=Dead }
let cell2 = { X=1; Y=1; State=Dead }

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; State=Dead }
let cell2 = { X=1; Y=(-1); State=Dead }

// 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; State=Dead }
let cell2 = { X=1; Y=0; State=Dead }

// 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; State=Dead }
let cell2 = { X=1; Y=1 ; State=Dead }

// Verify
cell1 |> isNeighbor cell2
|> should equal true

[<Test>]
let ``cell that's up 1 is neighbor``() =
// Setup
let cell1 = { X=0; Y=0; State=Dead }
let cell2 = { X=0; Y=1 ; State=Dead }

// Verify
cell1 |> isNeighbor cell2
|> should equal true

[<Test>]
let ``cell that's down 1 is neighbor``() =
// Setup
let cell1 = { X=0; Y=0;    State=Dead }
let cell2 = { X=0; Y=(-1); State=Dead }

// 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; State=Dead }
let cell2 = { X=(-1); Y=1 ; State=Dead }

// 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;    State=Dead }
let cell2 = { X=(-1); Y=(-1); State=Dead }

// Verify
cell1 |> isNeighbor cell2
|> should equal true

[<Test>]
let ``far away x-coordinates are not neighbors``() =
// Setup
let cell1 = { X=(-1); Y=0; State=Dead }
let cell2 = { X=(+1); Y=0; State=Dead }

// Verify
cell1 |> isNeighbor cell2
|> should equal false

[<Test>]
let ``far away y-coordinates are not neighbors``() =
// Setup
let cell1 = { X=0; Y=(+1); State=Dead }
let cell2 = { X=0; Y=(-1); State=Dead }

// Verify
cell1 |> isNeighbor cell2
|> should equal false

[<Test>]
let ``far away x,y-coordinates are not neighbors``() =
// Setup
let cell1 = { X=(+1); Y=(+1); State=Dead }
let cell2 = { X=(+1); Y=(-1); State=Dead }

// Verify
cell1 |> isNeighbor cell2
|> should equal false

[<Test>]
let ``cells with same coordinates cannot be neighbors``() =
// Setup
let cell1 = { X=0; Y=0; State=Dead }
let cell2 = { X=0; Y=0; State=Dead }

// Verify
cell1 |> isNeighbor cell2
|> should equal false

[<Test>]
let ``create grid``() =
// Test
let rowCount = 3
let grid = rowCount |> createGrid

// Verify
grid.Count |> should equal 9

[<Test>]
let ``find center``() =
// Setup
let rowCount = 3
let grid = rowCount |> createGrid

let getCoordinate coordinate =
match grid.TryFind coordinate with
| Some coordinate -> true
| None            -> false

// Test
let found = getCoordinate (2,2)

// Verify
found |> should equal true

[<Test>]
let ``get status``() =
// Setup
let rowCount = 3
let grid = rowCount |> createGrid

// Test
let center = grid |> getStatus (2,2)

// Verify
center |> should equal Dead

[<Test>]
let ``set cell to alive``() =
// Setup
let rowCount = 3
let target = { X=2; Y=2; State=Alive }

let grid = rowCount |> createGrid
|> setCell target
// Test
let result = grid |> getStatus (2,2)

// Verify
result |> should equal Alive

[<Test>]
let ``get neighbors``() =
// Setup
let rowCount = 3
let grid = rowCount |> createGrid

let center = 2,2
let count = center |> getNeighbors
|> List.length
// Verify
count |> should equal 8

[<Test>]
let ``Any live cell with fewer than two live neighbors dies, as if caused by under-population``() =
// Setup
let rowCount = 3
let grid = rowCount |> createGrid
|> setCell { X=2; Y=2; State=Alive }
|> setReaction (2,2)
// Verify
grid |> getStatus (2,2) |> should equal Dead

[<Test>]
let ``Any live cell with two or three live neighbours lives on to the next generation``() =
// Setup
let rowCount = 3
let grid = rowCount |> createGrid
|> setCell { X=1; Y=2; State=Alive }
|> setCell { X=2; Y=2; State=Alive }
|> setCell { X=3; Y=2; State=Alive }
|> setReaction (2,2)
// Verify
grid |> getStatus (2,2) |> should equal Alive

[<Test>]
let ``Any live cell with more than three live neighbours dies, as if by over-population``() =
// Setup
let rowCount = 3
let grid = rowCount |> createGrid
|> setCell { X=1; Y=2; State=Alive }
|> setCell { X=2; Y=2; State=Alive }
|> setCell { X=3; Y=2; State=Alive }
|> setCell { X=3; Y=3; State=Alive }
|> setCell { X=2; Y=1; State=Alive }
|> setReaction (2,2)
// Verify
grid |> getStatus (2,2) |> should equal Dead

[<Test>]
let ``Any dead cell with exactly three live neighbours becomes a live cell, as if by reproduction``() =
// Setup
let rowCount = 3
let grid = rowCount |> createGrid
|> setCell { X=1; Y=2; State=Alive }
|> setCell { X=2; Y=2; State=Dead }
|> setCell { X=3; Y=2; State=Alive }
|> setCell { X=3; Y=3; State=Alive }
|> setReaction (2,2)
// Verify
grid |> getStatus (2,2) |> should equal Alive
```

# Conclusion

In conclusion, I have been crafting the logic required for the Game of Life. In the last article, I documented how I struggled with life cycles. However, I made some progress recently. I showed how I retrieved neighbors of a cell as well as update a cell’s state in response to it’s neighbors.

Advertisements