Skip to content

Game of Life in Java: Solution for Coderetreat facilitators

License

Notifications You must be signed in to change notification settings

nelkinda/gameoflife-java

Repository files navigation

Game of Life

Java CI with Gradle Java CI with Maven

This is an example implementation of Conway's Game of Life in Java. The primary focus of the implementation is cleanliness, not performance. It serves as a lose guideline for Nelkinda Coderetreat facilitators.

Rules of Conway's Game of Life

The universe of the Game of Life is an infinite, two-dimensional orthogonal grid of square cells. Each cell is in one of two possible states:

  • Alive aka populated
  • Dead aka unpopulated

Every cell interacts with its eight neighbors. The neighbors are the cells that are horizontally, vertically, or diagonally adjacent. At each step in time, the following transitions occur:

  1. Underpopulation: Any live cell with fewer than 2 live neighbors dies.
  2. Survival: Any live cell with 2 or 3 live neighbors survives on to the next generation.
  3. Overpopulation Any live cell with more than 3 live neighbors dies.
  4. Reproduction (birth): Any dead cell with exactly 3 live neighbors becomes a live cell.

Conway's Game of Life - Wikipedia

Activities (aka Constraints)

This implementation of Game of Life follows the following activities and constraints:

  • Behavior Driven Development.
  • Test-Driven Development.
  • Immutable objects only. Only pure functions.
  • No variable reassignments (except for the Parser).
  • Started: No naked primitives, not followed through yet.
  • Short functions only. Most functions are one line only. Exception: Some constructors are 2 lines, the Parser is big.
  • Domain-Specific Language: The symbol names are taken from the problem domain. A point, for example, is constructed with P(x, y) instead of new Point(x, y). That makes the code shorter and easier to read.
  • Functional Core, Imperative Shell: The code is purely functional. The imperative shell is so far out that it's in the test only. The Parser implementation is imperative, but its interface and observable behavior are functional.

Quality

Testing, Mutation Test Coverage

  • The acceptance tests are written using BDD in Gherkin and executed via Cucumber.
  • The unit tests are written and executed with JUnit 5. Regular code coverage is measured using JaCoCo which reports 100% lines and condition coverage. On top of that, Pitest is used to perform mutation testing. The mutation tests run by Pitest report 0 surviving mutations.

SonarQube

  • The project has a SonarQube analysis. The project has the best possible rating imaginable: 0 bugs, 0 vulnerabilities, 0 security hotspots, 0 debt, 0 code smells, 100% coverage, 0.0% duplications, 0 duplicated blocks.

SonarQube report Pitest report

References

Questions/Contact