Files
core/src/sammo/RandUtil.php
T

164 lines
4.0 KiB
PHP

<?php
namespace sammo;
class RandUtil
{
public function __construct(public readonly RNG $rng)
{
}
public function nextFloat1(): float
{
return $this->rng->nextFloat1();
}
public function nextRange(int|float $min, int|float $max): float
{
$range = $max - $min;
return $this->nextFloat1() * $range + $min;
}
public function nextRangeInt(int $min, int $max): int
{
$range = $max - $min;
if ($range > $this->rng->getMaxInt()) {
throw new \InvalidArgumentException("Invalid random int range");
}
return $this->rng->nextInt($range) + $min;
}
public function nextInt(?int $max = null): int{
return $this->rng->nextInt($max);
}
public function nextBit(): bool
{
return $this->rng->nextBits(1) !== "\0";
}
public function nextBool(int|float $prob = 0.5): bool
{
if ($prob >= 1) {
return true;
}
if ($prob === 0.5){
return $this->nextBit();
}
if ($prob <= 0){
return false;
}
return $this->nextFloat1() < $prob;
}
public function shuffle(array $srcArray): array
{
if(!$srcArray){
return $srcArray;
}
$cnt = count($srcArray);
if ($cnt > $this->rng->getMaxInt()) {
throw new \InvalidArgumentException("Invalid random int range");
}
$result = [];
foreach ($srcArray as $val) {
$result[] = $val;
}
//PHP의 range는 max 포함
foreach (range(0, $cnt - 1) as $srcIdx) {
$destIdx = $this->rng->nextInt($cnt - $srcIdx - 1) + $srcIdx;
if($srcIdx === $destIdx){
continue;
}
$tmpVal = $result[$srcIdx];
$result[$srcIdx] = $result[$destIdx];
$result[$destIdx] = $tmpVal;
}
return $result;
}
public function shuffleAssoc(array $srcArray): array
{
if(!$srcArray){
return $srcArray;
}
$result = [];
foreach ($this->shuffle(array_keys($srcArray)) as $key) {
$result[$key] = $srcArray[$key];
}
return $result;
}
public function choice(array $items)
{
$keys = array_keys($items);
if(!$keys){
throw new \InvalidArgumentException();
}
$keyIdx = $this->rng->nextInt(count($keys) - 1);
return $items[$keys[$keyIdx]];
}
public function choiceUsingWeight(array $items)
{
if(!$items){
return 2; // 내특 줄 수 있는게 하나도 없을시 일단 강제로 상재로 주는걸로 긴급 버그 수정
//throw new \InvalidArgumentException();
}
$sum = 0;
foreach ($items as $value) {
if ($value <= 0) {
continue;
}
$sum += $value;
}
$rd = $this->nextFloat1() * $sum;
foreach ($items as $item => $value) {
if ($value <= 0) {
$value = 0;
}
if ($rd <= $value) {
return $item;
}
$rd -= $value;
}
//fallback. 이곳으로 빠지지 않음
end($items);
return $items[key($items)][0];
}
public function choiceUsingWeightPair(array $items)
{
if(!$items){
throw new \InvalidArgumentException();
}
$sum = 0;
foreach ($items as [$item, $value]) {
if ($value <= 0) {
continue;
}
$sum += $value;
}
$rd = $this->nextFloat1() * $sum;
foreach ($items as [$item, $value]) {
if ($value <= 0) {
$value = 0;
}
if ($rd <= $value) {
return $item;
}
$rd -= $value;
}
//fallback. 이곳으로 빠지지 않음
end($items);
return $items[key($items)][0];
}
}