Episode 13 of the Coder's Block podcast out now
How To Code Blackjack Using JavaScript

Today I will be building a small BlackJack game in pure JavaScript in the hopes that you out there reading this can use it as a frame to build something much bigger. And if you're a beginner in the programming world, than perhaps this tutorial will help you get a much better idea of how function, objects and DOM manipulation works in JS.

While the following post won't be using any incredibly advanced topics in JavaScript, it is rather involved in what needs to go into a Blackjack game. I recommend the following book Web Design with HTML, CSS, JavaScript and jQuery for anybody that's somewhat relatively new to JavaScript and web development in general.

Separating the UI

In order to modularize the code more, I will be splitting each function into 2 parts. One will deal with data manipulation and logic, and the other will perform the UI functions, such as drawing the cards onto the screen and such.

BlackJack game rules

Most people should be familiar with the concept of the game BlackJack. But if not, here is a quick overview. Essentially, players are dealt a starting hand of 2 cards with the hopes of getting to the magical number of 21, or to get as close to 21 as possible. If a player gets 21 on his initial hand, it is called a "blackjack" or a "natural". The player wins, unless the house reaches blackjack as well. The other ways to win are to hold a higher sum of cards at the end of the play than the house, or to have the house go over 21.

The game area

How To Code Black Jack Using JavaScript

I'm going to be making as simple a game board as I can think of, in order to avoid an excessive amount of UI rendering code and such. And to keep everything focused on the logic as much as I can.


<div class="game">
    <h1>Blackjack</h1>
    <input type="button" class="btn" value="start" onclick="start()" />
    <input type="button" class="btn" value="hit me" onclick="hitMe()" />
    <input type="button" class="btn" value="stay" onclick="stay()" />

    <div id="players" class="players">
    </div>

    <div id="deck" class="deck">
        <div class="card" id="deckcount">52</div>
        <div class="status" id="status"></div>
    </div>

    <div class="clear"></div>
</div>

Build your deck

The first thing we're going to need in order to make our card game, are cards. And if you don't know how to make them, feel free to check out my post on that process. But essentially, we'll be making a Deck array with 52 Card objects.


    var suits = ["Spades", "Hearts", "Diamonds", "Clubs"];
    var values = ["2", "3", "4", "5", "6", "7", "8", "9", "10", "J", "Q", "K", "A"];
    var deck = new Array();

    function createDeck()
    {
        deck = new Array();
        for (var i = 0 ; i < values.length; i++)
        {
            for(var x = 0; x < suits.length; x++)
            {
                var weight = parseInt(values[i]);
                if (values[i] == "J" || values[i] == "Q" || values[i] == "K")
                    weight = 10;
                if (values[i] == "A")
                    weight = 11;
                var card = { Value: values[i], Suit: suits[x], Weight: weight };
                deck.push(card);
            }
        }
    }

The beauty of the Array is that it is stack by its nature. So we can pop cards off the top with the built in Array pop() method.

Shuffle

A very quick shuffle algorithm.


    function shuffle()
    {
        // for 1000 turns
        // switch the values of two random cards
        for (var i = 0; i < 1000; i++)
        {
            var location1 = Math.floor((Math.random() * deck.length));
            var location2 = Math.floor((Math.random() * deck.length));
            var tmp = deck[location1];

            deck[location1] = deck[location2];
            deck[location2] = tmp;
        }
    }

Create the players

For this example, I'll be working with 2 players only. The "House" and yourself. There are a few things that we'll want to keep track of for each player, such as an "Id" and their current "Score". An array for the players current Hand will also be added on to the player object.


    var players = new Array();
    function createPlayers(num)
    {
        players = new Array();
        for(var i = 1; i <= num; i++)
        {
            var hand = new Array();
            var player = { Name: 'Player ' + i, ID: i, Points: 0, Hand: hand };
            players.push(player);
        }
    }

That was the logic portion. And next up is the UI portion


        function createPlayersUI()
        {
            document.getElementById('players').innerHTML = '';
            for(var i = 0; i < players.length; i++)
            {
                var div_player = document.createElement('div');
                var div_playerid = document.createElement('div');
                var div_hand = document.createElement('div');
                var div_points = document.createElement('div');

                div_points.className = 'points';
                div_points.id = 'points_' + i;
                div_player.id = 'player_' + i;
                div_player.className = 'player';
                div_hand.id = 'hand_' + i;

                div_playerid.innerHTML = players[i].ID;
                div_player.appendChild(div_playerid);
                div_player.appendChild(div_hand);
                div_player.appendChild(div_points);
                document.getElementById('players').appendChild(div_player);
            }
        }

Deal the hand

Now we're ready to start the game. As mentioned above, the game starts with a quick shuffle. And then the hands are dealt.


    function dealHands()
    {
        // alternate handing cards to each player
        // 2 cards each
        for(var i = 0; i < 2; i++)
        {
            for (var x = 0; x < players.length; x++)
            {
                var card = deck.pop();
                players[x].Hand.push(card);
                renderCard(card, x);
                updatePoints();
            }
        }

        updateDeck();
    }

We'll be using the handy pop() method for this one, which returns to us the top most item in the stack. We'll push the cards to each players hands and then render the cards.

Render the cards

This is the UI portion of card dealing. Once a card is dealt to a particular it will need to be added to their 'hand'.


    function renderCard(card, player)
    {
        var hand = document.getElementById('hand_' + player);
        hand.appendChild(getCardUI(card));
    }

    function getCardUI(card)
    {
        var el = document.createElement('div');
        el.className = 'card';
        el.innerHTML = card.Suit + ' ' + card.Value;
        return el;
    }

Hit me

Now we're ready to start the game. This will pop a Card right out of our stack and will sum the Card value to the current users Total score.


    var currentPlayer = 0;
    function hitMe()
    {
        // pop a card from the deck to the current player
        // check if current player new points are over 21
        var card = deck.pop();
        players[currentPlayer].Hand.push(card);
        renderCard(card, currentPlayer);
        updatePoints();
        check();
    }

    function check()
    {
        if (players[currentPlayer].Points > 21)
        {
            document.getElementById('status').innerHTML = 'Player: ' + players[currentPlayer].ID + ' LOST';
        }
    }

The check() method will run after each card is dealt in order to determine if the player has lost the game.

Stay

If a player chooses to keep his hand, then the stay method will check if there are any more players in action, and if so, will transfer control over to them by updating the currentPlayer variable. If however, there are no players left, then the end method is called and points will be tallied up.


    function stay()
    {
        // move on to next player, if any
        if (currentPlayer != players.length-1) {
            document.getElementById('player_' + currentPlayer).classList.remove('active');
            currentPlayer += 1;
            document.getElementById('player_' + currentPlayer).classList.add('active');
        }

        else {
            end();
        }
    }

    function end()
    {
        var winner = -1;
        var score = 0;

        for(var i = 0; i < players.length; i++)
        {
            if (players[i].Points > score && players[i].Points < 22)
            {
                winner = i;
            }

            score = players[i].Points;
        }

        document.getElementById('status').innerHTML = 'Winner: Player ' + players[winner].ID;
    }

A winner?

And as the game is so aptly titled, ye who gets closer to 21 without going over will be the victor. The gameplay logic itself is very straightforward and no more than a hundred lines of code. UI however is another story, which is why I broke the code up into elements of both. Feel free to keep the logic and update the UI to your liking. Down below is the game in action. Again, it's a very rudimentary example, but it gives a general idea of how a few method calls and objects can make for a quick card game.

In Action

Blackjack

52
Full Source

<html>
<head>
<script type="text/javascript">
        var suits = ["Spades", "Hearts", "Diamonds", "Clubs"];
        var values = ["2", "3", "4", "5", "6", "7", "8", "9", "10", "J", "Q", "K", "A"];
        var deck = new Array();
        var players = new Array();
        var currentPlayer = 0;

        function createDeck()
        {
            deck = new Array();
            for (var i = 0 ; i < values.length; i++)
            {
                for(var x = 0; x < suits.length; x++)
                {
                    var weight = parseInt(values[i]);
                    if (values[i] == "J" || values[i] == "Q" || values[i] == "K")
                        weight = 10;
                    if (values[i] == "A")
                        weight = 11;
                    var card = { Value: values[i], Suit: suits[x], Weight: weight };
                    deck.push(card);
                }
            }
        }

        function createPlayers(num)
        {
            players = new Array();
            for(var i = 1; i <= num; i++)
            {
                var hand = new Array();
                var player = { Name: 'Player ' + i, ID: i, Points: 0, Hand: hand };
                players.push(player);
            }
        }

        function createPlayersUI()
        {
            document.getElementById('players').innerHTML = '';
            for(var i = 0; i < players.length; i++)
            {
                var div_player = document.createElement('div');
                var div_playerid = document.createElement('div');
                var div_hand = document.createElement('div');
                var div_points = document.createElement('div');

                div_points.className = 'points';
                div_points.id = 'points_' + i;
                div_player.id = 'player_' + i;
                div_player.className = 'player';
                div_hand.id = 'hand_' + i;

                div_playerid.innerHTML = players[i].ID;
                div_player.appendChild(div_playerid);
                div_player.appendChild(div_hand);
                div_player.appendChild(div_points);
                document.getElementById('players').appendChild(div_player);
            }
        }

        function shuffle()
        {
            // for 1000 turns
            // switch the values of two random cards
            for (var i = 0; i < 1000; i++)
            {
                var location1 = Math.floor((Math.random() * deck.length));
                var location2 = Math.floor((Math.random() * deck.length));
                var tmp = deck[location1];

                deck[location1] = deck[location2];
                deck[location2] = tmp;
            }
        }

        function start()
        {
            // deal 2 cards to every player object
            currentPlayer = 0;
            createDeck();
            shuffle();
            createPlayers(2);
            createPlayersUI();
            dealHands();
            document.getElementById('player_' + currentPlayer).classList.add('active');
        }

        function dealHands()
        {
            // alternate handing cards to each player
            // 2 cards each
            for(var i = 0; i < 2; i++)
            {
                for (var x = 0; x < players.length; x++)
                {
                    var card = deck.pop();
                    players[x].Hand.push(card);
                    renderCard(card, x);
                    updatePoints();
                }
            }

            updateDeck();
        }

        function renderCard(card, player)
        {
            var hand = document.getElementById('hand_' + player);
            hand.appendChild(getCardUI(card));
        }

        function getCardUI(card)
        {
            var el = document.createElement('div');
            el.className = 'card';
            el.innerHTML = card.Suit + ' ' + card.Value;
            return el;
        }

        // returns the number of points that a player has in hand
        function getPoints(player)
        {
            var points = 0;
            for(var i = 0; i < players[player].Hand.length; i++)
            {
                points += players[player].Hand[i].Weight;
            }
            players[player].Points = points;
            return points;
        }

        function updatePoints()
        {
            for (var i = 0 ; i < players.length; i++)
            {
                getPoints(i);
                document.getElementById('points_' + i).innerHTML = players[i].Points;
            }
        }

        function hitMe()
        {
            // pop a card from the deck to the current player
            // check if current player new points are over 21
            var card = deck.pop();
            players[currentPlayer].Hand.push(card);
            renderCard(card, currentPlayer);
            updatePoints();
            updateDeck();
            check();
        }

        function stay()
        {
            // move on to next player, if any
            if (currentPlayer != players.length-1) {
                document.getElementById('player_' + currentPlayer).classList.remove('active');
                currentPlayer += 1;
                document.getElementById('player_' + currentPlayer).classList.add('active');
            }

            else {
                end();
            }
        }

        function end()
        {
            var winner = -1;
            var score = 0;

            for(var i = 0; i < players.length; i++)
            {
                if (players[i].Points > score && players[i].Points < 22)
                {
                    winner = i;
                }

                score = players[i].Points;
            }

            document.getElementById('status').innerHTML = 'Winner: Player ' + players[winner].ID;
        }

        function check()
        {
            if (players[currentPlayer].Points > 21)
            {
                document.getElementById('status').innerHTML = 'Player: ' + players[currentPlayer].ID + ' LOST';
            }
        }

        function updateDeck()
        {
            document.getElementById('deckcount').innerHTML = deck.length;
        }

        window.addEventListener('load', function(){
            createDeck();
            shuffle();
            createPlayers(1);
        });
    </script>

    <style>
        .game
        {
            width: 720px;
            border: solid 1px #ddd;
            margin: 0 auto;
            padding: 30px;
        }

        .card{
            width: 70px;
            height: 100px;
            padding: 10px;
            border: solid 1px #808080;
            background-color: white;
            display: inline-block;
            border-radius: 10px;
            font-size: 8pt;
            text-align: center;
            margin: 3px;
        }

        .players{
            float:left;
            width: 500px;
        }

        .player{
            width: 40%;
            border: solid 2px #ccc;
            border-radius: 10px;
            padding: 10px;
            display: inline-block;
            margin:1%;
            vertical-align: top;
        }

        .player.active{
            border: solid 2px #1caff6;
        }

        .points{
            text-align: center;
            font-size: 20pt;
            font-weight: bold;
            margin: 10px;
        }

        .deck{
            float:right;
            width: 200px;
        }
    </style>
</head>

<body>
<div class="game">
        <h1>Blackjack</h1>
        <input type="button" class="btn" value="start" onclick="start()" />
        <input type="button" class="btn" value="hit me" onclick="hitMe()" />
        <input type="button" class="btn" value="stay" onclick="stay()" />

        <div id="players" class="players">
        </div>

        <div id="deck" class="deck">
            <div class="card" id="deckcount">52</div>
            <div class="status" id="status"></div>
        </div>

        <div class="clear"></div>
    </div>
</body>
</html>

Have a question?

j
jess
Hello, Thank you for the explanation however; this code does not work. I cannot even see it in action on your page. Can you please help me?
11/16/2017 10:19:51 PM
Walt
Hey there. Seems to work for me! Sent you a message!
11/17/2017 7:13:49 AM
M
Mark
Is there anyway to make the second player the dealer? I've tried to create a dealer instead of a second player and now I nothing is working. Would greatly appreciate some help because your game is awesome.
12/16/2017 6:16:39 PM
Walt
Hey Mark, thanks for the comment! I would say that you can handle the dealer role automatically if you update the following function:

    function stay()
        {
            // move on to next player, if any
            if (currentPlayer != players.length-1) {
                document.getElementById('player_' + currentPlayer).classList.remove('active');
                currentPlayer += 1;
                document.getElementById('player_' + currentPlayer).classList.add('active');
            }

            else {
                end();
            }
        }

So once a player decides to "stay" and we check for the last player, if it is indeed the last player, then we can maybe do something like the following: * Have "hitme()" return true or fall. Whether the player lost or not * and in a loop, call hitme() until the player loses pretty much There are only 2 small changes you need to make. Have the "check()" function return true or false Have the hitme function stop once a false is detected.

function check()
        {
            if (players[currentPlayer].Points > 21)
            {
                document.getElementById('status').innerHTML = 'Player: ' + players[currentPlayer].ID + ' LOST';
                return false;
            }

            return true;
        }

And then essentially, for the dealer turn do something like the following:

while (hitme())
{
}

It's essentially an infinite loop, until the check() function return false. Hope that helps!
12/22/2017 8:11:31 PM
J
John
It keeps giving me unexpected identifier at line 12...
4/5/2018 12:38:00 PM
J
John
To clarify that's this code: "if (values[i] == "J" || values[i] == "Q" || values[i] == "K") {" I put them in seperate files :)
4/5/2018 12:39:25 PM
Hey Walt, nice game! I was dealt two aces and automatically lost because I wasn't able to split the aces. I'm fairly new to JS, but this might be a nice challenge to try to push my skills. I'll send it your way if I get it.
4/28/2018 9:34:44 AM
Walt
Hey there Michael, many thanks for the words. And I did not think of that use case! haha. For sure send it on over if you do!
4/29/2018 10:11:21 AM
R
Raisa Shafiyyullah
Hi, nice tutorial! Thanks!
5/14/2018 9:54:21 PM

Add a comment

"sometimes you have to delete, to find your answer"
Copyright © 2018 thatsoftwaredude.com
humans.txt
Start
Score: 0
snake left
snake up
snake down
snake right