LoginSignup
11
11

More than 5 years have passed since last update.

Bacon.js でカタンのサイコロをシミュレーションしてみた

Last updated at Posted at 2014-08-28

概要

Bacon.js を用いて、カタンのサイコロをシミュレーションし、サイコロの目に偏りがあるのかを検証しました。36回をひとまとめとし、各出目(2〜12)が平均確率以上の頻度でどの程度出るのかを確認します。

注: 特にカタンについて知らなくても、支障ありません。Bacon.js に興味ある方は、入門編としてわりと役に立つと思います。

準備

サイコロ

Bacon.js の EventStream.fromPoll メソッドを用いて、100msec に1回サイコロを振ります。

function rollDie() {
    return Math.ceil(Math.random() * 6);
}


function rollTwoDice() {
    return rollDie() + rollDie();
}


var diceStream = Bacon.fromPoll(100, function() {
    return new Bacon.Next(rollTwoDice());
});

試行回数をカウント

withStateMachine を用いて試行回数をカウントします。

var counterStream = diceStream.withStateMachine(0, function(sum, event) {
    if (event.hasValue()) {
        sum = sum + 1;
        return [sum, [new Bacon.Next(sum)]];
    }
});

36回をひとまとめに

出目の偏りを見るために、連続する36回ごとにひとまとめにします。

  • 空の配列を用意
  • event を受け取ったら後ろに追加
  • 36件より多くなったら、古いものから削除

このようにして、最大36の長さの配列を subscriber に渡します。

var RANGE = 36;

var bufferedStream = diceStream.withStateMachine(new Array(), function(sum, event) {
    if (event.hasValue()) {
        sum.push(event.value());
        if (sum.length > RANGE) {
            sum.shift();
        }
        return [sum, [new Bacon.Next(sum)]];
    }
});

出現確率を計算

最新の出目の(過去36回内での)出現回数と、理論上の出現確率との比を subscriber へ返します。ただし、36回貯まるまでの間は、比率を返さないようにします(ややイケてない)。

var PRODUCTIVITY = {
    2: 1/36,
    3: 2/36,
    4: 3/36,
    5: 4/36,
    6: 5/36,
    7: 6/36,
    8: 5/36,
    9: 4/36,
    10: 3/36,
    11: 2/36,
    12: 1/36
};

var productivityStream = bufferedStream.map(function (value) {
    var current = value[value.length - 1];
    var prod = PRODUCTIVITY[current];
    var num = value.filter(function (x) {return x == current;}).length;
    var rate = (num / RANGE) / prod;
    if (value.length < RANGE) {
        return [num, undefined];
    } else {
        return [num, rate];
    }
});

出現確率の確率を評価

出現確率の偏りに応じて、メッセージを表示します。

比率 メッセージ
3倍以上 キタァ━━━( ´∀`)━━━━!!!
2倍以上 キタ(・∀・)コレ!!
0.5~2倍 表示なし
0.5倍以下 ∑( ̄Д ̄;)なぬぅっ!!
var productivityStateStream = productivityStream.map(function (value) {
    if (value[1] === undefined) {
        return "";
    }
    if (value[1] >= 3.0) {
        return "キタァ━━━( ´∀`)━━━━!!!";
    } else if (value[1] >= 2.0) {
        return "キタ(・∀・)コレ!!";
    } else if (value[1] > 0.5) {
        return "";
    } else {
        return "∑( ̄Д ̄;)なぬぅっ!!";
    }
});

実行

最後に、これらの EventStream を結合して画面に表示します。event の同期を取るのに combineTemplate が便利です。

    var $result = $('#result');
    Bacon.combineTemplate({
        'dice': diceStream,
        'counter': counterStream,
        'productivity': productivityStream,
        'state': productivityStateStream
    }).onValue(function(value) {
        var val = value.counter + ": " + value.dice + " (" + value.productivity[0] + ") " + value.state;
        $result.append($('<li>').text(val));
    });

ソースコードと実行結果

ソースコードはこちらです。

実行結果はここで見れます。

参考

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