我已经写了一个德州扑克的均衡器作为一个爱好项目。它的功能是正确的,但还有一件事我不太满意:
在模拟手牌的整个过程中,评估手牌的过程约占用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;
}
这个递归方法返回所有可能的五张牌中的最高点数。这个方法由最终的公共方法调用:
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张牌的值缓存到哈希表中,然后只需查找它。但如果我没错的话,它将不得不存储超过133,784,560个32位整数值,约为500MB。
有什么好的哈希函数可以将每个可能的组合分配给一个数组索引吗?
在此创建了一个新问题:Hashfunction to map combinations of 5 to 7 cards
更新: 有关已接受答案的进一步改进,请参见: Efficient way to randomly select set bit