c# check for a poker straight

2019-02-21 17:52发布

I am trying to write a poker hand evaluation method in c#. I have managed to do this for every poker hand using linq except a straight. For those that don't play a straight is made up of 5 cards with increments of 1 for each card. Ace can be high or low.

I have created an object called card which has a suit, rank and value (J = 11, Q =12 etc..). My method will be passed a list of this object containing 7 cards (hole cards and the board.)

Another thing to bear in mind is that a straight can only be made if the player has a 5 or 10.

See below my methods for other poker hands and please let me know if you have an idea for the straight method. Pseudo code would be fine also.


public bool CheckPair(List<Card> cards)
{
    //see if exactly 2 cards card the same rank.
    return cards.GroupBy(card => card.Rank).Count(group => group.Count() == 2) == 1;
}

public bool CheckTwoPair(List<Card> cards)
{
    //see if there are 2 lots of exactly 2 cards card the same rank.
    return cards.GroupBy(card => card.Rank).Count(group => group.Count() >= 2) == 2;
}

public bool CheckTrips(List<Card> cards)
{
    //see if exactly 3 cards card the same rank.
    return cards.GroupBy(card => card.Rank).Any(group => group.Count() == 3);
}
public bool CheckStraight(List<Card> cards)
{
    // order by decending to see order
    var cardsInOrder = cards.OrderByDescending(a => a.Value).ToList();
    // check for ace as can be high and low
    if (cardsInOrder.First().Rank == "A")
    {
        // check if straight with ace has has 2 values
        bool highStraight = cards.Where(a => a.Rank == "K" || a.Rank == "Q" || a.Rank == "J" || a.Rank == "10").Count() == 4;
        bool lowStraight = cards.Where(a => a.Rank == "2" || a.Rank == "3" || a.Rank == "4" || a.Rank == "5").Count() == 4;
        // return true if straight with ace
        if (lowStraight == true || highStraight == true)
        {
            return true;
        }
    }
    else
    {
        // check for straight here
        return true;
    }
    // no straight if reached here.
    return false;

}

public bool CheckFlush(List<Card> cards)
{
    //see if 5 or more cards card the same rank.
    return cards.GroupBy(card => card.Suit).Count(group => group.Count() >= 5) == 1;
}

public bool CheckFullHouse(List<Card> cards)
{
    // check if trips and pair is true
    return CheckPair(cards) && CheckTrips(cards);
}
public bool CheckQuads(List<Card> cards)
{
    //see if exactly 4 cards card the same rank.
    return cards.GroupBy(card => card.Rank).Any(group => group.Count() == 4);
}

// need to check same 5 cards
public bool CheckStraightFlush(List<Card> cards)
{
    // check if flush and straight are true.
    return CheckFlush(cards) && CheckStraight(cards);
}

标签: c# poker
4条回答
家丑人穷心不美
2楼-- · 2019-02-21 18:29

I have made some small changes to Glubus answer. The code below does the job however you will have to check manually for a wheel (A,1,2,3,4,5) straight.

public bool CheckStraight(List<Card> cards)
    {
        //maybe check 5 and 10 here first for performance

        var ordered = cards.OrderByDescending(a => a.Value).ToList();
        for (var i = 0; i < ordered.Count - 4; i++)
        {
            var skipped = ordered.Skip(i);
            var possibleStraight = skipped.Take(5).ToList();
            if (IsStraight(possibleStraight))
            {
                return true;
            }
        }
        return false;
    }
public bool IsStraight(List<Card> cards)
{
    return cards.GroupBy(card => card.Value).Count() == cards.Count() && cards.Max(card => (int)card.Value) - cards.Min(card => (int)card.Value) == 4;
    }
查看更多
闹够了就滚
3楼-- · 2019-02-21 18:44

This might not be the best performing check, but I'd say it's very readable which is usually a good property.

Just grab 5 cards, skipping cards you've already seen every iteration and check for a straight for each sequence. An ordered sequence is a straight if it does not contain doubles and if the first and last cards difference is 5.

public bool CheckStraight(List<Card> cards)
{
     //maybe check 5 and 10 here first for performance

     var ordered = cards.OrderByDescending(a => a.Value).ToList();
     for(i = 0; i < ordered.Count - 5; i++) {
          var skipped = ordered.Skip(i);
          var possibleStraight = skipped.Take(5);
          if(IsStraight(possibleStraight)) {
               return true;
          }
     }
     return false;
}

public bool IsStraight(List<Card> fiveOrderedCards) {
     var doubles = cards.GroupBy(card => card.Rank).Count(group => group.Count() > 1);
     var inARow = cards[4] - cards[0] = 5; //Ace is 0

     return !doubles && inARow;
}
查看更多
贼婆χ
4楼-- · 2019-02-21 18:45

I cannot think about real one liner, since A can be 1 or 14, but this should be good:

int c = 5; // How many cards straight
bool Ais1 = cards.OrderBy(a => a.Value).Select((i,j) => i.Value-j).Distinct().Skip(1).Count() <= (cards.Count - c);
bool Ais14 = cards.OrderBy(a => (a.Value == 1 ? 14 : a.Value)).Select((i,j) => (i.Value == 1 ? 14 : i.Value)-j).Distinct().Skip(1).Count() <= (cards.Count - c);
return Ais1 || Ais14;

(Updated - thank you Janne, I've fixed the code)

查看更多
老娘就宠你
5楼-- · 2019-02-21 18:48

erm,

function bool IsStraight(IEnumerable<int> cards)
{
    var orderedCards = cards.OrderBy(n => n).ToList();
    var test = orderdCards.Zip(orderdCards.Skip(1), (a, b) => b - a);

    var count = 0;
    foreach(var n in test)
    {
        if (n == 1)
        {
            count++;
            if (count == 4)
            {
                return true;
            }
        }
        else
        {
            count = 0;
        }
    }

    return false;
}
查看更多
登录 后发表回答