3
2

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

Ruby と JavaScript でライフゲームを書いた

Last updated at Posted at 2020-02-18

ハッカーになろう模造クリスタル『ゲーム部』2で言及されてたライフゲームが面白そうだったので書いてみた。ライフゲームはセル平面上(要は方眼紙のこと)で生命をシミュレートするモデルです。

ライフゲームのルール

  • セルには生と死の二つの状態がある。
  • 時間(世代)が経過すると、あるルールに従ってセルの状態が変わる。
  • あるルールとは次の4つ。
    • 過疎による死: 自身が生で、周りの8セルのうち1セル以下が生のとき、次の世代で死ぬ。
    • 生存: 自身が生で、周りの8セルのうち2〜3セルが生のとき、次の世代で生き続ける。
    • 過密による死: 自身が生で、周りの8セルのうち4セル以上が生のとき、次の世代で死ぬ。
    • 誕生: 自身が死で、周りの8セルのうち3セルが生のとき、次の世代で生になる。

コードで表現しやすそうなルールだ。疑似コードで書いてみるとこんな感じ?

class Cell
  def next_alive?
    alive_count = 周囲.count { |item| item.alive? }

    # 過疎
    return false if self.alive? && alive_count <= 1
    # 生存
    return true if self.alive? && 2 <= alive_count && alive_count <= 3
    # 過密
    return false if self.alive? && 4 <= alive_count
    # 誕生
    return false if self.dead? && alive_count == 3

    false
  end
end

で、これを1世代ごとに全てのセルに対してチェックすればいけそう。

Ruby で実装

https://github.com/oieioi/lifegame.rb
こんな感じに動きます。JoyDivisionっぽい見た目になった。
lifegame.rb.gif

上に示した次世代の生死判定はこんな感じのコードになりました。

lib/lifegame/game.rb#L47-L78
    # あるセルが次のターンに生きてるか確認する
    def next_alive?(x, y)
      target = self[x, y]

      # 隣接セルの座標
      adjoining = [
        [x - 1, y - 1],
        [x    , y - 1],
        [x + 1, y - 1],
        [x - 1, y],
        # [x    , y],
        [x + 1, y],
        [x - 1, y + 1],
        [x    , y + 1],
        [x + 1, y + 1],
      ]

      dead_or_live = adjoining.map { |point|
        n_x, n_y = point
        self[n_x, n_y]&.alive?
      }.compact

      live_count = dead_or_live.count { |live| live }

      if target.dead?
        # 3の時のみ誕生
        live_count == 3
      else
        # 2,3の時のみ生き残る
        (2..3).include?(live_count)
      end
    end

JavaScript (with React)で実装

CLI だとインタラクティブなのがやりづらいのでJSでも書いてみた。

https://github.com/oieioi/lifegame.js
デモはこちら: https://dreamy-lumiere-0f384d.netlify.com/

画面収録 2020-02-04 14.36.33.gif

こちらは全てのセルを二次元配列で受け取って新しい生死の二次元配列を返すようにした。

src/lib/LifegameLogic.js#L1-L18
function nextCells(cells) {
  return cells.map((line, x)=> {
    return line.map((alive, y) => {
      // 周囲を調べる
      const aliveCount = getAdojoiningPositions(x, y).filter((position) => {
        const [x,y] = position;
        if (!cells[x]) return false;
        return cells[x][y]
      }).length
      if (alive) {
        // 周囲の生き残りが2,3のとき生存
        return aliveCount === 2 || aliveCount === 3;
      } else {
        return aliveCount === 3
      }
    });
  });
}
3
2
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
3
2

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?