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:
If No:
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:
The result would be:
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()
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