Sunday, February 2, 2014

Conway's Game of Life in Java

Last December I attended the Global Day of Code Retreat in Valencia.

It was a lot of fun and we thought and discussed a lot about the problem. Thanks to all the participants and the organizers for the great time.

When I came back to Barcelona I decided to go on practicing by developing a full solution to Conway's Game of Life on my own.

I wanted the solution to include several of the ideas that we had been discussing during the code retreat:
  • Tracking only living cells. 
  • Open/Closed with regard to the rules based on the number of neighbors. 
  • Open/Closed with regard to the number and location of a cell's neighbors. 
  • Open/Closed with regard to the dimensions of the grid (2D, 3D, 4D, etc).

It took me several rewrites but finally I came up with this solution that respects all the previous ideas.



- Tracking only living cells 
A Generation has a collection of cells that are alive, LivingCells, and a set of Rules.

This way the "state of the cell" concept we tried in some iterations of the code retreat becomes pointless and it requires less space to store the current generation.

I also made Generation immutable.

To generate the next Generation of LivingCells (produceNextGeneration method), it first adds the surviving cells (addSurvivors method) and then the newly born cells (addNewCells method).


- Open/Closed with regard to the rules based on the number of neighbors.
Rules is an interface with two methods, shouldStayAlive and shouldBeBorn, that you can implement the way you wish.

The rules are still based on the number of neighbors which is the parameter passed to both methods.

In this case, I only implemented the rules of the Conway's Game of Life: ConwaysRules class, but more rules based on the number of neighbors might be added.


- Open/Closed with regard to the number and location of a cell's neighbors and Open/Closed with regard to the dimensions of the grid (2D, 3D, 4D, etc).
This two are possible thanks to the Cell interface. It has only a method, getNeighbors, which returns the neighbors of a cell. It's up to the cell to know which are its neighbors.

In this way each implementation of Cell can have a different dimension and a different number of neighbors which can be located following different stencils.

In this case, I implemented several types of cells: ConwaysCell, CellX2D, CellCross3D and CellCross2D. The code that is common to all 2D cells is in the Cell2D abstract class, whereas the one that is common to all 3D cells is in the Cell3D abstract class.

You can have a look at the code on GitHub.

Update: I refactored this code making it much simpler. Take a look at the new version.

1 comment: