rustでライフゲームを作る#2

rust

前回は、ライフゲームの骨格である、フィールドとセルの状況を調べる、盤面を描画するっていう3つ部分を作りました。

今回は、ライフゲームの次の段階。

世代更新の部分を作っていきます。

世代更新

ライフゲームは、自分と自分の周りのセルの状況(生と死)によって、自分のふるまい(誕生か死亡)が決まります。

おさらいすると

  • 過密
    • 生きているセルの周りに4つ以上ならそのセルは死亡
  • 均衡状態
    • 生きているセルの周りのセルが2か3であれば生き延びる
  • 過疎
    • 生きているセルの周りのセルが1つの場合は、死亡
  • 誕生
    • 死んでいるセル周りのセルがちょうど3つの時に死んでるセルは生き返る

このルールをもとにプログラミングしていきます。

世代更新の実装

次の世代に行く世代更新をプログラミングしていきます。

fn next_gen(&mut self){
        let mut next_cells = self.cells.clone();

        for row in 1..self.height+1{
            for column in 1..self.width+1{
                let idx = self.get_index(row, column);
                let cell = self.cells[idx];
                let alive_cells = self.get_alive_cells(row, column);
                let next_cell = match (cell,alive_cells) {
                    (Cell::Alive,x) if x < 2 => Cell::Dead,
                    (Cell::Alive,2) |(Cell::Alive,3) =>Cell::Alive,
                    (Cell::Alive,x) if x >3 =>Cell::Dead,
                    (Cell::Dead,3)=>Cell::Alive,
                    (otherwise,_) =>otherwise
                };
                next_cells[idx]=next_cell;
            }
        }
        self.cells = next_cells;
    }

引数を&mut selfとして、自己の更新をできるようにします。

まず最初にセルの状態の自身のコピーを作ります。

そして、全セルに対して更新していきます。

それをforループで回しています。

パターンマッチングを使って、自身のセルが生きているか死んでいるか、そして、自分以外の周りのセルがいくつ生きているか。これで、次の自分の運命が決まります。

一個一個取り出して更新をかけて終わりです。

実際に動くか確かめてみる

では、実際にちゃんと動くか確かめてみましょう。

検証用にメイン関数を作ります。

fn main() {
    let mut i = Field::new();
    println!("{}",i.to_string());
    i.next_gen();
    println!("{}",i.to_string());   
    i.next_gen();
    println!("{}",i.to_string());
}

このコードでは、2回更新を行ってます。

わかりやすく、グライダーを作ります。

let cells = [
                    0,0,0,0,0,0,0,0,0,0,
                    0,0,0,0,1,0,0,0,0,0,
                    0,0,0,0,0,1,0,0,0,0,
                    0,0,0,1,1,1,0,0,0,0,
                    0,0,0,0,0,0,0,0,0,0,
                    0,0,0,0,0,0,0,0,0,0,
                    0,0,0,0,0,0,0,0,0,0,
                    0,0,0,0,0,0,0,0,0,0,
                    0,0,0,0,0,0,0,0,0,0,
                    0,0,0,0,0,0,0,0,0,0,
                    ].into_iter()
                    .map(|i|{
                        if i==1{
                            Cell::Alive
                        }else{
                            Cell::Dead
                        }
                    }).collect();

今回は10行10列のセルで行います。

実行するとこんな感じです。

・・・・・・・・・・
・・・・〇・・・・・
・・・・・〇・・・・
・・・〇〇〇・・・・
・・・・・・・・・・
・・・・・・・・・・
・・・・・・・・・・
・・・・・・・・・・
・・・・・・・・・・
・・・・・・・・・・

・・・・・・・・・・
・・・・・・・・・・
・・・〇・〇・・・・
・・・・〇〇・・・・
・・・・〇・・・・・
・・・・・・・・・・
・・・・・・・・・・
・・・・・・・・・・
・・・・・・・・・・
・・・・・・・・・・

・・・・・・・・・・
・・・・・・・・・・
・・・・・〇・・・・
・・・〇・〇・・・・
・・・・〇〇・・・・
・・・・・・・・・・
・・・・・・・・・・
・・・・・・・・・・
・・・・・・・・・・
・・・・・・・・・・

ちゃんとグライダーが飛んでますね。

まとめ

これで、ライフゲームの基本的な動き、アルゴリズムは実装できました

この後できることは

たとえば、好きな形を自由に挿入できるようにする、setterを作ったり、ビジュアル表現できるようにwasm使ってみたりbevy使ってみたり、nannou使ってみたり。

いろいろ幅はあります。

予告ではありませんが、一応この後bevyを使った表現をしていこうかなーなんて思ってます。

ライフゲームbevy編が始まるかどうか!?

こうご期待。

参考資料

作るうえで参考にしたサイトや書籍、資料など

書籍

・岡瑞起、池上高志、ドミニク・チェン、青木竜太、丸山典宏『作って動かすALife』 オライリー・ジャパン(2018)

参考サイト

Rust and WebAssembly

コメント

タイトルとURLをコピーしました