'Размер колоды', '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 tryPlay($card) { for ($i = 0; $i < count($this->hand); $i++) { if ($this->hand[$i] == $card) { $this->hand[$i] = $this->hand[count($this->hand) - 1]; array_pop($this->hand); return true; } } return false; } private function removeFromDeck($i) { $this->deck[$i] = $this->deck[count($this->deck) - 1]; array_pop($this->deck); } private function useInitiate() { for ($i = count($this->deck) - 1; $i >= 0 && $i > count($this->deck) - 4; $i--) { if ($this->deck[$i] == self::CARD_WEAPON_SPELL) { $this->removeFromDeck($i); $this->hand[] = self::CARD_WEAPON_SPELL; break; } } $this->shuffleDeck(); } 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(); $initiate_played = false; for ($round = 0; $round < self::COMPUTE_ROUNDS; $round++) { if ($this->haveWeapon()) { $this->addProb($round); return; } $initiate_used = false; for ($action = 0; $action < 3; $action++) { if (!$initiate_used) { $this->useInitiate(); $initiate_used = true; } if ($this->tryPlay(self::CARD_WEAPON_ITEM)) { $this->addProb($round); return; } if ($this->tryPlay(self::CARD_WEAPON_SPELL)) { $this->addProb($round); return; } // try do best action if ($this->tryPlay(self::CARD_PREPARED)) { for ($i = count($this->deck) - 1; $i >= 0 && $i > count($this->deck) - 10; $i--) { if ($this->deck[$i] == self::CARD_WEAPON_ITEM || $this->deck[$i] == self::CARD_WEAPON_SPELL) { $this->hand[] = $this->deck[$i]; $this->removeFromDeck($i); break; } } $this->shuffleDeck(); continue; } if ($this->tryPlay(self::CARD_BACKPACK_2)) { for ($i = count($this->deck) - 1; $i >= 0 && $i > count($this->deck) - 13; $i--) { if ($this->deck[$i] == self::CARD_WEAPON_ITEM) { $this->removeFromDeck($i); $this->hand[] = self::CARD_WEAPON_ITEM; break; } } $this->shuffleDeck(); continue; } if ($this->tryPlay(self::CARD_BACKPACK_0)) { for ($i = count($this->deck) - 1; $i >= 0 && $i > count($this->deck) - 7; $i--) { if ($this->deck[$i] == self::CARD_WEAPON_ITEM) { $this->removeFromDeck($i); $this->hand[] = self::CARD_WEAPON_ITEM; break; } } $this->shuffleDeck(); continue; } if ($this->weapons_spells > 0 && !$initiate_played) { if ($this->tryPlay(self::CARD_INITIATE)) { $initiate_played = true; } } $this->hand[] = array_pop($this->deck); } if (!$initiate_used) { $this->useInitiate(); $initiate_used = true; } } } }