さまざまなランクにグループ化された、いわゆるバトルの数が増えています。ユーザーに表示される戦闘をランダム化したい。表示率は、1 位のランク (より高いランク - より多くのインプレッション) によって定義され、2 番目のレベルは、このランクのコレクションからランダムなバトルを獲得することです。ランク内のすべての戦闘には、独自のインプレッション数があります。
$battles では、DB から戦闘を取得し、いくつかの計算を実行して、表示率と各ランクが取得する必要があるインプレッションを定義します。
foreach ($battles as $el => &$values) {
$values['show_rate'] = $values['rank'] * 100 / $totals['sum_of_ranks'];
$values['dedicated_impressions'] = $totals['total_battle_impressions'] * $values['show_rate'] / 100;
$values['impressions_left'] = $values['dedicated_impressions'] - $values['sum_of_impressions'];
}
これは前のサイクルの結果です。キーbattle_ids
には、このランクの戦闘の ID がありbattle_impressions
、同じ方法で並べられた同じ戦闘の印象があります。
$battles = array(
0 => array(
'battles_in_rank' => '1',
'battle_ids' => array(
0 => '28',
),
'battle_impressions' => array(
0 => '3',
),
'sum_of_impressions' => '3',
'rank' => '0',
'show_rate' => 0,
'dedicated_impressions' => 0,
'impressions_left' => -3,
),
1 => array(
'battles_in_rank' => '4',
'battle_ids' => array(
0 => '27',
1 => '19',
2 => '18',
3 => '17',
),
'battle_impressions' => array(
0 => '0',
1 => '0',
2 => '0',
3 => '0',
),
'sum_of_impressions' => '0',
'rank' => '1',
'show_rate' => 6.6666666666667,
'dedicated_impressions' => 230.53333333333,
'impressions_left' => 230.53333333333,
),
2 => array(
'battles_in_rank' => '2',
'battle_ids' => array(
0 => '7',
1 => '3',
),
'battle_impressions' => array(
0 => '0',
1 => '3',
),
'sum_of_impressions' => '3',
'rank' => '3',
'show_rate' => 20,
'dedicated_impressions' => 691.6,
'impressions_left' => 688.6,
),
3 => array(
'battles_in_rank' => '2',
'battle_ids' => array(
0 => '12',
1 => '5',
),
'battle_impressions' => array(
0 => '17',
1 => '1',
),
'sum_of_impressions' => '18',
'rank' => '4',
'show_rate' => 26.666666666667,
'dedicated_impressions' => 922.13333333333,
'impressions_left' => 904.13333333333,
),
4 => array(
'battles_in_rank' => '1',
'battle_ids' => array(
0 => '2',
),
'battle_impressions' => array(
0 => '3434',
),
'sum_of_impressions' => '3434',
'rank' => '7',
'show_rate' => 46.666666666667,
'dedicated_impressions' => 1613.7333333333,
'impressions_left' => -1820.2666666667,
),
);
この情報をすべて取得したら、クリーンアップを実行して、ランダム関数の良い結果を取得します。
$elements = array();
$weights = array();
foreach ($battles as $el => &$values) {
$elements[] = array($values['battle_ids'], $values['battle_impressions']);
$weights[] = $values['show_rate'];
}
現時点で私が持っているランダム関数は次のとおりです。
public function getRandom($values, $weights)
{
$pos = mt_rand(1, array_sum($weights));
$em = 0;
foreach ($values as $k => $v) {
$em += $weights[$k];
if ($em >= $pos) {
if (is_array($v)) {
return $this->getRandom($v[0], $v[1]);
} else {
return $v;
}
}
}
}
そして、私はそれをそのように呼び出して、1 つのランダムな戦闘 ID を取得します。
$this->getRandom($elements, $weights);
必要なのは、5 つまたは 10 の一意のランダム ID を持つことです。
それは機能しますが、この関数は各呼び出しのランダムな要素を1つだけ提供し、何度か呼び出すと、10回のうち6回のように、同じIDを頻繁に取得します。
たとえば、5 つのランダム バトルが必要な場合、5 つのユニークなランダム バトルを取得するには、20 ~ 30 回のサイクルで関数を呼び出す必要があります。上位ランクでの戦闘が終了すると、下位ランクでの戦闘で配列がいっぱいになるはずなので、常に 5 戦 (または 10 戦) になります。
ランダム化の第 2 レベルは、インプレッションによって加重された、1 つのランクの戦闘であるべきです。これが、ランダム関数が再帰的である理由です。