javascriptlogicgame-developmentblackjackgambling

BlackJack Wager System Error - Programmed a web-based game done in HTML, JavaScript, and CSS. Logic issue in JavaScript


I tried to make a very simple Blackjack game only using HTML, JavaScript, and CSS in Visual Studio Code, but I'm pretty sure you can use any code editor or IDE that allows you to make those files and run them from a single folder for a working program. Obviously, all the logic and card set-up is done in JS. I've built a wager system that seems to work fine, but there are issues with it. For the sake of the problem, I suggest learning the rules of the game beforehand. I haven't implemented the splitting pairs, doubling down, insurance, and many more parts of the game yet because I need to get the current issue fixed first before I move on to anything else.

General synopsis of how the game should go: The account balance will start at $1,000 and I have the freedom to bet any amount, in this case I will bet $100. Once after placing the bet, the game will display the dealer's cards and my cards with a hand value total with the updated balance at the top ($900). If I win, the balance must be $1,100 ($1,150 if Blackjack). If I lose, my balance should stay at $900.

However, my game gains the wagered amount whenever I lose and it doesn't do the 1.5x Blackjack feature correctly. Here is the entire JS file:

var deck, playerHand, dealerHand;
var balance = 1000;
var currentWager = 0;
var balanceBeforeWager = 1000;

var suitsSymbols = {
    'Hearts': '♥',
    'Diamonds': '♦',
    'Clubs': '♣',
    'Spades': '♠'
};

var ranksSymbols = {
    '2': '2', '3': '3', '4': '4', '5': '5', '6': '6', '7': '7', '8': '8', '9': '9', '10': '10',
    'Jack': 'J', 'Queen': 'Q', 'King': 'K', 'Ace': 'A'
};

var values = {
    '2': 2, '3': 3, '4': 4, '5': 5, '6': 6, '7': 7, '8': 8, '9': 9, '10': 10,
    'Jack': 10, 'Queen': 10, 'King': 10, 'Ace': 11
};

document.getElementById('hit-button').addEventListener('click', hit);
document.getElementById('stand-button').addEventListener('click', stand);
document.getElementById('place-wager-button').addEventListener('click', placeWager);

function createDeck() {
    deck = [];
    for (var suit in suitsSymbols) {
        for (var rank in ranksSymbols) {
            deck.push({rank, suit});
        }
    }
    shuffleDeck(deck);
}

function shuffleDeck(deck) {
    for (var i = deck.length - 1; i > 0; i--) {
        var j = Math.floor(Math.random() * (i + 1));
        [deck[i], deck[j]] = [deck[j], deck[i]];
    }
}

function getCardDisplay(card) {
    var rank = ranksSymbols[card.rank];
    var suit = suitsSymbols[card.suit];

    return `
 ____________
|${rank.padEnd(2, ' ')}         |
|${suit}          |
|           |
|      ${suit}    |
|           |
|          ${suit}|
|_________${rank.padStart(2, ' ')}|`
}

function startGame() {
    document.getElementById('new-game-button').style.display = 'none';
    createDeck();
    document.getElementById('hit-button').disabled = true;
    document.getElementById('stand-button').disabled = true;
    clearHands();
    updateBalanceDisplay();
}

function clearHands() {
    document.getElementById('player-cards').innerHTML = '';
    document.getElementById('dealer-cards').innerHTML = '';
    document.getElementById('player-total').textContent = 'Total: 0';
    document.getElementById('dealer-total').textContent = 'Total: ?';
}

function dealCards() {
    playerHand = [deck.pop(), deck.pop()];
    dealerHand = [deck.pop(), deck.pop()];

    document.getElementById('hit-button').disabled = false;
    document.getElementById('stand-button').disabled = false;

    updateHands();
    checkForBlackjack();
}

function updateHands() {
    var playerCardsElement = document.getElementById('player-cards');
    var dealerCardsElement = document.getElementById('dealer-cards');

    playerCardsElement.innerHTML = '';
    dealerCardsElement.innerHTML = '';

    playerHand.forEach(card => {
        var cardDisplay = document.createElement('pre');
        cardDisplay.className = 'card';
        cardDisplay.textContent = getCardDisplay(card);
        playerCardsElement.appendChild(cardDisplay);
    });

    dealerHand.forEach((card, index) => {
        var cardDisplay = document.createElement('pre');
        cardDisplay.className = 'card';
        if (index === 0 && !document.getElementById('hit-button').disabled) {
            cardDisplay.textContent = `
 ____________
|Hidden      |
|            |
|            |
|            |
|            |
|            |
|____________|`;
        } else {
            cardDisplay.textContent = getCardDisplay(card);
        }
        dealerCardsElement.appendChild(cardDisplay);
    });

    document.getElementById('player-total').textContent = `Total: ${calculateHandValue(playerHand)}`;
    document.getElementById('dealer-total').textContent = document.getElementById('hit-button').disabled ?
        `Total: ${calculateHandValue(dealerHand)}` : 'Total: ?';

    updateBalanceDisplay();
}

function checkForBlackjack() {
    var playerValue = calculateHandValue(playerHand);
    var dealerValue = calculateHandValue(dealerHand);

    if (playerValue === 21) {
        endGame('Blackjack! You win 1.5x your wager.');
    } else if (dealerValue === 21) {
        endGame('Dealer has Blackjack. You lose.');
    }
}

function hit() {
    playerHand.push(deck.pop());
    updateHands();

    if (calculateHandValue(playerHand) > 21) {
        endGame('You bust! Dealer wins.');
    }
}

function stand() {
    document.getElementById('hit-button').disabled = true;
    document.getElementById('stand-button').disabled = true;

    dealerTurn();
}

function dealerTurn() {
    while (calculateHandValue(dealerHand) < 17) {
        dealerHand.push(deck.pop());
        updateHands();
    }

    if (calculateHandValue(dealerHand) > 21) {
        endGame('Dealer busts! You win!');
    } else {
        compareHands();
    }
}

function compareHands() {
    var playerValue = calculateHandValue(playerHand);
    var dealerValue = calculateHandValue(dealerHand);

    if (playerValue > dealerValue) {
        endGame('You win!');
    } else if (playerValue < dealerValue) {
        endGame('Dealer wins.');
    } else {
        endGame("It's a tie!");
    }
}

function calculateHandValue(hand) {
    var value = 0;
    var numAces = 0;

    for (var card of hand) {
        value += values[card.rank];
        if (card.rank === 'Ace') {
            numAces += 1;
        }
    }

    while (value > 21 && numAces > 0) {
        value -= 10;
        numAces -= 1;
    }

    return value;
}

function endGame(message) {
    document.getElementById('hit-button').disabled = true;
    document.getElementById('stand-button').disabled = true;
    document.getElementById('message').textContent = message;

    if (message.includes('win')) {
        if (message.includes('Blackjack')) {
            balance = balanceBeforeWager + currentWager * 2.5;
        } else {
            balance = balanceBeforeWager + currentWager * 2;
        }
    } else if (message.includes('tie')) {
        balance = balanceBeforeWager;
    }

    currentWager = 0;
    updateHands();

    document.getElementById('new-game-button').style.display = 'inline-block';
    document.getElementById('place-wager-button').disabled = false;
    document.getElementById('wager-input').disabled = false;
}

function placeWager() {
    var wagerInput = document.getElementById('wager-input');
    var wagerAmount = parseInt(wagerInput.value, 10);

    if (isNaN(wagerAmount) || wagerAmount <= 0) {
        alert('Please enter a valid wager amount.');
        return;
    }

    if (wagerAmount > balance) {
        alert('Not enough balance!');
        return;
    }

    currentWager = wagerAmount;
    balanceBeforeWager = balance;
    balance -= currentWager; 
    wagerInput.value = ''; 

    document.getElementById('message').textContent = `Wager placed: $${currentWager}`;

    document.getElementById('place-wager-button').disabled = true;
    document.getElementById('wager-input').disabled = true;

    dealCards(); 
    updateBalanceDisplay();
}

document.getElementById('new-game-button').addEventListener('click', function() {
    startGame(); 
    document.getElementById('message').textContent = ''; 
});

function updateBalanceDisplay() {
    document.getElementById('balance').textContent = balance;
}

window.onload = function() {
    updateBalanceDisplay();
    startGame(); 
};

These may not be important, but here are the HTML and CSS file if you'd like to test out the program on your own:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Blackjack Game</title>
    <link rel="stylesheet" href="style.css">
</head>
<body>
    <div class="game-container">
        <h1>Blackjack</h1>
        
        <div class="balance">
            <h2>Balance: $<span id="balance">1000</span></h2>
        </div>

        <div class="wager">
            <h2>Place Your Wager</h2>
            <input type="number" id="wager-input" min="1" max="1000" step="1" placeholder="Enter wager amount">
            <button id="place-wager-button">Place Wager</button>
        </div>

        <div id="dealer-hand" class="hand">
            <h2>Dealer's Hand</h2>
            <div id="dealer-cards" class="cards"></div>
            <p id="dealer-total"></p>
        </div>

        <div id="player-hand" class="hand">
            <h2>Your Hand</h2>
            <div id="player-cards" class="cards"></div>
            <p id="player-total"></p>
        </div>

        <div class="controls">
            <button id="hit-button">Hit</button>
            <button id="stand-button">Stand</button>
            <button id="new-game-button">New Game</button>
        </div>

        <p id="message"></p>
    </div>

    <script src="script.js"></script>
</body>
</html>

body {
    font-family: Arial, sans-serif;
    background-color: #2c3e50;
    color: #ecf0f1;
    display: flex;
    justify-content: center;
    align-items: center;
    height: 100vh;
    margin: 0;
}

.game-container {
    text-align: center;
    background-color: #34495e;
    padding: 20px;
    border-radius: 10px;
    width: 400px;
}

.balance, .wager {
    margin-bottom: 20px;
}

.wager input {
    padding: 10px;
    border: 1px solid #7f8c8d;
    border-radius: 5px;
    margin-right: 10px;
    width: 100px;
}

.wager button {
    padding: 10px;
    background-color: #3498db;
    color: #ecf0f1;
    border: none;
    border-radius: 5px;
    cursor: pointer;
}

.wager button:hover {
    background-color: #2980b9;
}

.hand {
    margin-bottom: 20px;
}

.cards {
    display: flex;
    justify-content: center;
    margin: 10px 0;
    flex-wrap: wrap;
}

.card {
    font-family: "Courier New", Courier, monospace;
    background-color: #ecf0f1;
    color: #2c3e50;
    border: 1px solid #7f8c8d;
    padding: 10px;
    margin: 5px;
    border-radius: 5px;
    white-space: pre;
    text-align: left;
    line-height: 1.2;
}

button {
    padding: 10px;
    background-color: #e74c3c;
    color: #ecf0f1;
    border: none;
    border-radius: 5px;
    margin: 5px;
    cursor: pointer;
}

button:disabled {
    background-color: #95a5a6;
}

button:hover:not(:disabled) {
    background-color: #c0392b;
}

#message {
    font-size: 18px;
    margin-top: 20px;
}

I've tried tweaking function updateHands() function endGame, function placeWager(), and many more logic lines within the code but the program still adds more cash to the balance even after I lose a bet. The balance does get updated when I bet $100 (from $1,000 initial to $900 throughout the game) but it adds my bet to my balance even when I lose ($1,100).

I appreciate all the help in advance, and if there are any more things that I should add, please let me know as I want to make a really great, but simple, Blackjack program. Thanks!


Solution

  • Fixed.

    In the endGame function, you check if the message contains the word 'win'. But also 'Dealer wins' contains 'win'. :-)

    Now it checks for 'You win' but this is sloppy code. I would rewrite endGame, adding another parameter that unambiguosly indicates who won or a tie.

    var deck, playerHand, dealerHand;
    var balance = 1000;
    var currentWager = 0;
    var balanceBeforeWager = 1000;
    
    var suitsSymbols = {
        'Hearts': '♥',
        'Diamonds': '♦',
        'Clubs': '♣',
        'Spades': '♠'
    };
    
    var ranksSymbols = {
        '2': '2', '3': '3', '4': '4', '5': '5', '6': '6', '7': '7', '8': '8', '9': '9', '10': '10',
        'Jack': 'J', 'Queen': 'Q', 'King': 'K', 'Ace': 'A'
    };
    
    var values = {
        '2': 2, '3': 3, '4': 4, '5': 5, '6': 6, '7': 7, '8': 8, '9': 9, '10': 10,
        'Jack': 10, 'Queen': 10, 'King': 10, 'Ace': 11
    };
    
    document.getElementById('hit-button').addEventListener('click', hit);
    document.getElementById('stand-button').addEventListener('click', stand);
    document.getElementById('place-wager-button').addEventListener('click', placeWager);
    
    function createDeck() {
        deck = [];
        for (var suit in suitsSymbols) {
            for (var rank in ranksSymbols) {
                deck.push({rank, suit});
            }
        }
        shuffleDeck(deck);
    }
    
    function shuffleDeck(deck) {
        for (var i = deck.length - 1; i > 0; i--) {
            var j = Math.floor(Math.random() * (i + 1));
            [deck[i], deck[j]] = [deck[j], deck[i]];
        }
    }
    
    function getCardDisplay(card) {
        var rank = ranksSymbols[card.rank];
        var suit = suitsSymbols[card.suit];
    
        return `
     ____________
    |${rank.padEnd(2, ' ')}         |
    |${suit}          |
    |           |
    |      ${suit}    |
    |           |
    |          ${suit}|
    |_________${rank.padStart(2, ' ')}|`
    }
    
    function startGame() {
        document.getElementById('new-game-button').style.display = 'none';
        createDeck();
        document.getElementById('hit-button').disabled = true;
        document.getElementById('stand-button').disabled = true;
        clearHands();
        updateBalanceDisplay();
    }
    
    function clearHands() {
        document.getElementById('player-cards').innerHTML = '';
        document.getElementById('dealer-cards').innerHTML = '';
        document.getElementById('player-total').textContent = 'Total: 0';
        document.getElementById('dealer-total').textContent = 'Total: ?';
    }
    
    function dealCards() {
        playerHand = [deck.pop(), deck.pop()];
        dealerHand = [deck.pop(), deck.pop()];
    
        document.getElementById('hit-button').disabled = false;
        document.getElementById('stand-button').disabled = false;
    
        updateHands();
        checkForBlackjack();
    }
    
    function updateHands() {
        var playerCardsElement = document.getElementById('player-cards');
        var dealerCardsElement = document.getElementById('dealer-cards');
    
        playerCardsElement.innerHTML = '';
        dealerCardsElement.innerHTML = '';
    
        playerHand.forEach(card => {
            var cardDisplay = document.createElement('pre');
            cardDisplay.className = 'card';
            cardDisplay.textContent = getCardDisplay(card);
            playerCardsElement.appendChild(cardDisplay);
        });
    
        dealerHand.forEach((card, index) => {
            var cardDisplay = document.createElement('pre');
            cardDisplay.className = 'card';
            if (index === 0 && !document.getElementById('hit-button').disabled) {
                cardDisplay.textContent = `
     ____________
    |Hidden      |
    |            |
    |            |
    |            |
    |            |
    |            |
    |____________|`;
            } else {
                cardDisplay.textContent = getCardDisplay(card);
            }
            dealerCardsElement.appendChild(cardDisplay);
        });
    
        document.getElementById('player-total').textContent = `Total: ${calculateHandValue(playerHand)}`;
        document.getElementById('dealer-total').textContent = document.getElementById('hit-button').disabled ?
            `Total: ${calculateHandValue(dealerHand)}` : 'Total: ?';
    
        updateBalanceDisplay();
    }
    
    function checkForBlackjack() {
        var playerValue = calculateHandValue(playerHand);
        var dealerValue = calculateHandValue(dealerHand);
    
        if (playerValue === 21) {
            endGame('Blackjack! You win 1.5x your wager.');
        } else if (dealerValue === 21) {
            endGame('Dealer has Blackjack. You lose.');
        }
    }
    
    function hit() {
        playerHand.push(deck.pop());
        updateHands();
    
        if (calculateHandValue(playerHand) > 21) {
            endGame('You bust! Dealer wins.');
        }
    }
    
    function stand() {
        document.getElementById('hit-button').disabled = true;
        document.getElementById('stand-button').disabled = true;
    
        dealerTurn();
    }
    
    function dealerTurn() {
        while (calculateHandValue(dealerHand) < 17) {
            dealerHand.push(deck.pop());
            updateHands();
        }
    
        if (calculateHandValue(dealerHand) > 21) {
            endGame('Dealer busts! You win!');
        } else {
            compareHands();
        }
    }
    
    function compareHands() {
        var playerValue = calculateHandValue(playerHand);
        var dealerValue = calculateHandValue(dealerHand);
    
        if (playerValue > dealerValue) {
            endGame('You win!');
        } else if (playerValue < dealerValue) {
            endGame('Dealer wins.');
        } else {
            endGame("It's a tie!");
        }
    }
    
    function calculateHandValue(hand) {
        var value = 0;
        var numAces = 0;
    
        for (var card of hand) {
            value += values[card.rank];
            if (card.rank === 'Ace') {
                numAces += 1;
            }
        }
    
        while (value > 21 && numAces > 0) {
            value -= 10;
            numAces -= 1;
        }
    
        return value;
    }
    
    function endGame(message) {
        document.getElementById('hit-button').disabled = true;
        document.getElementById('stand-button').disabled = true;
        document.getElementById('message').textContent = message;
    
        if (message.includes('You win')) {
            if (message.includes('Blackjack')) {
                balance = balanceBeforeWager + currentWager * 2.5;
            } else {
                balance = balanceBeforeWager + currentWager * 2;
            }
        } else if (message.includes('tie')) {
            balance = balanceBeforeWager;
        }
    
        currentWager = 0;
        updateHands();
    
        document.getElementById('new-game-button').style.display = 'inline-block';
        document.getElementById('place-wager-button').disabled = false;
        document.getElementById('wager-input').disabled = false;
    }
    
    function placeWager() {
        var wagerInput = document.getElementById('wager-input');
        var wagerAmount = parseInt(wagerInput.value, 10);
    
        if (isNaN(wagerAmount) || wagerAmount <= 0) {
            alert('Please enter a valid wager amount.');
            return;
        }
    
        if (wagerAmount > balance) {
            alert('Not enough balance!');
            return;
        }
    
        currentWager = wagerAmount;
        balanceBeforeWager = balance;
        balance -= currentWager; 
        wagerInput.value = ''; 
    
        document.getElementById('message').textContent = `Wager placed: $${currentWager}`;
    
        document.getElementById('place-wager-button').disabled = true;
        document.getElementById('wager-input').disabled = true;
    
        dealCards(); 
        updateBalanceDisplay();
    }
    
    document.getElementById('new-game-button').addEventListener('click', function() {
        startGame(); 
        document.getElementById('message').textContent = ''; 
    });
    
    function updateBalanceDisplay() {
        document.getElementById('balance').textContent = balance;
    }
    
    window.onload = function() {
        updateBalanceDisplay();
        startGame(); 
    };
    body {
        font-family: Arial, sans-serif;
        background-color: #2c3e50;
        color: #ecf0f1;
        display: flex;
        justify-content: center;
        align-items: center;
        height: 100vh;
        margin: 0;
    }
    
    .game-container {
        text-align: center;
        background-color: #34495e;
        padding: 20px;
        border-radius: 10px;
        width: 400px;
    }
    
    .balance, .wager {
        margin-bottom: 20px;
    }
    
    .wager input {
        padding: 10px;
        border: 1px solid #7f8c8d;
        border-radius: 5px;
        margin-right: 10px;
        width: 100px;
    }
    
    .wager button {
        padding: 10px;
        background-color: #3498db;
        color: #ecf0f1;
        border: none;
        border-radius: 5px;
        cursor: pointer;
    }
    
    .wager button:hover {
        background-color: #2980b9;
    }
    
    .hand {
        margin-bottom: 20px;
    }
    
    .cards {
        display: flex;
        justify-content: center;
        margin: 10px 0;
        flex-wrap: wrap;
    }
    
    .card {
        font-family: "Courier New", Courier, monospace;
        background-color: #ecf0f1;
        color: #2c3e50;
        border: 1px solid #7f8c8d;
        padding: 10px;
        margin: 5px;
        border-radius: 5px;
        white-space: pre;
        text-align: left;
        line-height: 1.2;
    }
    
    button {
        padding: 10px;
        background-color: #e74c3c;
        color: #ecf0f1;
        border: none;
        border-radius: 5px;
        margin: 5px;
        cursor: pointer;
    }
    
    button:disabled {
        background-color: #95a5a6;
    }
    
    button:hover:not(:disabled) {
        background-color: #c0392b;
    }
    
    #message {
        font-size: 18px;
        margin-top: 20px;
    }
    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <meta name="viewport" content="width=device-width, initial-scale=1.0">
        <title>Blackjack Game</title>
        <link rel="stylesheet" href="style.css">
    </head>
    <body>
        <div class="game-container">
            <h1>Blackjack</h1>
            
            <div class="balance">
                <h2>Balance: $<span id="balance">1000</span></h2>
            </div>
    
            <div class="wager">
                <h2>Place Your Wager</h2>
                <input type="number" id="wager-input" min="1" max="1000" step="1" placeholder="Enter wager amount">
                <button id="place-wager-button">Place Wager</button>
            </div>
    
            <div id="dealer-hand" class="hand">
                <h2>Dealer's Hand</h2>
                <div id="dealer-cards" class="cards"></div>
                <p id="dealer-total"></p>
            </div>
    
            <div id="player-hand" class="hand">
                <h2>Your Hand</h2>
                <div id="player-cards" class="cards"></div>
                <p id="player-total"></p>
            </div>
    
            <div class="controls">
                <button id="hit-button">Hit</button>
                <button id="stand-button">Stand</button>
                <button id="new-game-button">New Game</button>
            </div>
    
            <p id="message"></p>
        </div>
    
        <script src="script.js"></script>
    </body>
    </html>