Simple Vanilla Javascript Blackjack (Free 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
Javascript Useful Bits & Links The End

 

DOWNLOAD & DEMO

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

 

QUICK NOTES

If you spot a bug, feel free to comment below. I try to answer short 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.

 

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.

 

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.

 

 

THE HTML

That’s it for the simplified rules, let us now start with building the HTML game page.

 

BLACKJACK HTML PAGE

blackjack.html
<!-- (A) DEALER -->
<!-- (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>
 
<!-- (B) PLAYER'S CARDS -->
<!-- (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>
 
<!-- (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:

  1. 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.
  2. 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.
  3. <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.

 

 

THE JAVASCRIPT

Next, for the 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 : [],      // current deck of cards
  dealer : [],    // dealer's current hand
  player : [],    // player's current hand
  dpoints : 0,    // dealer's current points
  ppoints : 0,    // 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)
};

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
// (B) INITIALIZE GAME
init : () => {
  // (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").onclick = bj.start;
  document.getElementById("playc-hit").onclick = bj.hit;
  document.getElementById("playc-stand").onclick = bj.stand;
}
window.addEventListener("DOMContentLoaded", bj.init);

bj.init() 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 attach onclick actions to the game buttons.

 

 

C) GAME START

blackjack.js
// (C) START NEW GAME
start : () => {
  // (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; }
}

bj.start() is where the game… starts.

  • This may seem to be pretty complicated at first, but all it does is essentially reset 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
// (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 : () => {
  // (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);
  }
}

bj.draw() 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
// (E) CALCULATE AND UPDATE POINTS
points : () => {
  // (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 “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
// (F) CHECK FOR WINNERS (AND LOSERS)
check : () => {
  // (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
// (G) HIT A NEW CARD
hit : () => {
  // (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 – bj.hit() is fired whenever the player or dealer decides to draw a card.

  • Draw 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
// (H) STAND
stand : () => {
  // (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 – bj.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
next : () => {
  // (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”, which decides whose turn is next, and runs the computer AI if it is the dealer’s turn.

 

J) THE NOT-SO-SMART AI

blackjack.js
// (J) "SMART" COMPUTER MOVE
ai : () => { 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.

 

COMPATIBILITY CHECKS

Does not use a lot of advanced features, this game will work on most modern browsers.

 

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.