php poker генерирует случайные результаты, которые не соответствуют ожидаемым
Я провел исследование покерных акций. Что я сделал, так это использовал программу pokerstove с некоторыми выбранными. И с помощью этой программы рассчитываются акции с использованием метода enumerate all. Итак, покерстове результатов:
Я также сделал таблицу, где я храню случайные результаты:
CREATE TABLE poker_results
(
id int NOT NULL AUTO_INCREMENT,
matches_id int NOT NULL, -- just for filtering in case I will want another starting hands.
result varchar(255) NOT NULL,
winner_hands varchar(255) NOT NULL,
PRIMARY KEY (id)
)
Данные столбца результата выглядят так: Jd,9d,Qh,5c,Kc - это карты на борту.
Данные столбца Winner_hands выглядят так: Ks-Ac,6c-Ad,3c-Ah (можно выиграть 1 руку, можно выиграть все 8 рук).
Вот код, который генерирует результаты в базу данных. Это на основе codeigniter. А также, чтобы не копировать весь poker.php, я просто копирую пару функций, которые из него используются:
protected function get_probabilities($hands, $board_cards = array()) {
$players = count($hands);
$board = implode('', $board_cards);
$board = trim($board);
if (empty($board)) {
$board = '-';
}
$hx = '';
$hand_counter = 1;
foreach ($hands as $hand) {
$hx .= '&h' . $hand_counter++ . '=' . $hand[0] . $hand[1];
}
$url = 'http://' . $this->poker_server . '/?board=' . $board . $hx . '&auth=' . $this->auth;
//Output exm. string '0.1342, 0.2042, 0.13525, 0.52635'
//WAR!! check if alive
$result = $this->parse_url_link($url);
if (substr($result, 0, 3) == 'Err') {
$this->utils->logging('ERROR', 'Poker server authorization failed!');
}
//echo $result;
return array(
'hands' => $hands,
'prob' => explode(', ', $result),
'board' => $board_cards
);
}
// protected because in child class needed
protected function get_poker_winner($table_winners) {
$to_return = array();
foreach($table_winners['prob'] as $key => $val) {
if ($val > 0) {
$to_return[] = $table_winners['hands'][$key][0] . '-' . $table_winners['hands'][$key][1];
}
}
return $to_return;
}
poker_tests.php
<?php if ( ! defined('BASEPATH')) exit('No direct script access allowed');
include_once(APPPATH . 'controllers/poker.php');
require_once APPPATH . "libraries/downloaded/Mersenne_twister.php";
use mersenne_twister\twister;
class Poker_tests extends Poker {
public function __construct() {
parent::__construct();
}
/**
* Generates data in database with such structure:
* CREATE TABLE matches
* (
* id int NOT NULL AUTO_INCREMENT,
* player_cards varchar(255) NOT NULL,
*
* PRIMARY KEY (ID)
* )
*
* CREATE TABLE poker_results
* (
* id int NOT NULL AUTO_INCREMENT,
* result varchar(255) NOT NULL,
* PRIMARY KEY (id)
* )
*
*
* Here 1 match will have many results, because we use same preflop cards.
*
* Text results appended to pokerstove.txt
*
* 376,992 games 0.013 secs 28,999,384 games/sec
*
* Board:
* Dead:
*
* equity win tie pots won pots tied
* Hand 0: 20.925% 20.53% 00.40% 77382 1504.50 { KhQs }
* Hand 1: 06.215% 03.50% 02.72% 13190 10239.00 { 9c4d }
* Hand 2: 06.396% 04.08% 02.32% 15379 8734.00 { 8d4c }
* Hand 3: 18.906% 18.15% 00.76% 68426 2847.50 { AcKs }
* Hand 4: 08.767% 06.91% 01.86% 26032 7019.50 { 9h2c }
* Hand 5: 10.204% 09.83% 00.38% 37044 1424.00 { Ad6c }
* Hand 6: 09.046% 08.67% 00.38% 32678 1424.00 { Ah3c }
* Hand 7: 19.541% 18.08% 01.46% 68154 5514.50 { 8c7c }
*
*
* ---
*
*
*/
public function run() {
$this->benchmark->mark('start');
$this->output->enable_profiler(TRUE);
//close the current connection, because its not needed
$this->db->close();
$db_poker = $this->load->database('poker_test', TRUE);
$sql = "INSERT INTO poker_results (result, winner_hands, matches_id) VALUES (?, ?, ?)";
// matches_id = 1. Insert new match
$table8_hands = 'Kh,Qs,4d,9c,4c,8d,Ks,Ac,2c,9h,6c,Ad,3c,Ah,7c,8c'; // do test with this. Do those win the right amount of time?
for ($i=0; $i < 400000; $i++) { // pradejus id 100194
$flop = $this->poker_flop($table8_hands);
$turn = $this->poker_turn($flop, $table8_hands);
$river = $this->poker_stop($turn, $table8_hands);
//echo json_encode($river) . '<br>';
$db_poker->query($sql, array($river['river_board'], implode(',', $river['winner_hands8']), 2));
}
$db_poker->close();
$this->benchmark->mark('end');
echo $this->benchmark->elapsed_time('start', 'end') . '<br>';
}
/**
*
* Override - remove unneeded things for test from that function in poker.php
* Generates 3 flop cards
*/
public function poker_flop($table8_hands) {
$table8_cards = explode(',', $table8_hands);
$table8_results = $this->random_result($table8_cards, 3);
return $table8_results;
}
/**
* Generates 1 turn card
* @param $table8_hands - same as match score in database. But here we have hardcoded in run function
*
*/
public function poker_turn($table8_flop, $table8_hands) {
$table8_cards = explode(',', $table8_hands);
//Join players cards and opened board cards
$table8_reserved_cards = array_merge($table8_cards, $table8_flop);
//Pass all opened cards and get one new board card
$table8_results = $this->random_result($table8_reserved_cards, 1);
//Merge all opened board cards
$table8_results = array_merge($table8_flop, $table8_results);
// this is flop and turn both
return $table8_results;
}
/**
*
* Generates 1 river card
*/
public function poker_stop($table8_flop_turn, $table8_hands) {
$table8_cards = explode(',', $table8_hands);
$table8_reserved_cards = array_merge($table8_cards, $table8_flop_turn);
$table8_results = $this->random_result($table8_reserved_cards, 1);
$table8_results = array_merge($table8_flop_turn, $table8_results);
$table8_hands = $this->array_to_hands_array($table8_cards);
$flop_turn_results = implode(',', $table8_results);
// $this->benchmark->mark('code_start');
//Get new probabilities - they will be needed to determine if hand has won or not. When prob. > 0 - then won
$table8_prob = $this->get_probabilities($table8_hands, $table8_results);
// $this->benchmark->mark('code_end');
// echo $this->benchmark->elapsed_time('code_start', 'code_end');
return array(
'winner_hands8' => $this->get_poker_winner($table8_prob),
'river_board' => $flop_turn_results
);
}
/**
* for second generation - new random function
* @param array $reserved_cards
* @param integer $cards_amount
* @return array
*/
protected function random_result($reserved_cards, $cards_amount = 5) {
$card_types = array('s', 'c', 'h', 'd');
$card_values = array('A', 2, 3, 4, 5, 6, 7, 8, 9, 'T', 'J', 'Q', 'K');
$deck = array();
foreach ($card_values as $value) {
foreach ($card_types as $type) {
$deck[] = $value . $type;
}
}
$remaining_deck = array_diff($deck, $reserved_cards);
// make keys sequence:
$remaining_deck = array_values($remaining_deck);
$results = array();
while (count($results) != $cards_amount) {
$rand_card_key = $this->random(0, (count($remaining_deck) - 1));
$results[] = $remaining_deck[$rand_card_key];
// remove from deck
unset($remaining_deck[$rand_card_key]);
// make keys sequence:
$remaining_deck = array_values($remaining_deck);
}
return $results;
}
/**
* Picks random element from range
* @param integer $from
* @param integer $to
* @return integer
*/
private function random($from, $to) {
if (file_exists('/dev/urandom')) {
$twister4 = new twister;
$twister4->init_with_file("/dev/urandom", twister::N);
return $twister4->rangeint($from, $to);
}
else {
return mt_rand($from, $to);
}
}
}
Как мы видим в случайной функции - я использую библиотеку twister с linux dev/urnadom, когда я тестирую на linux и native mt_rand, когда я нахожусь на окнах. Не замечая разницы.
Поэтому для выбора результатов я использую такие запросы:
Чтобы получить общее количество результатов
select count(*) from poker_results where matches_id = 2 and id < 296351
Чтобы узнать, сколько составляет общий выигрыш (победа + ничья) руки:
select count(*) from poker_results where matches_id = 2 and id < 296351 and winner_hands like '%Kh-Qs%'
Чтобы узнать, сколько горшков связано с рукой:
select count(*) from poker_results where matches_id = 2 and id < 296351 and winner_hands like '%Kh-Qs%' and winner_hands != 'Kh-Qs'
Покерный сервер предназначен для получения эквити рук. По эквити рук на ривере я определяю, выиграл ли он или нет - когда эквити рук> 0, то он выиграл.
Этот инструмент используется на другом сервере - есть код php, который запускает программу на python, но здесь это не имеет значения.
http://pokersleuth.com/programmable-poker-calculator.shtml
Этот инструмент похож на pokerstove, но у него есть версия для командной строки. Кстати, не покупайте этот инструмент, мы купили, и они не отправили лицензионный ключ, вроде как им все равно.
А теперь результаты:
Теперь, если мы сравним, руки выигрывают + связывают чаще, чем покерстове или покерслейт показывает справедливость. И когда я смотрю муравейник% - это намного больше, чем шоу в покерных печах. Образец не такой маленький. Покерстово использует почти 400 тысяч игр, там их немного меньше, но тенденция остается прежней. Сначала я попробовал гораздо меньшую выборку, например, игры 10K, - та же тенденция. Поэтому, когда я сгенерирую еще 100K, я не удивлюсь, если результат останется примерно таким же. Также этот образец генерируется на Linux. Но примерно такая же выборка генерируется и на окнах, и все же выигрыши больше, чем в покерстоуве, и сумма выигрыша% также составляет 110-112 %.
Итак, мы не понимаем - я создаю что-то плохое или эти программы показывают неправильно? Программы, показывающие неправильные акции, маловероятны, поскольку они широко используются и, вероятно, уже должны быть проверены.
Обновить:
Я думаю, что я наконец понял:) Покерслейт вычисляет шансы на выигрыш руки (две карты), зная 5 карт на доске. Затем вы сравниваете эти шансы с реальным исходом (зная руки всех других игроков). Правильно?
Правильно. Я должен был написать здесь, потому что это не позволило в комментариях расширять обсуждения.
Обновить:
Создано больше строк - в настоящее время 515989 на сервере Linux,% остается примерно таким же, как и раньше. Так не двигаясь
1 ответ
У вас есть 296350 сгенерированных результатов, но 332911 побед и ничьих.
Примиряет ли какая-либо часть этого процесса тот факт, что когда есть ничья, это между двумя или более руками? Похоже, что связи переоцениваются.
Возьмите свой общий выигрыш и ничью%, 112,3371014%. Умножить (сгенерированные результаты делятся на выигрыши и связи). Вы получите ровно 100%. Что это говорит?
Также посмотрите на Ad6c и Ah3c. Их количество ничьих точно такое же, и, скорее всего, те же самые руки (где победой была пара тузов).
Но для рук, где они связывают, эта рука считается / взвешивается дважды (один раз для Ad6c и один раз для Ah3c). Вот почему ваш процент галстука как минимум вдвое больше, чем должен быть. Вам нужно будет нормализовать количество ничьих по количеству раздач