読者です 読者をやめる 読者になる 読者になる

Panda Noir

JavaScript の限界を究めるブログです。

もはや2番煎じとかそういったレベルでないライフゲーム実装してみた

(この記事はQiitaで僕が書いたものを移行した記事です。記事中のコメントはQiitaの該当記事を参照ください)

一応実装できてるはずですが、仕様熟読したわけじゃないのであやしいです。

簡単な説明

コードを簡単に説明すると、Cellクラスは位置情報、状態(生きているか死んでいるか)、次の時間で生き残ることができるまたは誕生できるか判定する canLive() メソッドを備えています。

Boardクラスはセル情報、大きさを格納したメインとなるボードを生成します。Boardは初期状態をセットする set() メソッド、時間を進める next() メソッドを持っています。それらのクラスを使い、Boardのインスタンスを生成し、setで初期化後、nextで時間を進めます。

コンパイル後、 node main.js を実行するとテストパターンの初期状態、その次の時間が表示されます。

自分で初期状態をセットする方法

testCaseに初期状態を格納した配列をプッシュします。 初期状態は2次配列で、ACTIVE(or A)、DEAD(or D)という定数を入れてください。 ACTIVEは生きている、DEADは死んでいる状態です。 言葉よりはサンプルのコード見たほうが早いと思います。

コード

main=()->
  class Board
    constructor:(width,height)->
      @width=width
      @height=height
      @board=[]
      for i in [0...width] by 1
        @board[i]=[]
        for j in [0...height] by 1
          @board[i].push(new Cell(i,j,DEAD))
      return
    next:()->
      newBoard=new Board(@width,@height)
      for row,i in @board
        for cell,j in row
          if cell.canLive()
            newBoard.board[i][j]=new Cell(i,j,ACTIVE)
          else
            newBoard.board[i][j]=new Cell(i,j,DEAD)
      @board=newBoard.board
      return
    set:(map)->
      for row,i in map
        for value,j in row
          @board[i][j]=new Cell(i,j,value)
      return
    print:()->
      res=''
      for row in @board
        for value in row
          if value.state==ACTIVE
            res+='■ '
          else
            res+='□ '
        res+='\n'
      return res

  class Cell
    constructor: (x,y,state) ->
      @x=x
      @y=y
      @state=state
    canLive: ()->
      neighbor=0
      for dx in [-1..1]
        for dy in [-1..1]
          if dx==0 and dy==0
            continue
          if mainBoard.board[@x+dx]?[@y+dy]?.state==ACTIVE
            neighbor++

      if @state==ACTIVE
        if neighbor==2 or neighbor==3
          return true
        if neighbor<=1
          return false
        if neighbor>=4
          return false
      else
        if neighbor==3
          return true
        return false

  next=()->
  mainBoard=new Board(0,0)
  ACTIVE=1
  DEAD=0
  A=ACTIVE
  D=DEAD

  testCase=[
    [
      [A,A,D]
      [A,D,D]
      [D,D,D]
    ]
    [
      [D,D,D,D]
      [D,A,A,D]
      [D,A,A,D]
      [D,D,D,D]
    ]
    [
      [D,D,D]
      [D,A,A]
      [D,D,D]
    ]
    [
      [A,A,A]
      [A,A,D]
      [D,D,D]
    ]
    [
      [D,A,D]
      [D,A,D]
      [D,A,D]
    ]
    [
      [D,D,D,D,D,D,D,D,D,D,D,D,D,D,D,D]
      [D,D,D,D,D,D,D,D,D,D,D,D,D,D,D,D]
      [D,D,D,D,D,D,D,D,D,D,D,D,D,D,D,D]
      [D,D,D,D,D,D,D,D,D,D,D,D,D,D,D,D]
      [D,D,D,D,D,D,D,D,D,D,D,D,D,D,D,D]
      [D,D,D,D,D,D,D,D,D,D,D,D,D,D,D,D]
      [D,D,D,D,D,D,D,D,D,D,D,D,D,D,D,D]
      [D,D,D,D,D,D,D,D,D,D,D,D,D,D,D,D]
      [D,D,D,D,D,A,A,A,D,D,D,D,D,D,D,D]
      [D,D,D,D,D,A,D,D,D,D,D,D,D,D,D,D]
      [D,D,D,D,D,D,A,D,D,D,D,D,D,D,D,D]
      [D,D,D,D,D,D,D,D,D,D,D,D,D,D,D,D]
    ]
  ]

  for map in testCase
    console.log('start')
    mainBoard=new Board(map.length,map[0].length)
    mainBoard.set(map)

    console.log 'first'
    console.log mainBoard.print()

    mainBoard.next()
    console.log 'next'
    console.log mainBoard.print()
  return
main()