ItemRoulette/ItemRoulette/ItemRoulette.php

82 lines
3.8 KiB
PHP
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<?php
declare(strict_types=1);
class ItemRoulette
{
/**
* @var array Массив шанса выпадения предметов. Ключом выступает имя предмета, значением выступает шанс выпадения.
* Шанс задаётся в виде десятичной дроби (25% = 0.25).
* ['prize1' => 0.25, 'prize2' => 0.06, 'prize3' => 0.1,]
*/
public array $items = [];
/**
* Рассчёт верхнего значения диапазона, подаваемого на рандомизатор через
* множитель в зависимости от количества знаков после запятой у значения подаваемого на вход, умноженный на это значение.
* Если на вход идёт целое число, система возвратит 0;
* Если на вход идёт дробное число, система вернёт количество знаков;
* Если на вход идёт вообще не число, система всё равно вернёт 0;
*
* @param $num
* @return int множитель.
*/
private function randMax($num): int
{
if ((int)$num == $num || !is_numeric($num)) {
return 0;
}
[, $a] = explode('.', strval($num));
return $num * pow(10, strlen($a));
}
/**
* Рассчёт выпадения определённого предмета.
* Система считает сумму подаваемых на вход процентов, высчитывает количесто знаков после запятой, высчитывает
* множитель, на который надо умножить полученное значение, чтобы получить целое число из дробного.
* После этого на полученный множитель умножается каждое процентное значение и гененируются диапазоны значений для
* каждого предмета. После этого берётся случайное число от 0 до максимального значения и сравнивается с
* диапазонами. В какой диапазон попадает, тот предмет и выпал.
* @return string|null имя выпавшего предмета.
*/
private function roll(): ?string
{
if (!is_array($this->items || empty($this->items))) {
return null;
}
$itemKey = '';
$sumOfPercents = array_sum($this->items);
$rand = mt_rand(1, $this->randMax($sumOfPercents));
$rangeStart = 1;
foreach ($this->items as $itemKey => $itemsPercent) {
$rangeFinish = $rangeStart + $itemsPercent;
if ($rand >= $rangeStart && $rand <= $rangeFinish) {
break;
}
$rangeStart = $rangeFinish + 1;
}
return $itemKey;
}
/**
* Функция, запускающая расчёт определённое количество раз и возвращающая массив выпавших предметов
* либо NULL в случае ошибки.
*
* @param int $rolls сколько предметов надо получить на выходе.
*
* @return array|null
*/
public function loot(int $rolls = 1): ?array
{
if ($rolls < 1) {
return null;
}
$result = [];
for ($i = 0; $i < $rolls; $i++) {
if (is_null($this->roll())) {
continue;
}
$result[] = $this->roll();
}
return $result;
}
}