Search code examples
c#vb.netlinqpoker

Visual Basic evaluate a list of cards for a straight combination


I'm creating a Poker evaluater, but I'm having trouble figuring out how to check for "straight" combinations (I also need to know what cards made the combination).

I have a list of cards, so what I need to figure out is the following:

Does the list contain an ace or not?

If yes:

  • Create a new list where ace is high.
  • Create a new list where ace is low.
  • Run check on both lists and return whichever has the higher count of cards that are in a straight combination.

If No:

  • Run check on list and return the cards that are in a straight combination.

How to check for a straight combination:

Run through the list and check whether the current card's rank + 1 is equal to the previous card's rank.

Using this method we will run into an issue....

Take the following into consideration:

  1. King
  2. Queen
  3. Jack
  4. Three
  5. Two

The result would be:

  1. King = Nothing = False
  2. Queen = King = True
  3. Jack = Queen = True
  4. Three = Jack = False
  5. Two = Three = True

That result is no good, the result in that case should be: King, Queen, Jack.

I'm not sure how to put this into code in a smart way, or just in a way that would work. I have tried doing LINQ and I have tried using for loops.

Here's the card class that I have made:

Public Enum CardRank
    Two = 2
    Three = 3
    Four = 4
    Five = 5
    Six = 6
    Seven = 7
    Eight = 8
    Nine = 9
    Ten = 10
    Jack = 11
    Queen = 12
    King = 13
    Ace = 14
End Enum

Public Enum CardSuit
    Club = 1
    Diamond = 2
    Heart = 3
    Spade = 4
End Enum

Public Class Card
    Public Rank As CardRank
    Public Suit As CardSuit

#Region "Constructor"
    Sub New()

    End Sub

    Sub New(ByVal Rank As CardRank, ByVal Suit As CardSuit)
        Me.Rank = Rank
        Me.Suit = Suit
    End Sub
#End Region

    Public Overrides Function ToString() As String
        Return [Enum].GetName(GetType(CardRank), Rank) + " of " + [Enum].GetName(GetType(CardSuit), Suit)
    End Function
End Class

Copy this to quickly get started:

Dim Deck As New List(Of Card)
Dim Cards As List(Of Card) = New Card() {New Card(CardRank.King, CardSuit.Spade), New Card(CardRank.Queen, CardSuit.Heart), New Card(CardRank.Jack, CardSuit.Club), New Card(CardRank.Three, CardSuit.Spade), New Card(CardRank.Two, CardSuit.Diamond)}.ToList()

'Add deck
For Each Suit As CardSuit In [Enum].GetValues(GetType(CardSuit))
    For Each Rank As CardRank In [Enum].GetValues(GetType(CardRank))
        Deck.Add(New Card(Rank, Suit))
    Next
Next

For Each Card As Card In Cards
    Deck.Remove(Card)
Next

Maybe I'm going about this the wrong way?

EDIT: A straight is five cards of sequential rank. Note that in holdem, Aces can be high or low. EDIT: Here's how I list my cards atm. (Can be altered to fit other methods of course)

Dim tempList = Cards.GroupBy(Function(card) card.Rank).Reverse().OrderByDescending(Function(group) group.Count()).SelectMany(Function(group) group).ToList()

Solution

  • I want to thank everybody who offered their time and help, this was a problem that I had been struggling with for days!

    In the end I figured it out myself. My method of doing it covers every possibility, not just some, and it also returns the list of cards that created the combination.

    The base function:

        Private Function ReturnStraight(ByVal tempList As List(Of Card)) As List(Of Card)
        Dim cardslist As New List(Of List(Of Card)) 'Lists of lists of cards in sequential rank
        Dim temporaryList As New List(Of Card) 'Temporary list to add seqeuntial ranked cards to, to later add to the above list
        Dim previousCard As Card = tempList(0) 'Gotta start somewhere
    
        For i = 0 To tempList.Count - 1
            Dim Card As Card = tempList(i)
    
            If Card.Rank + 1 = previousCard.Rank Then 'If the queen + 1 equals king
                If temporaryList.Find(Function(c) c.Rank = previousCard.Rank) Is Nothing Then : temporaryList.Add(previousCard) : End If 'If it doesn't already contain the previous card, add it (we want the king, which we wouldn't get without this)
                temporaryList.Add(Card) 'Add the card (the queen)
    
                If i = tempList.Count - 1 Then 'We need this if because of certain scenarios, e.g. King, Queen, Jack, Three, Two - King, Queen, Jack would be added, but three and two would not because we would not enter the else below when Two + 1 = 3...
                    If temporaryList.Count > 0 Then : cardslist.Add(temporaryList) : End If 'If the list is not empty, add it to the list of list of cards
                    temporaryList = New List(Of Card) 'Assign it a new empty list of cards to elimate referencing
                End If
            Else 'If the sequential list breaks (goes from jack to 3), add the temporary list of cards to the list of list of cards
                If temporaryList.Count > 0 Then : cardslist.Add(temporaryList) : End If  'If the list is not empty, add it to the list of list of cards
                temporaryList = New List(Of Card) 'Assign it a new empty list of cards to elimate referencing
            End If
    
            previousCard = Card 'Assign the current card to the previousCard holder
        Next
    
        cardslist = cardslist.OrderByDescending(Function(list) list.Count()).ToList() 'We want to list them in descending order by the count of cards
    
        If Not cardslist.Count = 0 Then 'We have to check to see if the cardlist is empty or not, because if it is and we return it, we get an error.... 
            Return cardslist(0) 'Return the highest count card list
        End If
    
        Return tempList 'Function failed because there are not enough cards, so return the original list
    End Function
    

    How I am using it:

        Dim tempList = Cards.GroupBy(Function(card) card.Rank).OrderByDescending(Function(group) group.Count()).SelectMany(Function(group) group).ToList()
    
        If tempList.Find(Function(Card) Card.Rank = CardRank.Ace) IsNot Nothing Then 'We have an ace
            Dim noAce = (From Card As Card In tempList Where Card.Rank <> CardRank.Ace Select Card).ToList()
            Dim lst = ReturnStraight(noAce)
            If lst(lst.Count - 1).Rank = CardRank.Two Or lst(0).Rank = CardRank.King Then
                lst.Add((From Card As Card In tempList Where Card.Rank = CardRank.Ace Select Card).ToList(0))
            End If
        Else
    
            Dim lst = ReturnStraight(tempList)
            For Each Card As Card In lst
                MsgBox(Card.ToString())
            Next
        End If