LoginSignup
3
7

More than 5 years have passed since last update.

必ず元の場所に戻るランダムウォークのサンプル

Last updated at Posted at 2017-03-23

概要

一定量の移動幅を持つランダムウォークをし終わったときに、必ず元の場所に戻ってくるコードのサンプルです。

原理

プラス方向に移動した分だけマイナス方向にも動く(どのタイミングで逆の動きをするかはランダム)ことにより、移動量の合計が0に戻る仕組みです。

デモ

キャプチャ画像

こんな風に横移動した後に最初の位置に戻ります。

デモページ:
http://codepen.io/butchi/pen/XMqevj

サンプルコード

シャッフルにはFisher–Yatesアルゴリズムを用いましたが、
Underscoreの_.shuffleとかで代用できるので読み飛ばせばOK。

const LENGTH = 25; // 25×2の50回ランダムウォークする
const MAGNITUDE = 10; // 振動ピクセル幅

// 入力した正の数を正負両方含む配列(倍のサイズ)として返す
function double(arr) {
  let ret = [];

  arr.forEach((num) => {
    ret.push(num);
    ret.push(-num);
  });

  return ret;
}

// Fisher–Yatesアルゴリズムによる配列シャッフル
function shuffle(arr) {
  let ret = [].concat(arr);

  for(let i = ret.length - 1; i > 0; i--){
    let r = Math.floor(Math.random() * (i + 1));
    let tmp = ret[i];
    ret[i] = ret[r];
    ret[r] = tmp;
  }

  return ret;
}

// ランダムウォークの対象要素
let walkerElm = document.querySelector('.walker')

// ランダムウォークを始めるボタン
let startBtn = document.querySelector('.btn-start');

startBtn.addEventListener('click', () => {
  // ランダム数値配列(mapを有効にするため一旦0で初期化)
  let deltaXArr = (new Array(LENGTH)).fill(0).map(() => {
    return Math.random() * MAGNITUDE;
  });

  let deltaXArr2 = double(deltaXArr);
  let shuffleXArr = shuffle(deltaXArr2);

  // 累積変動量
  let deltaX = 0;

  for(let i = 0; i < LENGTH * 2; i++) {
    setTimeout(() => {
      deltaX += shuffleXArr[i];
      walkerElm.style.transform = `translateX(${deltaX}px)`;
    }, i * 50);
  }
});

今回は簡単のため横軸のみ移動にしましたが、
X軸とY軸だったり絶対値(abs)と偏角(arg)の2つの配列で処理すれば平面上のランダムウォークも実装できます。

3
7
0

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