Possible Duplicate:
How to iteratively generate k elements subsets from a set of size n in java?
我想构建自己的扑克手牌评估器,但在特定部分遇到了问题。
如果两名玩家发两张牌,则一副牌还剩 48 张。在 Texas Hold'em 中,还会再发 5 张可能的公共(public)牌(这称为公共(public)牌)。我想枚举/循环遍历所有 48 个选择 5 种可能的棋盘组合,并计算玩家 A 获胜的次数和玩家 B 获胜的次数以及他们平局的时间。
我不确定如何系统地遍历每 5 张牌的组合。有人有什么想法吗?这些卡片表示为 Card 类的数组,但如果这样可以更快,我也可以将它们表示为一个位集。
我在 Java 中执行此操作。
非常感谢
(免责声明:我写了一个非常快速的扑克手评估器)
I want to enumerate / loop through all the 48 choose 5 possible
combinations of boards and count the times Player A wins and the times
Player B wins and when they tie.
您不想在每次翻牌前两名玩家之间的对局时都评估 C(48,5) (1 712 304) 手牌:大多数程序只是在翻牌前两个玩家之间的所有可能对局之间使用预先计算的查找表。
例如,假设您有“Ac Ad”与“7c 6c”,您只需查看包含以下内容的查找表:1 333 573, 371 831, 6900
(其中 1 333 573 是“Ac Ad”获胜的次数,371 831 是“7c 6c”获胜的次数,6 900 是平局的次数(总和为 1 712 304)。为了获得一些空间,您可以丢弃 6 900,知道平局数总是C(48,5) - (wins 1 + wins 2)。
(更多关于此答案末尾的查找表)
但要回答你的问题:
I'm not sure how I can systematically loop through every 5 card
combination.
如果您真的想遍历每个组合,您必须知道扑克手牌评估程序通常是需要非常非常快的程序。这些程序通常每秒可以评估数亿手牌(您没有看错:数亿手)。
当您需要如此高性能的“数字运算”时,您可以忘记“设计模式”和“面向对象”。您想要的是原始速度。
例如,下面的代码将通过最内层循环 C(48,5) 次并且速度非常快:
for ( int i = 0; i < n; i++ ) {
for ( int j = i + 1; j < n; j++ ) {
for ( int k = j + 1; k < n; k++ ) {
for (int l = k + 1; l < n; l++) {
for (int m = l + 1; m < n; m++) {
...
}
}
}
}
}
对于翻牌前的两个玩家来说,这可能是一个非常糟糕的主意:使用查找表会更快。
但是对于翻牌前的三位玩家(使用翻牌前表格是不切实际的,有太多的对局),你可能想要像这样循环,在 C(46,5) 手牌上,使用五个嵌套循环(当然你需要使用 i,j,k,l,m 从剩下的 46 张牌中得到正确的 5 张牌)。然后,在您拿到 5 张牌后,您可以使用快速手牌评估器从 7 张牌(棋盘上的 5 张牌 + 每个玩家的两张牌)中得出最好的牌。
关于查找表:
大多数人使用大约 169 对 169 的查找表(“Ac Kd”、“As Kh”、“Ad Ks”等都变成“AK offsuit”并且 C(52,2) 可能的起手牌被分组在 169 类型的起手牌中)。维基百科文章解释了如何获得 169 个非对等起手牌:
http://en.wikipedia.org/wiki/Texas_hold_%27em_starting_hands
当您考虑一手时,它们是不相等的,但是一旦您考虑手 1 与手 2,“169 与 169”就是一个近似值(说得很好)。
当然你可以变得更漂亮。只有 C(52,2)(给出 1326)个真正不同的 Hold'em 起手牌,这意味着在现代计算机上构建一个完美的查找表(根本没有近似)是非常实用的(C(1326,2) ain '那么大)如果你真的需要完美的数字。如果您可以接受近似值,请选择 169 对 169 表(它需要 C(169,2) 或 14 196 个条目)。