はじめに
前の投稿では、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メソッドを繰り返し呼び出し、描画を行うメイン処理を行うメインのプログラムです。
Promise
とasync/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>
実行結果
このプログラムですが、いいかげんな作りなので、Startボタンを複数クリックすると、クリックした数だけ点が生成され、複数の点が同時に動くようになります。
以下が、そのスクリーンショット。
ちょっと、点が小さいですが、5つの黒点があるのがわかると思います。
CodePenで書いて、埋め込んでみた
CodePenのページを埋め込んでみました。Startボタンを押せば、ランダムウォークが開始されます。
眺めてるだけでも楽しいです(笑)
See the Pen randomwalk2d by Gushwell (@gushwell) on CodePen.