Solidify knowledge of HTML, CSS and React by using it to build a standalone React app
How to deploy a React app to the internet
Introduction
High Card is a turn-based game between 2 or more players where each player draws a card and the player with the highest card wins that round. The overall winner is the player that has won the most rounds when the deck runs out of cards. We will implement High Card with React.
Starter Code
Clone starter code
Fork and clone Rocket's High Card repo (Rocket-themed Create React App) and understand the following starter code before creating High Card. Run npm install to install default packages our app needs to run, and run npm run dev to start the app next open your browser and navigate to http://localhost:5173.
Understand starter code
Notice a file utils.jsx (short for "utilities") in the src folder that contains helper functions for creating and shuffling a card deck. This is the same code we use in Coding Fundamentals.
utils.jsx
// Get a random index ranging from 0 (inclusive) to max (exclusive).
const getRandomIndex = (max) => Math.floor(Math.random() * max);
// Shuffle an array of cards
const shuffleCards = (cards) => {
// Loop over the card deck array once
for (let currentIndex = 0; currentIndex < cards.length; currentIndex += 1) {
// Select a random index in the deck
const randomIndex = getRandomIndex(cards.length);
// Select the card that corresponds to randomIndex
const randomCard = cards[randomIndex];
// Select the card that corresponds to currentIndex
const currentCard = cards[currentIndex];
// Swap positions of randomCard and currentCard in the deck
cards[currentIndex] = randomCard;
cards[randomIndex] = currentCard;
}
// Return the shuffled deck
return cards;
};
const makeDeck = () => {
// Initialise an empty deck array
const newDeck = [];
// Initialise an array of the 4 suits in our deck. We will loop over this array.
const suits = ["Hearts", "Diamonds", "Clubs", "Spades"];
// Loop over the suits array
for (let suitIndex = 0; suitIndex < suits.length; suitIndex += 1) {
// Store the current suit in a variable
const currentSuit = suits[suitIndex];
// Loop from 1 to 13 to create all cards for a given suit
// Notice rankCounter starts at 1 and not 0, and ends at 13 and not 12.
// This is an example of a loop without an array.
for (let rankCounter = 1; rankCounter <= 13; rankCounter += 1) {
// By default, card name and card rank are the same as rankCounter
let cardName = `${rankCounter}`;
let cardRank = rankCounter;
// If rank is 1, 11, 12, or 13, set cardName to the ace or face card's name
if (cardName === "1") {
cardName = "Ace";
// Ace has higher rank than all other cards
cardRank = 14;
} else if (cardName === "11") {
cardName = "Jack";
} else if (cardName === "12") {
cardName = "Queen";
} else if (cardName === "13") {
cardName = "King";
}
// Create a new card with the current name, suit, and rank
const card = {
name: cardName,
suit: currentSuit,
rank: cardRank,
};
// Add the new card to the deck
newDeck.push(card);
}
}
// Return the completed card deck
return newDeck;
};
// Export functionality to create a shuffled 52-card deck
export const makeShuffledDeck = () => shuffleCards(makeDeck());
Understand App.jsx's logic to deal 2 cards at a time from the card deck. Understand what each line of code does before moving on, and ask your batch mates if you're not sure what the code is doing.
App.jsx
import React from "react";
import "./App.css";
import { makeShuffledDeck } from "./utils.jsx";
import { useState } from "react";
function App(props) {
// Set default value of card deck to new shuffled deck
const [cardDeck] = useState(makeShuffledDeck());
// currCards holds the cards from the current round
const [currCards, setCurrCards] = useState([]);
const dealCards = () => {
const newCurrCards = [cardDeck.pop(), cardDeck.pop()];
setCurrCards(newCurrCards);
};
// You can write JavaScript here, just don't try and set your state!
// You can access your current components state here, as indicated below
const currCardElems = currCards.map(({ name, suit }) => (
// Give each list element a unique key
<div key={`${name}${suit}`}>
{name} of {suit}
</div>
));
return (
<div className="App">
<header className="App-header">
<h2>React High Card 🚀</h2>
{currCardElems}
<br />
<button onClick={dealCards}>Deal</button>
</header>
</div>
);
}
export default App;
Base
Complete High Card with the following features.
Determine who has won each round (Player 1 or Player 2)
Keep score during each game (how many rounds has each player won)
Declare a winner at the end of each game when the deck has run out of cards, and give the players the option to restart the game.
Comfortable
Add nice-to-have features.
Style the app to clarify what each UI component is for. Clarify which card belongs to which player. Consider using React Bootstrap or MUI components as default styles.
Create a re-usable PlayingCard component to render cards nicely. This component can use playing card images or create a custom playing card UI.
More Comfortable
If you have time and want to practise more.
Allow players to keep track of scores across games, not just across rounds within a single game.
Submission
Submit a pull request to the main branch of Rocket's High Card repo and share your PR link in your section Slack channel.