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, но у него есть версия для командной строки. Кстати, не покупайте этот инструмент, мы купили, и они не отправили лицензионный ключ, вроде как им все равно.

А теперь результаты:

https://docs.google.com/spreadsheet/pub?key=0ArMZCQvNc-oQdEs0a1UyMkFGazVoN09KZmU1Q0FCU0E&output=html&richtext=true

Теперь, если мы сравним, руки выигрывают + связывают чаще, чем покерстове или покерслейт показывает справедливость. И когда я смотрю муравейник% - это намного больше, чем шоу в покерных печах. Образец не такой маленький. Покерстово использует почти 400 тысяч игр, там их немного меньше, но тенденция остается прежней. Сначала я попробовал гораздо меньшую выборку, например, игры 10K, - та же тенденция. Поэтому, когда я сгенерирую еще 100K, я не удивлюсь, если результат останется примерно таким же. Также этот образец генерируется на Linux. Но примерно такая же выборка генерируется и на окнах, и все же выигрыши больше, чем в покерстоуве, и сумма выигрыша% также составляет 110-112 %.

Итак, мы не понимаем - я создаю что-то плохое или эти программы показывают неправильно? Программы, показывающие неправильные акции, маловероятны, поскольку они широко используются и, вероятно, уже должны быть проверены.

Обновить:

Я думаю, что я наконец понял:) Покерслейт вычисляет шансы на выигрыш руки (две карты), зная 5 карт на доске. Затем вы сравниваете эти шансы с реальным исходом (зная руки всех других игроков). Правильно?

Правильно. Я должен был написать здесь, потому что это не позволило в комментариях расширять обсуждения.

Обновить:

Создано больше строк - в настоящее время 515989 на сервере Linux,% остается примерно таким же, как и раньше. Так не двигаясь

1 ответ

Решение

У вас есть 296350 сгенерированных результатов, но 332911 побед и ничьих.

Примиряет ли какая-либо часть этого процесса тот факт, что когда есть ничья, это между двумя или более руками? Похоже, что связи переоцениваются.

Возьмите свой общий выигрыш и ничью%, 112,3371014%. Умножить (сгенерированные результаты делятся на выигрыши и связи). Вы получите ровно 100%. Что это говорит?

Также посмотрите на Ad6c и Ah3c. Их количество ничьих точно такое же, и, скорее всего, те же самые руки (где победой была пара тузов).

Но для рук, где они связывают, эта рука считается / взвешивается дважды (один раз для Ad6c и один раз для Ah3c). Вот почему ваш процент галстука как минимум вдвое больше, чем должен быть. Вам нужно будет нормализовать количество ничьих по количеству раздач

Другие вопросы по тегам