Background photo created by freepik – www.freepik.com

DISCLAIMER: The author does not endorse gambling through this post.

Introduction to Blackjack

Blackjack is one of the simplest, quickest card games one can play. And there really is no cap on the number of players – every players goal is only to beat the dealer. The game is played with n persons, with one person designated the dealer and n-1 players. The dealer’s role, as the name implies, is to deal cards and be the backbone of the gameplay. The dealer deals two cards to each player, face-up, and deals two to himself, one face-up and one face-down. The cards of each player are collectively referred to as a “hand”, which comprises of two cards per person right after dealing. The value of a hand is the sum of the values of all cards in the hand; where an Ace has a variable value of either 1 or 11, depending upon what the player chooses; Jacks, Queens and Kings have values of 10 and the rest of the cards have values equal to their ranks/face value.

After two rounds of dealing, the players must “play” their hands. They can do so in one of 5 ways – stand, hit, surrender, double down or split. However, in this version, we will only use the first 3. A person can “stand” if he/she is satisfied with his/her hand, and no change will be made to the hand. A person can “hit” if he/she feels the need to add cards to his/her deck, one by one, until he/she chooses to stand. The person “surrenders”, assuming the house rules allow it, if he/she feels that it is impossible to win, thereby forfeiting and automatically losing the game. After all the players play their hands, the dealer must play his/her hand, but can only do so by either standing or hitting.

To beat the dealer, the value of the player’s hand must be closer to 21 than the value of the dealer’s hand. However, if the value of the person’s hand go over 21, the person automatically loses or “busts”. If both the dealer and the player bust, or they get the same hand values; depending upon the house rules, either the game is drawn or the dealer wins.

To know more about a complete game of blackjack, visit https://www.blackjackapprenticeship.com/how-to-play-blackjack/.

The Logic Behind Blackjack

Flowchart depicting the sequence of events in a game of blackjack.

Every game of blackjack follows the same sequence of events. First, the dealer deals cards. After that, the players, in turn, play their hands until they stand (or surrender, in which case the dealer wins by default). Then, the dealer plays his or her hand until he or she stands. Then, the hands of the player and the dealer are compared, and whoever has the higher hand, as long is it is equal to or less than 21, wins.

This is the gameplay that we need to code into the program. So, how do we do this?

Step-by-Step Instructions to Implement the Above Logic (using OOP)

NOTE: Before reading on, it is recommended that you have a basic knowledge of object oriented programming.

When coding any card game, the first thing we need to do is create cards, and a deck of cards. A card for blackjack could be a simple class taking three parameters – the “rank” (or number) of the card, the “suit” (hearts, diamonds, spades, clubs) of the card and the “value” of the card (as per the values allowed in blackjack). Apart from these three, upon initialisation of a card object, we must use another variable, the cardname, which is basically a concatenation of the rank and suit with an “of” in between (for example, AceofSpades). Below is the Scala code for it, which can also serve as pseudocode:

//Card class
class Card(rank: String, suit: String, value: Int) {
  val cardrank: String = rank
  val cardsuit: String = suit
  val cardname: String = cardrank + "of" + cardsuit
  var cardval: Int = value
}

After this, we create the class Deck, which should be a collection of Card objects. It should have a variable “deck”, an array of variable length in which the cards are stored. To add cards to the deck, we first make a list of all the ranks and one of all the suits. Also, we make a dictionary to store the values of each rank. Then, we iterate through each rank and each suit in a nested for loop, and append to the deck the card created, feeding it the rank, suit and value. Also, we must make a function for the class that allows us to draw a random card from the deck. Below is the Scala code for it:

//Deck class
class Deck() {
  val cardvals: Map[String, Int] = Map("Ace" -> 1, "Two" -> 2, "Three" -> 3, "Four" -> 4, "Five" -> 5, "Six" -> 6,
    "Seven" -> 7, "Eight" -> 8, "Nine" -> 9, "Ten" -> 10, "Jack" -> 10, "Queen" -> 10, "King" -> 10)
  val ranks: Array[String] = Array("Ace", "Two", "Three", "Four", "Five", "Six", "Seven", "Eight", "Nine", "Ten",
    "Jack", "Queen", "King")
  val suites: Array[String] = Array("Hearts", "Spades", "Diamonds", "Clubs")
  var deck: ArrayBuffer[Card] = ArrayBuffer()
  for (rank <- ranks) {
    for (suit <- suites) {
      deck = deck :+ new Card(rank, suit, cardvals(rank))
    }
  }

  def drawcard(): Card = {
    val cardindex = Random.nextInt(deck.length)
    var drawncard = deck(cardindex)
    deck -= drawncard //pop or remove the card after drawing it
    return drawncard
  }
}

Now, we need to make a class Hand, representing each player’s/ the dealer’s hands. It must have 2 variables – an array of variable length to store the Cards, and another to store the value of the hand. This class must have a lot more functions – a function to evaluate the value of the hand (make sure you do not simply increment the value), one to add a card to the hand, one to print a player’s hand and one to print the dealer’s hand. Below is the Scala code for the class Hand:

//Hand class
class Hand() {
  var cardsinhand: ArrayBuffer[Card] = ArrayBuffer()
  var value: Int = 0
  for (card <- cardsinhand) {
    value += card.cardval
  }

  def add(card: Card): Unit = {
    cardsinhand = cardsinhand :+ card
    evaluate()
  }

  def evaluate(): Unit = {
    var tempval = 0
    for (card <- cardsinhand) {
      tempval += card.cardval
      value = tempval
    }
  }

  def printhand(): Unit = {
    print("Your hand is: ")
    for (card <- cardsinhand) {
      print(card.cardname + ", ")
    }
    println()
  }

  def printdealerhand(): Unit = {
    print("Dealer's hand is: ")
    for (card <- cardsinhand) {
      print(card.cardname + ", ")
    }
    println()
  }
}

Now, we just need to make the classes for the persons playing the game – a Dealer and a Player. For the Dealer class, that takes a Deck object as a parameter, there are only two variables – the hand (a Hand object) and a boolean win variable, which will be changed later on. The dealer must be allowed only two actions – hit or stand. A dealer hits only if the value of its hand is <17 and <=21. The dealer must also have a function to deal cards and one to play its hand. The Scala code for all this is:

//Dealer class
class Dealer(deck: Deck) {
  var hand = new Hand()
  var win: Boolean = false

  def playhand(): Unit = {
    hand.evaluate()
    if (hand.value < 17 && hand.value <= 21) {
      hit()
    }
    else {
      stand()
    }
  }

  def hit(): Unit = {
    println("Dealer hits")
    while (hand.value <= 21 && hand.value <= 16) {
      hand.add(deal())
      hand.evaluate()
    }
    hand.printdealerhand()
  }

  def deal(): Card = {
    val card = deck.drawcard()
    return card
  }

  def stand(): Unit = {
    println("Dealer stands")
    hand = hand
  }

}

Now for the Player class, which takes in its dealer as a parameter. It has the same variables as the Dealer, with the addition of two more variables – a list of all actions available to it (3 in this program) which can be typed in fully or in short form, and an Integer variable to represent the value of an ace. A Player object has 4 functions – to stand, to surrender, which are fairly straightforward, one to allow the Player to play his/her hand and one to allow the player to hit, and keep hitting until he/she decides to stand. In the playhand() function, the user should be allowed to input an action if and only if it is valid, and after choosing to stand, must be allowed to choose the value(s) of his/her ace(s). Below is the Scala code for the Player class:

//Player class
class Player(dealer: Dealer) {
  val actions: Array[String] = Array("stand", "hit", "surrender", "h", "st", "su")
  var hand = new Hand()
  var win: Boolean = false
  var aceval: Int = 1

  def playhand(): Unit = {
    val acevals = Array(1, 11)
    var playeraction = scala.io.StdIn.readLine(s"What would you like to do (hit(h)/stand(st)/surrender(su))? ")
    while (actions.indexOf(playeraction) == -1) {
      playeraction = scala.io.StdIn.readLine("Invalid response! Please enter a valid action: ")
    }
    if (playeraction == "hit" || playeraction == "h") {
      hit()
    }
    else if (playeraction == "stand" || playeraction == "st") {
      stand()
    }
    else if (playeraction == "surrender" || playeraction == "su") {
      surrender()
    }
    for (card <- hand.cardsinhand) {
      if (card.cardrank == "Ace") {
        aceval = scala.io.StdIn.readLine("What do you want the value of your ace to be (1/11)? ").toInt
        while (acevals.indexOf(aceval) == -1) {
          aceval = scala.io.StdIn.readLine("Invalid response! Please enter a valid rank: ").toInt
        }
        card.cardval = aceval
      }
    }
  }

  def stand(): Unit = {
    hand = hand
    hand.printhand()
  }

  def hit(): Unit = {
    hand.add(dealer.deal())
    hand.printhand()
    var more = scala.io.StdIn.readLine("Would you like another card (Y/N)? ").toUpperCase
    while (more == "Y" && hand.value <= 21) {
      hand.add(dealer.deal())
      hand.printhand()
      more = scala.io.StdIn.readLine("Would you like another card (Y/N)? ").toUpperCase
    }
    hand.printhand()
  }

  def surrender(): Unit = {
    win = false
    dealer.win = true
    hand.printhand()
  }

}

Now, all that’s left is the object Blackjack, in which we will actually code in the gameplay of the game. We have a few basic helper functions – to reset the game, to print instructions and to check for a win at the end of a game. The functions in the spotlight are the play() function, and of course, the main() function. All the main function needs to do is print instructions in the starting, and in while loop, keep playing the game until the user decides to quit. In the play() function, the dealer must deal two cards to each player, and the one of the dealer’s cards in hand must be revealed. Then the user’s hand must be shown, and the user should be allowed to play his/her hand. After the user stands, evaluate the user’s hand and let the dealer play its hand, and print out the dealer’s hand after it stands. Then, call the check() function to check whether or not the player won. The code in Scala is:

//the gameplay
def play(): Unit = {
    for (_ <- 1 until 3) {
      user.hand.add(dealer.deal())
      dealer.hand.add(dealer.deal())
    }
    println("Dealer's hand: " + dealer.hand.cardsinhand(0).cardname + ", ???")
    user.hand.printhand()
    user.playhand()
    user.hand.evaluate()
    dealer.hand.printdealerhand()
    dealer.playhand()
    dealer.hand.evaluate()
    println(s"Dealer's hand's value is: ${dealer.hand.value}, your hand's value is: ${user.hand.value}")
    if (!dealer.win && !user.win) {
      if (user.hand.value > 21 && dealer.hand.value > 21) {
        println("Well, looks like a push (draw)!")
      }
      else if (user.hand.value > 21) {
        user.win = false
        dealer.win = true
        check()
      }
      else if (dealer.hand.value > 21) {
        user.win = true
        dealer.win = false
        check()
      }
      else if (dealer.hand.value > user.hand.value) {
        dealer.win = true
        user.win = false
        check()
      }
      else if (dealer.hand.value < user.hand.value) {
        dealer.win = false
        user.win = true
        check()
      }
      else {
        println("Looks like a push (draw)!")
      }
    }
    else {
      check()
    }
  }

  def check(): Unit = {
    if (dealer.hand.value != user.hand.value) {
      if (dealer.win) {
        println("Oh no, you lost!")
      }
      else if (user.win) {
        println("Congratulations, you won!")
      }
    }

  }

  def reset(): Unit = {
    deck = new Deck()
    dealer = new Dealer(deck)
    user = new Player(dealer)
  }

  def print_instructions(): Unit = {
    println("WELCOME TO BLACKJACK!")
    println("Please make sure that you are familiar with basic blackjack gameplay before playing.")
    println("Visit https://www.blackjackapprenticeship.com/how-to-play-blackjack/ if you are not.")
    println("   Rules of the House:-")
    println("1. NO BETS. This is a friendly single player game of blackjack.")
    println("2. If you and the dealer both go over 21, it is a tie.")
    println("3. If you and the dealer get the same hand value, it is a tie.")
    println("4. Whoever gets the higher value wins, assuming that the value remains lesser than or equal to 21.")
    println("5. When the system prompts you for a yes/no (Y/N) input, make sure you type either 'Y' or 'N'. \n " +
      "  You will NOT get re-prompted. In all other prompts, you will get re-prompted.")
    println("6. You have only 3 ways of playing your hand - you can either hit, stand or surrender. You CANNOT \n" +
      "   double down or split.")
    println("7. The dealer always takes an ace as a 1. The dealer can either stand or hit.")
    println("8. That's just about it. Enjoy!")
    println()
  }

}

And that’s it! That’s all we need to create a game of blackjack. The above steps can be used to create a game of blackjack in any Object-Oriented Programming language. Here are a few screenshots of it in action:


The github link for the above program is:

https://github.com/adityapentyala/Scala/blob/master/blackjack.scala

Visits: 82

One Reply to “Blackjack in Scala”

Leave a Reply

Your email address will not be published. Required fields are marked *