Skip to content

Instantly share code, notes, and snippets.

@olim7t
Created July 2, 2011 19:38
Show Gist options
  • Save olim7t/1061569 to your computer and use it in GitHub Desktop.
Save olim7t/1061569 to your computer and use it in GitHub Desktop.
Game of Life
/**
* Clear-headed attempt at a functional-style, "Scala-way" implementation.
*
* Seems to work on trivial cases. Too lazy to write unit tests now (note to self: write them later and then pretend I did TDD).
*/
class GameOfLife(val width: Int, val height: Int, val liveCells: Set[(Int, Int)]) {
def nextIteration: GameOfLife = {
val newCells = for {
(cell, liveNeighborCount) <- liveNeighborCounts
currentState = liveCells.contains(cell)
stillAlive = newState(currentState, liveNeighborCount)
if (stillAlive)
} yield cell
new GameOfLife(width, height, newCells.toSet)
}
override def toString = {
def formatCell(x: Int, y: Int) = if (liveCells.contains(x, y)) "O" else "."
def formatLine(y: Int) = (0 to width - 1).map(formatCell(_, y)).mkString(" ")
(0 to height - 1).map(formatLine).mkString("\n")
}
private val liveNeighborCounts: Map[(Int, Int), Int] = {
// For each live cell, generate an increment for all its neighbors
val increments = for {
(x, y) <- liveCells.toList
deltaX <- -1 to 1
deltaY <- -1 to 1
if (deltaX != 0 || deltaY != 0) // don't increment oneself
neighborX = x + deltaX
if (0 <= neighborX && neighborX < width) // ignore out of the grid
neighborY = y + deltaY
if (0 <= neighborY && neighborY < height)
} yield (neighborX, neighborY)
// Group the increments by cell
increments.groupBy(identity).mapValues(_.size)
}
private def newState(currentState: Boolean, liveNeighborCount: Int): Boolean =
liveNeighborCount match {
case 2 => currentState
case 3 => true
case fatalCount if (fatalCount < 2 || fatalCount > 3) => false
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment