概要
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));
});
ソースコードと実行結果
ソースコードはこちらです。
実行結果はここで見れます。
- http://ledmonster.github.io/joking.bacon.catan/ (1000件で打ち止め)