php扑克生成的随机结果与预期不符

时间:2014-02-24 08:32:17

标签: php random poker

我对扑克股票进行了研究。我做的是使用pokerstove程序和一些选定的。并使用该程序使用枚举所有方法计算股票。所以pokerstove结果:

enter image description here

我还制作了一个表格,用于存储随机结果:

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); 
        }



    }


}

正如我们在随机函数中看到的那样 - 当我在linux上进行测试时,我使用带有linux dev / urnadom的twister库,当我在windows上时,我使用本机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'

扑克服务器用于获得手中的资产。通过河上的手工资产,我确定手是否赢了 - 当手资产为&gt; 0然后赢了。

这个工具在另一台服务器上使用 - 有运行python程序的php代码,但这并不重要。

http://pokersleuth.com/programmable-poker-calculator.shtml

该工具就像pokerstove但它有命令行版本。顺便说一句,不买这个工具,我们买了,他们没有发送许可证密钥,有点像他们不在乎。

现在的结果是:

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

现在,如果我们进行比较,那么双手胜过+平局比pokerstove或pokersleuth表现出平等。当我看起来蚂蚁领带% - 它比啤酒炉显示更大。样本不是那么小。 Pokerstove使用了近400K的游戏,虽然它有点少,但是tendencty仍然是相同的。首先,我尝试了更小的样本,如10K游戏 - 同样的趋势。因此,当我生成100K以上时,如果结果大致相同,我并不感到惊讶。此示例也是在linux上生成的。但是关于同样的样本也是在Windows上生成的,并且胜利仍然超过pokerstove节目,胜利%的总和也是110-112%。

所以我们不理解 - 我生成的东西是坏的还是那些程序显示错误?显示错误股票的计划不太可能,因为它们被广泛使用,并且可能已经进行了大量测试。

更新

  

我想我终于明白了:) Pokersleuth计算了一个机会   知道板上的5张牌,获胜(两张牌)。你是   然后将这些机会与真实结果进行比较(了解双手的情况)   所有其他球员)。正确?

右。我不得不在这里写,因为它不允许在评论中进行扩展讨论。

更新:

生成更多行 - 目前在Linux服务器上为515989,%仍然与以前大致相同。所以不动了

1 个答案:

答案 0 :(得分:4)

您有296350个生成的结果,但332911胜出&amp;的关系。

这个过程的任何部分是否都会调和这样一个事实:当有一个平局时,它是在两手或更多手之间?看起来关系正在被计算在内。

获得总胜率和平局百分比,112.3371014%。乘以(生成的结果除以胜利和关系)。你会得到100%。这表明了什么?

另外,看看Ad6c和Ah3c。他们的领带数完全相同,很可能是同一只手(胜利是一对A)。

但对于他们打平的牌,该牌数被计算/加权两次(一次用于Ad6c,一次用于Ah3c)。这就是为什么你的领带%至少是他们应该的两倍。你必须按领带数量

来规范领带数