I have a project due where I need to create a Blackjack game with the following functionality:
a) “Splitting” capability: What is splitting? If you hold two cards with the same value, like two eights or two sixes, you can split them into separate hands and play each hand individually. For this project, once the two cards are split, they should be treated as two separate hands, each with its own “hit,” “stay,” and “split” (if the two cards are the same) buttons. To achieve this, I need to add a button that appears only when the player holds two identical cards, and otherwise stays hidden. Once the button is clicked, the two cards should be split into two hands.
b) “Reset” capability: Currently, the game can only be reset by refreshing the page. I need to create a button that resets the game environment and starts a new game by clearing the scores and cards, without refreshing the page.
c) Disable “hit” button: When the player’s total exceeds 21, the “hit” button should be disabled and grayed out to prevent further action, until the game is reset or a new game begins.
I’ve managed to get b) and c) working, but no matter what I try, I haven’t been able to get splitting to work. Additionally, I need to add a backlog feature that tracks matches, pauses, and records the player’s progress, so users can return to their previous place in the game.
I’ve tried everything and I’m at my wit’s end.
Split Button Visibility: Showed the “Split” button when the player had two cards of the same rank (e.g., two 8s).
splitHand() Function: Created the splitHand() function to split the player’s two cards into two separate hands.
Rendering Cards: Used renderHand() to display the cards for both the player and the dealer.
Card Dealing: Implemented card dealing with dealCard() to distribute cards to both the player and the dealer.
Calculating Totals: Used calculateTotal() to compute the sum of the cards in the player’s and dealer’s hands, accounting for aces as 1 or 11.
Reset Game: Created a resetGame() function to reset the game environment (clearing hands and resetting the deck). The Split button should appear when the player has two matching cards (e.g., two 8s). When clicked, it splits the cards into two hands, dealing one additional card to each. Each hand becomes independent, allowing the player to “Hit” or “Stand” on each hand separately. The game continues with the player playing both hands, and the dealer plays their turn afterward to be more precise I am trying to find what is wrong with my code here:
<!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="blackjack.css">
</head>
<body>
<h1>Blackjack Game</h1>
<div id="game">
<div id="player-hand">
<h3>Player's Hand</h3>
<div id="player-cards"></div>
<p id="player-total">Total: 0</p>
<button id="hit-button">Hit</button>
<button id="stand-button">Stand</button>
<button id="split-button" style="display:none;">Split</button>
</div>
<!-- Split Hand Section -->
<div id="split-hand" style="display: none;">
<h3>Split Hand</h3>
<div id="split-cards"></div>
<p id="split-total">Total: 0</p>
</div>
<div id="dealer-hand">
<h3>Dealer's Hand</h3>
<div id="dealer-cards"></div>
<p id="dealer-total">Total: 0</p>
</div>
<button id="reset-button">Start New Game</button>
<div id="result"></div>
</div>
<script src="blackjack.js"></script>
</body>
</html>
I’ve been getting this error anytime I try to press the split Button
blackjack.js:215 Uncaught TypeError: Cannot read properties of null (reading 'classList')
at HTMLButtonElement.split (blackjack.js:215:43)
it’s saying it can’t find an element in html in particular split-section
the ther problem I am having is adding a Backlog feature that saves an unfinished Game pauses and lists some data and keeps track for how long other matches were and record like that but but the main issue is my the splitting not working here is the entire Javascript file for how it works
// Card deck setup
const cardImages = {
"2-C": "https://upload.wikimedia.org/wikipedia/commons/3/30/English_pattern_2_of_clubs.svg",
"2-D": "https://upload.wikimedia.org/wikipedia/commons/9/99/English_pattern_2_of_diamonds.svg",
"2-H": "https://upload.wikimedia.org/wikipedia/commons/2/26/English_pattern_2_of_hearts.svg",
"2-S": "https://upload.wikimedia.org/wikipedia/commons/0/0b/English_pattern_2_of_spades.svg",
"3-C": "https://upload.wikimedia.org/wikipedia/commons/1/14/English_pattern_3_of_clubs.svg",
"3-D": "https://upload.wikimedia.org/wikipedia/commons/2/2c/English_pattern_3_of_diamonds.svg",
"3-H": "https://upload.wikimedia.org/wikipedia/commons/0/0f/English_pattern_3_of_hearts.svg",
"3-S": "https://upload.wikimedia.org/wikipedia/commons/a/a5/English_pattern_3_of_spades.svg",
"4-C": "https://upload.wikimedia.org/wikipedia/commons/c/c0/English_pattern_4_of_clubs.svg",
"4-D": "https://upload.wikimedia.org/wikipedia/commons/4/4e/English_pattern_4_of_diamonds.svg",
"4-H": "https://upload.wikimedia.org/wikipedia/commons/b/bb/English_pattern_4_of_hearts.svg",
"4-S": "https://upload.wikimedia.org/wikipedia/commons/3/34/English_pattern_4_of_spades.svg",
"5-C": "https://upload.wikimedia.org/wikipedia/commons/7/74/English_pattern_5_of_clubs.svg",
"5-D": "https://upload.wikimedia.org/wikipedia/commons/6/6c/English_pattern_5_of_diamonds.svg",
"5-H": "https://upload.wikimedia.org/wikipedia/commons/c/c6/English_pattern_5_of_hearts.svg",
"5-S": "https://upload.wikimedia.org/wikipedia/commons/9/9c/English_pattern_5_of_spades.svg",
"6-C": "https://upload.wikimedia.org/wikipedia/commons/0/02/English_pattern_6_of_clubs.svg",
"6-D": "https://upload.wikimedia.org/wikipedia/commons/4/4e/English_pattern_6_of_diamonds.svg",
"6-H": "https://upload.wikimedia.org/wikipedia/commons/d/da/English_pattern_6_of_hearts.svg",
"6-S": "https://upload.wikimedia.org/wikipedia/commons/a/ac/English_pattern_6_of_spades.svg",
"7-C": "https://upload.wikimedia.org/wikipedia/commons/6/60/English_pattern_7_of_clubs.svg",
"7-D": "https://upload.wikimedia.org/wikipedia/commons/5/5d/English_pattern_7_of_diamonds.svg",
"7-H": "https://upload.wikimedia.org/wikipedia/commons/c/cb/English_pattern_7_of_hearts.svg",
"7-S": "https://upload.wikimedia.org/wikipedia/commons/d/d1/English_pattern_7_of_spades.svg",
"8-C": "https://upload.wikimedia.org/wikipedia/commons/f/f0/English_pattern_8_of_clubs.svg",
"8-D": "https://upload.wikimedia.org/wikipedia/commons/1/18/English_pattern_8_of_diamonds.svg",
"8-H": "https://upload.wikimedia.org/wikipedia/commons/3/3c/English_pattern_8_of_hearts.svg",
"8-S": "https://upload.wikimedia.org/wikipedia/commons/4/4d/English_pattern_8_of_spades.svg",
"9-C": "https://upload.wikimedia.org/wikipedia/commons/1/14/English_pattern_9_of_clubs.svg",
"9-D": "https://upload.wikimedia.org/wikipedia/commons/f/f5/English_pattern_9_of_diamonds.svg",
"9-H": "https://upload.wikimedia.org/wikipedia/commons/2/22/English_pattern_9_of_hearts.svg",
"9-S": "https://upload.wikimedia.org/wikipedia/commons/f/f0/English_pattern_9_of_spades.svg",
"10-C": "https://upload.wikimedia.org/wikipedia/commons/4/48/English_pattern_10_of_clubs.svg",
"10-D": "https://upload.wikimedia.org/wikipedia/commons/d/da/English_pattern_10_of_diamonds.svg",
"10-H": "https://upload.wikimedia.org/wikipedia/commons/b/bb/English_pattern_10_of_hearts.svg",
"10-S": "https://upload.wikimedia.org/wikipedia/commons/d/da/English_pattern_10_of_spades.svg",
"J-C": "https://upload.wikimedia.org/wikipedia/commons/8/80/English_pattern_jack_of_clubs.svg",
"J-D": "https://upload.wikimedia.org/wikipedia/commons/1/16/English_pattern_jack_of_diamonds.svg",
"J-H": "https://upload.wikimedia.org/wikipedia/commons/5/56/English_pattern_jack_of_hearts.svg",
"J-S": "https://upload.wikimedia.org/wikipedia/commons/4/4f/English_pattern_jack_of_spades.svg",
"Q-C": "https://upload.wikimedia.org/wikipedia/commons/b/b3/English_pattern_queen_of_clubs.svg",
"Q-D": "https://upload.wikimedia.org/wikipedia/commons/4/4f/English_pattern_queen_of_diamonds.svg",
"Q-H": "https://upload.wikimedia.org/wikipedia/commons/9/9d/English_pattern_queen_of_hearts.svg",
"Q-S": "https://upload.wikimedia.org/wikipedia/commons/c/ca/English_pattern_queen_of_spades.svg",
"K-C": "https://upload.wikimedia.org/wikipedia/commons/3/3e/English_pattern_king_of_clubs.svg",
"K-D": "https://upload.wikimedia.org/wikipedia/commons/1/1c/English_pattern_king_of_diamonds.svg",
"K-H": "https://upload.wikimedia.org/wikipedia/commons/1/14/English_pattern_king_of_hearts.svg",
"K-S": "https://upload.wikimedia.org/wikipedia/commons/f/f1/English_pattern_king_of_spades.svg",
"A-C": "https://upload.wikimedia.org/wikipedia/commons/5/5f/English_pattern_ace_of_clubs.svg",
"A-D": "https://upload.wikimedia.org/wikipedia/commons/0/00/English_pattern_ace_of_diamonds.svg",
"A-H": "https://upload.wikimedia.org/wikipedia/commons/d/d4/English_pattern_ace_of_hearts.svg",
"A-S": "https://upload.wikimedia.org/wikipedia/commons/1/19/English_pattern_ace_of_spades.svg",
"hidden": "https://upload.wikimedia.org/wikipedia/commons/d/d4/Card_back_01.svg"
};
let deck, playerHand, dealerHand, playerTotal, dealerTotal, playerTurn, splitHand, splitTurn;
// Function to create a new shuffled deck
function createDeck() {
const cardValues = [
"2-C", "2-D", "2-H", "2-S",
"3-C", "3-D", "3-H", "3-S",
"4-C", "4-D", "4-H", "4-S",
"5-C", "5-D", "5-H", "5-S",
"6-C", "6-D", "6-H", "6-S",
"7-C", "7-D", "7-H", "7-S",
"8-C", "8-D", "8-H", "8-S",
"9-C", "9-D", "9-H", "9-S",
"10-C", "10-D", "10-H", "10-S",
"J-C", "J-D", "J-H", "J-S",
"Q-C", "Q-D", "Q-H", "Q-S",
"K-C", "K-D", "K-H", "K-S",
"A-C", "A-D", "A-H", "A-S", "hidden"
];
let deck = [...cardValues];
console.log(deck.length); // Should log 52
console.log("Deck created:", deck);
return deck.sort(() => Math.random() - 0.5); // Shuffle the deck
}
// Function to get the value of a card
function getCardValue(card) {
const value = card.slice(0, -2);
if (value === "A") return 11;
if (["J", "Q", "K"].includes(value)) return 10;
return parseInt(value);
}
// Function to calculate the total value of a hand
function calculateTotal(hand) {
let total = hand.reduce((sum, card) => sum + getCardValue(card), 0);
// Adjust for Aces (if total > 21, treat Ace as 1)
let aceCount = hand.filter(card => card.slice(0, -2) === "A").length;
while (total > 21 && aceCount > 0) {
total -= 10;
aceCount--;
}
return total;
}
// Function to update the display of the cards
function displayHand(hand, handId) {
const handDiv = document.getElementById(handId);
handDiv.innerHTML = '';
hand.forEach(card => {
const img = document.createElement("img");
img.src = cardImages[card];
img.className = 'card';
handDiv.appendChild(img);
});
}
// Function to update the total display
function updateTotal(hand, totalId) {
const total = calculateTotal(hand);
document.getElementById(totalId).textContent = `Total: ${total}`;
return total;
}
// Function to start a new game
function startGame() {
deck = createDeck();
playerHand = [deck.pop(), deck.pop()];
dealerHand = [deck.pop(), deck.pop()];
splitHand = [];
playerTurn = true;
splitTurn = false;
displayHand(playerHand, "player-cards");
displayHand(dealerHand, "dealer-cards");
playerTotal = updateTotal(playerHand, "player-total");
dealerTotal = updateTotal(dealerHand, "dealer-total");
document.getElementById("hit-button").disabled = false;
document.getElementById("split-button").style.display = (playerHand[0] === playerHand[1]) ? "inline-block" : "none";
document.getElementById("result").textContent = '';
document.getElementById("split-button").style.display =
(getCardValue(playerHand[0]) === getCardValue(playerHand[1])) ? "inline-block" : "none";
}
function hit() {
if (playerTurn) {
if (splitTurn) {
splitHand.push(deck.pop());
console.log("Updated Split Hand:", splitHand);
updateTotal(splitHand, "split-total");
displayHand(splitHand, "split-hand");
if (calculateTotal(splitHand) > 21) {
document.getElementById("result").textContent = "Split Hand Busts!";
splitTurn = false;
playerTurn = false;
}
} else {
playerHand.push(deck.pop());
console.log("Updated Player Hand:", playerHand);
updateTotal(playerHand, "player-total");
displayHand(playerHand, "player-cards");
if (calculateTotal(playerHand) > 21) {
document.getElementById("result").textContent = "Player Busts! Dealer Wins.";
playerTurn = false;
}
}
console.log("Player Hand:", playerHand, "Dealer Hand:", dealerHand);
}
}
function stand() {
if (playerTurn) {
if (splitTurn) {
// Finish the split hand
playerTurn = false;
while (dealerTotal < 17) {
dealerHand.push(deck.pop());
dealerTotal = updateTotal(dealerHand, "dealer-total");
displayHand(dealerHand, "dealer-cards");
}
// Determine results for split hands
const splitHandTotal = calculateTotal(splitHand);
if (splitHandTotal > 21) {
document.getElementById("result").textContent = "Dealer Wins. Split hand bust!";
}
} else {
// Regular stand handling
playerTurn = false;
while (dealerTotal < 17) {
dealerHand.push(deck.pop());
dealerTotal = updateTotal(dealerHand, "dealer-total");
displayHand(dealerHand, "dealer-cards");
}
const playerTotal = calculateTotal(playerHand);
if (playerTotal > dealerTotal) {
document.getElementById("result").textContent = "Player Wins!";
} else if (playerTotal < dealerTotal) {
document.getElementById("result").textContent = "Dealer Wins!";
} else {
document.getElementById("result").textContent = "It's a Tie!";
}
}
}
}
// Function to handle splitting
function split() {
if (getCardValue(playerHand[0]) === getCardValue(playerHand[1])) {
splitHand = [playerHand.pop()]; // Move one card to the split hand
playerHand.push(deck.pop()); // Add a new card to the original hand
splitHand.push(deck.pop()); // Add a new card to the split hand
splitTurn = true; // Mark that it's the split turn now
// Update the card displays
displayHand(playerHand, "player-cards");
displayHand(splitHand, "split-cards"); // Make sure to use the correct element id
// Disable the split button, enable the hit button for both hands
document.getElementById("split-button").style.display = "none";
document.getElementById("hit-button").disabled = false;
// Update totals for both hands
updateTotal(playerHand, "player-total");
updateTotal(splitHand, "split-total");
} else {
console.log("Cannot split, cards do not match.");
}
}
// Function to reset the game
function resetGame() {
startGame();
}
// Event listeners
document.getElementById("hit-button").addEventListener("click", hit);
document.getElementById("stand-button").addEventListener("click", stand);
document.getElementById("split-button").addEventListener("click", split);
document.getElementById("reset-button").addEventListener("click", resetGame);
// Initialize the game on page load
window.onload = startGame;
along with that here is my html file
<!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="blackjack.css">
</head>
<body>
<h1>Blackjack Game</h1>
<div id="game">
<div id="player-hand">
<h3>Player's Hand</h3>
<div id="player-cards"></div>
<p id="player-total">Total: 0</p>
<button id="hit-button">Hit</button>
<button id="stand-button">Stand</button>
<button id="split-button" style="display:none;">Split</button>
</div>
<!-- Split Section -->
<div id="split-section" style="display: none;">
<h3>Split Hand</h3>
<div id="split-cards"></div>
<p id="split-total">Total: 0</p>
</div>
<div id="dealer-hand">
<h3>Dealer's Hand</h3>
<div id="dealer-cards"></div>
<p id="dealer-total">Total: 0</p>
</div>
<button id="reset-button">Start New Game</button>
<div id="result"></div>
</div>
<script src="blackjack.js"></script>
</body>
</html>
and here is my CSS file
body {
font-family: Arial, sans-serif;
text-align: center;
}
#game {
margin-top: 20px;
}
#player-hand, #dealer-hand, #split-hand {
margin: 20px;
padding: 10px;
display: inline-block;
border: 2px solid #000;
border-radius: 10px;
}
button {
margin: 10px;
padding: 10px 20px;
font-size: 16px;
}
button:disabled {
background-color: gray;
}
#result {
margin-top: 20px;
font-size: 24px;
font-weight: bold;
}
img.card {
width: 60px;
height: 90px;
margin: 5px;
}
/* Styling for the split hand */
#split-hand {
margin: 20px;
padding: 10px;
display: inline-block;
border: 2px dashed #ff0000; /* Dashed red border to distinguish the split hand */
border-radius: 10px;
background-color: #fff5f5; /* Light red background for visibility */
}
#split-section {
display: none; /* Initially hidden until a split occurs */
}
#split-section.active {
display: block; /* Show when split logic is activated */
}
and here is the specific error I am getting
blackjack.js:107 Uncaught TypeError: Cannot set properties of null (setting 'innerHTML')
at displayHand (blackjack.js:107:23)
at HTMLButtonElement.hit (blackjack.js:151:13)