Created
April 30, 2020 07:51
-
-
Save fteychene/097b836b5f7cb9669190dd7734c03b56 to your computer and use it in GitHub Desktop.
GameOfLife TypeDD and Sequence test
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
package mtpcraft.tdd.kata | |
import kotlin.random.Random | |
sealed class Cell { | |
companion object | |
} | |
object Dead : Cell() | |
object Living : Cell() | |
sealed class Neighbors { | |
object Two : Neighbors() | |
object Three : Neighbors() | |
object LessThanTwo : Neighbors() | |
object MoreTHanThree : Neighbors() | |
} | |
data class GridCell(val living: Cell, val x: Int, val y: Int) | |
typealias Grid = Sequence<GridCell> | |
typealias AnalyzableCells = Pair<Cell, Neighbors> | |
fun evolve(analyzableCell: AnalyzableCells): Cell = analyzableCell.let { (focus, neighbours) -> | |
when (neighbours) { | |
Neighbors.Three -> Living | |
Neighbors.Two -> focus | |
Neighbors.LessThanTwo -> Dead | |
Neighbors.MoreTHanThree -> Dead | |
} | |
} | |
fun isAdjacent(focus: GridCell, other: GridCell): Boolean = | |
other.x in focus.x - 1..focus.x + 1 && | |
other.y in focus.y - 1..focus.y + 1 | |
fun neighbors(cells: Sequence<Cell>): Neighbors = | |
when (cells.filter { it is Living }.toList().size) { | |
in 0..1 -> Neighbors.LessThanTwo | |
2 -> Neighbors.Two | |
3 -> Neighbors.Three | |
else -> Neighbors.MoreTHanThree | |
} | |
fun adjacentCells(grid: Grid): Sequence<Pair<GridCell, Neighbors>> = | |
grid.map { focus -> | |
// Slow | |
focus to neighbors(grid.filter { it != focus && isAdjacent(focus, it) }.map { it.living }.take(9)) | |
} | |
fun nextGeneration(grid: Grid): Grid = | |
adjacentCells(grid).map { (gridCell, neighbors) -> gridCell.copy(living = evolve(gridCell.living to neighbors)) } | |
fun main() { | |
// Could also use | |
val startingGrid = random(200, 200) | |
// val startingGrid = from( | |
// """ | |
// | | O | O | O | O | O | O | O | O | O | | | | | | O | O | | O | O | O | | | | | | O | | O | | |
// | O | | | | | | | | | | O | | | | O | O | | O | O | | | O | O | O | O | O | O | O | O | O | |
// | O | | | | O | O | O | | | | O | | O | O | O | O | | | | | O | O | O | O | | | | | | O | |
// O | | O | | | | O | | | O | | | | O | | O | O | | O | | O | O | O | | | | | | O | | O | |
// O | | | | | | | | | O | | | | O | | | O | | | | O | | O | | | | | | | | O | |
// O | | | | O | | O | O | | | | | | O | | O | | | | | O | | | | | | | | | | O | |
// | | | | O | | | | | O | | O | | | | O | | | | | | | | | | | | O | O | O | | |
// O | | | | | | | | | | O | | | | | | | | O | | | | | | O | O | O | | O | | | |
// O | O | | | | | | | O | O | O | O | | | O | | O | | O | O | O | | O | | | | | O | | O | | |
// | | | | | | | | | | O | | O | | | | | O | | O | | | | | | | | O | O | | | |
// O | O | | | | | | | O | | O | | O | | O | | | O | O | | O | | | O | | | | | O | | | |
// O | O | | O | | | | | O | | O | | O | | O | | | | | O | O | O | | | O | | O | | | | | |
// | | O | O | O | | O | O | | O | | | O | | | | | O | | O | | | O | | | | | | O | O | | |
// | O | O | | | | | | | | O | O | O | O | | | | | | O | O | O | | | | O | | O | | O | O | |
// O | | O | O | | | | O | | | | | O | | O | | | | | | | | | | | O | | O | | O | O | |
// O | | | | | O | | | | | | | | | | | | | | | | O | O | O | | O | | | | O | O | |
// | O | O | O | | O | | O | | | | | O | | | O | | O | | | | | | | O | O | | O | | O | | |
// | O | | | | | | | | | | | O | O | | O | | | | | | O | | O | O | | | | O | O | | |
// | O | | | | | O | O | O | O | O | | O | | | | | O | | | | | O | | O | | O | | O | | | |
// O | | | | | | | | O | | | | O | | | | | | | | | | | O | O | | O | | | O | | |
// O | | | | O | | O | O | O | O | | | O | | | | | | | | | | | | | | | | O | O | | |
// | | O | O | O | O | | | | | O | O | O | | | | | | O | | | | | | O | O | O | O | O | | | |
// | | O | O | | | | | | | | | O | | | | | | | | | | | | O | O | | | | | O | |
// O | | | | O | | | | | | O | | | | | | | | | | | | | O | | | O | | | | O | |
// O | | | | | | | O | O | | O | | | | | | | | | | | | | | | | | O | | | | |
// | | O | | | | O | O | | | | | O | | O | | | | | | | O | | | | | | O | | | O | |
// | | | | O | | O | O | | | | | O | O | O | | O | | | | | | | | | O | | O | O | | O | |
// | | | O | | O | O | | | | | | | O | | O | | | | | O | O | | | | | | | | | O | |
// | | O | | O | O | | | | | | | | | | | | | O | | O | | | O | O | | | | | | | |
// O | | | | O | | | | | | | | | | | | | | O | O | O | O | | O | | | | | | O | O | |
// | O | O | | O | O | | O | O | | O | | O | | | | | | | | O | O | O | | | O | | O | O | | | |
// """.trimIndent() | |
// ) | |
val generations = generateSequence(startingGrid, { nextGeneration(it) }).drop(1) | |
generations.take(10) | |
.forEachIndexed { generationId, grid -> | |
println("Generation $generationId") | |
println(displayGrid(grid)) | |
println() | |
} | |
} | |
// Utils functions | |
fun Cell.Companion.random(): Cell = | |
if (Random.nextBoolean()) Living | |
else Dead | |
fun random(xBound: Int, yBound: Int): Grid = | |
(0..xBound) | |
.flatMap { x -> (0..yBound) | |
.map { y -> GridCell(living = Cell.random(), x= x, y= y) } } | |
.asSequence() | |
fun from(grid: String): Grid = | |
grid | |
.split("\n") | |
.mapIndexed { y, line -> | |
line.split("|") | |
.mapIndexed { x, cell -> | |
when (cell.trim()) { | |
"O" -> GridCell(Living, x = x, y = y) | |
else -> GridCell(Dead, x = x, y = y) | |
} | |
} | |
} | |
.flatten() | |
.asSequence() | |
fun displayCell(cell: GridCell): String = | |
when (cell.living) { | |
Dead -> " " | |
Living -> "O" | |
} | |
fun displayGrid(grid: Grid): String = | |
grid.groupBy { it.y } | |
.map { it.key to it.value.sortedBy { cell -> cell.x } } | |
.sortedBy { it.first } | |
.joinToString("\n") { (_, cells) -> cells.map(::displayCell).joinToString(" | ") } | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment