セル・オートマトン

プログラミング

ハンズオンJavascript (オライリー)を読み始めました。Javascript は苦手意識が強くって(と言っても得意な言語はないんですが…)、一から勉強しようと思いました。一章に出てきた「セル・オートマトン」は面白い。こういうアルゴリズムは大好きです。色々いじりたくなり、コードをローカル環境に再現しました。(この本は ePub で落とせる「オライリー公式ショプ」から買った方がよいかも)

Mac での作業になります。Windows のかたは、linux をインストールするなど対応してください。

// Terminal
$ brew update
$ brew install git // git を使わず、GitHub よりファイルをダウンロードして、配置してもよい
$ npm install -g http-server // ローカルの js を Chrome ブラウザで動かすにはサーバーを立てる必要があります
$ mkdir ~/GithHub // 私は Github ディレクトリを作りましたが、ご自由に場所を決めてください。
$ cd ~/GitHub
$ git clone git@github.com:oreilly-japan/hands-on-javascript.git
$ cd hands-on-javascript/ch01
$ http-server // ドキュメントのルートでサーバーを起動

これでローカル環境で「セル・オートマトン」が遊べます! http://localhost:8080 に接続すると、上記の画像が得られました。20段を 100段に変更してみます。先ほど配置したファイル(~/GitHub//hands-on-javascript/ch01/index.html)をテキストエディタで開きます。

      // index.html の scriptタグ
      for (let i = 0; i <= 100; i++) { // 20 => 100
        addResult(ca1)
        ca1.next()
      }

縦が 100段になった画像が表示されました。素敵な模様です。なんか見たことがある模様ですが、シェルピンスキーのギャスケット 名前が付いているそうです。こういうの(フラクタル図形)がいきなり出てくると、プログラミングが楽しくなってきます。次の課題のために、繰り返し回数は 20 に戻しておきましょう。

(注意点)普通にリロードしても画像は変更できません。Chrome Dev Console を開いた状態で、左上のリロードボタンを右クリックして「ハード再読み込み」を選ぶ必要があります。

さて本題の「練習問題 1-4」に挑戦してみましょう。「初心者向けとしては難しいんじゃないの」と思いましたが、ルール30 の結果見たさに頑張ってみました。index.html で ca1 の定義部分を書き換えます。(あとで気づいたのですが、本「ハンズオンJavascript」に解答がしっかり書かれていましたね。解答なしのプログラミング本が多いので、解答はないと思い込んでいました。DevTool でのやり方は、本「ハンズオンJavascript」を参照してください。)

      // index.html の scriptタグ
      // const ca1 = new CA1Rule90("00000000000000000000100000000000000000000")
      const ca1 = new CA1({
        rule:30,
        states:[
          0,0,0,0,0,0,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,0,0,0,0,0,0,0,0,0,0
        ]
      })

「ハード再読み込み」すると、真っ黒になってしまった… 惜しいですね。いい線いっているが、もう一歩です。次にindex.html の条件式の部分を書き換えます。

      // index.html の scriptタグ
      function addResult(ca) {
        const result = document.getElementById("result")
        for (let i = 0; i < ca.states.length; i++) {
          const cell = document.createElement("div")
          if (ca.states[i] === "0" || ca.states[i] === 0) { // 数字の 0 の時を追記
            cell.classList.add("cell", "dead")
          } else {
            cell.classList.add("cell", "live")
          }
          result.appendChild(cell)
        }
      }

「ハード再読み込み」して出てくる画像が「ルール30」です。またまた不思議な模様が現れました。WikiPedia によると「ルール30は「クラス3」の挙動を示し、単純な初期状態からもカオス的な経過を示し、無作為な履歴になっている。」とのことです。単純なルールからこんなもの(カオス)が出てくるのは驚異的に思えます。これだけでは「カオス」に見えないので、ルール30 を拡大してみます。

      // index.html の headerタグ
      :root {
        /* 一行あたりのセルの数 */
        --cells:1001; /* 変更 */

        /* 一行あたりの幅 */
        --width:1001px; /* 変更 */

        /* セルの幅 = 一行あたりの幅 / 一行あたりのセルの数*/
        --cell-size:calc(var(--width)/var(--cells));
      }
      // index.html の headerタグ
      /* セルの見た目(基本) */
      .cell {
        /* 幅 */
        flex:var(--cell-size);

        /* 高さ */
        height:var(--cell-size);

        /* 枠線をサイズ計算に含めない */
        box-sizing:border-box;

        /* 枠線。幅1px、実線、灰色 */
        /*border-top:1px solid gray;*/ /* コメントアウト */
        /*border-left:1px solid gray;*/ /* コメントアウト */
      }
      // index.html の scriptタグ
      // 追記 states を表す配列を作成
      const numberOfCells = 1000;
      let states = [];
      for (let i = 0; i <= numberOfCells; i++) {
        if (i === numberOfCells / 2) {
          states.push(1)
        } else {
          states.push(0)
        }
      }

      const ca1 = new CA1({
        rule:30,
        states:states // 変更
      })

      for (let i = 0; i <= numberOfCells / 2; i++) { // 変更
        addResult(ca1)
        ca1.next()
      }

す、すごい。カオスきましたね。プログラミングって、楽しい!

(おまけ1)ルール90

(おまけ2)ルール110

(参考)WikiPedia セル・オートマトン

コメント

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