Poker and VB.NET

CodeGuru content and product recommendations are editorially independent. We may make money when you click on links to our partners. Learn More.

Introduction

One of the most fun things to do in my life is to play cards with my wife. We invented our own game and play just for fun mostly. If there were bets involved, I always end up losing. We do like ordinary card games as well: I love Blackjack and Poker. Because I have already made a small app demonstrating how Blackjack works, “Creating a Blackjack Game in Visual Basic,” I thought it apt to demonstrate just how difficult Poker can be.

With this article, I will demonstrate how to calculate each winning hand in Poker. Let’s get started.

Practical

Create a new Visual Basic Console application. You may give it any name you desire. This application’s purpose is to calculate each winning hand and show how you the percentage of the occurrence of each hand.

Add The Card class:

Enum Suit

   None
   Diamonds
   Hearts
   Clubs
   Spades

End Enum

Enum Rank

   None
   Ace
   Two
   Three
   Four
   Five
   Six
   Seven
   Eight
   Nine
   Ten
   Jack
   Queen
   King

End Enum

Enum Score

   None
   JacksOrBetter
   TwoPair
   ThreeOfAKind
   Straight
   Flush
   FullHouse
   FourOfAKind
   StraightFlush
   RoyalFlush

End Enum

Class Card

   Private rRank As Rank

   Private sSuit As Suit

   Public ReadOnly Property rank As Rank

      Get

         Return rRank

      End Get

   End Property

   Public ReadOnly Property suit As Suit

      Get

         Return sSuit

      End Get

   End Property

   Public Sub New(ByVal rank As Rank, ByVal suit As Suit)

      Me.rRank = rank
      Me.sSuit = suit

   End Sub

   Public Overrides Function ToString() As String

      Return rRank & " " + sSuit

   End Function

   Public Function JackorHigher() As Boolean

      If rRank = Rank.Ace Then Return True
      If rRank >= Rank.Jack Then Return True

      Return False

   End Function

End Class

This class is quite straightforward. It creates the Card Suits, The Card Ranks, as well as the score. Add the Deck class next:

Class Deck

   Private cCard As Card()

   Private intTemp As Integer = 0

   Private rRand As Random = New Random()

   Public Sub New()

      Initialize()

   End Sub

   Private Sub Initialize()

      intTemp = 0

      cCard = New Card(51) {}

      Dim intCount As Integer = 0

      For Each s As Suit In [Enum].GetValues(GetType(Suit))
         For Each r As Rank In [Enum].GetValues(GetType(Rank))
            If r <> Rank.None AndAlso s <> Suit.None _
               Then cCard(Math.Min(System.Threading.Interlocked _
               .Increment(intCount), intCount - 1)) = _
               New Card(r, s)

         Next

      Next

   End Sub

   Public Function DrawCard() As Card

      Return cCard(Math.Min(System.Threading.Interlocked _
         .Increment(intTemp), intTemp - 1))

   End Function

   Private Sub SwapCards(ByVal i As Integer, ByVal j As Integer)

      Dim tmpcard As Card = cCard(i)

      cCard(i) = cCard(j)
      cCard(j) = tmpcard

   End Sub

   Public Sub Randomize(ByVal iCount As Integer)

      intTemp = 0

      Dim i As Integer
      Dim j As Integer

      While i < iCount

         While j < 52

            Dim index As Integer = rRand.[Next](52)

            SwapCards(j, index)

            System.Threading.Interlocked.Increment(j)

         End While

         System.Threading.Interlocked.Increment(i)

      End While

   End Sub

   Public Sub Shuffle()

      Randomize(10)

   End Sub

End Class

The Deck class is simply responsible for rearranging all 52 cards as well as exposing the Shuffling methods. Add the Hand class next:

Imports System.Text

Class Hand

   Private dDeck As Deck

   Private cCard As Card()

   Public Sub New(ByVal deck As Deck)

      dDeck = deck
      cCard = New Card(4) {}

   End Sub

   Public Sub DrawCards()

      Dim i As Integer

      While i < 5

         cCard(i) = dDeck.DrawCard()

         System.Threading.Interlocked.Increment(i)

      End While

   End Sub

   Public Overrides Function ToString() As String

      Dim sbMessage As StringBuilder = New StringBuilder()

      For Each c As Card In cCard

         sbMessage.Append(c)
         sbMessage.Append(", ")

      Next

      Return sbMessage.ToString()

   End Function

   Default Public ReadOnly Property Item(ByVal index As Integer) _
         As Card

      Get

         Return cCard(index)

      End Get

   End Property

End Class

The Hand class represents the dealt hand with the drawn cards. Add the physical Game scoring class that will identify how to score drawn cards.

Class Game

   Private Shared Function Flush(ByVal h As Hand) As Boolean

      If h(0).suit = h(1).suit AndAlso
         h(1).suit = h(2).suit AndAlso h(2).suit = h(3).suit _
            AndAlso
         h(3).suit = h(4).suit Then Return True

      Return False

   End Function

   Private Shared Function Straight(ByVal h As Hand) As Boolean

      If h(0).rank = h(1).rank - 1 AndAlso
         h(1).rank = h(2).rank - 1 AndAlso h(2).rank = h(3).rank _
            - 1 AndAlso
         h(3).rank = h(4).rank - 1 Then Return True

      If h(1).rank = Rank.Ten AndAlso h(2).rank = Rank.Jack _
            AndAlso
         h(3).rank = Rank.Queen AndAlso h(4).rank = Rank.King _
            AndAlso
         h(0).rank = Rank.Ace Then Return True

      Return False

   End Function

   Private Shared Function RoyalFlush(ByVal h As Hand) As Boolean

      If Straight(h) AndAlso Flush(h) AndAlso h(0).rank = _
            Rank.Ace AndAlso
         h(1).rank = Rank.Ten AndAlso h(2).rank = Rank.Jack _
            AndAlso h(3).rank = Rank.Queen AndAlso
         h(4).rank = Rank.King Then Return True

      Return False

   End Function

   Private Shared Function StraightFlush(ByVal h As Hand) _
         As Boolean

      If Straight(h) AndAlso Flush(h) Then Return True

      Return False

   End Function

   Private Shared Function FourOfAKind(ByVal h As Hand) As Boolean

      If h(0).rank = h(1).rank AndAlso h(1).rank = h(2).rank _
         AndAlso h(2).rank = h(3).rank Then Return True

      If h(1).rank = h(2).rank AndAlso h(2).rank = h(3).rank _
         AndAlso h(3).rank = h(4).rank Then Return True

      Return False

   End Function

   Private Shared Function FullHouse(ByVal h As Hand) As Boolean

      If h(0).rank = h(1).rank AndAlso h(2).rank = h(3).rank _
         AndAlso h(3).rank = h(4).rank Then Return True

      If h(0).rank = h(1).rank AndAlso h(1).rank = h(2).rank _
         AndAlso h(3).rank = h(4).rank Then Return True

      Return False

   End Function

   Private Shared Function ThreeOfAKind(ByVal h As Hand) As Boolean

      If h(0).rank = h(1).rank AndAlso h(1).rank = h(2).rank Then _
         Return True

      If h(1).rank = h(2).rank AndAlso h(2).rank = h(3).rank Then _
         Return True

      If h(2).rank = h(3).rank AndAlso h(3).rank = h(4).rank Then _
         Return True

      Return False

   End Function

   Private Shared Function TwoPair(ByVal h As Hand) As Boolean

      If h(0).rank = h(1).rank AndAlso h(2).rank = h(3).rank Then _
         Return True

      If h(0).rank = h(1).rank AndAlso h(3).rank = h(4).rank Then _
         Return True

      If h(1).rank = h(2).rank AndAlso h(3).rank = h(4).rank Then _
         Return True

      Return False

   End Function

   Private Shared Function JacksOrBetter(ByVal h As Hand) _
         As Boolean

      If h(0).rank = h(1).rank AndAlso h(0).JackorHigher() Then _
         Return True

      If h(1).rank = h(2).rank AndAlso h(1).JackorHigher() Then _
         Return True

      If h(2).rank = h(3).rank AndAlso h(2).JackorHigher() Then _
         Return True

      If h(3).rank = h(4).rank AndAlso h(3).JackorHigher() Then _
         Return True

      Return False
   End Function

   Public Shared Function score(ByVal h As Hand) As Score

      If RoyalFlush(h) Then

         Return Score.RoyalFlush

      ElseIf StraightFlush(h) Then

         Return Score.StraightFlush

      ElseIf FourOfAKind(h) Then

         Return Score.FourOfAKind

      ElseIf FullHouse(h) Then

         Return Score.FullHouse

      ElseIf Flush(h) Then

         Return Score.Flush

      ElseIf Straight(h) Then

         Return Score.Straight

      ElseIf ThreeOfAKind(h) Then

         Return Score.ThreeOfAKind

      ElseIf TwoPair(h) Then

         Return Score.TwoPair

      ElseIf JacksOrBetter(h) Then

         Return Score.JacksOrBetter

      Else

         Return Score.None

      End If

   End Function

End Class

Add the Results screen class:

Class Stats

   Private intCount As Integer

   Private Rounds As Integer() = New Integer([Enum].GetValues _
      (GetType(Score)).Length - 1) {}

   Public Sub Results()

      Console.WriteLine("{0,10}" & vbTab & "{1,10}" & _
         vbTab & "{2,10}", "Hand", "Count", "Percent")

      Dim i As Integer

      While i < Rounds.Length

         Console.WriteLine("{0,-10}" & vbTab & "{1,10}" & _
            vbTab & "{2,10:p4}", [Enum].GetName(GetType _
            (Score), i), Rounds(i), Rounds(i) / CDbl(intCount))

         System.Threading.Interlocked.Increment(i)

      End While

      Console.WriteLine("{0,10}" & vbTab & "{1,10}", _
         "Total Hands", intCount)

   End Sub

   Public Sub Append(ByVal sScore As Score)

      Rounds(CInt(sScore)) += 1

   End Sub

   Public Sub Clear()

      Dim i As Integer

      While i < Rounds.Length

         Rounds(i) = 0

         System.Threading.Interlocked.Increment(i)

      End While

   End Sub

   Public Sub New()

      Clear()

   End Sub

   Public Property Count As Integer

      Set(ByVal value As Integer)

         intCount = value

      End Set

      Get

         Return intCount

      End Get

   End Property

End Class

The Stats class outputs the results, as you will see in Figure 1.

Lastly, add the code for the Module:

Module Module1

   Public Sub Main(ByVal args As String())

      Dim intCount As Integer = 2500

      If args.Length = 1 Then intCount = Integer.Parse(args(0))

      Dim dDeck As Deck = New Deck()

      Dim hHand As Hand = New Hand(dDeck)

      Dim sStats As Stats = New Stats()

      sStats.Count = intCount

      For i As Integer = 0 To intCount - 1

         dDeck.Shuffle()
         hHand.DrawCards()

         Dim Score As Score = Game.score(hHand)

         sStats.Append(Score)

      Next

      Console.WriteLine()

      sStats.Results()

      Console.ReadLine()

   End Sub

End Module

When you run your application now, a summary output similar to Figure 1 will be displayed.

Summary
Figure 1: Summary

The source code for this article can be found on GitHub.

Conclusion

Scoring a Poker game is not too difficult. By knowing how the scores are computed, you are more than halfway in creating your game engine. Hopefully, I can post an updated version soon. Until then, cheers!

Hannes DuPreez
Hannes DuPreez
Ockert J. du Preez is a passionate coder and always willing to learn. He has written hundreds of developer articles over the years detailing his programming quests and adventures. He has written the following books: Visual Studio 2019 In-Depth (BpB Publications) JavaScript for Gurus (BpB Publications) He was the Technical Editor for Professional C++, 5th Edition (Wiley) He was a Microsoft Most Valuable Professional for .NET (2008–2017).

More by Author

Get the Free Newsletter!

Subscribe to Developer Insider for top news, trends & analysis

Must Read