C#中的更多Texas Holdem分析:第2部分(译文)
By robot-v1.0
本文链接 https://www.kyfws.com/games/more-texas-holdem-analysis-in-c-part-2-zh/
版权声明 本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!
- 18 分钟阅读 - 8733 个词 阅读量 0C#中的更多Texas Holdem分析:第2部分(译文)
原文地址:https://www.codeproject.com/Articles/19092/More-Texas-Holdem-Analysis-in-C-Part-2
原文作者:Keith Rule
译文由本站 robot-v1.0 翻译
前言
Using C# to do sophisticated analysis of Texas Holdem
使用C#对Texas Holdem进行复杂的分析
介绍(Introduction)
在(In) 第1部分(Part 1) 在本文中,您将找到以下主题:(of this article, you will find the following topics covered:)
-
掌上查询语言-(Pocket Query Language -)这提供了一组简单明了的方法,使您可以在不重写代码的情况下尝试不同的口袋手组合.(This offers a straightforward set of methods that allow you experiment with different pocket hand combinations without rewriting your code.)
-
抽奖方法(Outs and draw methods)-确定抽奖是分析情况的关键.本节讨论用于执行此操作的技术.(- Determining outs and draws is key to analyzing a situation. This section discusses techniques for doing just that.) 在本文中,我们将介绍以下主题.(In this article, we will cover the following topics.)
-
蒙特卡洛分析(Monte Carlo analysis)-有时快速估算就足够了.蒙特卡洛分析可以在很短的时间内做出高质量的估计.(- Sometimes quick estimates are good enough. Monte Carlo analysis makes it possible to make high quality estimates in a very short time.)
-
多人手牌分析-(Multi-player hand analysis -)通常,您正在与多个玩家对战.这是在合理的时间内计算对多个玩家的获胜几率的方法.(More often than not, you are playing against multiple players. Here’s how to calculate win odds against multiple players in a reasonable amount of time.)
-
多核支持(Multiple core support)-添加内核时,加速几乎是线性的.请注意,上面的基准测试图像显示在双四核系统上计算的每秒超过2.04亿手.(- The speed-ups are nearly linear when adding cores. Notice that the benchmark image above shows over 204 million hands/second calculated on a dual Quad Core system.)
蒙特卡洛分析(Monte Carlo analysis)
计算获胜几率(Calculating win odds)
考虑下面的代码.它计算出对与一个随机对手进行AK对抗的玩家的获胜几率.(Consider the following code. It calculates the win odds for a player being dealt AKs against a random opponent.) 在没有板卡的情况下,此程序在我的笔记本电脑上大约需要299秒(近5分钟)来计算.这意味着该代码正在评估14,084,025手/秒和总计2,097,572,400(是,十亿)的手匹配.板上有三张牌,需要0.263秒,总共进行了1,070,190手比赛.(This program takes about 299 seconds (nearly 5 minutes) on my laptop to calculate with no board cards. That means the code is evaluating 14,084,025 hands/sec and a total of 2,097,572,400 (yes, billions) of hand match-ups. With three cards on the board, it takes 0.263 seconds and a total of 1,070,190 hand match-ups.) 当板上有卡时,此功能非常有用.但是,如果您要以此计算出底洞获胜概率,则该算法太慢而无法使用.(When there are cards on the board, this function is very usable. However, if you are calculating hole card win probabilities with this, then the algorithm is far too slow to be usable.)
using System;
using System.Collections.Generic;
using HoldemHand;
namespace ConsoleApplication1
{
class Program
{
static void Main(string[] args)
{
// This code calculates the probablity of As Ks winning against
// another random hand.
ulong pocketmask = Hand.ParseHand("As Ks"); // Hole hand
ulong board = Hand.ParseHand(""); // No board cards yet
long wins = 0, ties = 0, loses = 0, count = 0;
// Iterate through all possible opponent hole cards
foreach (ulong oppmask in Hand.Hands(0UL, board | pocketmask, 2))
{
// Iterate through all board cards
foreach (ulong boardmask in Hand.Hands(
board, pocketmask | oppmask, 5))
{
// Evaluate the player and opponent hands and
// tally the results
uint pocketHandVal =
Hand.Evaluate(pocketmask | boardmask, 7);
uint oppHandVal = Hand.Evaluate(oppmask | boardmask, 7);
if (pocketHandVal > oppHandVal)
{
wins++;
}
else if (pocketHandVal == oppHandVal)
{
ties++;
}
else
{
loses++;
}
count++;
}
}
// Prints: Win 67.0446323092352%
Console.WriteLine("Win {0}%",
(((double)wins) + ((double)ties) / 2.0) / (
(double)count) * 100.0);
}
}
}
过去,我已经通过预先计算精确值然后使用查找表来解决此类问题.但是,在德州扑克中,很多情况下所需的计算时间很长,并且查找表不可行,例如计算对多个玩家的赔率.因此,对于某些问题,需要考虑其他技术.这就是为什么我首先研究蒙特卡洛分析的原因.(I’ve gotten around problems like this in the past by pre-calculating the exact values and then using lookup tables. However, there many situations in Texas Holdem where the computation time required is very long and lookup tables aren’t feasible, such as calculating odds win odds against multiple players. Because of this, other techniques need to be considered for some problems. That’s why I first looked into Monte Carlo analysis.)
快速获得"足够好"的结果(Getting “good enough” results fast)
我不是完美主义者,显然也不是许多成功的职业德州扑克玩家.(I’m not a perfectionist and apparently neither are many of the successful professional Texas Holdem Players.) 在菲尔`戈登(Phil Gordon)的<小绿皮书>(我可能会补充一本非常好的书)中,他描述了一种非常简单的启发式方法,可以在您的脑海中进行计算,并给出击中"失败"的大概几率.他称此为" 4和2的规则".这种启发式工作的方式是您数出自己的出路.如果您只是看到翻牌而不是转牌,那么将出局乘以4,您将获得出局的大致百分比.如果您看过转牌,但没看过河牌,则可以将出局乘以2,以获得出局的大致几率.(In Phil Gordon’s Little Green Book – a very good book, I might add – he describes a very simple heuristic that can be calculated in your head and that gives the approximate odds of hitting your “outs.” He calls this “the rule of 4 and 2.” The way this heuristic works is that you count your outs. If you’ve just seen the flop and not the turn card, then multiply the outs by 4 and you will have the approximate percentage of hitting your outs. If you’ve seen the turn but not the river, you multiply the outs by 2 to get the approximate odds of hitting your outs.) 这些类型的简单估计被许多专业参与者用来帮助评估他们的状况.如果估算对他们来说足够好,那么如果使用正确的话,对我们其他人可能就足够了.蒙特卡洛分析只是计算机在特定情况下快速估算赔率的一种方法.(These types of simple estimates are used by many of the professional players to help evaluate their situation. If an estimate is good enough for them, then it’s probably good enough for the rest of us if used correctly. Monte Carlo Analysis is just a method for a computer to quickly estimate the odds in a specific situation.) 考虑我们前面计算AK获胜几率的示例.遍历所有可能的情况并给出确切答案将需要299秒.下表是使用蒙特卡洛分析法计算的.左边的数字是试验次数,第二个数字是估计的获胜几率.准确几率是67.0446323092352%.第三列是精确答案与估计答案之间的差异.第四列是以秒为单位的时间.(Consider our previous example of calculating the win odds for AKs. It would take 299 seconds to iterate through all the possible situations and give us an exact answer. The following table was calculated using Monte Carlo analysis. The number on the left is the number of trials and the second number is the estimated win odds. The exact odds were 67.0446323092352%. The third column is the difference between the exact answer and the estimate answer. The fourth column is the time taken in seconds.)
试用版(Trials) | 获胜(Wins) | 区别(Difference) | 持续时间(Duration) |
---|---|---|---|
10 | 80.00% | 12.9554 | 0.00005 |
50 | 68.00% | 0.9554 | 0.00007 |
100 | 61.00% | 6.0446 | 0.00009 |
500 | 68.90% | 1.8554 | 0.00038 |
1000 | 67.10% | 0.0554 | 0.00071 |
5000 | 68.32% | 1.2754 | 0.00345 |
10000 | 67.15% | 0.1004 | 0.00759 |
15000 | 66.52% | 0.5246 | 0.01065 |
20000 | 67.96% | 0.9104 | 0.01451 |
25000 | 66.84% | 0.2006 | 0.01772 |
30000 | 67.00% | 0.0480 | 0.02197 |
40000 | 67.05% | 0.0029 | 0.02837 |
50000 | 67.16% | 0.1184 | 0.03610 |
100000 | 67.19% | 0.1449 | 0.07154 |
150000 | 66.98% | 0.0663 | 0.10710 |
200000 | 66.96% | 0.0856 | 0.15701 |
500000 | 66.94% | 0.1018 | 0.36579 |
1000000 | 67.04% | 0.0024 | 0.79401 |
2000000 | 67.04% | 0.0025 | 1.43816 |
5000000 | 67.05% | 0.0023 | 3.84238 |
10000000 | 67.03% | 0.0110 | 7.76830 |
20000000 | 67.04% | 0.0092 | 15.02408 |
请注意,在0.00071秒(0.7毫秒)处,我们有2个好数字.在0.02197(22毫秒)处,我们有3个好数字.在0.79401(794毫秒)处,我们有4个好数字.显而易见,我们可以在不到一秒钟的时间内获得非常好的估算.以下代码用于生成上一个表.(Notice that at 0.00071 seconds (0.7 milliseconds) we have 2 good digits. At 0.02197 (22 milliseconds) we have about 3 good digits. At 0.79401 (794 milliseconds) we have 4 good digits. It’s easy to see that we can get very good estimates in well less than a second. The following code was used to generate the previous table.)
using System;
using System.Collections.Generic;
using System.Runtime.InteropServices;
using HoldemHand;
namespace WinOddsMonteCarlo
{
///
/// This program shows the increase in accuracy of the Monte Carlo method
/// when increasing the number of samples.
///
class Program
{
static void Main(string[] args)
{
// This code calculates the probablity of As Ks winning against
// another random hand.
ulong pocketmask = Hand.ParseHand("As Ks"); // Hole hand
ulong board = Hand.ParseHand(""); // No board cards yet
// Trial numbers
int[] trialsTable = {
10, 50, 100, 500, 1000, 5000, 10000, 15000, 20000,
25000, 30000, 40000, 50000, 100000, 150000, 200000,
500000, 1000000, 2000000, 5000000, 10000000, 20000000
};
// timer values
double start = 0.0;
Console.WriteLine("Trials,Wins,Difference,Duration");
foreach (int trials in trialsTable)
{
long wins = 0, ties = 0, count = 0;
// Get start time
start = Hand.CurrentTime;
// Iterate through a series board cards
foreach (ulong boardmask in Hand.RandomHands(board,
pocketmask, 5, trials))
{
// Get a random opponent hand
ulong oppmask =
Hand.RandomHand(boardmask | pocketmask, 2);
// Evaluate the player and opponent hands
uint pocketHandVal =
Hand.Evaluate(pocketmask | boardmask, 7);
uint oppHandVal = Hand.Evaluate(oppmask | boardmask, 7;
// Calculate Statistics
if (pocketHandVal > oppHandVal)
{
wins++;
}
else if (pocketHandVal == oppHandVal)
{
ties++;
}
count++;
}
double duration = Hand.CurrentTime - start;
// Correct answer is 67.0446323092352%
Console.WriteLine("{0},{1:0.00}%,{2:0.0000},{3:0.00000}",
trials,
(((double)wins) + (
(double)ties) / 2.0) / ((double)count) *100.0,
Math.Abs(67.0446323092352 - ((((double)wins) +
((double)ties) / 2.0) / ((double)count) * 100)),
duration);
}
}
}
}
蒙特卡洛分析辅助方法(Monte Carlo analysis helper methods)
以下方法特意类似于(The following method is intentionally similar to the) IEnumerable Hands(ulong shared, ulong dead, int ncards)
方法.添加了另一个参数,该参数是此枚举器要迭代的随机手的数量.(method. One additional argument is added, which is the number of random hands that are to be iterated through by this enumerator.)
public static IEnumerable RandomHands(
ulong shared, ulong dead, int ncards, int trials)
这个(This) IEnumerable
方法允许foreach命令通过随机操作进行迭代.返回的手必须符合指定的标准.返回在最后一个参数中指定的手数.(method allows the foreach command to iterate through random hands. The hands returned must meet the criterion specified. The number of hands specified in the last argument are returned.)
public static IEnumerable RandomHands(
ulong shared, ulong dead, int ncards, double duration)
此方法类似于以前的方法.但是,不是指定试验次数,而是指定持续时间.这样可以指定时间预算以获取答案.我偏爱使用此版本的这些方法.(This method is similar to the previous method. However, rather than specifying the number of trials, a time duration is specified. This allows a time budget to be specified for getting an answer. I have a mild preference to using this version of these methods.)
计算多个玩家的获胜几率(Calculating win odds for multiple players)
计算一名球员的赔率很有趣.但是,您经常会与多个玩家对战.以下示例显示了如何计算1到9名玩家在相同情况下的获胜几率.(It’s interesting to calculate odds against one player. However, more often than not, you are playing against multiple players. The following example shows how to calculate the win odds for the same situation with 1 through 9 players.)
using System;
using HoldemHand;
// This example calculates the win odds for a player having "As Ks" against
// 1-9 random players
namespace WinOddsMultipleOpponents
{
class Program
{
// Expected output (approximate values)
// 1: win 67.08%
// 2: win 50.82%
// 3: win 41.53%
// 4: win 35.46%
// 5: win 31.13%
// 6: win 27.82%
// 7: win 24.99%
// 8: win 22.77%
// 9: win 20.77%
static void Main(string[] args)
{
const double time = 5.0;
ulong pocket = Hand.ParseHand("As Ks");
ulong board = Hand.ParseHand("");
ulong dead = Hand.ParseHand("");
for (int opponents = 1; opponents <= 9; opponents++)
{
Console.WriteLine("{0}: win {1:0.00}%",
opponents, WinOddsMonteCarlo(
pocket, board, dead, opponents, time) * 100.0);
}
}
// An example of how to calculate win odds for multiple players
static double WinOddsMonteCarlo(
ulong pocket, ulong board, ulong dead, int nopponents,
double duration)
{
System.Diagnostics.Debug.Assert(
nopponents > 0 && nopponents <= 9);
System.Diagnostics.Debug.Assert(
duration > 0.0);
System.Diagnostics.Debug.Assert(
Hand.BitCount(pocket) == 2);
System.Diagnostics.Debug.Assert(
Hand.BitCount(board) >= 0 && Hand.BitCount(board) <= 5);
// Keep track of stats
double win = 0.0, count = 0.0;
// Keep track of time
double start = Hand.CurrentTime;
// Loop for specified time duration
while ((Hand.CurrentTime-start) < duration)
{
// Player and board info
ulong boardmask = Hand.RandomHand(board, dead | pocket, 5);
uint playerHandVal = Hand.Evaluate(pocket | boardmask);
// Ensure that dead, board, and pocket cards are not
// available to opponent hands.
ulong deadmask = dead | boardmask | pocket;
// Comparison Results
bool greaterthan = true;
bool greaterthanequal = true;
// Get random opponent hand values
for (int i = 0; i < nopponents; i++)
{
// Get Opponent hand info
ulong oppmask = Hand.RandomHand(deadmask, 2);
uint oppHandVal = Hand.Evaluate(oppmask | boardmask);
// Remove these opponent cards from future opponents
deadmask |= oppmask;
// Determine compare status
if (playerHandVal < oppHandVal)
{
greaterthan = greaterthanequal = false;
break;
}
else if (playerHandVal <= oppHandVal)
{
greaterthan = false;
}
}
// Calculate stats
if (greaterthan)
win += 1.0;
else if (greaterthanequal)
win += 0.5;
count += 1.0;
}
// Return stats
return (count == 0.0 ? 0.0 : win/count);
}
}
}
方法(The method) WinOddsMonteCarlo
在这里完成所有艰苦的工作.您会注意到,与我们之前的计算相比,单个对手的结果似乎精确到3位数字.我不能保证对手数大于1的准确度-坦率地说,获取答案的时间太长了-但是当在MultiOddsApp应用程序上绘制时,这些值非常稳定.您可以在可下载项目中包含的演示程序中找到MultiOddsApp.因此,我相信结果是相当准确的.(does all of the hard work here. You will notice that the results for a single opponent appear to be accurate to 3 digits when compared against our previous calculation. I can’t vouch for the digits of accuracy for opponent counts greater than 1 – frankly, it takes too long to get answers – but the values are very stable when plotted on the MultiOddsApp application. You’ll find MultiOddsApp in the demo programs included in the downloadable project. Because of this, I believe that the results are reasonably accurate.)
计算所有口袋手的获胜几率(Calculating win odds for all pocket hands)
可以使用上述程序的一个简单变体来计算1-9个对手的169种可能的起始口袋手的每局的近似获胜几率.请注意,我已经包含了结果表,该表给出了1到9个对手的每个可能的起始手的典型示例的近似赔率.我没有在线浏览过相同的信息,因此认为这对某些玩家可能很有趣.(A simple variation of the above program can be used to calculate the approximate win odds for each of the 169 possible starting pocket hands for 1-9 opponents. Note that I’ve include the resulting table that gives approximate odds for a representative example of every possible starting hand for 1 though 9 opponents. I haven’t run across the equivalent information online and thought that might be interesting for some players.)
using System;
using HoldemHand;
// This example calculates the win odds for a player having "As Ks" against
// 1-9 random players. The results is comma separated so that
// it can be imported
// into Excel using the .csv file type.
namespace WinOddsMultipleOpponentsTable
{
class Program
{
static void Main(string[] args)
{
const double time = 5.0;
ulong board = Hand.ParseHand("");
ulong dead = Hand.ParseHand("");
// Table Header
Console.Write(",");
for (int i = 1; i <= 9; i++)
{
Console.Write("{0},", i);
}
Console.WriteLine();
// Iterates through one representative hand of each of the
// 169 possible
// pocket hand types
foreach (ulong pocket in PocketHands.Hands169())
{
// Show Pocker Hand
Console.Write("\"{0}\",", Hand.MaskToString(pocket));
// Calculate and Display the Approximate odds for 1-9
// opponents
for (int opponents = 1; opponents <= 9; opponents++)
{
Console.Write("{0}%,", WinOddsMonteCarlo(
pocket, board, dead, opponents, time) * 100.0);
}
Console.WriteLine();
}
}
// An example of how to calculate win odds for multiple players
static double WinOddsMonteCarlo(ulong pocket, ulong board, ulong dead,
int nopponents, double duration)
{
System.Diagnostics.Debug.Assert(
nopponents > 0 && nopponents <= 9);
System.Diagnostics.Debug.Assert(duration > 0.0);
System.Diagnostics.Debug.Assert(Hand.BitCount(pocket) == 2);
System.Diagnostics.Debug.Assert(
Hand.BitCount(board) >= 0 && Hand.BitCount(board) <= 5);
// Keep track of stats
double win = 0.0, count = 0.0;
// Keep track of time
double start = Hand.CurrentTime;
// Loop for specified time duration
while ((Hand.CurrentTime-start) < duration)
{
// Player and board info
ulong boardmask = Hand.RandomHand(board, dead | pocket, 5);
uint playerHandVal = Hand.Evaluate(pocket | boardmask);
// Ensure that dead, board, and pocket cards are not
// available to opponent hands.
ulong deadmask = dead | boardmask | pocket;
// Comparison Results
bool greaterthan = true;
bool greaterthanequal = true;
// Get random opponent hand values
for (int i = 0; i < nopponents; i++)
{
// Get Opponent hand info
ulong oppmask = Hand.RandomHand(deadmask, 2);
uint oppHandVal = Hand.Evaluate(oppmask | boardmask);
// Remove these opponent cards from future opponents
deadmask |= oppmask;
// Determine compare status
if (playerHandVal < oppHandVal)
{
greaterthan = greaterthanequal = false;
break;
}
else if (playerHandVal <= oppHandVal)
{
greaterthan = false;
}
}
// Calculate stats
if (greaterthan)
win += 1.0;
else if (greaterthanequal)
win += 0.5;
count += 1.0;
}
// Return stats
return (count == 0.0 ? 0.0 : win/count);
}
}
}
结果输出如下.该表给出了指定的口袋手相对于指定对手数的获胜几率.每个单元格都有30秒的计算时间,因此结果可能好几位数.但是,我尚未验证大于1的对手数.(The resulting output is below. This table gives the approximate odds of winning, given the specified pocket hand against the number of specified opponents. Each cell was given 30 seconds of calculation time, so the results are probably good to several digits. However, I haven’t verified that for opponent numbers greater then 1.) 口袋卡vs对手获胜的近似胜算(Pocket Cards vs Approximate Win Odds Given Opponent Count)||1个(1)|2(2)|3(3)|4(4)|5(5)|6(6)|7(7)|8(8)|9(9)| |-|-|-|-|-|-|-|-|-|-| |作为啊(As Ah)|85.20%|73.50%|63.91%|55.91%|49.24%|43.59%|38.75%|34.66%|31.14%| |s(Ks Kh)|82.40%|68.93%|58.30%|49.88%|43.01%|37.46%|32.95%|29.24%|26.15%| |Qs Qh(Qs Qh)|79.93%|64.98%|53.58%|44.79%|37.92%|32.58%|28.35%|24.98%|22.28%| |Js Jh(Js Jh)|77.46%|61.22%|49.25%|40.32%|33.63%|28.59%|24.70%|21.71%|19.40%| |Th(Ts Th)|75.01%|57.63%|45.27%|36.41%|30.00%|25.27%|21.82%|19.17%|17.20%| |9秒9小时(9s 9h)|72.06%|53.70%|41.21%|32.65%|26.70%|22.50%|19.47%|17.26%|15.61%| |8秒8小时(8s 8h)|69.16%|50.01%|37.67%|29.56%|24.09%|20.38%|17.77%|15.91%|14.55%| |7秒7小时(7s 7h)|66.23%|46.56%|34.48%|26.85%|21.96%|18.69%|16.44%|14.87%|13.70%| |6秒6小时(6s 6h)|63.29%|43.29%|31.60%|24.59%|20.19%|17.36%|15.44%|14.09%|13.10%| |5秒5小时(5s 5h)|60.32%|40.17%|29.01%|22.54%|18.63%|16.16%|14.50%|13.33%|12.43%| |4秒4小时(4s 4h)|57.02%|36.88%|26.41%|20.69%|17.37%|15.34%|13.93%|12.98%|12.21%| |3秒3小时(3s 3h)|53.69%|33.77%|24.12%|19.14%|16.35%|14.67%|13.56%|12.75%|12.08%| |2秒2小时(2s 2h)|50.33%|30.82%|22.10%|17.86%|15.62%|14.24%|13.30%|12.59%|11.99%| |作为Ks(As Ks)|67.03%|50.82%|41.53%|35.50%|31.16%|27.80%|25.06%|22.73%|20.79%| |作为Kh(As Kh)|65.31%|48.29%|38.64%|32.41%|27.94%|24.48%|21.68%|19.33%|17.30%| |作为Qs(As Qs)|66.21%|49.50%|39.97%|33.81%|29.42%|26.09%|23.39%|21.19%|19.37%| |作为Qh(As Qh)|64.44%|46.89%|36.94%|30.56%|26.04%|22.59%|19.82%|17.56%|15.66%| |作为Js(As Js)|65.37%|48.27%|38.56%|32.36%|27.98%|24.72%|22.12%|20.03%|18.30%| |作为Jh(As Jh)|63.56%|45.57%|35.40%|28.99%|24.46%|21.04%|18.39%|16.21%|14.43%| |作为Ts(As Ts)|64.59%|47.15%|37.35%|31.12%|26.84%|23.65%|21.16%|19.15%|17.48%| |如Th(As Th)|62.74%|44.38%|34.08%|27.62%|23.16%|19.85%|17.26%|15.20%|13.50%| |作为9s(As 9s)|62.77%|44.64%|34.63%|28.45%|24.27%|21.18%|18.85%|17.02%|15.52%| |截至9h(As 9h)|60.76%|41.65%|31.19%|24.70%|20.36%|17.19%|14.77%|12.86%|11.34%| |作为8s(As 8s)|61.93%|43.62%|33.58%|27.48%|23.35%|20.39%|18.12%|16.35%|14.92%| |截至8h(As 8h)|59.87%|40.53%|30.03%|23.64%|19.36%|16.30%|13.95%|12.13%|10.65%| |作为7秒(As 7s)|60.98%|42.47%|32.50%|26.52%|22.51%|19.68%|17.49%|15.81%|14.43%| |截至7小时(As 7h)|58.83%|39.32%|28.86%|22.60%|18.44%|15.47%|13.24%|11.51%|10.13%| |6s(As 6s)|59.90%|41.25%|31.41%|25.58%|21.74%|19.01%|16.96%|15.35%|14.06%| |截至6h(As 6h)|57.67%|37.99%|27.67%|21.56%|17.57%|14.75%|12.65%|11.02%|9.74%| |5s(As 5s)|59.94%|41.52%|31.87%|26.13%|22.31%|19.61%|17.56%|15.96%|14.61%| |5小时(As 5h)|57.71%|38.26%|28.13%|22.14%|18.20%|15.37%|13.27%|11.62%|10.31%| |作为4秒(As 4s)|59.01%|40.63%|31.10%|25.50%|21.81%|19.19%|17.21%|15.64%|14.35%| |4小时(As 4h)|56.72%|37.29%|27.29%|21.43%|17.61%|14.91%|12.87%|11.30%|10.04%| |作为3秒(As 3s)|58.22%|39.73%|30.33%|24.89%|21.30%|18.77%|16.84%|15.34%|14.09%| |3小时(As 3h)|55.86%|36.33%|26.47%|20.75%|17.06%|14.46%|12.51%|10.97%|9.74%| |作为2秒(As 2s)|57.37%|38.86%|29.58%|24.20%|20.75%|18.27%|16.40%|14.91%|13.73%| |2小时(As 2h)|54.93%|35.37%|25.57%|19.99%|16.42%|13.90%|12.02%|10.52%|9.33%| |Qs(Ks Qs)|63.40%|47.19%|38.30%|32.58%|28.45%|25.24%|22.66%|20.51%|18.74%| |千卡(Ks Qh)|61.47%|44.48%|35.28%|29.39%|25.15%|21.84%|19.21%|17.02%|15.21%| |s(Ks Js)|62.58%|45.98%|36.94%|31.18%|27.08%|23.95%|21.45%|19.44%|17.76%| |J(Ks Jh)|60.58%|43.18%|33.82%|27.85%|23.62%|20.40%|17.85%|15.77%|14.05%| |s(Ks Ts)|61.81%|44.88%|35.73%|30.02%|25.95%|22.93%|20.54%|18.61%|17.01%| |s(Ks Th)|59.73%|42.02%|32.54%|26.57%|22.41%|19.25%|16.80%|14.83%|13.22%| |9秒(Ks 9s)|60.01%|42.38%|33.07%|27.35%|23.37%|20.47%|18.22%|16.43%|14.99%| |9小时(Ks 9h)|57.81%|39.34%|29.61%|23.63%|19.57%|16.57%|14.26%|12.44%|10.95%| |8秒(Ks 8s)|58.31%|40.25%|30.92%|25.29%|21.49%|18.77%|16.67%|15.04%|13.72%| |8小时(Ks 8h)|56.01%|37.03%|27.27%|21.43%|17.53%|14.71%|12.57%|10.91%|9.58%| |7秒(Ks 7s)|57.52%|39.39%|30.07%|24.51%|20.81%|18.15%|16.13%|14.56%|13.28%| |7小时(Ks 7h)|55.20%|36.07%|26.33%|20.59%|16.75%|14.00%|11.95%|10.35%|9.10%| |6秒(Ks 6s)|56.66%|38.39%|29.17%|23.71%|20.15%|17.61%|15.65%|14.15%|12.92%| |6小时(Ks 6h)|54.21%|35.02%|25.37%|19.72%|16.03%|13.39%|11.43%|9.90%|8.71%| |5秒(Ks 5s)|55.80%|37.51%|28.41%|23.11%|19.63%|17.14%|15.28%|13.84%|12.66%| |5小时(Ks 5h)|53.29%|34.05%|24.54%|19.02%|15.44%|12.92%|11.02%|9.57%|8.42%| |4秒(Ks 4s)|54.88%|36.64%|27.68%|22.53%|19.15%|16.78%|14.97%|13.58%|12.45%| |每小时4小时(Ks 4h)|52.33%|33.10%|23.73%|18.37%|14.90%|12.47%|10.68%|9.28%|8.18%| |3秒(Ks 3s)|54.05%|35.83%|26.99%|21.99%|18.74%|16.44%|14.68%|13.33%|12.26%| |3小时(Ks 3h)|51.43%|32.20%|22.98%|17.77%|14.43%|12.09%|10.36%|9.03%|7.96%| |2秒(Ks 2s)|53.20%|35.01%|26.35%|21.45%|18.34%|16.10%|14.45%|13.13%|12.08%| |2小时(Ks 2h)|50.50%|31.34%|22.24%|17.20%|13.98%|11.75%|10.11%|8.79%|7.79%| |Qs Js(Qs Js)|60.26%|44.30%|35.80%|30.31%|26.35%|23.30%|20.90%|18.96%|17.36%| |Qs Jh(Qs Jh)|58.11%|41.46%|32.69%|27.05%|22.98%|19.86%|17.43%|15.45%|13.83%| |s(Qs Ts)|59.46%|43.23%|34.65%|29.19%|25.26%|22.36%|20.04%|18.19%|16.69%| |Th(Qs Th)|57.30%|40.31%|31.43%|25.81%|21.81%|18.78%|16.42%|14.58%|13.07%| |问9(Qs 9s)|57.66%|40.74%|31.99%|26.54%|22.75%|19.94%|17.75%|16.04%|14.68%| |Qs 9小时(Qs 9h)|55.37%|37.67%|28.55%|22.92%|19.04%|16.14%|13.93%|12.21%|10.81%| |Qs 8秒(Qs 8s)|56.02%|38.66%|29.84%|24.52%|20.85%|18.21%|16.19%|14.60%|13.34%| |Qs 8小时(Qs 8h)|53.61%|35.41%|26.23%|20.74%|16.99%|14.29%|12.22%|10.64%|9.39%| |问7秒(Qs 7s)|54.30%|36.57%|27.86%|22.66%|19.21%|16.71%|14.84%|13.41%|12.22%| |Qs 7小时(Qs 7h)|51.76%|33.15%|24.07%|18.74%|15.18%|12.64%|10.75%|9.32%|8.18%| |6秒(Qs 6s)|53.62%|35.86%|27.15%|22.05%|18.65%|16.24%|14.45%|13.03%|11.92%| |6小时(Qs 6h)|51.02%|32.37%|23.29%|18.05%|14.57%|12.11%|10.28%|8.89%|7.82%| |5秒(Qs 5s)|52.77%|34.98%|26.40%|21.44%|18.16%|15.84%|14.10%|12.75%|11.69%| |5小时(Qs 5h)|50.12%|31.44%|22.50%|17.34%|14.00%|11.67%|9.92%|8.59%|7.55%| |Qs 4秒(Qs 4s)|51.87%|34.15%|25.72%|20.86%|17.72%|15.47%|13.82%|12.49%|11.47%| |Qs 4小时(Qs 4h)|49.14%|30.49%|21.73%|16.73%|13.49%|11.25%|9.58%|8.30%|7.32%| |3秒(Qs 3s)|51.02%|33.34%|25.06%|20.33%|17.29%|15.15%|13.54%|12.29%|11.28%| |3小时(Qs 3h)|48.23%|29.64%|21.01%|16.14%|13.03%|10.87%|9.29%|8.07%|7.11%| |2秒(Qs 2s)|50.17%|32.55%|24.42%|19.82%|16.91%|14.84%|13.29%|12.08%|11.11%| |Qs 2小时(Qs 2h)|47.31%|28.76%|20.29%|15.59%|12.61%|10.53%|9.02%|7.86%|6.94%| |s(Js Ts)|57.52%|42.05%|33.98%|28.75%|24.98%|22.13%|19.88%|18.13%|16.70%| |Th(Js Th)|55.23%|39.16%|30.80%|25.45%|21.61%|18.69%|16.43%|14.64%|13.23%| |9s(Js 9s)|55.62%|39.60%|31.35%|26.15%|22.50%|19.77%|17.67%|16.03%|14.72%| |9小时(Js 9h)|53.23%|36.50%|27.99%|22.64%|18.87%|16.09%|13.97%|12.35%|11.05%| |Js 8s(Js 8s)|54.02%|37.51%|29.23%|24.15%|20.64%|18.07%|16.12%|14.60%|13.39%| |8小时(Js 8h)|51.51%|34.26%|25.68%|20.46%|16.87%|14.24%|12.29%|10.79%|9.59%| |Js 7s(Js 7s)|52.31%|35.50%|27.27%|22.29%|18.95%|16.54%|14.70%|13.30%|12.20%| |7小时(Js 7h)|49.67%|32.07%|23.53%|18.43%|15.03%|12.57%|10.75%|9.38%|8.29%| |Js 6s(Js 6s)|50.60%|33.49%|25.40%|20.62%|17.44%|15.18%|13.53%|12.22%|11.20%| |6小时(Js 6h)|47.82%|29.92%|21.53%|16.60%|13.38%|11.12%|9.45%|8.19%|7.21%| |5秒(Js 5s)|49.98%|32.87%|24.83%|20.13%|17.04%|14.86%|13.21%|11.96%|10.95%| |5小时(Js 5h)|47.16%|29.27%|20.88%|16.06%|12.92%|10.73%|9.11%|7.89%|6.94%| |Js 4s(Js 4s)|49.07%|32.04%|24.13%|19.60%|16.59%|14.49%|12.92%|11.70%|10.74%| |JS 4小时(Js 4h)|46.19%|28.36%|20.16%|15.46%|12.43%|10.34%|8.80%|7.63%|6.72%| |Js 3s(Js 3s)|48.24%|31.27%|23.50%|19.08%|16.21%|14.18%|12.67%|11.49%|10.57%| |3小时(Js 3h)|45.29%|27.48%|19.44%|14.89%|11.98%|9.95%|8.50%|7.40%|6.53%| |2秒(Js 2s)|47.36%|30.47%|22.86%|18.59%|15.82%|13.89%|12.45%|11.32%|10.42%| |2小时(Js 2h)|44.35%|26.63%|18.72%|14.34%|11.56%|9.65%|8.24%|7.18%|6.35%| |9秒(Ts 9s)|54.04%|38.90%|31.10%|26.09%|22.54%|19.89%|17.83%|16.26%|15.02%| |9小时(Ts 9h)|51.54%|35.81%|27.80%|22.66%|19.04%|16.33%|14.28%|12.74%|11.48%| |8秒(Ts 8s)|52.33%|36.83%|29.02%|24.13%|20.73%|18.21%|16.33%|14.87%|13.70%| |8小时(Ts 8h)|49.72%|33.58%|25.54%|20.51%|17.04%|14.52%|12.64%|11.21%|10.07%| |7秒(Ts 7s)|50.62%|34.79%|27.04%|22.30%|19.04%|16.68%|14.93%|13.55%|12.50%| |7小时(Ts 7h)|47.91%|31.40%|23.39%|18.50%|15.21%|12.84%|11.10%|9.78%|8.74%| |6秒(Ts 6s)|48.95%|32.85%|25.17%|20.56%|17.49%|15.26%|13.66%|12.38%|11.37%| |6小时(Ts 6h)|46.09%|29.29%|21.35%|16.65%|13.53%|11.31%|9.70%|8.48%|7.54%| |5秒(Ts 5s)|47.22%|30.94%|23.40%|19.01%|16.12%|14.07%|12.57%|11.38%|10.45%| |5小时(Ts 5h)|44.28%|27.25%|19.46%|15.00%|12.03%|10.02%|8.53%|7.42%|6.56%| |4秒(Ts 4s)|46.53%|30.35%|22.91%|18.60%|15.75%|13.75%|12.26%|11.12%|10.21%| |4小时(Ts 4h)|43.50%|26.58%|18.90%|14.48%|11.64%|9.66%|8.23%|7.15%|6.30%| |3秒(Ts 3s)|45.68%|29.58%|22.28%|18.10%|15.36%|13.45%|12.03%|10.93%|10.06%| |3小时(Ts 3h)|42.58%|25.76%|18.21%|13.94%|11.19%|9.31%|7.93%|6.90%|6.11%| |2秒(Ts 2s)|44.84%|28.82%|21.66%|17.61%|14.99%|13.16%|11.79%|10.74%|9.89%| |2小时(Ts 2h)|41.65%|24.93%|17.52%|13.40%|10.77%|9.00%|7.67%|6.70%|5.94%| |9秒8秒(9s 8s)|50.78%|36.13%|28.61%|23.79%|20.40%|17.95%|16.09%|14.66%|13.53%| |9秒8小时(9s 8h)|48.10%|32.87%|25.16%|20.21%|16.78%|14.30%|12.46%|11.06%|9.99%| |9秒7秒(9s 7s)|49.11%|34.24%|26.81%|22.17%|18.97%|16.68%|14.97%|13.67%|12.63%| |9秒7小时(9s 7h)|46.30%|30.83%|23.20%|18.46%|15.22%|12.93%|11.25%|9.98%|9.00%| |9秒6秒(9s 6s)|47.44%|32.33%|24.96%|20.50%|17.48%|15.36%|13.75%|12.53%|11.54%| |9秒6小时(9s 6h)|44.49%|28.76%|21.22%|16.64%|13.60%|11.45%|9.91%|8.74%|7.85%| |9秒5秒(9s 5s)|45.72%|30.43%|23.22%|18.91%|16.07%|14.05%|12.56%|11.41%|10.50%| |9秒5小时(9s 5h)|42.71%|26.73%|19.32%|14.92%|12.06%|10.07%|8.64%|7.55%|6.73%| |9秒4秒(9s 4s)|43.87%|28.55%|21.52%|17.43%|14.76%|12.88%|11.51%|10.45%|9.59%| |9秒4小时(9s 4h)|40.69%|24.70%|17.47%|13.31%|10.63%|8.80%|7.48%|6.50%|5.75%| |9秒3秒(9s 3s)|43.26%|28.00%|21.05%|17.04%|14.43%|12.61%|11.27%|10.21%|9.39%| |9秒3小时(9s 3h)|40.01%|24.10%|16.95%|12.88%|10.27%|8.48%|7.23%|6.26%|5.52%| |9秒2秒(9s 2s)|42.44%|27.27%|20.46%|16.57%|14.07%|12.34%|11.04%|10.05%|9.23%| |9秒2小时(9s 2h)|39.11%|23.28%|16.28%|12.35%|9.86%|8.18%|6.96%|6.07%|5.36%| |8秒7秒(8s 7s)|47.93%|33.96%|26.80%|22.22%|19.10%|16.84%|15.17%|13.90%|12.87%| |8秒7小时(8s 7h)|45.06%|30.58%|23.22%|18.57%|15.39%|13.16%|11.54%|10.29%|9.35%| |8秒6秒(8s 6s)|46.27%|32.13%|25.11%|20.73%|17.78%|15.71%|14.17%|12.96%|12.03%| |8秒6小时(8s 6h)|43.24%|28.62%|21.39%|16.94%|13.98%|11.92%|10.45%|9.32%|8.44%| |8秒5秒(8s 5s)|44.54%|30.25%|23.36%|19.18%|16.39%|14.46%|13.01%|11.90%|11.01%| |8秒5小时(8s 5h)|41.42%|26.59%|19.52%|15.25%|12.47%|10.57%|9.21%|8.17%|7.36%| |8秒4秒(8s 4s)|42.71%|28.39%|21.66%|17.66%|15.00%|13.18%|11.83%|10.79%|9.96%| |8秒4小时(8s 4h)|39.45%|24.57%|17.64%|13.59%|10.99%|9.20%|7.93%|6.99%|6.24%| |8秒3秒(8s 3s)|40.86%|26.55%|19.99%|16.21%|13.78%|12.06%|10.81%|9.86%|9.06%| |8秒3小时(8s 3h)|37.48%|22.58%|15.86%|12.04%|9.59%|8.00%|6.84%|5.96%|5.30%| |8秒2秒(8s 2s)|40.27%|26.00%|19.56%|15.85%|13.46%|11.82%|10.60%|9.64%|8.89%| |8秒2小时(8s 2h)|36.84%|22.00%|15.36%|11.62%|9.27%|7.69%|6.58%|5.74%|5.09%| |7秒6秒(7s 6s)|45.36%|32.12%|25.24%|20.92%|18.02%|15.99%|14.49%|13.33%|12.39%| |7秒6小时(7s 6h)|42.32%|28.62%|21.59%|17.19%|14.28%|12.28%|10.82%|9.74%|8.91%| |7秒5秒(7s 5s)|43.69%|30.32%|23.62%|19.54%|16.84%|14.95%|13.56%|12.47%|11.58%| |7秒5小时(7s 5h)|40.52%|26.71%|19.83%|15.69%|12.99%|11.15%|9.82%|8.84%|8.07%| |7秒4秒(7s 4s)|41.84%|28.46%|21.94%|18.03%|15.49%|13.70%|12.41%|11.39%|10.58%| |7秒4小时(7s 4h)|38.58%|24.70%|18.02%|14.04%|11.50%|9.81%|8.59%|7.67%|6.95%| |7秒3秒(7s 3s)|40.00%|26.59%|20.24%|16.53%|14.13%|12.51%|11.26%|10.30%|9.51%| |7秒3小时(7s 3h)|36.61%|22.68%|16.17%|12.43%|10.06%|8.47%|7.35%|6.52%|5.85%| |7秒2秒(7s 2s)|38.16%|24.78%|18.63%|15.15%|12.93%|11.39%|10.26%|9.37%|8.65%| |7秒2小时(7s 2h)|34.59%|20.71%|14.45%|10.91%|8.76%|7.30%|6.28%|5.53%|4.92%| |6秒5秒(6s 5s)|43.13%|30.48%|23.88%|19.84%|17.19%|15.34%|13.97%|12.90%|12.01%| |6秒5小时(6s 5h)|39.93%|26.87%|20.14%|16.04%|13.41%|11.59%|10.30%|9.31%|8.55%| |6秒4秒(6s 4s)|41.32%|28.71%|22.33%|18.48%|16.02%|14.27%|13.04%|12.01%|11.20%| |6秒4小时(6s 4h)|38.02%|24.97%|18.46%|14.56%|12.10%|10.48%|9.28%|8.39%|7.68%| |6秒3秒(6s 3s)|39.52%|26.88%|20.66%|17.02%|14.68%|13.07%|11.90%|10.94%|10.18%| |6s 3小时(6s 3h)|36.09%|22.97%|16.64%|12.99%|10.68%|9.15%|8.07%|7.24%|6.60%| |6秒2秒(6s 2s)|37.67%|25.02%|19.02%|15.57%|13.38%|11.88%|10.77%|9.89%|9.15%| |6秒2小时(6s 2h)|34.07%|20.98%|14.86%|11.40%|9.28%|7.85%|6.86%|6.11%|5.51%| |5秒4秒(5s 4s)|41.46%|29.24%|22.87%|19.08%|16.61%|14.91%|13.62%|12.63%|11.77%| |5秒4小时(5s 4h)|38.17%|25.56%|19.05%|15.19%|12.77%|11.13%|9.95%|9.06%|8.34%| |5秒3秒(5s 3s)|39.70%|27.50%|21.33%|17.76%|15.49%|13.87%|12.71%|11.76%|10.98%| |5秒3小时(5s 3h)|36.26%|23.68%|17.39%|13.78%|11.55%|10.04%|8.96%|8.13%|7.46%| |5秒2秒(5s 2s)|37.86%|25.65%|19.71%|16.29%|14.17%|12.69%|11.58%|10.69%|9.95%| |5秒2小时(5s 2h)|34.30%|21.69%|15.62%|12.20%|10.13%|8.77%|7.76%|6.99%|6.40%| |4秒3秒(4s 3s)|38.66%|26.63%|20.58%|17.10%|14.88%|13.32%|12.20%|11.26%|10.48%| |4秒3小时(4s 3h)|35.16%|22.78%|16.57%|13.07%|10.91%|9.44%|8.42%|7.62%|6.99%| |4秒2秒(4s 2s)|36.83%|24.90%|19.07%|15.80%|13.75%|12.34%|11.27%|10.42%|9.70%| |4秒2小时(4s 2h)|33.20%|20.89%|14.96%|11.67%|9.68%|8.39%|7.43%|6.72%|6.14%| |3秒2秒(3s 2s)|36.00%|24.07%|18.34%|15.15%|13.19%|11.83%|10.80%|9.96%|9.27%| |3秒2小时(3s 2h)|32.32%|19.99%|14.16%|10.99%|9.09%|7.84%|6.92%|6.23%|5.65%|
使用多核(Using multiple cores)
在"计算获胜几率"部分中,我们显示了在笔记本电脑上使用" As Ks"的常规方法大约需要5分钟.但是,修改代码以支持多个内核很简单,并且会产生一些惊人的结果.(In the “Calculating win odds” section, we showed that the conventional method for “As Ks” takes about 5 minutes on my laptop computer. However, modifying the code to support multiple cores is straightforward and yields some spectacular results.)
单线程(Single Thread (s)) | 多线程(Multiple Thread (s)) | 加速(X)(Speedup (X)) | |
---|---|---|---|
单核(带/超线程)(Single Core (w/Hyperthreading)) | 225.16 | 202.38 | 1.11 |
双核的(Dual Core) | 163.69 | 80.89 | 2.02 |
四核(Quad Core) | 198.45 | 47.46 | 4.18 |
双四核(Dual Quad Core) | 171.91 | 21.26 | 8.09 |
以下代码用于对上表中的"多线程"列进行基准测试.此示例使用线程池使所有内核保持"活动"状态.这项技术实施起来非常简单,结果是基于内核数,速度大致呈线性增长.我相信以下示例是不言自明的,但是下面是一些要点.(The following code was used to benchmark the “Multiple Threads” column in the previous table. This example uses a thread pool to keep all of the cores “active.” This technique is fairly straightforward to implement and the result is a roughly linear increase in speed based on the number of cores. I believe that the following example is fairly self-explanatory, but here are some of the highlights.)
CalculateOdds()
–此方法等效于"计算获胜几率"示例中的内部循环.(– This is a method that is the equivalent of the inner loop in the “Calculating win odds” example.)Main()
:(:)- 确定我们将喂入的对手的手数(Determines the number of opponent hands that we will feed to)
CalculateOdds
;为每个线程池结果创建存储.(; creates storage for each thread pool result.) - 使用创建每个对手手的线程池条目(Creates a thread pool entry for each opponent hand using)
BeginInvoke
.的(. The)IAsyncResult
保留此条目,并在以后用于等待和收集结果.(is held for this entry and used later to wait for and collect the results.) - 用途(Uses)
EndInvoke
等待线程项完成并收集结果.(to wait for the thread items to complete and collects the results.) - 取得结果并使用与"计算获胜赔率"示例中相同的方程式计算赔率.请注意,返回的结果完全相同.(Takes the results and calculates the odds using the same equations as in the “Calculating win odds” example. Note that the returned result is exactly the same.)
- 确定我们将喂入的对手的手数(Determines the number of opponent hands that we will feed to)
using System;
using System.Collections.Generic;
using System.Runtime.InteropServices;
using System.Threading;
using HoldemHand;
namespace WinOddsMultipleThreads
{
class Program
{
// Holds Calculated Results
public struct Results
{
public long win, ties, count;
}
// Delegate used in threadpool
delegate Results CalculateOddsDelegate(
ulong pocket, ulong opp, ulong board, ulong dead);
// Method called and inserted in the threadpool
static Results CalculateOdds(
ulong pocket, ulong opp, ulong board, ulong dead)
{
// Initialize local results
Results results = new Results();
results.win = results.ties = results.count = 0;
// Loop through all possible boards and tally the results
foreach (
ulong boardmask in Hand.Hands(board, dead | opp | pocket, 5))
{
uint playerHandval = Hand.Evaluate(pocket | boardmask, 7);
uint oppHandval = Hand.Evaluate(opp | boardmask, 7);
if (playerHandval > oppHandval)
results.win++;
else if (playerHandval == oppHandval)
results.ties++;
results.count++;
}
// Return tally
return results;
}
// Converts a hand iteration specification into an array of hands.
static ulong [] HandList(ulong shared, ulong dead, int ncards)
{
List result = new List();
foreach (ulong mask in Hand.Hands(shared, dead, ncards))
{
result.Add(mask);
}
return result.ToArray();
}
static void Main(string[] args)
{
// This code calculates the probablity of As Ks winning against
// another random hand.
ulong pocketmask = Hand.ParseHand("As Ks"); // Hole hand
ulong board = Hand.ParseHand(""); // No board cards yet
long wins = 0, ties = 0, count = 0;
// Iterate through all possible opponent hole cards
ulong [] opphands = HandList(0UL, board | pocketmask, 2);
// Create Array of Opponent Hands
// Create delegate
CalculateOddsDelegate d =
new CalculateOddsDelegate(CalculateOdds);
// Create results array
IAsyncResult[] results = new IAsyncResult[opphands.Length];
// start time
double start = Hand.CurrentTime;
// Put calculation requests into the threadpool
for (int i = 0; i < opphands.Length; i++)
{
results[i] = d.BeginInvoke(
pocketmask, opphands[i], 0UL, 0UL, null, null);
}
// Collect results once the threads have completed
for (int i = 0; i < opphands.Length; i++)
{
Results r = d.EndInvoke(results[i]);
wins += r.win;
ties += r.ties;
count += r.count;
}
// Prints: Win 67.0446323092352%
Console.WriteLine("Win {0}%, Elapsed Time {1}",
(((double)wins) + ((double)ties) / 2.0) / (
(double)count) * 100.0,
Hand.CurrentTime-start);
}
}
}
演示程序(Demo programs)
我在可下载项目中包含了几个演示程序和示例.这是每个演示应用程序的快速摘要:(I’ve included several demo programs and examples in the downloadable project. This is a quick summary of each of the demo applications:)
基准测试(Benchmark)
基准程序测试手动评估器几个方面的响应能力.以下是基准测试选择的列表:(The benchmark program tests the responsiveness of several aspects of the hand evaluator. Here is a list of the benchmark choices:)
Evaluate()
-尝试仅测量9种手型中每种类型的评估速度.(- Attempts to measure just the evaluation speed for each of the 9 hand types.)EvaluateType()
-尝试测量手型评估方法.此方法不返回完整的手牌值,而只是返回手牌类型.该方法比全手评估更快.(- Attempts to measure the hand type evaluation method. This method doesn’t return a complete hand value, but just returns the hand type. This method is faster than full hand evaluation.)- 内联迭代(Inline Iterations)-使用手动编码的迭代器而不是手来测量多只手的迭代(- Measures iteration of multiple hands using hand-coded iterators rather than)
IEnumerable
.(.) - C#迭代(C# Iterations)-使用测量多手的迭代(- Measures iteration of multiple hands using)
IEnumerable
C#迭代器.这种方法比较慢,但是更容易理解.(C# iterators. This method is slower, but more understandable.) - 评估/迭代(Evaluate/Iterate)-测量C#迭代和(- Measures both C# Iterations and)
Evaluate()
.(.) - 线程池评估/迭代(Thread Pool Evaluate/Iterate)-测量C#迭代和(- Measures C# Iterations and)
Evaluate()
但是这样做的方式最多要利用16个内核.当跨内核使用时,可以用来查看"评估/迭代"的相对改进.(but does it in a way that utilized up to 16 cores. This can be used to see the relative improvement of Evaluate/Iterate when split across cores.)
多赔率(Multi-Odds)
此应用程序类似于手赔率,但允许选择随机对手的数量.此应用程序不允许将Pocket Query Language用作Pocket Hand和Opponent Hand输入的参数.这是为未来而付出的努力.(This application is similar to Hand Odds, but allows the number of random opponents to be selected. This application does not allow the Pocket Query Language to be used as arguments to the Pocket Hand and Opponent Hand input. That is an effort deferred for the future.)
致谢(Acknowledgements)
- Wesley Tansey-对于确定不同输出变化的功能提供了很多帮助.(Wesley Tansey - For a lot of help with functions determining different variations of outs.)
- 马特
贝克(Matt Baker)-有关讨论和提供(*Matt Baker - For many discussions on outs and for providing the*)
DiscountedOuts` 功能.(functions.) - Scott Turner-用于使用增强功能并提供反馈.(Scott Turner - For using and providing feedback on enhancements.)
- 扑克评估(poker-eval) -我评估引擎的核心.(- The core to my evaluation engine.)
- ZedGraph(ZedGraph) -我在几个用图形表示结果的示例中使用了ZedGraph.(- I’ve used ZedGraph in several of the examples that graph results.)
- 马尔科姆`克劳(Malcolm Crowe) -我用于Pocket Query Language的C#的lexer生成器/解析器生成器工具的作者.(- Author of the lexer generator/parser generator tools for C# that I used for the Pocket Query Language.)
发牌(Licensing)
此代码使用LGPL许可.有关更多信息,请参见源中的注释.我使用此许可证,因为它是扑克评估代码所引用的许可证,我将其用作我的核心评估引擎.(This code is licensed using LGPL. See the comments in the source for more information. I use this license because it is the license referenced by the poker-eval code, which I use as my core evaluation engine.)
免责声明(Disclaimer)
我很容易花了6个月的时间来编辑和调整代码和示例.我决定在此上花足够的时间,并且拥有大量可用的功能.因此,这是我当前的代码,疣和所有代码.(I could easily have spent another 6 months editing and tweaking the code and examples. I decided that I had spent enough time on this and had a “critical mass” of features available. So, here is my current code, warts and all.) 就此而言,我并没有声称自己是一名出色的扑克玩家,甚至不是一名优秀的扑克玩家.换个说法:可以做的人,不能编码的人.我不建议您在未经独立验证的情况下接受我可能在本文中提供(或暗示提供)的任何扑克建议.(I don’t claim to be a great poker player or even a good one, for that matter. To paraphrase: those who can do, those who can’t code. I don’t recommend taking any poker advice I may have given (or implied to have given) in this article without independent verification.) 我也想鼓励反馈.我敢肯定,扑克程序员似乎有些秘密.从过去一年左右的反馈中,我学到了很多东西.请继续.(I’d also like to encourage feedback. Poker programmers appear to be a somewhat secretive lot, for good reason I’m sure. I’ve learned a lot from the feedback I’ve been given over the last year or so. Please keep it coming.)
历史(History)
2007年5月首次发布(First released May 2007)
许可
本文以及所有相关的源代码和文件均已获得The Code Project Open License (CPOL)的许可。
C# Windows .NET .NET2.0 Visual-Studio Dev 新闻 翻译