--- title: 2次元ランダムウォークを可視化する tags: JavaScript ランダムウォーク canvas es2015 author: gushwell slide: false --- ## はじめに 前の投稿では、[1次元ランダムウオーク](https://qiita.com/gushwell/items/59e11f0029b45515fe19)のプログラムを書いたので、今度は2次元ランダムウォークのプログラムを書いてみました。 (x,y)にある点の次の位置を(x+1,y) (x-1,y) (x,y+1) (x,y-1)の4つとし、それぞれが、1/4の確率である場合の動きを可視化するプログラムです。 この記事の最後に、CodePenのページを埋め込んでいるので、動きを確認できます。 ## MyCanvasクラス 1次元ランダムウォークの時と同じように、まず、MyCanvasクラスを定義します。 ```js 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メソッドを呼び出すたびに、ランダムに一歩だけ座標が動きます。なお、ここでは描画は行っていません。 ```js 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メソッドを繰り返し呼び出し、描画を行うメイン処理を行うメインのプログラムです。 `Promise`と`async/await`を使って、無限ループ風のコードを書こうとしたのですが、CodePenだと、無限ループはダメだよ、とエラーになってしまうので、`setInterval`を使った従来の書き方にしました。 ```js 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は以下の通り。 ```html sample
``` ## 実行結果 ![スクリーンショット 2019-03-08 20.47.21.png](https://qiita-image-store.s3.amazonaws.com/0/29415/b6a645b9-533e-e6fb-32ce-76a44c7abb5f.png "スクリーンショット 2019-03-08 20.47.21.png") このプログラムですが、いいかげんな作りなので、Startボタンを複数クリックすると、クリックした数だけ点が生成され、複数の点が同時に動くようになります。 以下が、そのスクリーンショット。 ![スクリーンショット 2019-03-08 20.47.44.png](https://qiita-image-store.s3.amazonaws.com/0/29415/a494452e-35fc-5be6-f4ee-90685bb8a833.png "スクリーンショット 2019-03-08 20.47.44.png") ちょっと、点が小さいですが、5つの黒点があるのがわかると思います。 ## CodePenで書いて、埋め込んでみた CodePenのページを埋め込んでみました。Startボタンを押せば、ランダムウォークが開始されます。 眺めてるだけでも楽しいです(笑)

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