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!
TABLE OF CONTENTS
THE GAME RULES & DEMO
Before we go into the code, let us start with the game rules and a demo. For you guys who already know how to play Blackjack, please feel free to skip this section.
JAVASCRIPT BLACKJACK DEMO
HOW TO PLAY
The “full version” rules of Blackjack can be pretty long-winded, so let us adopt a simplified version for this project:
- There will be a deck of 52 cards and 2 players (computer vs player).
- The goal of Black Jack is to get as close to 21 points as possible. Any player that goes past 21 loses the game.
- 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.
- 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.
- The player only has to choose between 2 actions – “Hit” (get another card) and “Stand” (done, compare points with the dealer).
- 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.
JAVASCRIPT BLACKJACK
That’s it for the simplified rules, let us now get into the details of the Javascript Blackjack.
PART 1) BLACKJACK HTML PAGE
<!-- (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:
- 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.
- 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.
<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.
PART 2) THE JAVASCRIPT
2A) GAME PROPERTIES
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.
2B) INITIALIZE GAME
// (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.
2C) GAME START
// (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.
- Empty the deck, dealer, and player hands –
- 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.
2D) DRAW A CARD
// (D) DRAW A CARD FROM THE DECK
dsymbols : ["♥", "♦", "♣", "♠"], // 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.
2E) COUNT THE POINTS
// (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 arrayvar minmax
. - Finally, we try to pick the highest point from
minmax
that is less than or equals 21 as the “final”.
2F) CHECK – WINNERS & LOSERS
// (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.
2G) HIT
// (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.
2H) STAND
// (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
andbj.dstand
flag accordingly. - Check if there is a winner.
- Continue the game if not.
2I) NEXT TURN
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.
2J) THE NOT-SO-SMART AI
// (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.
DOWNLOAD & NOTES
Here is the download link to the example code, so you don’t have to copy-paste everything.
SORRY FOR THE ADS...
But someone has to pay the bills, and sponsors are paying for it. I insist on not turning Code Boxx into a "paid scripts" business, and I don't "block people with Adblock". Every little bit of support helps.
Buy Me A Coffee Code Boxx eBooks
EXAMPLE CODE DOWNLOAD
Click here for the source code on GitHub gist, just click on “download zip” or do a git clone. I have released it under the MIT license, so feel free to build on top of it or use it in your own project.
EXTRA 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
- Arrow Function – CanIUse
Does not use a lot of advanced features, and this game will work on most modern browsers.
LINKS & REFERENCES
- BlackJack Application with JavaScript – Hackernoon
- Making a Simple Blackjack Game With HTML and JavaScript – Iadon Hatch
- Javascript BlackJack – Code Boxx
- Javascript MineSweeper – Code Boxx
- Javascript Hangman – Code Boxx
- Javascript Quiz – Code Boxx
- Javascript Memory Game – Code Boxx
- Javascript Number Guessing Game – Code Boxx
- Javascript Tic-Tac-Toe – Code Boxx
- Javascript Rock Paper Scissors Game – Code Boxx
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!