Overview




 
This is a console game that I first wrote in VB 2013 and then re-wrote in C# 2013 as a learning exercise.






Anyone who has ever played cards before has probably played BlackJack.
Blackjack, also known as twenty-one, is the most widely played casino banking game in the world. Blackjack is a comparing card game between a player and dealer.  Players compete against the dealer but not against any other players. It is played (in this version) with a deck of 52 cards. The object of the game is to beat the dealer, which can be done in a number of ways:
  • Get 21 points on the player's first two cards (called a blackjack), without a dealer blackjack;
  • Reach a final score higher than the dealer without exceeding 21; or
  • Let the dealer draw additional cards until his or her hand exceeds 21.
The player is dealt an initial two-card hand and adds together the value of their cards. Face cards (kings, queens, and jacks) are counted as ten points. A player and the dealer can count his or her own ace as 1 point or 11 points. All other cards are counted as the numeric value shown on the card. After receiving their initial two cards, players have the option of getting a "hit" (twisting), which is taking an additional card, or not (sticking). In a given round, the player or the dealer wins by having a score of 21 or by having the highest score that is less than 21. Scoring higher than 21 (called "busting" or "going bust") results in a loss. A player may win by having any final score equal to or less than 21 if the dealer busts.




The Code



First some Variables and a Structure, at Module level, to hold the deck of cards, the values of the cards, and the game statistics.
​There's also a Module level Random Object, which is used when shuffling the deck.



 
Dim deck() As String

Dim r As New Random 
Private Structure value

    Dim cardName As String

    Dim cardValue As Integer

    Public Sub New(ByVal cn As String, ByVal cv As Integer)

        Me.cardName = cn

        Me.cardValue = cv

    End Sub

End Structure 
Dim values As New List(Of value)
Dim gamesPlayed As Integer

Dim youWon As Integer

Dim dealerWon As Integer 
Dim balance As Decimal = 100D
Dim bet As Decimal





In Sub Main, the suits Arrays are loaded, and also the values List. then the game loop begins...



Sub Main() 
    Dim hearts() As String = Enumerable.Range(2, 9).Select(Function(x) x.ToString & Chr(3)).ToArray

    hearts = hearts.Concat(New String() {"J" & Chr(3), "Q" & Chr(3), "K" & Chr(3), "A" & Chr(3)}).ToArray 
    Dim diamonds() As String = Enumerable.Range(2, 9).Select(Function(x) x.ToString & Chr(4)).ToArray

    diamonds = diamonds.Concat(New String() {"J" & Chr(4), "Q" & Chr(4), "K" & Chr(4), "A" & Chr(4)}).ToArray 
    Dim clubs() As String = Enumerable.Range(2, 9).Select(Function(x) x.ToString & Chr(5)).ToArray

    clubs = clubs.Concat(New String() {"J" & Chr(5), "Q" & Chr(5), "K" & Chr(5), "A" & Chr(5)}).ToArray 
    Dim spades() As String = Enumerable.Range(2, 9).Select(Function(x) x.ToString & Chr(6)).ToArray

    spades = spades.Concat(New String() {"J" & Chr(6), "Q" & Chr(6), "K" & Chr(6), "A" & Chr(6)}).ToArray

 
    values.Add(New value("2", 2))

    values.Add(New value("3", 3))

    values.Add(New value("4", 4))

    values.Add(New value("5", 5))

    values.Add(New value("6", 6))

    values.Add(New value("7", 7))

    values.Add(New value("8", 8))

    values.Add(New value("9", 9))

    values.Add(New value("10", 10))

    values.Add(New value("J", 10))

    values.Add(New value("Q", 10))

    values.Add(New value("K", 10))

    values.Add(New value("A", 11)) 
    Dim playAgain As String 
    Do

        playAgain = If(balance > 0, playAHand(), "n") 
        If playAgain.ToLower = "y" Then 
            deck = hearts.Concat(diamonds).Concat(clubs).Concat(spades).ToArray

            shuffle() 
            Dim playersHand() As String = deal(2)             

            Dim dealersHand() As String = deal(2)

            
            Dim dealerScore As Integer = dealersHand.Sum(Function(c) values.First(Function(v) If(Val(c) > 0, Val(c).ToString = v.cardName, c.StartsWith(v.cardName))).cardValue)

            If dealerScore = 22 Then dealerScore = 12
            Dim playerScore As Integer = playersHand.Sum(Function(c) values.First(Function(v) If(Val(c) > 0, Val(c).ToString = v.cardName, c.StartsWith(v.cardName))).cardValue)

            If playerScore = 22 Then playerScore = 12 
            showCards("Your hand: ", playersHand) 
            Console.WriteLine() 
            If playerScore = 21 And Not dealerScore = 21 Then

                Console.WriteLine("BlackJack! You win.")

                Console.WriteLine()

                showCards("Dealer's hand: ", dealersHand)

                updateStats("user")

            ElseIf playerScore = 21 And dealerScore = 21 Then

                showCards("Dealer's hand: ", dealersHand)

                Console.WriteLine("It's a draw. No one wins.")

                updateStats("draw")

            ElseIf (Not playerScore = 21 And Not dealerScore = 21) OrElse (Not playerScore = 21 And dealerScore = 21) Then

                playGame("user", playerScore, dealerScore, playersHand, dealersHand)

            End If
        End If
        Console.WriteLine()
    Loop While playAgain.ToLower = "y" 
    Console.ReadLine()
End Sub




The playAHand Function prompts the player, asking whether to continue.



Private Function playAHand() As String

    Console.WriteLine("Play a hand? (y/n)")

    Dim response As String = Console.ReadLine

    If response.ToLower = "y" Then

        Console.Clear()

        Console.WriteLine("Hands played: {0}", gamesPlayed)

        Console.WriteLine("You won: {0}, Dealer won: {1}", youWon, dealerWon)

        Console.WriteLine("Balance: {0:c2}", balance) 
        If balance = 0 Then

            Console.WriteLine("Zero balance")

            Return "n"

        End If 
        Do

            Console.WriteLine("How much would you like to bet?")

            If Decimal.TryParse(Console.ReadLine, bet) AndAlso bet <= balance AndAlso bet > 0 Then

                Console.WriteLine()

                Console.WriteLine("Bet: {0:c2}", bet)

                Exit Do

            Else

                Console.WriteLine()

                Console.WriteLine("Invalid bet")

            End If

        Loop
    End If
    Return response
End Function




The playGame subroutine is the core of the game. This sub handles Twisting, recursively calling itself as well as branching out to the showCards and updateStats methods...




























Private Sub playGame(ByVal player As String, ByVal score1 As Integer, ByVal score2 As Integer, ByVal hand1() As String, ByVal hand2() As String)
    Dim response As String = ""

    If player = "user" Then

        Console.WriteLine("Twist? (y/n)")

        response = Console.ReadLine

        Console.WriteLine()

    Else

        response = "y"

    End If
    If response.ToLower = "y" Then 
        hand1 = hand1.Concat(deal(1)).ToArray 
        If player = "user" Then

            showCards("Your hand: ", hand1)

            Console.WriteLine()

        End If 
        score1 = hand1.Sum(Function(c) values.First(Function(v) If(Val(c) > 0, Val(c).ToString = v.cardName, c.StartsWith(v.cardName))).cardValue) 
        If player = "user" Then

            If score1 > 21 And Not (score1 - (hand1.Count(Function(c) c.StartsWith("A")) * 10) <= 21) Then

                showCards("Dealer's hand: ", If(player = "user", hand2, hand1))

                Console.WriteLine()

                updateStats(winner(player, hand1, hand2))

            ElseIf score1 > 21 And (score1 - (hand1.Count(Function(c) c.StartsWith("A")) * 10) <= 21) Then

                Dim count As Integer = 0

                While count < hand1.Count(Function(c) c.StartsWith("A")) And score1 > 21

                    count += 1

                    score1 -= 10

                End While

                If score1 < 21 Then

                    playGame("user", score1, score2, hand1, hand2)

                Else

                    showCards("Dealer's hand: ", hand2)

                    updateStats(winner(player, hand1, hand2))

                End If

            ElseIf score1 < 21 Then

                playGame("user", score1, score2, hand1, hand2)

            ElseIf score1 = 21 Then

                playGame("dealer", score2, score1, hand2, hand1)

            End If
        Else
            If score1 < 17 Then

                playGame("dealer", score1, score2, hand1, hand2)

            Else

                If score1 < 20 Then

                    If r.Next(0, 4) = 1 Then

                        playGame("dealer", score1, score2, hand1, hand2)

                    Else

                        showCards("Dealer's hand: ", hand1)

                        updateStats(winner(player, hand1, hand2))

                    End If

                ElseIf score1 > 21 And (score1 - (hand1.Count(Function(c) c.StartsWith("A")) * 10) <= 21) Then

                    Dim count As Integer = 0

                    While count < hand1.Count(Function(c) c.StartsWith("A")) And score1 > 21

                        count += 1

                        score1 -= 10

                    End While

                    If score1 < 21 Then

                        playGame("dealer", score1, score2, hand1, hand2)

                    Else

                        showCards("Dealer's hand: ", hand1)

                        updateStats(winner(player, hand1, hand2))

                    End If

                Else

                    showCards("Dealer's hand: ", hand1)

                    updateStats(winner(player, hand1, hand2))

                End If

            End If

        End If



    
Else
        If score2 < 17 Then

            playGame("dealer", score2, score1, hand2, hand1)

        Else

            If score2 < 20 Then

                If r.Next(0, 4) = 1 Then

                    playGame("dealer", score2, score1, hand2, hand1)

                Else

                    showCards("Dealer's hand: ", hand2)

                    updateStats(winner(player, hand1, hand2))

                End If

            Else

                showCards("Dealer's hand: ", hand2)

                updateStats(winner(player, hand1, hand2))

            End If

        End If

    End If

 
End Sub









The winner Function compares the scores and writes output to the Console.





Private Function winner(ByVal player As String, ByVal hand1() As String, ByVal hand2() As String) As String
    Dim score1 As Integer = hand1.Sum(Function(c) values.First(Function(v) If(Val(c) > 0, Val(c).ToString = v.cardName, c.StartsWith(v.cardName))).cardValue)

    Dim count As Integer = 0

    While count < hand1.Count(Function(c) c.StartsWith("A")) And score1 > 21

         count += 1

        score1 -= 10

    End While 
    Dim score2 As Integer = hand2.Sum(Function(c) values.First(Function(v) If(Val(c) > 0, Val(c).ToString = v.cardName, c.StartsWith(v.cardName))).cardValue)

    count = 0

    While count < hand2.Count(Function(c) c.StartsWith("A")) And score2 > 21

        count += 1

        score2 -= 10

    End While 
    If player = "user" Then

        If score1 <= 21 AndAlso score2 <= 21 Then

            If score1 > score2 Then

                Console.WriteLine("You win.")

                Return "user"

            ElseIf score2 > score1 Then

                Console.WriteLine("Dealer wins.")

                Return "dealer"

            Else 'draw

                Console.WriteLine("No one wins.")

                Return "draw"

            End If

        Else

            If score1 > 21 Then

                Console.WriteLine("You bust. Dealer wins.")

                Return "dealer"

            Else 'score2 > 21

                Console.WriteLine("Dealer bust. You win.")

                Return "user"

            End If

        End If

    Else '"dealer"

        If score1 <= 21 AndAlso score2 <= 21 Then

            If score2 > score1 Then

                Console.WriteLine("You win.")

                Return "user"

            ElseIf score1 > score2 Then

                Console.WriteLine("Dealer wins.")

                Return "dealer"

            Else 'draw

                Console.WriteLine("No one wins.")

                Return "draw"

            End If

        Else

            If score2 > 21 Then

                Console.WriteLine("You bust. Dealer wins.")

                Return "dealer"

            Else 'score1 > 21

                Console.WriteLine("Dealer bust. You win.")

                Return "user"

            End If

        End If

    End If 
End Function






The shuffle method, randomly shuffles the deck..





Private Sub shuffle()

    deck = deck.OrderBy(Function(x) r.NextDouble).ToArray

End Sub






The deal Function takes the specified number of cards from the deck and returns them as a String Array...





Private Function deal(ByVal count As Integer) As String()

    Dim a() As String = deck.Take(count).ToArray

    deck = deck.Except(a).ToArray

    Return a

End Function





The updateStats method updates the balance and statistics Variables in preparation for the next hand...




Private Sub updateStats(ByVal winner As String)

    gamesPlayed += 1

    youWon += If(winner = "user", 1, 0)

    dealerWon += If(winner = "dealer", 1, 0)

    balance += If(winner = "user", bet, If(winner = "dealer", -bet, 0))

End Sub





Finally the showCards method writes the contents of a hand to the Console, using appropriate symbols and coloring...






Private Sub showCards(ByVal label As String, ByVal cards() As String)

    Console.Write(label)

 
    Dim reds() As String = {Chr(3), Chr(4)}

    For x As Integer = 0 To cards.GetUpperBound(0)

        Console.ForegroundColor = If(reds.Any(Function(s) cards(x).Contains(s)), ConsoleColor.Red, ConsoleColor.Gray)

        Console.Write(cards(x) & " ")

    Next x 
    Dim cardSum As Integer = cards.Sum(Function(c) values.First(Function(v) If(Val(c) > 0, Val(c).ToString = v.cardName, c.StartsWith(v.cardName))).cardValue)



    
Dim count As Integer = 0

    While count < cards.Count(Function(c) c.StartsWith("A")) And cardSum > 21

        count += 1

        cardSum -= 10

    End While 
    Console.ForegroundColor = ConsoleColor.White 
    Console.Write("({0})", cardSum)

    Console.WriteLine()
End Sub






See Also

 
(Download) VB/C#


Articles related to game programming



VB.Net - WordSearch
VB.Net - Vertex
VB.Net - Perspective
VB.Net - MasterMind
VB.Net - OOP BlackJack
VB.Net - Numbers Game
VB.Net - HangMan
TicTacToe - VB.Net | C#
OOP Conway's Game of Life - VB.Net | C#
OOP Sudoku - VB.Net | C#
OctoWords VB.Net | C#
OOP Buttons Guessing Game VB.Net | C#
OOP Tangram Shapes Game VB.Net | C#
VB.Net - Three-card Monte
VB.Net - Split Decisions
VB.Net - Pascal's Pyramid
VB.Net - Random Maze Games
(Office) Wordsearch Creator
VB.Net - Event Driven Programming - LockWords Game
C# - Crack the Lock
VB.Net - Totris