patternMinor
Conway life game implementation with scala
Viewed 0 times
withconwayscalagamelifeimplementation
Problem
I've tried to create optimal in terms of performance and memmory consumption. But also I've tried to make it functional and scala way. I want to get you comment on how to make it more 'scala'stic
object LifeGame extends App {
trait Matrix extends Iterable[(Int, Int)] {
def apply(p: (Int, Int)): Boolean
def update(p: (Int, Int), b: Boolean): Unit
def newInstance: Matrix;
}
class SparseMapMatrix extends Matrix {
type Point = (Int, Int)
private var data = Set[(Int, Int)]()
def apply(p: Point): Boolean = data.contains(p)
def update(p: Point, b: Boolean) = if (b) data += p else data -= p
def newInstance = new SparseMapMatrix()
def iterator = data.iterator
override def toString() = {
val sb = new StringBuilder()
def best(func: (Int, Int) => Int)(p1: Point, p2: Point) = (func(p1._1, p2._1), func(p1._2, p2._2))
val minBoundary = ((0, 0) /: iterator)(best(math.min))
val maxBoundary = ((0, 0) /: iterator)(best(math.max))
for (i input(p)).count(_ == true)
case class State(l: Boolean, n: Int)
val newValue = State(input(p), nn) match {
case State(true, n) if n false
case State(true, 2) | State(true, 3) => true
case State(true, n) if n > 3 => false
case State(false, 3) => true
case State(value, _) => value
};
if(newValue) Some(p) else None
}
liveCells.seq.foreach { _ match { case Some(p:Point) => result(p) = true; case _ => ;}}
result
}
}
def block1D(i: Int) = i - 1 to i + 1
}Solution
The main-things I changed:
The code:
- Matrix is now completely immutable
- Code is more self-documenting (extract complex code to methods, etc.)
- I deleted the unnecessary inheritance
- I don't like apply-methods which are used as contains-methods -> name change
- I deleted parentheses in side-effect free methods
- Many syntax improvements
The code:
object LifeGame extends App {
case class Point(x: Int = 0, y: Int = 0)
object Matrix {
def empty: Matrix =
Matrix(Set.empty)
}
case class Matrix(private val data: Set[Point]) {
def contains(p: Point): Boolean =
data contains p
def update(p: Point, b: Boolean) =
if (b) copy(data+p) else copy(data-p)
def iterator: Iterator[Point] =
data.iterator
override def toString = {
def best(func: (Int, Int) => Int)(p1: Point, p2: Point) =
Point(func(p1.x, p2.x), func(p1.y, p2.y))
val minBoundary = (Point() /: iterator) { best(math.min) }
val maxBoundary = (Point() /: iterator) { best(math.max) }
val sb = StringBuilder.newBuilder
for (i Boolean = {
case (true, 0 | 1) => false
case (true, 2 | 3) => true
case (true, _) => false
case (false, n) => n == 3
}
def apply(input: Matrix): Matrix = {
def block1D(i: Int) =
Seq(i-1, i, i+1)
def block2D(p: Point) =
for (x p }
(Matrix.empty /: cells) { (result, p) => result(p) = true }
}
}
}Code Snippets
object LifeGame extends App {
case class Point(x: Int = 0, y: Int = 0)
object Matrix {
def empty: Matrix =
Matrix(Set.empty)
}
case class Matrix(private val data: Set[Point]) {
def contains(p: Point): Boolean =
data contains p
def update(p: Point, b: Boolean) =
if (b) copy(data+p) else copy(data-p)
def iterator: Iterator[Point] =
data.iterator
override def toString = {
def best(func: (Int, Int) => Int)(p1: Point, p2: Point) =
Point(func(p1.x, p2.x), func(p1.y, p2.y))
val minBoundary = (Point() /: iterator) { best(math.min) }
val maxBoundary = (Point() /: iterator) { best(math.max) }
val sb = StringBuilder.newBuilder
for (i <- minBoundary.x to maxBoundary.x) {
sb.append("\n")
for (j <- minBoundary.y to maxBoundary.y) {
sb.append(if (this contains Point(i, j)) "x" else " ")
}
}
sb.append("\nmin=%s, max=%s" format (minBoundary, maxBoundary))
sb.toString
}
}
object Engine {
def newCell: (Boolean, Int) => Boolean = {
case (true, 0 | 1) => false
case (true, 2 | 3) => true
case (true, _) => false
case (false, n) => n == 3
}
def apply(input: Matrix): Matrix = {
def block1D(i: Int) =
Seq(i-1, i, i+1)
def block2D(p: Point) =
for (x <- block1D(p.x); y <- block1D(p.y)) yield Point(x, y)
def points =
(input.iterator flatMap block2D).toSet.par
def calcCell(p: Point) = {
val neighbours = block2D(p) filter { p != }
val alive = neighbours map { input contains } count { true == }
if (newCell(input contains p, alive)) Some(p)
else None
}
val cells = (points map calcCell).seq collect { case Some(p) => p }
(Matrix.empty /: cells) { (result, p) => result(p) = true }
}
}
}Context
StackExchange Code Review Q#5097, answer score: 4
Revisions (0)
No revisions yet.