Lucas Parkins Lucas Parkins - 5 months ago 16
Vb.net Question

Find matches in a card hand turns up slightly off results around 10% of the time

This is my code which is supposed to compare the values in the array 'arrHands' which stores a hand of x cards (x = cardsDrawn) as singles where the integer part is the suit (1 to 4) and the decimal represents the card number ( .01 = 1 = Ace, etc).
However around 1 in 10 times it runs it returns values that are off by one or two pairs. I know that this will happen when the hand contains a three-of-a-kind, as i haven't written the code for that yet, but it still doesn't make sense. if the value returned is wrong it is always higher than i expected.
here's the code:

Dim numPairs As Integer = 0
Dim A As Integer = 1
Dim B As Integer = 1

'A and B represent the position in the array of the cards being compared

For A = 1 To cardsDrawn

For B = 1 To cardsDrawn
If (A <> B) And (A < B) And (arrHand(A) <> 0) And (arrHand(B) <> 0) Then
'The above line stops cards from being compared to each other, or to a card they have already been compared to.

If (arrHand(A) - (Int(arrHand(A))) = (arrHand(B) - (Int(arrHand(B))))) Then

'the code above extracts the card number from the single that each card is stored as

numPairs += 1
arrHand(A) = 0
arrHand(B) = 0
End If

End If
Next
Next


Thanks for any help or ideas you may have.

Answer

It is almost always a bad idea to glue 2 pieces of information into one variable. Classes make it easy to track the various datum for a card:

Public Class Card
    Private Faces() As String = {"Jack", "Queen", "King", "Ace"}

    Private Names() As String = {"Ace", "Deuce", ..."King"}
    Public Property Value As Int32
    Public Property Rank As Int32
    Public Property Suit As String
    Public Property Img As Image
    Public Property Name As String

    Public Overrides Function ToString() As String
        Return String.Format("{0} of {1}", Names(Rank - 1), Suit)
    End Function
End Class

There is a Value and a Rank because a card always has the same rank, but depending on the game, the Value may change (e.g. Euchre and Baccarat). A Deck class could use a Stack(Of Card) and a hand can be a List(Of Card) or an array depending on the game.

Given an array of 5 cards, ranking the hand for poker is simple with linq (and assuming Poker):

Dim pairs = cards.
    GroupBy(Function(v) v.Value,
            Function(key, values) New With {
                    Key .Rank = key,
                    Key .Count = values.Count()
                    }).
            OrderByDescending(Function(o) o.Count).
            ThenByDescending(Function(r) r.Rank).
            ToArray()

If pairs.Count is 4, there is Four of a Kind; likewise 2pair when Count=2 and a pair when the count is one. If pairs(0).Count = 3 then you have trips.

If pairs.Count = 2 AndAlso pairs(0).Count = 3, then you have a FullHouse. It is pretty simple to also do a Group on the suit to determine a flush, and put them in order to see if it is a Straight.

Do be sure to test hands from high to low: you don't want to return 2 pair when it is really a Full House.

Comments