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

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
+11 -80
View File
@@ -2,6 +2,7 @@
namespace app\controllers; namespace app\controllers;
use app\models\ComputationResult;
use Yii; use Yii;
use yii\filters\AccessControl; use yii\filters\AccessControl;
use yii\web\Controller; use yii\web\Controller;
@@ -9,6 +10,7 @@ use yii\web\Response;
use yii\filters\VerbFilter; use yii\filters\VerbFilter;
use app\models\LoginForm; use app\models\LoginForm;
use app\models\ContactForm; use app\models\ContactForm;
use app\models\DeckForm;
class SiteController extends Controller class SiteController extends Controller
{ {
@@ -18,23 +20,6 @@ class SiteController extends Controller
public function behaviors() public function behaviors()
{ {
return [ return [
'access' => [
'class' => AccessControl::class,
'only' => ['logout'],
'rules' => [
[
'actions' => ['logout'],
'allow' => true,
'roles' => ['@'],
],
],
],
'verbs' => [
'class' => VerbFilter::class,
'actions' => [
'logout' => ['post'],
],
],
]; ];
} }
@@ -47,10 +32,6 @@ class SiteController extends Controller
'error' => [ 'error' => [
'class' => 'yii\web\ErrorAction', 'class' => 'yii\web\ErrorAction',
], ],
'captcha' => [
'class' => 'yii\captcha\CaptchaAction',
'fixedVerifyCode' => YII_ENV_TEST ? 'testme' : null,
],
]; ];
} }
@@ -61,68 +42,18 @@ class SiteController extends Controller
*/ */
public function actionIndex() public function actionIndex()
{ {
return $this->render('index'); $computation_result = new ComputationResult();
} $deck_form = new DeckForm();
if ($deck_form->load(Yii::$app->request->post()))
/**
* Login action.
*
* @return Response|string
*/
public function actionLogin()
{ {
if (!Yii::$app->user->isGuest) { if ($deck_form->validate())
return $this->goHome(); {
$computation_result = $deck_form->compute();
} }
$model = new LoginForm();
if ($model->load(Yii::$app->request->post()) && $model->login()) {
return $this->goBack();
} }
return $this->render('index', [
$model->password = ''; 'deck_form' => $deck_form,
return $this->render('login', [ 'result' => $computation_result,
'model' => $model,
]); ]);
} }
/**
* Logout action.
*
* @return Response
*/
public function actionLogout()
{
Yii::$app->user->logout();
return $this->goHome();
}
/**
* Displays contact page.
*
* @return Response|string
*/
public function actionContact()
{
$model = new ContactForm();
if ($model->load(Yii::$app->request->post()) && $model->contact(Yii::$app->params['adminEmail'])) {
Yii::$app->session->setFlash('contactFormSubmitted');
return $this->refresh();
}
return $this->render('contact', [
'model' => $model,
]);
}
/**
* Displays about page.
*
* @return string
*/
public function actionAbout()
{
return $this->render('about');
}
} }
+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;
}
}
}
}
+29 -42
View File
@@ -1,53 +1,40 @@
<?php <?php
/** @var yii\web\View $this */ use yii\bootstrap5\ActiveForm;
use yii\helpers\Html;
$this->title = 'My Yii Application'; $this->title = 'Карточный ужас Аркхэма. Калькулятор вероятностей.';
?> ?>
<div class="site-index"> <div class="site-index">
<div class="jumbotron text-center bg-transparent mt-5 mb-5">
<h1 class="display-4">Congratulations!</h1>
<p class="lead">You have successfully created your Yii-powered application.</p>
<p><a class="btn btn-lg btn-success" href="https://www.yiiframework.com">Get started with Yii</a></p>
</div>
<div class="body-content"> <div class="body-content">
<div class="row"> <div class="row">
<div class="col-lg-4 mb-3"> <div class="col-md-6">
<h2>Heading</h2> <h3>Параметры колоды</h3>
<?php $form = ActiveForm::begin([
<p>Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et 'layout' => 'horizontal' ,
dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip 'class' => 'form-horizontal' ,
ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu ]); ?>
fugiat nulla pariatur.</p> <?= $form->field($deck_form, 'size')->textInput(); ?>
<?= $form->field($deck_form, 'weapons_items')->textInput(); ?>
<p><a class="btn btn-outline-secondary" href="https://www.yiiframework.com/doc/">Yii Documentation &raquo;</a></p> <?= $form->field($deck_form, 'weapons_spells')->textInput(); ?>
</div> <?= $form->field($deck_form, 'card_prepared_to_worst')->textInput(); ?>
<div class="col-lg-4 mb-3"> <?= $form->field($deck_form, 'card_backpack_0')->textInput(); ?>
<h2>Heading</h2> <?= $form->field($deck_form, 'card_backpack_2')->textInput(); ?>
<?= $form->field($deck_form, 'card_initiate')->textInput(); ?>
<p>Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et <?= Html::submitButton(); ?>
dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip <?php $form->end(); ?>
ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu
fugiat nulla pariatur.</p>
<p><a class="btn btn-outline-secondary" href="https://www.yiiframework.com/forum/">Yii Forum &raquo;</a></p>
</div>
<div class="col-lg-4">
<h2>Heading</h2>
<p>Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et
dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip
ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu
fugiat nulla pariatur.</p>
<p><a class="btn btn-outline-secondary" href="https://www.yiiframework.com/extensions/">Yii Extensions &raquo;</a></p>
</div>
</div>
</div> </div>
</div> </div>
<div class="row">
<div class="col-md-6">
<ul>
<?php for ($i = 0; $i < count($result->probabilities); $i++): ?>
<li>Ход <?= ($i + 1); ?>: <?= sprintf("%.3f", $result->probabilities[$i] * 100); ?>%</li>
<?php endfor; ?>
</ul>
</div>
</div>
</div>
</div>