Skip to content

Instantly share code, notes, and snippets.

@AdrianoCelentano
Last active January 29, 2021 13:40
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save AdrianoCelentano/c65c58a65b63489821777dba042633cb to your computer and use it in GitHub Desktop.
Save AdrianoCelentano/c65c58a65b63489821777dba042633cb to your computer and use it in GitHub Desktop.
package com.adriano.gameoflife
import android.os.Bundle
import androidx.appcompat.app.AppCompatActivity
import androidx.compose.foundation.Canvas
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.runtime.LaunchedEffect
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.ui.Modifier
import androidx.compose.ui.geometry.Offset
import androidx.compose.ui.geometry.Size
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.graphics.drawscope.DrawScope
import androidx.compose.ui.graphics.drawscope.Fill
import androidx.compose.ui.platform.setContent
import com.adriano.gameoflife.CellGrid.Companion.cellColumnSize
import com.adriano.gameoflife.CellGrid.Companion.cellRowSize
import kotlinx.coroutines.delay
import kotlinx.coroutines.isActive
import kotlin.random.Random
class MainActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContent {
val cellGrid = remember { mutableStateOf(CellGrid.create()) }
LaunchedEffect(Unit) {
while (isActive) {
cellGrid.value = cellGrid.value.calculateNextGrid()
delay(100)
}
}
Canvas(
modifier = Modifier
.fillMaxSize()
) {
cellGrid.value.draw(this)
}
}
}
}
data class Cell(
val x: Int,
val y: Int,
var isAlive: Boolean,
) {
fun draw(drawScope: DrawScope, cellWidth: Float, cellHeight: Float) {
val color = if (isAlive) Color.Black else Color.White
drawScope.drawRect(
color = color,
topLeft = Offset(x = x * cellWidth, y = y * cellHeight),
size = Size(cellWidth, cellHeight),
style = Fill
)
}
}
data class CellGrid constructor(
private val cells: MutableList<MutableList<Cell>>
) {
fun calculateNextGrid(): CellGrid {
val newGrid = create()
(0 until cellRowSize).forEach { x ->
(0 until cellColumnSize).forEach { y ->
val above = if (y == 0) cellColumnSize - 1 else y - 1
val below = if (y == cellColumnSize - 1) 0 else y + 1
val left = if (x == 0) cellRowSize - 1 else x - 1
val right = if (x == cellRowSize - 1) 0 else x + 1
val currentCell = cells[x][y]
val neighbours = mutableListOf<Cell>()
neighbours.add(cells[left][above])
neighbours.add((cells[left][y]))
neighbours.add((cells[left][below]))
neighbours.add(cells[x][below])
neighbours.add(cells[right][below])
neighbours.add(cells[right][y])
neighbours.add(cells[right][above])
neighbours.add(cells[x][above])
val aliveNeighbours = neighbours.count { it.isAlive }
val nextStep = classicalRules(currentCell, aliveNeighbours)
newGrid.cells[x][y] = Cell(isAlive = nextStep, x = x, y = y)
}
}
return newGrid
}
fun draw(drawScope: DrawScope) {
val cellWidth = drawScope.size.width / cellRowSize
val cellHeight = drawScope.size.height / cellColumnSize
(0 until cellRowSize).forEach { x ->
(0 until cellColumnSize).forEach { y ->
cells[x][y].draw(drawScope, cellWidth, cellHeight)
}
}
}
private fun classicalRules(
currentCell: Cell,
aliveNeighbours: Int
) = when {
currentCell.isAlive && aliveNeighbours in 2..3 -> true
currentCell.isAlive.not() && aliveNeighbours == 3 -> true
else -> false
}
private fun vichniacVoteRules(
currentCell: Cell,
aliveNeighbours: Int
): Boolean {
val aliveCount = aliveNeighbours + if (currentCell.isAlive) 1 else 0
return when {
aliveCount <= 4 -> false
else -> true
}
}
companion object {
const val cellRowSize = 100
const val cellColumnSize = 200
fun create(): CellGrid {
return CellGrid(MutableList(cellRowSize) { x ->
MutableList(cellColumnSize) { y ->
Cell(
x = x,
y = y,
isAlive = Random.nextFloat() > 0.5f
)
}
})
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment