php poker 生成的随机结果与预期不符
Posted
技术标签:
【中文标题】php poker 生成的随机结果与预期不符【英文标题】:php poker generated random results do not match what is expected 【发布时间】:2014-03-25 19:22:52 【问题描述】:我对扑克股票进行了研究。我所做的是使用 pokerstove 程序并选择了一些。并通过该程序使用枚举所有方法计算股票。所以pokerstove结果:
我还制作了一个存储随机结果的表格:
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'
扑克服务器用于获取手牌赢率。通过河牌的手牌赢率,我确定手牌是否赢 - 当手牌赢率 > 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 游戏,虽然少了一点,但趋势保持不变。首先,我尝试了小得多的样本,比如 10K 游戏——同样的趋势。因此,当我将生成 100K 更多时,如果结果保持大致相同,我并不感到惊讶。此示例也是在 linux 上生成的。但是在 Windows 上也生成了大约相同的样本,但获胜次数仍然超过 pokerstove 显示,获胜百分比的总和也是 110-112 %。
所以我们不理解 - 我是在生成错误的东西还是那些程序显示错误?显示错误股票的程序不太可能,因为它们被广泛使用并且可能已经进行了很多测试。
更新:
我想我终于明白了 :) Pokersleuth 计算了 知道棋盘上的 5 张牌,手(两张牌)获胜。你是 然后将这些机会与实际结果进行比较(了解 所有其他玩家)。对吧?
没错。我不得不写在这里,因为它不允许在 cmets 进行扩展讨论。
更新:
生成了更多行 - 目前在 linux 服务器上为 515989,% 仍然与以前大致相同。所以不动
【问题讨论】:
所以您正在生成手牌,然后使用能够生成正确数据的 pokerstove 以及您认为不能生成正确数据的其他工具来计算股票?get_probabilities
是使用pokerstove产生数据的方法吗?
我正在根据玩家的手牌生成卡片。我的意思是所有样本玩家都拥有相同的牌。只有板子不同。 pokerstove 与其他工具获得几乎相同的权益。我不记得了,但可能在使用 enumerate 时 - 它应该得到完全相同的 eqwities。问题是我随机生成的数据与那些股票不匹配。它接近但不够接近。如果是因为方差,我应该会起起落落,但不同样本的结果往往会像我展示的那样。
get_probabilities() 方法在河牌圈产生赢率 - 换句话说,当所有公共牌都打开时。它在服务器中使用扑克侦探工具。如果 1 手获胜,该工具提供 100% 的胜率,如果 2 手获胜(平局),则每人 50% 的胜率,依此类推。
get_probabilities() 仅用于为 get_poker_winner() 函数提供输入
所以您基本上是在尝试将 pokersleuth 的准确性与基于最终开放棋盘的实际赢率进行比较?
【参考方案1】:
您有 296350 个生成的结果,但有 332911 个获胜和平局。
这个过程的任何部分是否可以协调这样一个事实,即当出现平局时,它是在两只或多只手之间?似乎关系被多算了。
计算您的总赢率和平局 %,112.3371014%。相乘(生成的结果除以胜率)。您将获得准确的 100%。这说明了什么?
另外,看看 Ad6c 和 Ah3c。他们的平局数完全相同,而且很可能是同一手牌(获胜是一对 A)。
但是对于他们平手的牌,该牌被计算/加权两次(一次用于 Ad6c,一次用于 Ah3c)。这就是为什么您的领带百分比至少是应有的两倍。您必须通过平局的手数来标准化平局计数
【讨论】:
欢迎来到 Stack Overflow。这些都是很好的见解,但您应该编辑您的答案而不是对其发表评论。 我猜你是对的。现在尝试通过对胜利进行分组来选择,当有 2 个获胜者时 - 然后除以 2 平局数,当有 8 个获胜者时 - 除以 8,然后求和,百分比现在看起来更好,总数是 100% 而不是 110 -112 :) 谢谢。所以我猜赏金点会自动添加给你。那么我可以等着看其他人是否会注意到一些错误以上是关于php poker 生成的随机结果与预期不符的主要内容,如果未能解决你的问题,请参考以下文章