Skip to content

Instantly share code, notes, and snippets.

@ygrenzinger
Created March 18, 2019 15:24
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save ygrenzinger/a52c19f1a1f30e0e494a28c38f2f47c6 to your computer and use it in GitHub Desktop.
Save ygrenzinger/a52c19f1a1f30e0e494a28c38f2f47c6 to your computer and use it in GitHub Desktop.
Kotlin Game of Life with JC Melikian
enum class Cell {
ALIVE {
override fun nextGeneration(neighbors: Int): Cell {
if (neighbors == 2 || neighbors == 3) return this
return DEAD
}
}, DEAD {
override fun nextGeneration(neighbors: Int): Cell {
if (neighbors == 3) return ALIVE
return this
}
};
abstract fun nextGeneration(neighbors: Int): Cell
}
import Cell.ALIVE
import Cell.DEAD
import org.assertj.core.api.Assertions.assertThat
import org.junit.jupiter.api.Test
import org.junit.jupiter.params.ParameterizedTest
import org.junit.jupiter.params.provider.ValueSource
internal class CellTest {
@Test
fun alive_cell_should_die_if_less_than_2_neighbors() {
assertThat(ALIVE.nextGeneration(0)).isEqualTo(DEAD)
assertThat(ALIVE.nextGeneration(1)).isEqualTo(DEAD)
}
@Test
fun alive_cell_should_survive_if_2_or_3_neighbors() {
assertThat(ALIVE.nextGeneration(2)).isEqualTo(ALIVE)
assertThat(ALIVE.nextGeneration(3)).isEqualTo(ALIVE)
}
@ParameterizedTest
@ValueSource(ints = [4, 5, 6, 7, 8])
fun alive_cell_should_die_if_more_than_3_neighbors(neighbors: Int) {
assertThat(ALIVE.nextGeneration(neighbors)).isEqualTo(DEAD)
}
@Test
fun dead_cell_should_reborn_if_3_neighbors() {
assertThat(DEAD.nextGeneration(3)).isEqualTo(ALIVE)
}
@ParameterizedTest
@ValueSource(ints = [0, 1, 2, 4, 5, 6, 7, 8])
fun dead_cell_should_stay_dead_if_other_than_3_neighbors(neighbors: Int) {
assertThat(DEAD.nextGeneration(neighbors)).isEqualTo(DEAD)
}
}
import Cell.ALIVE
import Cell.DEAD
data class GameOfLife(val grid: List<List<Cell>>) {
private val numberOfRow: Int = grid.size
private val numberOfColumn: Int
init {
numberOfColumn = if (numberOfRow == 0) {
0
} else {
grid[0].size
}
}
fun nextGeneration(): GameOfLife {
val newGeneration: MutableList<MutableList<Cell>> = mutableListOf()
for (rowIndex in 0 until numberOfRow) {
val row: MutableList<Cell> = mutableListOf()
for (columnIndex in 0 until numberOfColumn) {
row.add(nextCellGeneration(rowIndex, columnIndex))
}
newGeneration.add(row)
}
return GameOfLife(newGeneration);
}
private fun nextCellGeneration(rowIndex: Int, columnIndex: Int): Cell {
return cellAt(rowIndex, columnIndex)
.nextGeneration(countNeighborsAt(columnIndex, rowIndex))
}
fun countNeighborsAt(x: Int, y: Int): Int {
var count = 0
for (row in (y - 1)..(y + 1)) {
for (column in (x - 1)..(x + 1)) {
if (row == y && column == x) {
continue
}
if (cellAt(row, column) == ALIVE) {
count++
}
}
}
return count
}
private fun cellAt(rowIndex: Int, columnIndex: Int): Cell {
return if (isOutOfGrid(rowIndex, columnIndex)) {
DEAD
} else {
grid[rowIndex][columnIndex]
}
}
private fun isOutOfGrid(rowIndex: Int, columnIndex: Int) =
rowIndex < 0 || columnIndex < 0 || rowIndex >= numberOfRow || columnIndex >= numberOfColumn
}
import Cell.ALIVE
import Cell.DEAD
import org.assertj.core.api.Assertions.assertThat
import org.junit.jupiter.api.Test
class GameOfLifeTest {
@Test
fun cell_has_at_least_1_neighbor() {
val gameOfLife = GameOfLife(
listOf(
listOf(DEAD, DEAD, DEAD, DEAD),
listOf(DEAD, ALIVE, ALIVE, DEAD),
listOf(DEAD, ALIVE, ALIVE, DEAD),
listOf(DEAD, DEAD, DEAD, DEAD)
)
)
assertThat(gameOfLife.countNeighborsAt(0, 0)).isEqualTo(1)
assertThat(gameOfLife.countNeighborsAt(3, 3)).isEqualTo(1)
}
@Test
fun cell_has_at_least_3_neighbors() {
val gameOfLife = GameOfLife(
listOf(
listOf(DEAD, DEAD, DEAD, DEAD),
listOf(DEAD, ALIVE, ALIVE, DEAD),
listOf(DEAD, ALIVE, ALIVE, DEAD),
listOf(DEAD, DEAD, DEAD, DEAD)
)
)
assertThat(gameOfLife.countNeighborsAt(2, 2)).isEqualTo(3)
assertThat(gameOfLife.countNeighborsAt(1, 1)).isEqualTo(3)
}
@Test
fun should_handle_block_pattern() {
val grid = listOf(
listOf(DEAD, DEAD, DEAD, DEAD),
listOf(DEAD, ALIVE, ALIVE, DEAD),
listOf(DEAD, ALIVE, ALIVE, DEAD),
listOf(DEAD, DEAD, DEAD, DEAD)
)
var gameOfLife = GameOfLife(grid)
gameOfLife = gameOfLife.nextGeneration()
val nextGrid = listOf(
listOf(DEAD, DEAD, DEAD, DEAD),
listOf(DEAD, ALIVE, ALIVE, DEAD),
listOf(DEAD, ALIVE, ALIVE, DEAD),
listOf(DEAD, DEAD, DEAD, DEAD)
)
assertThat(gameOfLife).isEqualTo(GameOfLife(nextGrid))
}
@Test
fun should_handle_blinker_pattern() {
val grid = listOf(
listOf(DEAD, DEAD, DEAD, DEAD, DEAD),
listOf(DEAD, DEAD, ALIVE, DEAD, DEAD),
listOf(DEAD, DEAD, ALIVE, DEAD, DEAD),
listOf(DEAD, DEAD, ALIVE, DEAD, DEAD),
listOf(DEAD, DEAD, DEAD, DEAD, DEAD)
)
var gameOfLife = GameOfLife(grid)
gameOfLife = gameOfLife.nextGeneration()
val nextGrid = listOf(
listOf(DEAD, DEAD, DEAD, DEAD, DEAD),
listOf(DEAD, DEAD, DEAD, DEAD, DEAD),
listOf(DEAD, ALIVE, ALIVE, ALIVE, DEAD),
listOf(DEAD, DEAD, DEAD, DEAD, DEAD),
listOf(DEAD, DEAD, DEAD, DEAD, DEAD)
)
assertThat(gameOfLife).isEqualTo(GameOfLife(nextGrid))
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment