Scala でライフゲームを書いてみた

2〜3時間で軽く書いてみました。
初めて Scala をガッツリ書いたのであまり Scala らしさが感じられないコードですが…。

[コード]

import scala.sys.process._

object Lifegame {
    type Table = List[List[Boolean]]
    val o = false
    val x = true

    def width(table: Table) = {
        table(0).size
    }

    def height(table: Table) = {
        table.size
    }

    def at_cell(table: Table, x: Int, y: Int) = {
             if(x < 0 || width(table)  <= x) o
        else if(y < 0 || height(table) <= y) o
        else table(y)(x)
    }

    def dead_or_alive(table: Table, x: Int, y: Int) = {
        val cell  = at_cell(table, x, y)
        val count = List(
            at_cell(table, x - 1, y - 1),
            at_cell(table, x - 0, y - 1),
            at_cell(table, x + 1, y - 1),
            at_cell(table, x + 1, y - 0),
            at_cell(table, x + 1, y + 1),
            at_cell(table, x - 0, y + 1),
            at_cell(table, x - 1, y + 1),
            at_cell(table, x - 1, y - 0)
        ).count(x => x)
        if(cell) count == 3 || count == 2 else count == 3
    }

    def update(table: Table) = {
        table.zipWithIndex.map { case(row, y) =>
            row.zipWithIndex.map { case(cell, x) =>
                dead_or_alive(table, x, y)
            }
        }
    }

    def print(table: Table) = {
        Process("clear").run
        println(Range(0, width(table) + 2).map(x => "-").mkString)
        println(table.map(row => "|" + row.map(x => if(x) "*" else " " ).mkString).mkString("|\n") + "|")
        println(Range(0, width(table) + 2).map(x => "-").mkString)
        Console.flush()
    }

    def run(table: Table):Int = {
        print(table)
        Thread.sleep(500)
        run(update(table))
        return 0
    }

    def main(args: Array[String]) {
        val table = List(
            List(o, o, o, o, o, o, o, o, o, o, o, o, o, o, o, o, o, o, o, o, o, o, o),
            List(o, o, o, o, o, o, o, o, o, o, o, o, o, o, o, o, o, o, o, o, o, o, o),
            List(o, o, o, o, o, o, o, o, x, o, o, o, o, o, o, o, o, o, o, o, o, o, o),
            List(o, o, o, o, o, o, x, o, x, x, o, o, o, o, o, o, o, o, o, o, o, o, o),
            List(o, o, o, o, o, o, x, o, x, o, o, o, o, o, o, o, o, o, o, o, o, o, o),
            List(o, o, o, o, o, o, x, o, o, o, o, o, o, o, o, o, o, o, o, o, o, o, o),
            List(o, o, o, o, x, o, o, o, o, o, o, o, o, o, o, o, o, o, o, o, o, o, o),
            List(o, o, x, o, x, o, o, o, o, o, o, o, o, o, o, o, o, o, o, o, o, o, o),
            List(o, o, o, o, o, o, o, o, o, o, o, o, o, o, o, o, o, o, o, o, o, o, o),
            List(o, o, o, o, o, o, o, o, o, o, o, o, o, o, o, o, o, o, o, o, o, o, o),
            List(o, o, o, o, o, o, o, o, o, o, o, o, o, o, o, o, o, o, o, o, o, o, o),
            List(o, o, o, o, o, o, o, o, o, o, o, o, o, o, o, o, o, o, o, o, o, o, o),
            List(o, o, o, o, o, o, o, o, o, o, o, o, o, o, o, o, o, o, o, o, o, o, o),
            List(o, o, o, o, o, o, o, o, o, o, o, o, o, o, o, o, o, o, o, o, o, o, o),
            List(o, o, o, o, o, o, o, o, o, o, o, o, o, o, o, o, o, o, o, o, o, o, o),
            List(o, o, o, o, o, o, o, o, o, o, o, o, o, o, o, o, o, o, o, o, o, o, o)
        )

        run(table)
    }
}

[所感]

要所要所でつまずいたものの、全体的にみればそこまで難しくなかったかなーという感じです。
まあ元々 C++ の実装をそのまま Scala で書きなおしただけですしね(なので Scala らしさがあまりないとも言える
型に関しては C++ よりも厳しいという印象を受けました。
本当は List[List[Boolean]] という型に依存したくなかったんですが、上手く消すことが出来なかった…。
ダックタイピングするだけでも結構いろいろと記述必要があるぽいのがちょっと厳しい…(良し悪しは別として。
Scala は他にはパターンマッチや trait、Structural Subtyping、implicit あたりなど面白い機能があるぽいので、次 Scala を書くときはそのあたりを少し意識してかいてみたい。

[気になったところ]

  • 条件演算子がない
  • List[List[Boolean]] 型に依存してしまっている
  • table の多次元配列をもっとすっきり記述したい
  • 型に対して厳しいのでつらい
    • val is_even = x => x % 2 == 0 みたいな事がやりたかった。
  • どのあたりが Scala らしいのかわからなかった