Build a Clean “Game of Life” App in Flutter Using Hexagonal Architecture and TDD: Part 2
By: Romain Straet
Tags: Software Architecture, Software Development, Flutter, Tdd, Dart

Use case 1 : Get the next state of a game

Let’s pause and think before writing anything. What do I need to implement the rules of the game of life ?

First, I need a way to express the state of a cell. It could be 0 and 1 but I want to be expressive so I’ll use an enum for this. Let’s code it right away since there is nothing to test here :

Obviously, considering the rules, I need a method that returns the next state of a cell depending on its initial state and the number of alive neighbours;

Therefore, I also need a method that counts the number of alive neighbours of a given cell;

Finally, of course, I need to iterate through the cells of the provided game, apply the new state of each cells, and returns a new refreshed game.

Let’s start with the smaller piece and work on the Cell level.

Get the next state of a Cell

According to the TDD approach, let’s start by writing a test.

Here is the very first test I wrote for this method. In fact, I’m just following the rules of the game of life.

You will notice I already took some decisions here :

I will code a Cell class that requires a CellState as argument ;

class that requires a as argument ; The Cell class will contain a getNextState method that will require the number of alive neighbours as argument.

For the fun of strictly following the TDD approach, let’s run the test in a terminal with the following command :

$ pub run test

The result :

This is expected since we have not even created that Cell class yet.

So let’s write the smallest amount of code required to make the test passes :

Let’s verify :

Good! Let’s write a second test and run the tests.

It failed once again. Let’s adjust the code to make it pass :

Run the tests…

Great ! Third test (then I’ll take some shortcuts for this article ;-) :

Run the tests…

Oh wait… It passed without any changes. Great!

Finally, I wrote the following tests (one by one) and tried to make them pass (one by one*).

And here is the final result.

Count the number of alive neighbours

As stated above, in order to get the next state of a cell, I need to count and provide the number of alive neighbours of the cell.

In this respect, I took the following decisions :

I will code a Game class that requires a state as argument. The state is the game grid that will be represented as a List of List of CellState* ;

class that requires a as argument. The state is the game grid that will be represented as a List of List of CellState* ; The Game class will contain a countAliveNeighboursOfCell method that will require the row and the col index as arguments.

* By the way here is an illustration of a game grid in code. Each list inside the root list is a row. Inside the rows are the cells. First cell is in the first column, second cell is in the second column, etc.

As per TDD approach, I wrote the below tests one by one and try to make it pass one by one. You’ll notice that the complexity of the tests increase progressively.

Given a 2 by 2 game grid with only dead cells, each cells of the game should have 0 alive neighbours ; Given a 2 by 2 game grid with only alive cells on the top row, the bottom cells of the game should have 2 alive neighbours ; Given a 2 by 2 game grid with only alive cells on the bottom row, the top cells of the game should have 2 alive neighbours ; Given a 2 by 2 game grid with only alive cells, each cells of the game should have 3 alive neighbours ; Given a 3 by 3 game grid with only alive cells :

- Corner cells should have 3 alive neighbours ;

- Top/Right/Bottom/Left-center cells should have 5 alive neighbourg ;

- Center cell should have 8 alive neighbours ; Given a 4 by 4 game grid with alive and dead cells, random tested cells should have the correct number of neighbours.

This battery of tests can be found here.

And here below is the result. It might not be perfect but it passes the tests and therefore gives a solid foundation.

Get the next state of a game

I have now to link everything to implement the use case.

Once again, I follow the TDD approach. I therefore wrote the below tests one by one and tried to implement it one by one :

Given a 2 by 2 game grid with only dead cells, the next state of the game should only contains dead cells ; Given a 2 by 2 game grid with only alive cells, the next state of the game should only contains alive cells ; Given a 2 by 2 game grid with only 1 alive cell, the next state of the game should only contains dead cells ; Given a 2 by 2 game grid with 3 alive cells, the next state of the game should only contains alive cells ; Given a 3 by 3 game grid with only alive cells, the next state of the game should evolve according to the rules of the game of life (here : only corner cells should remain alive) ; Given a 4 by 4game grid with dead and alive cells, the next state of the game should evolve according to the rules of the game of life.

This battery of tests can be found here.

In practice, to make those tests pass, I create a GetNextGameState class in the usecases folder with a call method.

Here below is the result. In the call method :

I create an instance of the Game class with the provided game ;

I iterate over each cells and count their alive neighbours ;

Given this information, I get the next state of each cells ;

I add those cell state in a new game variable ;

When iteration is finished, it returns the new game state.

One again, it might not be perfect but this is a solid foundation.

Let’s move on.