1

I'm developing a poker game which works out what hand you have made given the cards dealt out. I'm currently stuck on the logic for the straight (5 cards in an incremental sequence e.g. 3,4,5,6,7). The Card objects I'm using have a int property which represents its value (ace is 14 by default).

Here's what I have so far:

private static bool CheckForStraight()
{
        List<Card> tmpCards = new List<Card>(_cards); //local copy of the cards
        if (tmpCards.Count < 5) //need atleast 5 cards to make a straight
            return false;

        tmpCards = tmpCards.DistinctBy(v => v.CardValue).ToList(); //remove duplicate values
        tmpCards = tmpCards.OrderBy(x => x.CardValue).ToList(); //order list

        int count = 0;

        if (tmpCards.Zip(tmpCards.Skip(1), (a, b) => (a.CardValue + 1) == b.CardValue).Any(x => x))
        {
            count++;
        }
        else
        {
            count = 0;
        }
        return false;
}

When this code is run, the linq expression will check if any of the card values in the list are in sequence... so if the list contains cards with values 2,3,5,8,11 it would +1 to count as 2 and 3 are sequential. So count is always either going to be 0 or 1 which is no use to me. Ideally I'd want count to be 5 if there are five cards in sequence. Then if count was equal to 5, I could go on and find the cards that make the straight.

(Would be even better if a linq expression could determine which 5 cards were in sequence, not sure if that is possible in one expression mind).

My question: How can my current linq expression be modified to get the result I need? Or can I be pointed in the right direction if I'm going about this the wrong way, thanks in advance.

rejy11
  • 742
  • 2
  • 12
  • 25
  • 1
    what's wrong with simple `for` loop over sorted array, rather than using LINQ. ? It looks like code would be much more clear in your case. – Tigran Mar 01 '17 at 14:27
  • Also http://stackoverflow.com/q/20469416/579895 – Pikoh Mar 01 '17 at 14:30
  • For 5 card poker this works : List input = new List() { 1, 3, 5, 6, 7 }; Boolean straight = (input.Distinct().Count() == 5) && (input.Max() - input.Min() == 4); – jdweng Mar 01 '17 at 14:32
  • Found better solution see edit above – jdweng Mar 01 '17 at 14:35

2 Answers2

2

You're close - just check each card with the card 4 places after it and see if the difference is 4.

private static bool CheckForStraight()
{
    List<Card> tmpCards = new List<Card>(_cards); //local copy of the cards
    if (tmpCards.Count < 5) //need atleast 5 cards to make a straight
        return false;

    tmpCards = tmpCards.DistinctBy(v => v.CardValue).ToList(); //remove duplicate values
    tmpCards = tmpCards.OrderBy(x => x.CardValue).ToList(); //order list

    return tmpCards
        .Zip(tmpCards.Skip(4), (a, b) => (a.CardValue + 4) == b.CardValue)
        .Any(x => x);
}
Rawling
  • 49,248
  • 7
  • 89
  • 127
0

You´re on a good track, now simply add a loop:

private static bool CheckForStraight()
{
    List<Card> tmpCards = _cards.DistinctBy(v => v.CardValue).OrderBy(v => v.CardValue).ToList();
    if(tmpCards.Count < 5) return false;

    int count = 0;

    for(int i = 1; i < tmpCards.Count; i++)
    {
        if(tmpCards[i] != tmpCards[i - 1] + 1 && count < 4) return false;
        count++;
    }
    return count >= 5;
}
MakePeaceGreatAgain
  • 35,491
  • 6
  • 60
  • 111
  • Again, don't see much reason in using LINQ here. 2 `ToList()` calls => 2 `List` from one, where it's enough simply iterate over already present and *ordered* collection to find clusters of consecutive numbers. – Tigran Mar 01 '17 at 14:32
  • @AdamHouldsworth I can´t see how it´ll return false on `1, 3, 2, 4, 5`, do you have another test-case? – MakePeaceGreatAgain Mar 01 '17 at 14:42
  • @HimBromBeere Ah sorry, you're right. The check I was referring to is actually baked into the `if` at the end `&& count < 4`. Apologies. – Adam Houldsworth Mar 02 '17 at 07:45