JavaScriptでお絵かき - 拡散律速凝集 (Diffusion-Limited Aggregation)

ここまでの試行錯誤と、ドットインストールの「はじめてのJavaScript」の 知識で、簡易なDLAシミュレーションを行ってみます。

ドットインストール「はじめてのJavaScripthttps://dotinstall.com/lessons/basic_javascript_v4

拡散律速凝集 (Diffusion-Limited Aggregation)の詳細は Wikipediaにお任せするとして、 ここでは似たような形を描ければよしという考えです。

ja.wikipedia.org

実は、20年以上前に同じようなプログラムを作ったことがあります。 そのときはDelphi(Object-Pascal)を使っていました。

ソフトの砂場(DLA)

その劣化版を作りました。実行結果はこんなの。 もっと大きい図を描きたいのですが、 一定時間以内に実行を終えないといけないようなので、 これくらいにしました。

f:id:yamamoto-works:20200215125706p:plain

ソースコードは次のとおりです。 途中でsleepなどにより実行権放棄ができればよいのですが、 やり方がよくわからないので断念しました。 他にも改善したいところはあるのですが、 経験値が足りないので、今はここまでにしておきます。

<!DOCTYPE html>
<html lang="ja">
  <head>
    <meta charset="utf-8">
    <title>拡散律速凝集 (Diffusion-Limited Aggregation)</title>
    <style>
      #mycanvas {
        border: 1px solid black;
      }
    </style>
  </head>
  <body>
    <canvas width="400" height="400" id="mycanvas"></canvas>
    <script src="https://ajax.googleapis.com/ajax/libs/jquery/1.12.4/jquery.min.js"></script>
    <script>
      $(function() {
        const canvas = document.getElementById('mycanvas');
        if (!canvas || !canvas.getContext) return false;
        const ctx = canvas.getContext('2d');
        const maxW = canvas.width;
        const maxH = canvas.height;
        const imgData = ctx.createImageData(maxW, maxH);

        const h = maxW/2;
        const h2 = h*h - 5;
        const r = h * 0.75;

        let idx = (h + h*maxW) * 4;
        imgData.data[idx]   = 0;
        imgData.data[idx+1] = 0;
        imgData.data[idx+2] = 0;
        imgData.data[idx+3] = 255;

        for (let i = 0; i < 3000; ) {
          let t = Math.random() * Math.PI * 2;
          let x = Math.floor(Math.cos(t) * r) + h;
          let y = Math.floor(Math.sin(t) * r) + h;

          while ((x-h)*(x-h) + (y-h)*(y-h) < h2) {
            if (imgData.data[(x-1 +  y   *maxW)*4 + 3] > 0
             || imgData.data[(x+1 +  y   *maxW)*4 + 3] > 0
             || imgData.data[(x   + (y-1)*maxW)*4 + 3] > 0
             || imgData.data[(x   + (y+1)*maxW)*4 + 3] > 0) {

              i++;
              idx = (x + y*maxW) * 4;
              imgData.data[idx]   = 0;
              imgData.data[idx+1] = 0;
              imgData.data[idx+2] = 0;
              imgData.data[idx+3] = 255;
              ctx.putImageData(imgData, 0, 0);
              // ここで実行権放棄しないと描画されない??
              break;
            }

            let m = Math.random();
            if (m < 0.25) {
              x -= 1;
            } else if (m < 0.5) {
              x += 1;
            } else if (m < 0.75) {
              y -= 1;
            } else {
              y += 1;
            }
          }
        }
      });
    </script>
  </body>
</html>

JavaScriptでお絵かきは、とりあえず満足しました。