Какой-то базовый расчёт, просто вероятности без ничего

This commit is contained in:
ftc
2025-09-25 23:41:03 +03:00
parent eea03e920e
commit 2a54332e4b
4 changed files with 238 additions and 157 deletions
+7
View File
@@ -0,0 +1,7 @@
<?php
namespace app\models;
class ComputationResult
{
public $probabilities = [];
}
+156
View File
@@ -0,0 +1,156 @@
<?php
namespace app\models;
use Yii;
use yii\base\Model;
class DeckForm extends Model
{
const COMPUTE_TRIES = 10000;
const COMPUTE_ROUNDS = 10;
const CARD_ANY = 0;
const CARD_WEAPON_ITEM = 1;
const CARD_WEAPON_SPELL = 2;
const CARD_PREPARED = 3;
const CARD_BACKPACK_0 = 4;
const CARD_BACKPACK_2 = 5;
const CARD_INITIATE = 6;
public $size = 30;
public $weapons_items = 0;
public $weapons_spells = 0;
public $card_prepared_to_worst = 0;
public $card_backpack_0 = 0;
public $card_backpack_2 = 0;
public $card_initiate = 0;
/**
* @return array the validation rules.
*/
public function rules()
{
return [
[['size', 'weapons_items', 'weapons_spells', 'card_prepared_to_worst', 'card_backpack_0', 'card_backpack_2', 'card_initiate'], 'required'],
[['size', 'weapons_items', 'weapons_spells', 'card_prepared_to_worst', 'card_backpack_0', 'card_backpack_2', 'card_initiate'], 'integer'],
];
}
/**
* @return array customized attribute labels
*/
public function attributeLabels()
{
return [
'size' => 'Размер колоды',
'weapons_items' => 'Оружие (вещь)',
'weapons_spells' => 'Оружие (заклинание)',
'card_prepared_to_worst' => 'Готовность к худшему',
'card_backpack_0' => 'Рюкзак (0)',
'card_backpack_2' => 'Рюкзак (2)',
'card_initiate' => 'Посвящённая',
];
}
private $result;
public function compute() : ComputationResult
{
$this->result = new ComputationResult();
$this->result->probabilities = [];
for ($i = 0; $i < self::COMPUTE_ROUNDS; $i++) $this->result->probabilities[] = 0;
for ($i = 0; $i < self::COMPUTE_TRIES; $i++)
{
$this->generateTry();
}
for ($i = 0; $i < self::COMPUTE_ROUNDS; $i++) $this->result->probabilities[$i] /= (self::COMPUTE_TRIES + 0.0);
return $this->result;
}
private $deck;
private $hand;
private function fillDeck()
{
$this->deck = [];
for ($i = 0; $i < $this->size; $i++) $this->deck[] = self::CARD_ANY;
$pos = 0;
for ($i = 0; $i < $this->weapons_items && $pos < count($this->deck); $i++)
{
$this->deck[$pos++] = self::CARD_WEAPON_ITEM;
}
for ($i = 0; $i < $this->weapons_spells && $pos < count($this->deck); $i++)
{
$this->deck[$pos++] = self::CARD_WEAPON_SPELL;
}
for ($i = 0; $i < $this->card_backpack_0 && $pos < count($this->deck); $i++)
{
$this->deck[$pos++] = self::CARD_BACKPACK_0;
}
for ($i = 0; $i < $this->card_backpack_2 && $pos < count($this->deck); $i++)
{
$this->deck[$pos++] = self::CARD_BACKPACK_2;
}
for ($i = 0; $i < $this->card_prepared_to_worst && $pos < count($this->deck); $i++)
{
$this->deck[$pos++] = self::CARD_PREPARED;
}
for ($i = 0; $i < $this->card_initiate && $pos < count($this->deck); $i++)
{
$this->deck[$pos++] = self::CARD_INITIATE;
}
}
private function shuffleDeck()
{
for ($i = 0; $i < count($this->deck); $i++)
{
$j = rand(0, $i);
$t = $this->deck[$j];
$this->deck[$j] = $this->deck[$i];
$this->deck[$i] = $t;
}
}
private function addProb($round)
{
for ($i = $round; $i < self::COMPUTE_ROUNDS; $i++) $this->result->probabilities[$i]++;
}
private function haveWeapon()
{
foreach ($this->hand as $card)
{
if ($card == self::CARD_WEAPON_ITEM) return true;
if ($card == self::CARD_WEAPON_SPELL) return true;
}
return false;
}
private function generateTry()
{
$this->fillDeck();
$this->shuffleDeck();
// mulligan
$this->hand = [];
$replace = [];
for ($i = 0; $i < 5; $i++)
{
$current = array_pop($this->deck);
if ($current != self::CARD_ANY) $this->hand[] = $current;
else $replace[] = $current;
}
while (count($this->hand) < 5) $this->hand[] = array_pop($this->deck);
foreach ($replace as $r) $this->deck[] = $r;
$this->shuffleDeck();
for ($round = 0; $round < self::COMPUTE_ROUNDS; $round++)
{
if ($this->haveWeapon())
{
$this->addProb($round);
return;
}
}
}
}