Created
March 18, 2019 15:24
-
-
Save ygrenzinger/a52c19f1a1f30e0e494a28c38f2f47c6 to your computer and use it in GitHub Desktop.
Kotlin Game of Life with JC Melikian
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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 | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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) | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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 | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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