package com.rumi object GameOfLife { /** * Calculate the next iteration of the Game of Life. The game state is * represented by a Set[(Int,Int)] of alive cells. A new set is generated * for every generation. Coordinates count from (1,1) to (w,h), while the * (1,1) cell is in the top left corner. * * @param cells The current set of alive cells * @param xdim The width dimension of the playing field. * @param ydim The height dimension of the playing field. * @return The next generation of cells */ def nextIteration(cells: Set[(Int,Int)], xdim: Int, ydim: Int): Set[(Int,Int)] = { val allCells = for { ox <- 1 to xdim oy <- 1 to ydim } yield { val ac: Int = aliveNeighbourCount(cells, xdim, ydim, ox, oy) if (cells.contains((ox, oy))) { // if this cell is alive if (ac < 2) (0, 0) // and it has < 2 live neighbours, -> die else if (ac == 2 || ac == 3) (ox, oy) // and it has 2 or 3 live neightbours, -> continue to live else (0, 0) // more than 3 live neighbours -> die } else if (ac == 3) { // if the cell is dead and it has exactly 3 live neighboutrs (ox, oy) // make it alive } else { (0, 0) // everything else -> dead cell } } allCells.filterNot(_ equals (0,0)).toSet } /** * Counts the number of alive cells neighbouring the cell with the given * coordinates. * * @param cells The Set of all alive cells * @param xdim The width dimension of the playing field. * @param ydim The height dimension of the playing field. * @param ox X Coordinate of the cell under test * @param oy Y Coordinate of the cell under test * @return */ def aliveNeighbourCount(cells: Set[(Int, Int)], xdim: Int, ydim: Int, ox: Int, oy: Int): Int = { val aliveCount = (for { nx <- Math.max(1, ox - 1) to Math.min(ox + 1, xdim) ny <- Math.max(1, oy - 1) to Math.min(oy + 1, ydim) if !(nx == ox && ny == oy) && cells.contains((nx, ny)) } yield 1).sum aliveCount } def main(args: Array[String]): Unit = { // The famous "Beacon" starting pattern val startCells = Set((2,2), (3,2), (2,3), (5,4), (5,5), (4,5)) // We create an infinite stream of game iterations but only take 10 of them // and print the resulting game states. val game = Stream.iterate(startCells){ ni => nextIteration(ni, 6,6) } game.take(10).foreach { citer => for { x <- 1 to 6 } { for (y <- 1 to 6) { if (citer.contains((x,y))) print("X") else print(".") } println() } println() } } }