c# - IComparable 和 OrderBy。尝试用 C# 对扑克牌进行排序

标签 c# poker icomparer

我正在尝试创建一个简单的程序来分析扑克牌。给定 n 手牌/玩家和公共(public)牌(德州扑克),我想确定获胜者。然而,当我有两个确切的结果时,我的测试失败了 - 它只返回一个获胜者。即,双方玩家的牌局结果均包含 J J 9 9 K,但我的获胜者列表中包含一个。

我在这里发帖有几个原因。显然,首先这里有什么明显的错误吗?这是实现排序的好方法吗(我看不出分开排序的理由),是否有更好的方法以及为什么?

我有一个 JudgeWinners 方法,它对玩家的 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
}

这是 HandRanking 枚举上的 GetGrouping 扩展。它用于在比较值时帮助迭代卡片:

    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 实现,我错了吗?

最佳答案

IComparable提供的比较(无论如何,您应该使用通用版本 IComparable<T>)仅通过接口(interface)方法 int CompareTo(IComparable other) 来表示其结果是

  • 0 if the current object is greater than other

  • < 0 如果当前对象小于 other
  • = 0 表示相等

重载的比较运算符对于依赖 IComparable 的任何代码都无关紧要。 .

关于c# - IComparable 和 OrderBy。尝试用 C# 对扑克牌进行排序,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/3303945/

相关文章:

c# - 动态添加点击事件

c# - 从类型名称转换为类型作为字符串

c# - 如何在 C# 中读取已编译的资源 (.res) 文件?

c# - 填充扑克 jar

c# - LINQ orderby 与 IComparer

C# 使用 IComparer 对 x 列进行排序

c# - 在 C# 中将 List<string> 转换为 DataRow

java - 实现动态奖励制度

java - 解释一下代码

c# - 为什么 IComparer 要求您定义 IComparer.Compare(Object x, Object y) 而不仅仅是 Compare(Object x, Object y)?