How do I shuffle and deal cards one at a time to players?

This is the wrong way to go about it:

Dim rand As New Random  
Dim rand1 As Integer = rand.Next(12)  
Dim rand2 As Integer = rand.Next(3) 

You can easily end up with duplicate cards because you are picking THIS card without knowing if it has already been dealt (even in this click!). You also want one Random used per game/app, not per card. Representing a Card as suit & face will work, but it glues 2 important pieces of information together – in most games you will later have to parse it to get that info.

A deck is made up of 52 cards; each Card is made of a Suit and a Rank. Lets build a simple class or two which mimics that:

Public Class Card
    Public Property Suit As String
    Public Property Rank As Integer

    ' card images from
    ' http://www.jfitz.com/cards/
    Public Property Img As Image

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

    ' for text version of the game
    Public Function CardText() As String
        Dim tmp As String = Rank.ToString
        If Rank = 1 Then
            tmp = "Ace"
        ElseIf Rank >= 11 Then
            tmp = Faces(Rank - 11)
        End If
        Return String.Format("{0} of {1}", tmp, Suit)

    End Function

    ' iDeck class will assign Rank, Suit and img to an "empty" card
    Public Sub New(strSuit As String, nRank As Integer, i As Image)
        Suit = strSuit
        Rank = nRank
        Img = i
    End Sub

    Public Overrides Function ToString() As String
        Return CardText()
    End Function
End Class

In reality, you’d also want a Value property since in most games it is not the same as the Rank.

With the Rank and Suit as individual properties you can test the cards of one player versus another to see who has the best card. This is easy in some games like BlackJack since all you will care about is the Rank and the sum. Hand evaluation is more complex in other games since you can have combos like FullHouse and Flush. Now the deck (with both shuffle methods there for illustrative purposes):

Public Class Deck
    Dim rand As Random

    ' the deck will be built in the same order a real deck comes in
    Private Suits() As String = {"Spades", "Diamonds", "Clubs", "Hearts"}
    Private Rank() As Integer = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13}

    ' useful for blackjack
    Private Const Ace As Integer = 1

    ' freshly opened pack where they are in order.  this is reused rather 
    ' than building a new deck each time
    Private freshDeck As List(Of Card)

    ' shuffled deck; Stack prevents any bugs from a botched counter var
    Private shoe As Stack(Of Card)

    ' using an imagelist but My.Resources could work depending on card names
    Private imglist As ImageList

    ' the GAME object passes us the imagelist holding the card pics
    Public Sub New(imgs As ImageList)     ' ctor
        ' new random ONCE
        rand = New Random
        imglist = imgs
        NewDeck()
    End Sub

    ' create a new deck (done ONCE) but could be called again 
    Private Sub NewDeck()
        freshDeck = New List(Of Card)      ' new object

        For Each s As String In Suits
            For Each n As Integer In Rank
                Dim key As String = CardKey(s, n)

                freshDeck.Add(New Card(s, n, imglist.Images(key)))
            Next
        Next
    End Sub

    Private keys() As String = {"J", "Q", "K"}

    Private Function CardKey(suit As String, rank As Integer) As String
        ' convert Suit / Key to the key used in the imglist
        ' (e.g C1.JPG for Clubs, Ace)
        ' cards come from http://www.jfitz.com/cards/
        ' use the windows set (or rename them all)

        Dim key As String = suit.Substring(0, 1)   ' => C, H, D, S
        If rank < 11 Then
            key &= rank.ToString
        Else
            key &= keys(rank - 11)      ' cvt 11, 12, 13 => J, Q, K
        End If

        Return key & ".png"
    End Function

    ' Shuffle deck using Fisher-Yates; sub optimal here since we "use up"
    ' the shoe each hand and are not reshuffling a deck
    Public Sub Shuffle()
        ' new temp deck preserves the new deck starting point
        Dim thisDeck As New List(Of Card)(freshDeck.ToArray)
        Dim tmp As Card

        Dim j As Integer
        ' hi to low, so the rand pick result is meaningful
        ' lo to hi introduces a definite bias
        For i As Integer = thisDeck.Count - 1 To 0 Step -1
            j = rand.Next(0, i + 1)        ' NB max param is EXCLUSIVE

            tmp = thisDeck(j)
            ' swap Card j and Card i 
            thisDeck(j) = thisDeck(i)
            thisDeck(i) = tmp
        Next

        ' using a stack for the actual deck in use; copy shuffled deck to the Shoe
        shoe = New Stack(Of Card)(thisDeck.ToArray)

    End Sub

    ' shuffle using random and LINQ (neo's answer)
    Public Sub ShuffleLinq()
        ' using the same rand per app run may be random enough
        ' but would not suffice for most 'serious' games or standards
        shoe = New Stack(Of Card)(freshDeck.OrderBy(Function() rand.Next))

    End Sub

    Public Function DealCard() As Card
        ' get a card
        If shoe.Count = 0 Then
            ' ToDo: out of cards
            ' happens with 9+ handed, 7 card games and many hi-lo games...
            ' usually mucked and burn cards are reshuffled
            ' some games use shared cards at the end
            ' (muck/burn list not implemented)
        End If
        Return shoe.Pop
    End Function

End Class

Rather than simply looking for code to paste, you should start trying to learn concepts presented (even if it is just the learning the names of concepts you want/need to learn more about: Classes, Enum, Collections, Objects, Methods…). The above is much more involved than a simple array, but if you study it you’ll see Card and Deck mimic the real world versions. The deck builds itself so elsewhere we just have to use it.

Next is a Player Class to hold the cards and a Game Class to implement the rules for the game, deal cards and control the order (these are left for the student to complete). This results in almost no code in the form, just some calls to Game (and only Game) which in turn uses Deck and Player, controls turns, give cards to players etc. e.g.:

Private poker As Game
...
New Game(theImgList, 3)     ' 3 == the human player

Shuffle button:

    poker.ShuffleDeck()
    poker.NewHand()
    thisRound = Game.Rounds.HoleCards

Deal button:

    Select Case thisRound
        Case Game.Rounds.HoleCards
            poker.NewHand()                ' clears the display etc
            poker.DealRound(thisRound)     ' deal cards
            thisRound = Game.Rounds.Flop   ' change round indicator

        Case Game.Rounds.Flop             ' even this could be internal to Game(poker)
            poker.DealRound(thisRound)     
            thisRound = Game.Rounds.Turn

In Game.DealRound:

    Case Rounds.Flop
        myDeck.DealCard()            ' burn card
        players(0).AddCard(myDeck.DealCard)  ' Player(0) is the house or community
        players(0).AddCard(myDeck.DealCard)
        players(0).AddCard(myDeck.DealCard)

Using classes, the form doesnt know or care HOW anything happens (like which suffle method), just that it happens when requested. Texas HoldEm Game, where the Community Cards are held by Player(0) who has an IsHouse property and some other player who IsHuman (basically so their cards always show):

enter image description here

.o0( Yea, “Jon” go all in, PLEASE go all in.)
And I definitely want to see a ‘6’ come out for “Neo”. Definitely a ‘6’ for “Neo”.

Leave a Comment

tech