Help us understand the problem. What is going on with this article?

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

More than 1 year has passed since last update.

はじめに

前の投稿では、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.

gushwell
株式会社ジード / Microsoft MVP for Developer Technologies 2005-2019 / 著書『実戦で役立つ C#プログラミングのイディオム/定石&パターン』『新・標準プログラマーズライブラリ なるほどなっとく C#入門』『C#プログラミング入門―オブジェクト指向のプログラミング手法を基礎から解説』
https://github.com/gushwell
Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
Comments
No comments
Sign up for free and join this conversation.
If you already have a Qiita account
Why do not you register as a user and use Qiita more conveniently?
You need to log in to use this function. Qiita can be used more conveniently after logging in.
You seem to be reading articles frequently this month. Qiita can be used more conveniently after logging in.
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
ユーザーは見つかりませんでした