- html - 出于某种原因,IE8 对我的 Sass 文件中继承的 html5 CSS 不友好?
- JMeter 在响应断言中使用 span 标签的问题
- html - 在 :hover and :active? 上具有不同效果的 CSS 动画
- html - 相对于居中的 html 内容固定的 CSS 重复背景?
我已经为 Hold'em Poker 编写了一个平衡器作为一个业余项目。它工作正常,但还有一件事我不满意:在整个模拟手的过程中,评估手的过程大约占用了35%的时间。与迭代和克隆大型数组等其他必须完成的工作相比,这对我来说似乎非常重要。
任何关于如何获得更高性能的想法都会很棒。
这是代码:
private static int getHandvalue(List<Card> sCards)
{
// --- Auf Straight / Straight Flush prüfen ---
if ((sCards[0].Value - 1 == sCards[1].Value) && (sCards[1].Value - 1 == sCards[2].Value) && (sCards[2].Value - 1 == sCards[3].Value) && (sCards[3].Value - 1 == sCards[4].Value))
{
if ((sCards[0].Color == sCards[1].Color) && (sCards[1].Color == sCards[2].Color) && (sCards[2].Color == sCards[3].Color) && (sCards[3].Color == sCards[4].Color))
return (8 << 20) + (byte)sCards[0].Value; // Höchste Karte Kicker
else
return (4 << 20) + (byte)sCards[0].Value; // Höchste Karte Kicker (Straight)
}
// --- Auf Wheel / Wheel Flush prüfen ---
if ((sCards[4].Value == Card.CardValue.Two) && (sCards[3].Value == Card.CardValue.Three) && (sCards[2].Value == Card.CardValue.Four) && (sCards[1].Value == Card.CardValue.Five) && (sCards[0].Value == Card.CardValue.Ace))
{
if ((sCards[0].Color == sCards[1].Color) && (sCards[1].Color == sCards[2].Color) && (sCards[2].Color == sCards[3].Color) && (sCards[3].Color == sCards[4].Color))
return(8 << 20) + (byte)sCards[1].Value; // Zweithöchste Karte Kicker
else
return(4 << 20) + (byte)sCards[1].Value; // Zweithöchste Karte Kicker (Straight)
}
// --- Auf Flush prüfen ---
if ((sCards[0].Color == sCards[1].Color) && (sCards[1].Color == sCards[2].Color) && (sCards[2].Color == sCards[3].Color) && (sCards[3].Color == sCards[4].Color))
return (5 << 20) + ((byte)sCards[0].Value << 16) + ((byte)sCards[1].Value << 12) + ((byte)sCards[2].Value << 8) + ((byte)sCards[3].Value << 4) + (byte)sCards[4].Value;
// --- Auf Vierling prüfen ---
if (((sCards[0].Value == sCards[1].Value) && (sCards[1].Value == sCards[2].Value) && (sCards[2].Value == sCards[3].Value)) || ((sCards[1].Value == sCards[2].Value) && (sCards[2].Value == sCards[3].Value) && (sCards[3].Value == sCards[4].Value)))
return (7 << 20) + (byte)sCards[1].Value; // Wert des Vierlings (keine Kicker, da nicht mehrere Spieler den selben Vierling haben können)
// --- Auf Full-House / Drilling prüfen ---
// Drilling vorne
if ((sCards[0].Value == sCards[1].Value) && (sCards[1].Value == sCards[2].Value))
{
// Full House
if (sCards[3].Value == sCards[4].Value)
return (6 << 20) + ((byte)sCards[0].Value << 4) + (byte)sCards[3].Value; // Drilling (höher bewerten)
// Drilling
return (3 << 20) + ((byte)sCards[0].Value << 8) + ((byte)sCards[3].Value << 4) + (byte)sCards[4].Value; // Drilling + Kicker 1 + Kicker 2
}
// Drilling hinten
if ((sCards[2].Value == sCards[3].Value) && (sCards[3].Value == sCards[4].Value))
{
// Full House
if (sCards[0].Value == sCards[1].Value)
return (6 << 20) + ((byte)sCards[2].Value << 4) + (byte)sCards[0].Value; // Drilling (höher bewerten)
// Drilling
return (3 << 20) + ((byte)sCards[2].Value << 8) + ((byte)sCards[0].Value << 4) + (byte)sCards[1].Value; // Drilling + Kicker 1 + Kicker 2
}
// Drilling mitte
if ((sCards[1].Value == sCards[2].Value) && (sCards[2].Value == sCards[3].Value))
return (3 << 20) + ((byte)sCards[1].Value << 8) + ((byte)sCards[0].Value << 4) + (byte)sCards[4].Value; // Drilling + Kicker 1 + Kicker 2
// --- Auf Zwei Paare prüfen ---
// Erstes Paar vorne, zweites Paar mitte
if ((sCards[0].Value == sCards[1].Value) && (sCards[2].Value == sCards[3].Value))
return (2 << 20) + ((byte)sCards[0].Value << 8) + ((byte)sCards[2].Value << 4) + (byte)sCards[4].Value; // Erstes Paar + Zweites Paar + Kicker
// Erstes Paar vorne, zweites Paar hinten
if ((sCards[0].Value == sCards[1].Value) && (sCards[3].Value == sCards[4].Value))
return (2 << 20) + ((byte)sCards[0].Value << 8) + ((byte)sCards[3].Value << 4) + (byte)sCards[2].Value; // Erstes Paar + Zweites Paar + Kicker
// Erstes Paar mitte, zweites Paar hinten
if ((sCards[1].Value == sCards[2].Value) && (sCards[3].Value == sCards[4].Value))
return (2 << 20) + ((byte)sCards[1].Value << 8) + ((byte)sCards[3].Value << 4) + (byte)sCards[0].Value; // Erstes Paar + Zweites Paar + Kicker
// --- Auf Paar prüfen ---
// Paar vorne
if (sCards[0].Value == sCards[1].Value)
return (1 << 20) + ((byte)sCards[0].Value << 12) + ((byte)sCards[2].Value << 8) + ((byte)sCards[3].Value << 4) + (byte)sCards[4].Value; // Paar + Kicker 1 + Kicker 2 + Kicker 3
// Paar mitte-vorne
if (sCards[1].Value == sCards[2].Value)
return (1 << 20) + ((byte)sCards[1].Value << 12) + ((byte)sCards[0].Value << 8) + ((byte)sCards[3].Value << 4) + (byte)sCards[4].Value; // Paar + Kicker 1 + Kicker 2 + Kicker 3
// Paar mitte-hinten
if (sCards[2].Value == sCards[3].Value)
return (1 << 20) + ((byte)sCards[2].Value << 12) + ((byte)sCards[0].Value << 8) + ((byte)sCards[1].Value << 4) + (byte)sCards[4].Value; // Paar + Kicker 1 + Kicker 2 + Kicker 3
// Paar hinten
if (sCards[3].Value == sCards[4].Value)
return (1 << 20) + ((byte)sCards[3].Value << 12) + ((byte)sCards[0].Value << 8) + ((byte)sCards[1].Value << 4) + (byte)sCards[2].Value; // Paar + Kicker 1 + Kicker 2 + Kicker 3
// --- High Card bleibt übrig ---
return ((byte)sCards[0].Value << 16) + ((byte)sCards[1].Value << 12) + ((byte)sCards[2].Value << 8) + ((byte)sCards[3].Value << 4) + (byte)sCards[4].Value; // High Card + Kicker 1 + Kicker 2 + Kicker 3 + Kicker 4
}
此方法返回扑克中每个排序的 5 张牌组合的精确值。它被另一种方法调用:
private static int getHandvalueList(List<Card> sCards)
{
int count = sCards.Count;
if (count == 5) return getHandvalue(sCards);
int HighestValue = 0;
Card missingOne;
int tempValue;
for (int i = 0; i < count - 1; i++)
{
missingOne = sCards[i];
sCards.RemoveAt(i);
tempValue = getHandvalueList(sCards);
if (tempValue > HighestValue) HighestValue = tempValue;
sCards.Insert(i, missingOne);
}
missingOne = sCards[count - 1];
sCards.RemoveAt(count - 1);
tempValue = getHandvalueList(sCards);
if (tempValue > HighestValue) HighestValue = tempValue;
sCards.Add(missingOne);
return HighestValue;
}
此递归方法返回所有可能的 5 张牌组合的最大值。这个方法被最终的公共(public)方法调用:
public static int GetHandvalue(List<Card> sCards)
{
if (sCards.Count < 5) return 0;
sCards.Sort(new ICardComparer());
return getHandvalueList(sCards);
}
最多可交付 7 张卡片。
更新
到目前为止:每次调用 public 函数时有 7 张牌(大多数情况下都是这种情况),它必须调用手牌评估方法 21 次(每种可能的 5 张牌组合一次) ).
我考虑过将每组可能的 5 到 7 张卡片的值缓存在哈希表中,然后查找它。但如果我没记错的话,它必须存储超过 133.784.560 个 32 位整数值,大约 500MB。
将所有可能的组合分配给一个数组索引的好散列函数是什么?
为此创建了一个新问题:Hashfunction to map combinations of 5 to 7 cards
更新:有关已接受答案的进一步改进,请查看: Efficient way to randomly select set bit
最佳答案
我过去写过一个相当快的扑克手评估器。我使用了与您的完全不同的表示,我认为这是性能的关键。
我用一个 64 位整数表示了一手最多 7 张牌;位 4 是红心二,位 5 是方 block 二,六是黑桃二,七是梅花二,八是红心三,依此类推。
您首先检查同花顺;形成 hh = h & (h>>4) & (h>>8) & (h>>12) & (h>>16)
。如果 hh
不为零,那么您的同花顺从高位开始。
然后检查四种类型;形成 hh = h & (h>>1) & (h>>2) & (h>>3) & 0x1111...1
。如果 hh
是非零的,那么您就得到了一个 4。
在这一点上,您想要找出哪些行列具有同类三项,哪些行列具有对子。与同类四的情况类似,形成位掩码告诉您哪些等级至少有三张牌,哪些等级至少有两张牌,哪些等级至少有一张牌。 (考虑对手牌的每个半字节进行排序。)如果 popcount(threes) + popcount(twos) >= 2
,您可以找到满屋子。
平直条件很容易检查。而且,在这一点上,同类三项、两对和配对条件也是如此。
这种方法的一个很好的特点是它可以直接返回一个代表手牌等级的整数,将手牌比较减少到一堆位摆弄以预处理手牌然后一个整数比较。 (正如您所做的那样,现在我再次查看了您的帖子。)如果编写得当,它还可以直接对 7 张牌进行操作,从而无需迭代手牌中 5 张牌的所有子集。
关于c# - 优化 Poker-Monte-Carlo-Simulation 的手牌评估算法,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/22412698/
滑动窗口限流 滑动窗口限流是一种常用的限流算法,通过维护一个固定大小的窗口,在单位时间内允许通过的请求次数不超过设定的阈值。具体来说,滑动窗口限流算法通常包括以下几个步骤: 初始化:设置窗口
表达式求值:一个只有+,-,*,/的表达式,没有括号 一种神奇的做法:使用数组存储数字和运算符,先把优先级别高的乘法和除法计算出来,再计算加法和减法 int GetVal(string s){
【算法】前缀和 题目 先来看一道题目:(前缀和模板题) 已知一个数组A[],现在想要求出其中一些数字的和。 输入格式: 先是整数N,M,表示一共有N个数字,有M组询问 接下来有N个数,表示A[1]..
1.前序遍历 根-左-右的顺序遍历,可以使用递归 void preOrder(Node *u){ if(u==NULL)return; printf("%d ",u->val);
先看题目 物品不能分隔,必须全部取走或者留下,因此称为01背包 (只有不取和取两种状态) 看第一个样例 我们需要把4个物品装入一个容量为10的背包 我们可以简化问题,从小到大入手分析 weightva
我最近在一次采访中遇到了这个问题: 给出以下矩阵: [[ R R R R R R], [ R B B B R R], [ B R R R B B], [ R B R R R R]] 找出是否有任
我正在尝试通过 C++ 算法从我的 outlook 帐户发送一封电子邮件,该帐户已经打开并记录,但真的不知道从哪里开始(对于 outlook-c++ 集成),谷歌也没有帮我这么多。任何提示将不胜感激。
我发现自己像这样编写了一个手工制作的 while 循环: std::list foo; // In my case, map, but list is simpler auto currentPoin
我有用于检测正方形的 opencv 代码。现在我想在检测正方形后,代码运行另一个命令。 代码如下: #include "cv.h" #include "cxcore.h" #include "high
我正在尝试模拟一个 matlab 函数“imfill”来填充二进制图像(1 和 0 的二维矩阵)。 我想在矩阵中指定一个起点,并像 imfill 的 4 连接版本那样进行洪水填充。 这是否已经存在于
我正在阅读 Robert Sedgewick 的《C++ 算法》。 Basic recurrences section it was mentioned as 这种循环出现在循环输入以消除一个项目的递
我正在思考如何在我的日历中生成代表任务的数据结构(仅供我个人使用)。我有来自 DBMS 的按日期排序的任务记录,如下所示: 买牛奶(18.1.2013) 任务日期 (2013-01-15) 任务标签(
输入一个未排序的整数数组A[1..n]只有 O(d) :(d int) 计算每个元素在单次迭代中出现在列表中的次数。 map 是balanced Binary Search Tree基于确保 O(nl
我遇到了一个问题,但我仍然不知道如何解决。我想出了如何用蛮力的方式来做到这一点,但是当有成千上万的元素时它就不起作用了。 Problem: Say you are given the followin
我有一个列表列表。 L1= [[...][...][.......].......]如果我在展平列表后获取所有元素并从中提取唯一值,那么我会得到一个列表 L2。我有另一个列表 L3,它是 L2 的某个
我们得到二维矩阵数组(假设长度为 i 和宽度为 j)和整数 k我们必须找到包含这个或更大总和的最小矩形的大小F.e k=7 4 1 1 1 1 1 4 4 Anwser是2,因为4+4=8 >= 7,
我实行 3 类倒制,每周换类。顺序为早类 (m)、晚类 (n) 和下午类 (a)。我固定的订单,即它永远不会改变,即使那个星期不工作也是如此。 我创建了一个函数来获取 ISO 周数。当我给它一个日期时
假设我们有一个输入,它是一个元素列表: {a, b, c, d, e, f} 还有不同的集合,可能包含这些元素的任意组合,也可能包含不在输入列表中的其他元素: A:{e,f} B:{d,f,a} C:
我有一个子集算法,可以找到给定集合的所有子集。原始集合的问题在于它是一个不断增长的集合,如果向其中添加元素,我需要再次重新计算它的子集。 有没有一种方法可以优化子集算法,该算法可以从最后一个计算点重新
我有一个包含 100 万个符号及其预期频率的表格。 我想通过为每个符号分配一个唯一(且前缀唯一)的可变长度位串来压缩这些符号的序列,然后将它们连接在一起以表示序列。 我想分配这些位串,以使编码序列的预
我是一名优秀的程序员,十分优秀!