To learn Scala, coming from Java and Python, I'm attempting to program an implementation of Conway's Game of Life.
I've implemented two different approaches so far, with the first being so bad I'm not even going to ask for review.
The second is a bit cleaner, and produces the correct output, but since I'm new to Scala, I want to know a more Scala-centric way to write things.
I'm also curious about feasibility for my third approach to this game, such as a bit-map approach to neighborhoods, and value caching.
What I want to know is:
- Does my implementation fit well with the Scala way of writing code?
- Can my code by reduced and made more concise than it already may or may not be?
- Would representing all outcomes as a 9-bit map, then pre-caching all 512 possible outcomes have a positive or negative effect on performance?
The code in question is here, and also on Github.
package com.himself12794.main
import scala.collection.mutable.HashMap
object GameLife2 {
def mappify(str: String, pad: Char = ' ') = {
val its = new HashMap[(Int,Int), Boolean]
var x,y = 0
var items = str.stripMargin split("\n") toBuffer
val m = items.reduceLeft((a,b) => a max b ).length
if (items.length < 100) 0 to 100 - items.length foreach { _ => items append "" }
items = items map { _ padTo(100, pad) }
items foreach { z => z foreach { c => its put((x,y),c == 'X'); x += 1}; y += 1; x = 0 }
its
}
}
class GameLife2(m: String, val living: Char = 'X', val dead: Char = ' ') {
private var cells = GameLife2.mappify(m, dead)
private val hw = cells.keySet reduceLeft { (a,b) => (a._1 max b._1, a._2 max b._2) }
val height = hw._2 + 1
val width = hw._1 + 1
def getCount(x1: Int, y1: Int) = {
var am = 0
for {
x <- x1 - 1 to x1 + 1
y <- y1 - 1 to y1 + 1
} {
if (x > -1 && y > -1 && x < width && y < height && (x,y) != (x1,y1) && this(x,y)) am += 1
}
am
}
def apply(x: Int, y: Int) = {
cells.get((x,y)).get
}
def doCycle = {
val cp = cells.clone
cells foreach {
cell => {
val coords = cell._1
val c = cell._2
val am = getCount(coords._1, coords._2)
if (c && (am < 2 || am > 3)) cp.put(coords, false)
else if (am == 3) cp.put(coords, true)
}
}; cells = cp
}
def clearConsole = print("\n" * 9)
def getCells = cells
}