![]() |
In this tutorial, we’ll embark on a journey to create a fully functional Blackjack game using React for the frontend and Node for the backend. This engaging and interactive project will allow you to explore the realms of web development while learning how to implement key features of a classic card game. Preview of Final Output: Let’s have a look at what our final project will look like:
|
// blackjack-server/server.js const express = require( 'express' ); const mongoose = require( 'mongoose' ); const cors = require( 'cors' ); const bodyParser = require( 'body-parser' ); const app = express(); const PORT = process.env.PORT || 5000; app.use(cors()); app.use(bodyParser.json()); // Database connection configuration useNewUrlParser: true , useUnifiedTopology: true , }); const cardSchema = new mongoose.Schema({ suit: String, rank: String, value: Number, }); const playerSchema = new mongoose.Schema({ name: String, hand: [cardSchema], score: Number, }); const gameSchema = new mongoose.Schema({ deck: [cardSchema], player: playerSchema, dealer: playerSchema, winner: String, // New field to store the winner }); const Card = mongoose.model( 'Card' , cardSchema); const Player = mongoose.model( 'Player' , playerSchema); const Game = mongoose.model( 'Game' , gameSchema); // Helper function to create a new deck function createDeck() { const suits = [ 'Hearts' , 'Diamonds' , 'Clubs' , 'Spades' ]; const ranks = [ '2' , '3' , '4' , '5' , '6' , '7' , '8' , '9' , '10' , 'J' , 'Q' , 'K' , 'A' ]; const deck = []; for (const suit of suits) { for (const rank of ranks) { const card = new Card({ suit: suit, rank: rank, value: rank === 'A' ? 11 : isNaN(rank) ? 10 : parseInt(rank), }); deck.push(card); } } return deck; } // Endpoint to start a new game app.post( '/game/start' , async (req, res) => { try { const newDeck = createDeck(); // Shuffle the deck (Fisher-Yates algorithm) for (let i = newDeck.length - 1; i > 0; i--) { const j = Math.floor(Math.random() * (i + 1)); [newDeck[i], newDeck[j]] = [newDeck[j], newDeck[i]]; } const newGame = new Game({ deck: newDeck, player: { name: 'Player' , hand: [], score: 0 }, dealer: { name: 'Dealer' , hand: [], score: 0 }, }); // Deal the initial two cards to the player and the dealer newGame.player.hand.push(newGame.deck.pop()); newGame.dealer.hand.push(newGame.deck.pop()); newGame.player.hand.push(newGame.deck.pop()); newGame.dealer.hand.push(newGame.deck.pop()); // Update scores newGame.player.score = calculateScore( newGame.player.hand); newGame.dealer.score = calculateScore( newGame.dealer.hand); // Save the new game to the database await newGame.save(); res.status(201).json(newGame); } catch (error) { console.error(error); res.status(500).send( 'Internal Server Error' ); } }); // Endpoint to handle player hits app.post( '/game/hit' , async (req, res) => { try { const gameId = req.body.gameId; // Fetch the game from the database const game = await Game.findById(gameId); // Draw a card from the deck and add it to the player's hand const drawnCard = game.deck.pop(); game.player.hand.push(drawnCard); // Update the player's score game.player.score = calculateScore( game.player.hand); // Set the winner field game.winner = determineWinner(game.player.score, game.dealer.score); // Save the updated game to the database await game.save(); res.json({ ...game.toObject(), winner: game.winner }); } catch (error) { console.error(error); res.status(500).send( 'Internal Server Error' ); } }); app.post( '/game/stand' , async (req, res) => { try { const gameId = req.body.gameId; // Fetch the game from the database const game = await Game.findById(gameId); // Dealer draws cards until their score is 17 or higher while (game.dealer.score < 17) { const drawnCard = game.deck.pop(); game.dealer.hand.push(drawnCard); game.dealer.score = calculateScore( game.dealer.hand); } // Set the winner field game.winner = determineWinner(game.player.score, game.dealer.score); // Save the updated game to the database await game.save(); res.json({ ...game.toObject(), winner: game.winner }); } catch (error) { console.error(error); res.status(500).send( 'Internal Server Error' ); } }); // Helper function to calculate the score of a hand function calculateScore(hand) { let score = hand.reduce((total, card) => total + card.value, 0); // Handle Aces (reduce value from 11 to 1 if necessary) hand.filter(card => card.rank === 'A' ) .forEach(_ => { if (score > 21) { score -= 10; } }); return score; } // Helper function to determine the winner function determineWinner(playerScore, dealerScore) { if (playerScore > 21) { return 'Dealer' ; // Player busts, dealer wins } if (dealerScore > 21) { return 'Player' ; // Dealer busts, player wins } if (playerScore > dealerScore) { return 'Player' ; // Player has a higher score } else if (playerScore < dealerScore) { return 'Dealer' ; // Dealer has a higher score } else { return 'Draw' ; // Scores are equal, it's a draw } } // Start the server app.listen(PORT, () => { console.log(`Server is running on port ${PORT}`); }); |
Steps to Run the backend:
Step 1: Navigate to blackjack-server root directory.
cd blackjack-server
Step 2: Run the server using following command.
node server.js
Step 1: Set up a new React app using create-react-app.
npx create-react-app blackjack-frontend
Step 2: Go to the root directory using the following command.
cd blackjack-frontend
Step 3: Install necessary packages.
npm install axios
The updated dependencies in package.json file of frontend will look like:
"dependencies": {
"@testing-library/jest-dom": "^5.17.0",
"@testing-library/react": "^13.4.0",
"@testing-library/user-event": "^13.5.0",
"axios": "^1.6.7",
"react": "^18.2.0",
"react-dom": "^18.2.0",
"react-scripts": "5.0.1",
"web-vitals": "^2.1.4"
},
// blackjack-client/src/Game.js import React, { useState, useEffect } from 'react' ; import axios from 'axios' ; import './App.css' ; const Game = () => { const [gameState, setGameState] = useState( null ); const [winnerMessage, setWinnerMessage] = useState( '' ); useEffect(() => { // Fetch initial game state when the component mounts .then(response => setGameState(response.data)) . catch (error => console.error( 'Error starting a new game:' , error)); }, []); const handleHit = () => { // Implement logic for the player to hit { gameId: gameState._id }) .then(response => { setGameState(response.data); checkWinner(response.data.winner); }) . catch (error => console.error( 'Error hitting:' , error)); }; const handleStand = () => { // Implement logic for the player to stand { gameId: gameState._id }) .then(response => { setGameState(response.data); checkWinner(response.data.winner); }) . catch (error => console.error( 'Error standing:' , error)); }; const startNewGame = () => { // Implement logic to start a new game setWinnerMessage( '' ); // Clear the winner message .then(response => setGameState(response.data)) . catch (error => console.error( 'Error starting a new game:' , error)); }; const checkWinner = (winner) => { // Display winner message and start a new game setWinnerMessage(`Winner: ${winner}`); setTimeout(() => { startNewGame(); }, 3000); // Automatically start a new game after 3 seconds }; return ( <div className= "kl" > {gameState ? ( <> <h1>Blackjack Game</h1> {winnerMessage && <p className= "winner-message" > {winnerMessage} </p>} <div className= "ma" > <div className= "playerside" > <h2>Player Hand:</h2> <ul> {gameState.player.hand.map((card, index) => ( <li key={index}>{card.rank} of {card.suit}</li> ))} </ul> <p>Score: {gameState.player.score}</p> </div> <div className= "dealerside" > <h2>Dealer Hand:</h2> <ul> {gameState.dealer.hand.map((card, index) => ( <li key={index}>{card.rank} of {card.suit}</li> ))} </ul> <p>Score: {gameState.dealer.score}</p> </div> </div> <div className= "buttons" > <button onClick={handleHit}>Hit</button> <button onClick={handleStand}>Stand</button> <button onClick={startNewGame}> Start New Game </button> </div> </> ) : ( <p>Loading...</p> )} </div> ); }; export default Game; |
/* blackjack-client/src/App.css */ body { background-color : #00203F ; color : #ADEFD1 ; font-family : sans-serif ; } .App { text-align : center ; padding : 20px ; } ul { list-style-type : none ; padding : 0 ; } button { background-color : #ADEFD1 ; color : #00203F ; border : none ; padding : 10px 20px ; margin : 5px ; font-size : 16px ; cursor : pointer ; transition: background-color 0.3 s ease; } button:hover { background-color : #00203F ; color : #ADEFD1 ; } .winner-message { color : #FF5555 ; font-size : 30px ; font-weight : bolder ; margin-top : 20px ; animation: fadeIn 1 s ease; } @keyframes fadeIn { from { opacity: 0 ; } to { opacity: 1 ; } } .ma { display : flex; flex- direction : row; flex-wrap: wrap; justify- content : center ; } h 2 , p { color : #00203F ; } .playerside { padding : 2% ; background-color : #ADEFD1 ; color : #00203F ; width : fit-content; margin : 2% ; border-radius: 35px ; } .dealerside { width : fit-content; margin : 2% ; border-radius: 35px ; padding : 2% ; background-color : #ADEFD1 ; color : #00203F ; } |
1. Navigate to blackjack-frontend root directory.
cd blackjack-frontend
2. Run the following command.
npm start
Reffered: https://www.geeksforgeeks.org
Geeks Premier League |
Type: | Geek |
Category: | Coding |
Sub Category: | Tutorial |
Uploaded by: | Admin |
Views: | 12 |