c# – 优化Poker-Monte-Carlo-Simulation的手动评估算法
我为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 static int GetHandvalue(List<Card> sCards) { if (sCards.Count < 5) return 0; sCards.Sort(new ICardComparer()); return getHandvalueList(sCards); } 它最多可以发送7张卡. 更新 到目前为止:每次使用7张牌调用公共功能(大多数情况下就是这种情况),它必须将手动评估方法调用21次(每次可能的5张卡组合一次). 我想在哈希表中为每个可能的5到7张卡片缓存值,然后查看它. 什么可能是好的哈希函数将每个可能的组合分配给一个arrayindex? 创建了一个新问题:Hashfunction to map combinations of 5 to 7 cards 更新: 解决方法
我过去写过一个相当快速的扑克手评估员.我使用了与你不同的代表,我认为这是表现的关键.
我用64位整数表示最多7张牌的牌;第4位用于两颗心,第2位用于两颗钻石,6颗用于两个黑桃,7分用于两个球杆,8个用于三颗心,等等. 你先检查直冲;形式hh = h& (h>> 4)& (h>> 8)& (h>> 12)& (h取代;> 16).如果hh非零,则从高位开始有一个直接齐平. 然后检查四种类型;形式hh = h& (h>> 1)& (h>> 2)& (h>> 3)& 0x1111 … 1.如果……非零,那你就得到了四个人. 此时,您想要找出哪些排名有三种,哪些排名有哪些排名.类似于四种情况,形成位掩码,告诉你哪些排名至少有三张牌,哪些排名至少有两张牌,哪些排名至少有一张牌. (考虑对手的每个半字节进行排序.)如果popcount(threes)popcount(twos)> = 2,你可以找到一个完整的房子. 冲洗和直线条件很容易检查.而且,在这一点上,三种,两对和成对条件也是如此. 这种方法的一个很好的特点是它可以直接返回一个表示手的等级的整数,减少手比较到一堆比特摆动以预处理手然后进行单个整数比较. (正如你正在做的那样,现在我再次查看你的帖子.)如果写得正确,它也可以直接在7张牌上操作,无需迭代手中5张牌的所有子集. (编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |