IComparable и OrderBy.Попытка сортировать покерные руки с C # - PullRequest
2 голосов
/ 22 июля 2010

Я пытаюсь создать простую программу, которая анализирует покерные руки. Учитывая n рук / игроков и общие карты (Техасский Холдем), я бы хотел определить победителя (ей). Однако мой тест не пройден, когда у меня есть два точных результата - он возвращает только одного победителя. результат розыгрыша J J 9 9 K для обоих игроков, но мой список победителей содержит один.

Есть несколько причин, почему я публикую здесь. Очевидно, первое существо, есть ли что-то очевидное, что здесь не так? Является ли это хорошим подходом для реализации сортировки (я не вижу причины отделять сортировку), есть ли лучший подход и почему?

У меня есть метод DetermineWinners, который выполняет заказ на 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, я не прав?

Ответы [ 2 ]

3 голосов
/ 22 июля 2010

Сравнение, предоставляемое IComparable (в любом случае следует использовать универсальную версию IComparable<T>), представлено исключительно через метод интерфейса int CompareTo(IComparable other), чей результат

  • 0, если текущий объект больше other

  • <0, если текущий объект меньше <code>other
  • = 0 для равенства

Перегруженные операторы сравнения не имеют значения для любого кода, использующего IComparable.

0 голосов
/ 22 июля 2010

Вы пытаетесь выбрать победителей, выбрав тех, чьи результаты равны результату лучшей руки, но это верно только тогда, когда руки равны точно (думаю, у меня проблемы с просмотромвся картина, не зная, что именно находится в cardGroup [i].

Вы уверены, что руки, которые вы ожидаете, будут идентичны, на самом деле идентичны (как и в одной масти)?

также предполагает, что вы реализуете большинство перегрузок своих операторов в терминах других операторов. Например,! = может быть реализовано как! (==) (инвертируя результат вызова оператора ==, вместо того, чтобы переопределять весь набор условий- прямо сейчас, если вы измените способ определения Equals, вам придется продублировать эти изменения в! =)

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...