ラベル PHP の投稿を表示しています。 すべての投稿を表示
ラベル PHP の投稿を表示しています。 すべての投稿を表示

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
 )
*/

2013年9月16日月曜日

○○時まであと何時間何分?を取得する関数。(PHP)

FF14の方はLv.32の白魔導士までいきました。コンテンツファインダーのダンジョンがかなり難しくなってきていて、2,3回死ぬのが当たり前の状態になっています…汗。ただ、そういった激戦のあとはみんな達成感に満ちていて、なんかいい感じです。

PHPの時間関係の関数ややこしいですね。
なかなか想い通りのものを作るのに時間が掛かったので、忘備録として下記に指定時刻があと何時何分かを取得する関数を記載します。
/*
 * 指定時刻があと何時何分か'##:##'の書式文字列で取得する。
 * $time_expr: '13:15' のような時刻文字列を指定する。
*/
function get_time_left($time_expr){

    $now    = time();
    $target = date("Y-m-d {$time_expr}:00", $now);

    // 既に過ぎた時間であれば、翌日の日付にする。
    if (strtotime($target) < $now){
        $tommorow = date('d', $now) + 1;
        $target   = date("Y-m-{$tommorow} {$time_expr}:00");
    }

    $diff         = strtotime($target) - $now;
    $diff_hour    = intval($diff / 3600);
    $diff_minutes = intval($diff / 60) % 60;

    return sprintf("%02d:%02d", $diff_hour, $diff_minutes);
}

echo get_time_left('0:00')  . "\n";
echo get_time_left('4:30')  . "\n";
echo get_time_left('12:20') . "\n";
echo get_time_left('23:00') . "\n";
夜中の2時ちょうどに実行した時の出力結果
22:00
02:30
10:20
21:00

指定の時刻が過ぎた時間であれば、翌日の時間までを返すようにしています。なにか決まった時刻にイベントがある時に、あと何時間か取得する時に使えます。