LoginSignup
2
2

More than 5 years have passed since last update.

2次元ランダムウォークを可視化する

Last updated at Posted at 2019-03-11

はじめに

前の投稿では、1次元ランダムウオークのプログラムを書いたので、今度は2次元ランダムウォークのプログラムを書いてみました。

(x,y)にある点の次の位置を(x+1,y) (x-1,y) (x,y+1) (x,y-1)の4つとし、それぞれが、1/4の確率である場合の動きを可視化するプログラムです。

この記事の最後に、CodePenのページを埋め込んでいるので、動きを確認できます。

MyCanvasクラス

1次元ランダムウォークの時と同じように、まず、MyCanvasクラスを定義します。

class MyCanvas {
    constructor (id, width, height) {
        this.canvas = document.getElementById(id);
        this.ctx = this.canvas.getContext('2d');
        if (width)
            this.ctx.canvas.width = width;
        if (height)
            this.ctx.canvas.height = height;
        this.width = this.ctx.canvas.width;
        this.height =  this.ctx.canvas.height;
    }

    drawPoint(x1, y1, size, color = '#000') {
        this.ctx.save();
        this.ctx.beginPath();
        this.ctx.fillStyle = color;
        this.ctx.fillRect(x1, y1, size, size);
        this.ctx.restore();
    }

    // すべてをクリア
    clearAll() {
        this.ctx.clearRect(0, 0, this.width, this.height);
    }
}

drawPointメソッドとclearAllメソッドだけをもつ簡単なクラスです。

Walkerクラス

次は、Walkerクラスです。これは、ランダムウオークを行うこのプログラムの核となるクラスです。ひとつの点の動きを扱います。複数の点を同時に動かす場合には、このインスタンスを複数生成することになります。

walkメソッドを呼び出すたびに、ランダムに一歩だけ座標が動きます。なお、ここでは描画は行っていません。

class Walker {
    constructor (size) {
        this.x = 0;
        this.y = 0;
        this.maxHeight = 0;
        this.maxWidth = 0;
        this.size = size;
    }

    walk() {
        var d = Math.floor(Math.random() * 4) + 1;
        var diffx = 0, diffy = 0;
        switch (d) {
            case 1:
                diffx = +this.size;
                break;
            case 2:
                diffx = -this.size;
                break;
            case 3:
                diffy = +this.size;
                break;
            case 4:
                diffy = -this.size;
                break;
        }
        if (0 < this.x + diffx && this.x + diffx < this.maxWidth - this.size)
            this.x += diffx;
        if (0 < this.y + diffy && this.y + diffy < this.maxHeight - this.size)
            this.y += diffy;
        return {x:this.x, y:this.y};
    };
}

Prigramクラス

最後が、Walkerクラスのwalkメソッドを繰り返し呼び出し、描画を行うメイン処理を行うメインのプログラムです。

Promiseasync/awaitを使って、無限ループ風のコードを書こうとしたのですが、CodePenだと、無限ループはダメだよ、とエラーになってしまうので、setIntervalを使った従来の書き方にしました。

class Program {
    constructor() {
        this.height = 300;
        this.width = 300;

        this.canvas = new MyCanvas('mycanvas', this.width, this.height);
        this.loop = true; 
    }

    run() {
        let btn = document.querySelector('#startButton');
        btn.onclick = () => this.start();
        let btn2 = document.querySelector('#stopButton');
        btn2.onclick = () => this.stop(); 
    }

    start() {
        this.canvas.clearAll();
        const size = 2;
        var walker = new Walker(size);
        walker.x = this.width / 2;
        walker.y = this.height / 2;
        walker.maxWidth = this.width;
        walker.maxHeight = this.height;
        this.canvas.drawPoint(walker.x, walker.y, size);

        this.loop = true;
        let timer = setInterval(() => {
            this.canvas.drawPoint(walker.x, walker.y, size, '#ccc');
            walker.walk();
            this.canvas.drawPoint(walker.x, walker.y, size, '#000');
            if (this.loop === false)
                clearInterval(timer);
        }, 20);
    }

    stop() {
        this.loop = false;
    }
}

window.onload = function() {
    var pgm = new Program();
    pgm.run();
};

HTML

HTMLは以下の通り。

<!DOCTYPE html >
<html lang="ja">
<head>
    <meta charset="utf-8">
    <title>sample</title>
    <style>
      #mycanvas {
        background-color: beige;
      }
    </style>
</head>
<body>
  <div>
      <button id="startButton" type="button">Start</button>
      <button id="stopButton" type="button">Stop</button>
  </div>
  <div>
      <canvas id="mycanvas" width="200" height="200"></canvas>
  </div>
  <script src="randomwalk2d.js"></script>
</body>
</html>

実行結果

スクリーンショット 2019-03-08 20.47.21.png

このプログラムですが、いいかげんな作りなので、Startボタンを複数クリックすると、クリックした数だけ点が生成され、複数の点が同時に動くようになります。

以下が、そのスクリーンショット。

スクリーンショット 2019-03-08 20.47.44.png

ちょっと、点が小さいですが、5つの黒点があるのがわかると思います。

CodePenで書いて、埋め込んでみた

CodePenのページを埋め込んでみました。Startボタンを押せば、ランダムウォークが開始されます。

眺めてるだけでも楽しいです(笑)

See the Pen randomwalk2d by Gushwell (@gushwell) on CodePen.

2
2
1

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
2
2