2013年10月6日日曜日

重み付きのランダム抽選関数を作る(PHP)

新生FF14のチョコボ(バディー)は、何も設定しなければフリースタイルで戦うって知ってましたか?頑張ってバディーのディフェンススキルを上げているのに、どうもチョコボの戦い方がディフェンサーぽくないな〜。おいっチョコボ!ちゃんと仕事しろよ!!っと思っていたら、メニューのバディー画面でフリースタイルのアイコンに小さいチェックマークがあるではないですか!?ディフェンススタイルにチェックするようにしたら、ちゃんと仕事するようになりました♪ …ごめんよチョコボ、筆者が無知なだけでした。


重み付きの抽選ロジックは既に色々なところで紹介されていますが、ちょっと必要になったので作ってみました。配列要素の値に重み(確率)となる整数値を入れて渡すと抽選された要素のキーを返します。サンプルでは、hash配列を渡していますが、array配列でも同様に要素のキーを返します。
/*
* 配列から1つの要素キーを抽選する。
*
* $entries: array($key => $weight, ...)
*           配列の値に抽選の割合(重み)を整数値で指定。
*/
function array_rand_weighted($entries){
    $sum  = array_sum($entries);
    $rand = rand(1, $sum);

    foreach($entries as $key => $weight){
        if (($sum -= $weight) < $rand) return $key;
    }
}


// 抽選候補となる配列
$entries = array(
    "1等"    => 10,
    "2等"    => 20,
    "3等"    => 30,
    "ハズレ"  => 40,
);

// 抽選
$result_key = array_rand_weighted($entries);



本当に確率通りに抽選されているか、100回と、1000回動作させてみた結果です。
ちゃんと確率通りに分布しているようです。
// ▼100回実行 抽選結果をカウント
$result = array();
for($i=0; $i<100; $i++){
    $key = array_rand_weighted($entries);
    @$result[$key]++;
}
print_r($result);
/*
 Array (
    [ハズレ] => 40
    [3等]   => 32
    [2等]   => 21
    [1等]   => 7
 )
*/

// ▼1000回実行 抽選結果をカウント
$result = array();
for($i=0; $i<1000; $i++){
    $key = array_rand_weighted($entries);
    @$result[$key]++;
}
print_r($result);
/*
 Array (
    [ハズレ] => 418
    [3等]   => 291
    [2等]   => 203
    [1等]   => 88
 )
*/

0 件のコメント:

コメントを投稿