Simple Vanilla Javascript Blackjack – Free Code Download

Welcome to a tutorial on how to create a simple Blackjack game in vanilla Javascript. Yes, Blackjack is a traditional card game that is perfect as a beginner exercise for you code ninjas who want to go into web browser gaming.

But I guess there are already quite a number of other tutorials out there, so I will make this one slightly different – I will keep the interface as minimal as possible, so you guys can concentrate on the mechanics instead of the graphics. Read on!

ⓘ I have included a zip file with all the example source code at the start of this tutorial, so you don’t have to copy-paste everything… Or if you just want to dive straight in.

 

 

TABLE OF CONTENTS

Download & Demo Game Rules HTML & CSS
Javascript Useful Bits & Links The End

 

DOWNLOAD & DEMO

Firstly, here is the download link to the example code as promised.

 

EXAMPLE CODE DOWNLOAD

Click here to download the source code, I have released it under the MIT license, so feel free to build on top of it or use it in your own project.

 

QUICK NOTES

If you spot a bug, please feel free to comment below. I try to answer questions too, but it is one person versus the entire world… If you need answers urgently, please check out my list of websites to get help with programming.

 

JAVASCRIPT BLACKJACK DEMO

STAND Dealer’s Hand – ?
STAND Your Hand – 0

 

THE GAME RULES

Before we go into the code, let us start with the game rules… For you guys who already know how to play Blackjack, please feel free to skip this section.

 

HOW TO PLAY

The “full version” rules of Blackjack can be pretty long-winded, so let us adopt a simplified version for this project:

  1. There will be a deck of 52 cards and 2 players (computer vs player).
  2. The goal of Black Jack is to get as close to 21 points as possible. Any player that goes past 21 loses the game.
  3. The points of each card are as follow –
    • Aces can either be 1 or 11 points.
    • Cards from 2-10, points counted as-it-is.
    • The K, Q, J cards are counted as 10 points.
  4. On the first round of the game –
    • The dealer and player will each be served 2 cards. The first and third cards go to the player, the second and fourth cards to the computer.
    • The dealer’s first card will be hidden, all other cards will face up.
  5. The player only has to choose between 2 actions – “Hit” (get another card) and “Stand” (done, compare points with the dealer).
  6. At stand:
    • Whoever goes bust loses automatically (more than 21 points).
    • Whoever has more points wins.
    • It’s a draw if both players got the same points.
    • The player who gets Blackjack wins.
    • If both players got Blackjack with 2 cards – It’s a draw.
    • If both players got Blackjack with 3 or more cards – It’s a draw.

 

 

HTML & CSS

That’s it for the simplified rules – Let us now “translate” that into a script, starting with the HTML game page.

 

THE HTML

blackjack.html
<!-- (A) DEALER'S CARDS -->
<div id="deal-wrap">
  <!-- (A1) DEALER'S POINTS + STAND -->
  <div id="deal-data">
    <span id="deal-stand">STAND</span>
    Dealer's Hand - <span id="deal-points">?</span>
  </div>

  <!-- (A2) DEALER'S CARDS -->
  <div id="deal-cards"></div>
</div>
 
<!-- (B) PLAYER'S CARDS -->
<div id="play-wrap">
  <!-- (B1) PLAYERS'S POINTS + STAND -->
  <div id="play-data">
    <span id="play-stand">STAND</span>
    Your Hand - <span id="play-points">0</span>
  </div>
 
  <!-- (B2) PLAYER'S CARDS -->
  <div id="play-cards"></div>
</div>
 
<!-- (C) PLAY! -->
<div id="play-control">
  <!-- (C1) START -->
  <input type="button" id="playc-start" value="Play!"/>
  <!-- (C2) HIT OR STAND -->
  <input type="button" id="playc-hit" value="Hit"/>
  <input type="button" id="playc-stand" value="Stand"/>
</div>

This may seem a little complicated at first, but there are only 3 main sections to the Blackjack HTML:

  • A – We have <div id="deal-wrap"> to contain elements for the dealer.
    • <span id='deal-stand'> is a “flag” to indicate that the dealer has decided to stand.
    • <span id='deal-points'> holds the current number of points the dealer has.
    • <div id="deal-cards"> is a container to show the dealer’s HTML cards.
  • B – Following up, we have a similar <div id="play-wrap"> container for the player.
    • <span id='play-stand'> to indicate the player has decided to stand.
    • <span id='play-points'> for the current number of points the player has.
    • <div id="play-cards"> container to show the player’s HTML cards.
  • C – The bottom <div id="play-control"> is self-explanatory, containing the game controls.
    • <input id="playc-start"> starts the game.
    • <input id="playc-hit"> hits and draws a new card.
    • <input id="playc-stand"> stands.

Yep. That’s it for the game interface.

 

THE CSS

blackjack.css
/* (A) SHARED */
/* (A1) CONTAINERS */
#deal-wrap, #play-wrap {
  min-height: 120px;
}
#deal-data, #play-data {
  padding: 10px;
  color: #333;
}
#deal-stand, #play-stand {
  display: none;
  padding: 5px;
  background: #ab2323;
  color: #fff;
}
#deal-stand.stood, #play-stand.stood { display: inline-block; }
 
/* (A2) CARDS */
#deal-cards, #play-cards {
  display: grid;
  grid-template-columns: repeat(4, auto);
  grid-gap: 10px;
  padding: 10px;
}
.bj-card {
  box-sizing: border-box;
  font-size: 2em;
  text-align: center;
  padding: 10px;
  width: 100%;
  background: #fff;
  border: 1px solid #eaeaea;
}

/* (B) DEALER'S CARDS */
#deal-wrap { background: #e4f0ff; }
#deal-data { background: #d2e6ff; }
#deal-first .front { display: none; }
#deal-first.show .back { display: none; }
#deal-first.show .front { display: block; }

/* (C) PLAYER'S CARDS */
#play-wrap { background: #ffe7e7; }
#play-data { background: #f1caca; }

/* (D) PLAY CONTROLS */
#play-control {
  display: grid;
  grid-template-columns: 100%;
  grid-gap: 10px;
  padding: 10px;
  background: #eee;
}
#play-control input {
  box-sizing: border-box;
  cursor: pointer;
  border: 0;
  padding: 10px 0;
  background: #4381de;
  color: #fff;
  width: 100%;
}
#playc-hit, #playc-stand { display: none; }
#play-control.started { grid-template-columns: 50% 50%; }
#play-control.started #playc-start { display: none; }
#play-control.started #playc-hit, #play-control.started #playc-stand { display: block; }

Not going to explain the CSS line-by-line, but these are literally just some cosmetics to make the game look better. Feel free to change it however you like.

 

 

THE JAVASCRIPT

Let us now dive into the final and most complicated part of the project – The Javascript mechanics.

 

A) THE PROPERTIES

blackjack.js
var bj = {
  // (A) PROPERTIES
  // (A1) HTML REFERENCES
  hdstand : null, // dealer stand
  hdpoints : null, // dealer points
  hdhand : null, // dealer hand
  hpstand : null, // player stand
  hppoints : null, // player points
  hphand : null, // player hand
  hpcon : null, // player controls

  // (A2) GAME FLAGS
  deck : [], // The current deck of cards
  dealer : [], // The dealer's current hand
  player : [], // The player's current hand
  dpoints : 0, // The dealer's current points
  ppoints : 0, // The player's current points
  safety : 17, // Computer will stand on or past this point
  dstand : false, // Dealer has stood
  pstand : false, // Player has stood
  turn : 0, // Who's turn now? 0 for player, 1 for dealer (computer)
};

Captain Obvious to the rescue – For a start, all the Blackjack game mechanics will be contained within the var bj object. There are quite a lot of flags and properties here, but they are generally divided into 2 simple groups:

  • References to HTML elements.
  • Game flags and data.

They may not a lot of sense from the start, but just follow along and they will explain themselves.

 

B) INITIALIZE GAME

blackjack.js
var bj = {
  // (B) INITIALIZE GAME
  init : function () {
    // (B1) GET HTML ELEMENTS
    bj.hdstand = document.getElementById("deal-stand");
    bj.hdpoints = document.getElementById("deal-points");
    bj.hdhand = document.getElementById("deal-cards");
    bj.hpstand = document.getElementById("play-stand");
    bj.hppoints = document.getElementById("play-points");
    bj.hphand = document.getElementById("play-cards");
    bj.hpcon = document.getElementById("play-control");

    // (B2) ATTACH ONCLICK EVENTS
    document.getElementById("playc-start").addEventListener("click", bj.start);
    document.getElementById("playc-hit").addEventListener("click", bj.hit);
    document.getElementById("playc-stand").addEventListener("click", bj.stand);
  }
}
window.addEventListener("DOMContentLoaded", bj.init);

The init() function is the very first thing that runs when the page loads.  All we are doing here is to grab the necessary HTML elements into the “whole bunch of HTML properties” (section A1) above, and attaching onclick actions to the game buttons.

 

 

C) GAME START

blackjack.js
var bj = {
  // (C) START NEW GAME
  start : function () {
    // (C1) RESET POINTS, HANDS, AND DECK
    bj.deck = [];  bj.dealer = [];  bj.player = [];
    bj.dpoints = 0;  bj.ppoints = 0;
    bj.dstand = false;  bj.pstand = false;
    bj.hdpoints.innerHTML = "?"; bj.hppoints.innerHTML = 0;
    bj.hdhand.innerHTML = ""; bj.hphand.innerHTML = "";
    bj.hdstand.classList.remove("stood");
    bj.hpstand.classList.remove("stood");
    bj.hpcon.classList.add("started");

    // (C2) RESHUFFLE DECK
    // S: SHAPE (0 = HEART, 1 = DIAMOND, 2 = CLUB, 3 = SPADE)
    // N: NUMBER (1 = ACE, 2 TO 10 = AS-IT-IS, 11 = JACK, 12 = QUEEN, 13 = KING)
    for (let i=0; i<4; i++) { for (let j=1; j<14; j++) {
      bj.deck.push({s : i, n : j}); 
    }} 
    // CREDITS: 
    // https://medium.com/@nitinpatel_20236/how-to-shuffle-correctly-shuffle-an-array-in-javascript-15ea3f84bfb
    for (let i=bj.deck.length - 1; i>0; i--) {
      let j = Math.floor(Math.random() * i);
      let temp = bj.deck[i];
      bj.deck[i] = bj.deck[j];
      bj.deck[j] = temp;
    }

    // (C3) DRAW FIRST 4 CARDS
    bj.turn = 0; bj.draw(); bj.turn = 1; bj.draw(); 
    bj.turn = 0; bj.draw(); bj.turn = 1; bj.draw(); 
    
    // (C4) LUCKY 21 ON FIRST DRAW?
    bj.turn = 0; bj.points();
    bj.turn = 1; bj.points();
    var winner = bj.check(); 
    if (winner==null) { bj.turn = 0; }
  }
};

The start() function is where the game… starts.

  • This may seem to be pretty complicated at first, but all it does is essentially resetting the game flags and HTML game interface.
    • Empty the deck, dealer and player hands – bj.deck = []; bj.dealer = []; bj.player = [];
    • Reset the points – bj.dpoints = 0; bj.ppoints = 0;
    • Reset the “stand” flags – bj.dstand = false; bj.pstand = false;
    • Re-initialize the HTML game interface.
  • How we reshuffle the bj.deck array is to generate 52 “card objects” {s: SHAPE, n: NUMBER}, then randomly reorder them.
  • Finally, draw the first 2 cards for the dealer (computer) and player – Check if anyone got lucky with a Blackjack right from the start.

 

D) DRAW A CARD

blackjack.js
var bj = {
  // (D) DRAW A CARD FROM THE DECK
  dsymbols : ["&hearts;", "&diams;", "&clubs;", "&spades;"], // HTML symbols for cards
  dnum : { 1 : "A", 11 : "J", 12 : "Q", 13 : "K" }, // Card numbers
  draw : function () {
    // (D1) TAKE LAST CARD FROM DECK + CREATE HTML
    var card = bj.deck.pop(),
        cardh = document.createElement("div"),
        cardv = (bj.dnum[card.n] ? bj.dnum[card.n] : card.n) + bj.dsymbols[card.s];
    cardh.className = "bj-card";
    cardh.innerHTML = cardv ;
 
    // (D2) DEALER'S CARD
    // NOTE : HIDE FIRST DEALER CARD
    if (bj.turn) {
      if (bj.dealer.length==0) {
        cardh.id = "deal-first";
        cardh.innerHTML = `<div class="back">?</div><div class="front">${cardv}</div>`;
      }
      bj.dealer.push(card);
      bj.hdhand.appendChild(cardh);
    }
 
    // (D3) PLAYER'S CARD
    else {
      bj.player.push(card);
      bj.hphand.appendChild(cardh);
    }
  }
};

The blackjack.draw() function takes the last card from the deck, and gives it to either the dealer bj.dealer or player bj.player (depending on who’s bj.turn it is)… Of course, this will also update the HTML.

 

 

E) COUNT THE POINTS

blackjack.js
var bj = {
  // (E) CALCULATE AND UPDATE POINTS
  points : function () {
    // (E1) RUN THROUGH CARDS
    // TAKE CARDS 1-10 AT FACE VALUE + J, Q, K AT 10 POINTS.
    // DON'T CALCULATE ACES YET, THEY CAN EITHER BE 1 OR 11.
    var aces = 0, points = 0;
    for (let i of (bj.turn ? bj.dealer : bj.player)) {
      if (i.n == 1) { aces++; }
      else if (i.n>=11 && i.n<=13) { points += 10; }
      else { points += i.n; }
    }
    
    // (E2) CALCULATIONS FOR ACES
    // NOTE: FOR MULTIPLE ACES, WE CALCULATE ALL POSSIBLE POINTS AND TAKE HIGHEST.
    if (aces!=0) {
      var minmax = [];
      for (let elevens=0; elevens<=aces; elevens++) { let calc = points + (elevens * 11) + (aces-elevens * 1); minmax.push(calc); } points = minmax[0]; for (let i of minmax) { if (i > points && i <= 21) { points = i; }
      }
    }
    
    // (E3) UPDATE POINTS
    if (bj.turn) { bj.dpoints = points; }
    else {
      bj.ppoints = points;
      bj.hppoints.innerHTML = points;
    }
  }
};

The bj.points() function is used to calculate the points that the dealer or player has… Yep, special thanks to the ace, the Math here is a little funky. We start with a “base points” by adding up the following:

  • Points from cards 2-10 are added as-it-is.
  • Jack, Queen, and King are 10 points.

Remember that aces can either be 1 or 11 points? That’s where it gets hairy when there is an ace card in the hand.

  • We calculate the total number of aces in the hand.
  • Then Math happens. Basically, calculating all the possible points with let calc = points + (elevens * 11) + (aces-elevens * 1), and putting it in the array var minmax.
  • Finally, we try to pick the highest point from minmax that is less than or equals 21 as the “final”.

 

F) CHECK – WINNERS & LOSERS

blackjack.js
var bj = {
  // (F) CHECK FOR WINNERS (AND LOSERS)
  check : function () {
    // (F1) FLAGS
    // WINNER - 0 FOR PLAYER, 1 FOR DEALER, 2 FOR A TIE
    var winner = null, message = "";
    
    // (F2) BLACKJACK - WIN ON FIRST ROUND
    if (bj.player.length==2 && bj.dealer.length==2) {
      // TIE
      if (bj.ppoints==21 && bj.dpoints==21) {
        winner = 2; message = "It's a tie with Blackjacks";
      }
      // PLAYER WINS
      if (winner==null && bj.ppoints==21) {
        winner = 0; message = "Player wins with a Blackjack!";
      }
      // DEALER WINS
      if (winner==null && bj.dpoints==21) {
        winner = 1; message = "Dealer wins with a Blackjack!";
      }
    }
    
    // (F3) WHO GONE BUST?
    if (winner == null) {
      // PLAYER GONE BUST
      if (bj.ppoints>21) {
        winner = 1; message = "Player has gone bust - Dealer wins!";
      }
      // DEALER GONE BUST
      if (bj.dpoints>21) {
        winner = 0; message = "Dealer has gone bust - Player wins!";
      }
    }
    
    // (F4) POINTS CHECK - WHEN BOTH PLAYERS STAND
    if (winner == null && bj.dstand && bj.pstand) {
      // DEALER HAS MORE POINTS
      if (bj.dpoints > bj.ppoints) {
        winner = 1; message = "Dealer wins with " + bj.dpoints + " points!";
      }
      // PLAYER HAS MORE POINTS
      else if (bj.dpoints < bj.ppoints) {
        winner = 0; message = "Player wins with " + bj.ppoints + " points!";
      }
      // TIE
      else {
        winner = 2; message = "It's a tie.";
      }
    }

    // (F5) DO WE HAVE A WINNER?
    if (winner != null) {
      // SHOW DEALER HAND AND SCORE
      bj.hdpoints.innerHTML = bj.dpoints;
      document.getElementById("deal-first").classList.add("show");

      // RESET INTERFACE
      bj.hpcon.classList.remove("started");

      // WINNER IS...
      alert(message);
    }
    return winner;
  }
};

The bj.check() function is another of the rather confusing ones – It is called right at the start after drawing the first cards, it is called whenever a card is drawn, and it is also called whenever someone decides to stand. But what it does is straightforward, to check if anyone has won or lost –

  • Did anyone get Blackjack right from the start? Is it a draw with both players getting Blackjack?
  • Who has gone bust?
  • Both players decided to stand – Who has more points and who wins?
  • Finally, update the HTML if there is a result.

 

 

G) HIT

blackjack.js
var bj = {
  // (G) HIT A NEW CARD
  hit : function () {
    // (G1) DRAW A NEW CARD
    bj.draw(); bj.points();
    
     // (G2) AUTO-STAND ON 21 POINTS
    if (bj.turn==0 && bj.ppoints==21 && !bj.pstand) {
      bj.pstand = true; bj.hpstand.classList.add("stood");
    }
    if (bj.turn==1 && bj.dpoints==21 && !bj.dstand) {
      bj.dstand = true; bj.hdstand.classList.add("stood");
    }
    
    // (G3) CONTINUE GAME IF NO WINNER
    var winner = bj.check();
    if (winner==null) { bj.next(); }
  }
};

Well, self-explanatory – hit() is fired whenever the player or dealer decides to draw a card.

  • Draws a new card, update the points.
  • Auto-stand at 21 points.
  • Check if there is a winner, continue the game if not.

 

H) STAND

blackjack.js
var bj = {
  // (H) STAND
  stand : function () {
    // (H1) SET STAND STATUS
    if (bj.turn) {
      bj.dstand = true; bj.hdstand.classList.add("stood");
    } else {
      bj.pstand = true; bj.hpstand.classList.add("stood");
    }

    // (H2) END GAME OR KEEP GOING?
    var winner = (bj.pstand && bj.dstand) ? bj.check() : null ;
    if (winner==null) { bj.next(); }
  }
};

Another self-explanatory – stand() is called when the player or dealer decides to stand.

  • Updates the bj.pstand and bj.dstand flag accordingly.
  • Check if there is a winner.
  • Continue the game if not.

 

I) NEXT TURN

blackjack.js
var bj = {
    next : function () {
    // (I1) UP NEXT...
    bj.turn = bj.turn==0 ? 1 : 0 ;

    // (I2) DEALER IS NEXT
    if (bj.turn==1) { 
      if (bj.dstand) { bj.turn = 0; } // SKIP DEALER TURN IF STOOD
      else { bj.ai(); }
    }
    
    // (I2) PLAYER IS NEXT
    else {
      if (bj.pstand) { bj.turn = 1; bj.ai(); } // SKIP PLAYER TURN IF STOOD
    }
  }
};

This is kind of like a “helper function”, decides whose turn is next, and run the computer AI if it is the dealers turn.

 

I) THE NOT-SO-SMART AI

blackjack.js
var bj = {
  // (J) "SMART" COMPUTER MOVE
  ai : function () { if (bj.turn) {
    // (J1) STAND ON SAFETY LIMIT
    if (bj.dpoints >= bj.safety) { bj.stand(); }

    // (J2) ELSE DRAW ANOTHER CARD
    else { bj.hit(); }
  }}
};

Probably the dumbest computer AI you have seen. Simply hits if the dealer points are below the set bj.safety and stand otherwise.

 

USEFUL BITS & LINKS

That’s all for this project, and here is a small section on some extras and links that may be useful to you.

 

LINKS & REFERENCES

 

THE END

Thank you for reading, and we have come to the end of this guide. I hope that it has helped you to better understand, and if you want to share anything with this guide, please feel free to comment below. Good luck and happy coding!

Leave a Comment

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