HiveBrain v1.2.0
Get Started
← Back to all entries
patternMinor

Conway life game implementation with scala

Submitted by: @import:stackexchange-codereview··
0
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:

  • 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.