Spde を使う 5

2011-10-16 19:40:09

とりあえずライフゲームが動いてアプレットにしてブラウザで見るとこまでできた:
http://dl.dropbox.com/u/217014/fixed-data/spde-gameoflife/graft.html

./sbt applet を実行すると 100x100 固定サイズで HTML が出力されるので、そこは自分で修正した。

TDDでいうと緑になっただけで、要リファクタリングですねーという段階。たぶん。

val screenW = 400;
val screenH = 400;

val cellSize = 4;

// 縦横のセルの数
val cellNumX = screenW / cellSize
val cellNumY = screenH / cellSize

size(screenW, screenH)
frameRate(30)

// true or false がランダムに詰まった cellNumX * cellNumY の二次元配列を生成
def generateRandomMatrix(): Array[Array[Boolean]] = {
  new Array[Int](cellNumX).map{ x =>
    new Array[Int](cellNumY).map{ y =>
      random(2) > 1
    }
  }
}

def getCell(matrix: Array[Array[Boolean]], _x: Int, _y: Int): Int = {
  val x = if( _x >= cellNumX ){
            0
          }else if( _x < 0 ){
            cellNumX - 1
          }else{
            _x
          }
  val y = if( _y >= cellNumY ){
            0
          }else if( _y < 0 ){
            cellNumY - 1
          }else{
            _y
          }

  if(matrix(x)(y)) 1 else 0
}

def getNeighbourLiving(matrix: Array[Array[Boolean]], x: Int, y: Int): Int = {
  var num = 0
  num += getCell(matrix, x-1, y-1)
  num += getCell(matrix, x,   y-1)
  num += getCell(matrix, x+1, y-1)
  num += getCell(matrix, x-1, y)
  num += getCell(matrix, x+1, y)
  num += getCell(matrix, x-1, y+1)
  num += getCell(matrix, x,   y+1)
  num += getCell(matrix, x+1, y+1)
  num
}

def getWeightMatrix(matrix: Array[Array[Boolean]]): Array[Array[Int]] = {
  var x = -1
  var y = -1

  matrix.map{ row =>
    y = -1
    x += 1
    row.map{ col =>
      y += 1
      getNeighbourLiving(matrix, x, y)
    }
  }
}

// 現世代のパターンから次世代のパターンを生成
def generateNextMatrix(matrix: Array[Array[Boolean]]): Array[Array[Boolean]] = {
  val weightMatrix = getWeightMatrix(matrix)

  var x = -1
  var y = -1

  matrix.map{ row =>
    y = -1
    x += 1
    row.map{ col =>
      y += 1
      val numLiving = weightMatrix(x)(y)

      val result = if(matrix(x)(y)){
        if(numLiving <=1 || 4 <= numLiving ){
          false
        }else{
          true
        }
      }else{
        if(numLiving == 3){
          true
        }else{
          false
        }
      }

      result
    }
  }
}

// 生きセルを追加
def addLivingCell(matrix: Array[Array[Boolean]]): Array[Array[Boolean]] = {
  matrix.map{ row =>
    row.map{ col =>
      if(random(1000) < 1) true else col
    }
  }
}

// matrix の内容に従って描画(trueならセルを描画)
def drawMatrix(matrix: Array[Array[Boolean]]) = {
  stroke(0)
  fill(0)
  for (yi <- 0 to cellNumY - 1){
    val y = yi * cellSize
    for (xi <- 0 to cellNumX - 1){
      val x = xi * cellSize
      if( matrix(xi)(yi) ){
        //rect(x, y, cellSize - 2, cellSize - 2)
        rect(x, y, cellSize - 2, cellSize - 2)
      }
    }
  }
}

/********************************/

var count = 0

// 最初のランダムなパターンを生成
var matrix = generateRandomMatrix

def draw {
  fill(255)
  rect(-1, -1, screenW+1, screenH+1)

  drawMatrix(matrix)

  // 現世代のパターンから次世代のパターンを生成
  matrix = generateNextMatrix(matrix)

  // 生きセルをランダムに追加
  if(count % 1000 == 0) matrix = addLivingCell(matrix)

  count += 1
  // if(count > 100){ exit }
}