IComparable 和 OrderBy。尝试用 C# 对扑克牌进行排序
我正在尝试创建一个简单的程序来分析扑克牌。给定 n 手牌/玩家和公共牌(德州扑克),我想确定获胜者。然而,当我有两个确切的结果时,我的测试失败了 - 它只返回一个获胜者。即,双方玩家的牌局结果都包含 JJ 9 9 K,但我的获胜者列表中包含一个。
我在这里发帖有几个原因。显然,首先这里有什么明显的错误吗?这是实现排序的好方法吗(我看不出分开排序的理由),是否有更好的方法以及为什么?
我有一个 DefineWinners 方法,它对玩家的 HandResult 执行命令:
var ordered = _players.OrderByDescending(player => player.Result);
var bestHand = ordered.First();
var winners = ordered.Where(s => s.Result == bestHand.Result).ToList();
这是我的手牌结果类:
public class HandResult : IComparable<HandResult>
{
public Hand WholeCards { get; set; }
public HandRanking HandRank { get; set; }
public IEnumerable<Card> CommunityCards { get; set; }
public IEnumerable<Card> UsedCards { get; set; }
public static bool operator !=(HandResult a, HandResult b)
{
if (a == null)
return b != null;
if (b == null)
return true;
if (a.HandRank != b.HandRank)
return true;
//Compare Used Cards
var aCards = a.UsedCards.Select(s => s.GetCardValue()).ToList();
var bCards = b.UsedCards.Select(s => s.GetCardValue()).ToList();
var cardGroup = a.HandRank.GetGrouping();
for (int i = 0; i < 5; i += cardGroup[i])
{
if (aCards[i] != bCards[i])
return true;
}
return false;
}
public static bool operator ==(HandResult a, HandResult b)
{
if ((object)a == null)
return (object)b == null;
if ((object)b == null)
return false;
if (a.HandRank != b.HandRank)
return false;
var aCards = a.UsedCards.Select(s => s.GetCardValue()).ToList();
var bCards = b.UsedCards.Select(s => s.GetCardValue()).ToList();
var cardGroup = a.HandRank.GetGrouping();
for (int i = 0; i < 5; i += cardGroup[i])
{
if (aCards[i] != bCards[i])
{
return false;
}
}
return true;
}
public static bool operator >(HandResult a, HandResult b)
{
if ((object)a == null)
return (object)b != null;
if ((object)b == null)
return false;
if ((object)a == (object)b)
return false;
if (a.HandRank != b.HandRank)
return a.HandRank > b.HandRank;
if (a == b)
return false;
var aCards = a.UsedCards.Select(s => s.GetCardValue()).ToList();
var bCards = b.UsedCards.Select(s => s.GetCardValue()).ToList();
var cardGroup = a.HandRank.GetGrouping();
for (int i = 0; i < 5; i += cardGroup[i])
{
if (aCards[i] != bCards[i])
{
return aCards[i] > bCards[i];
}
}
return false;
}
public static bool operator <(HandResult a, HandResult b)
{
if ((object)a == null)
return (object)b == null;
if ((object)b == null)
return true;
if ((object)a == (object)b)
return false;
if (a.HandRank != b.HandRank)
return a.HandRank < b.HandRank;
var aCards = a.UsedCards.Select(s => s.GetCardValue()).ToList();
var bCards = b.UsedCards.Select(s => s.GetCardValue()).ToList();
var cardGroup = a.HandRank.GetGrouping();
for (int i = 0; i < 5; i += cardGroup[i])
{
if (aCards[i] != bCards[i])
return aCards[i] < bCards[i];
}
return false;
}
#region IComparable<HandResult> Members
public int CompareTo(HandResult other)
{
if (this == null)
return other == null ? 0 : -1;
if (other == null)
return 1;
if (this == other)
return 0;
if (this > other)
return 1;
return -1;
}
#endregion
public override bool Equals(object obj)
{
return this == (HandResult)obj;
}
public override int GetHashCode()
{
var result = 0;
result = (result * 397) ^ (int)this.HandRank;
foreach (var card in this.UsedCards)
{
result = (result * 397) ^ card.GetHashCode();
}
return result;
}
}
GetCardResult 方法仅返回牌的整数表示形式,即 1 到 14。 这是 HandRanking 枚举:
public enum HandRanking
{
HighCard,
Pair,
TwoPair,
ThreeOfAKind,
Straight,
Flush,
FullHouse,
FourOfAKind,
StraightFlush,
RoyalFlush
}
这是 GetGrouping HandRanking 枚举的扩展。它用于在比较值时帮助迭代卡片:
internal static int[] GetGrouping(this HandRanking rank)
{
switch (rank)
{
case HandRanking.Pair:
return new int[] { 2, 0, 1, 1, 1 };
case HandRanking.TwoPair:
return new int[] { 2, 0, 2, 0, 1 };
case HandRanking.ThreeOfAKind:
return new int[] { 3, 0, 0, 1, 1 };
case HandRanking.FullHouse:
return new int[] { 3, 0, 0, 2, 0 };
case HandRanking.FourOfAKind:
return new int[] { 4, 0, 0, 0, 1 };
default:
return new int[] { 1, 1, 1, 1, 1 };
}
}
非常感谢您的帮助。
编辑:我对 CompareTo_Equal、CompareTo_LessThan 和 CompareTo_GreaterThan(使用我的运算符重载)的测试成功,结果分别为:0、-1 和 1。我相信这是我的 Linq.OrderByDescending 实现的问题。我认为这只是使用 CompareTo 实现,我错了吗?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
IComparable
提供的比较(无论如何,您应该使用通用版本IComparable
)仅通过接口方法int CompareTo(IComparable other)
来表示code> 其结果是0如果当前对象小于
other
重载的比较运算符对于依赖于
IComparable
的任何代码都无关紧要。The comparison provided by
IComparable
(you should use the generic versionIComparable<T>
anyway) is solely represented through the interface methodint CompareTo(IComparable other)
whose result isother
The overloaded comparison operators don't matter for any code that relies on
IComparable
.您试图通过选择结果等于最佳牌局结果的人来选择获胜者,但只有当牌局完全相同时才是正确的(我想,我很难看到整体在不知道 cardGroup[i] 中到底是什么的
您确定您期望相同的牌实际上是相同的(甚至在同一花色中)?
情况下, 例如,!= 可以实现为 !(==)(反转调用 == 运算符的结果,而不是重新实现整个条件集 - 现在,如果您更改确定 Equals 的方式,我必须复制这些更改!=)
You are trying to select the Winners by choosing those with Results equal to the best hand's Result, but that is only true when the hands are exactly the same (I think, I'm having trouble seeing the whole picture without knowing what exactly is in cardGroup[i].
Are you certain the hands you expect to be identical are actually identical (as in same suit even)?
And then I would also suggest that you implement most of your operator overloads in terms of other operators. For example, != could be implemented as !(==) (inverting the result of calling the == operator, rather than reimplementing the whole set of conditionals - right now, if you change the way Equals is determined you'll have to duplicate those changes in !=)