4
\$\begingroup\$

I started to learn React, and I wrote simple Blackjack game. I just need code review because I don't know anyone who know React well.

Whole state and logic of my game I have in Game.js component:

import React, { Component } from 'react';
import Hand from './Hand';
import DealersHand from './DealersHand';
import Bet from './Bet';
import cards from '../../data/cards';
import { Redirect } from 'react-router';

class Game extends Component{

    state = {
    gameStarted: false,
    bet: 5,
    deck: [],
    playerCards: [],
    dealerCards: [],
    money: 100,
    playerScore: 0,
    dealerScore: 0,
    playerWin: false,
    dealerWin: false,
    playerName: '',
    draw: false,
    finish: false

}

betLess = () => {
    if(this.state.bet >= 1){
        this.setState(state => ({ bet: state.bet - 5 }));
    }
}
betMore = () => {
    if(this.state.bet <= this.state.money){
        this.setState(state => ({ bet: state.bet + 5 }));
    }
}

letsPlay = () =>{
    this.setState({gameStarted: true})
}

getRandomCards = () =>{

    for(let i = 0; i < 2; i++){
        setTimeout(this.getPlayerCard, 100);

    }
    this.getDealerCard();
}

getDealerCard = () =>{

    const { deck, dealerCards, playerScore, money, bet } = this.state;
    let { dealerScore } = this.state 
    const deckCards = deck.length > 0 ? deck : cards;

    const randomIndex = Math.floor(Math.random() * deckCards.length);
    dealerScore += deckCards[randomIndex].cardValue;
    dealerCards.push(deckCards[randomIndex]);
    deckCards.splice(randomIndex, 1);

    const statesToSet = {
        dealerScore: dealerScore,
        dealerCards: dealerCards,
        deck: deckCards
    };

    if(dealerCards.length === 2){
        if(playerScore !== 21 && dealerScore < 15){
            const randomIndex = Math.floor(Math.random() * deckCards.length);
            dealerScore += deckCards[randomIndex].cardValue;
            dealerCards.push(deckCards[randomIndex]);
            deckCards.splice(randomIndex, 1);
            statesToSet.deck = deckCards;
            statesToSet.dealerCards = dealerCards;
            statesToSet.dealerScore = dealerScore;
            this.setState(statesToSet);
        }

        if(dealerScore === playerScore){
            statesToSet.draw = true;
            statesToSet.money = money + bet;
        } else if(dealerScore === 21){
            statesToSet.dealerWin = true;
            statesToSet.money = money - bet;
        } else if(playerScore === 21){
            statesToSet.playerWin = true;
            statesToSet.money = money + bet * 2;
        } else if(dealerScore > playerScore){
            statesToSet.dealerWin = true;
            statesToSet.money = money - bet;
        }else if(dealerScore < playerScore){
            statesToSet.playerWin = true;
            statesToSet.money = money + bet * 2;
        }else if(dealerScore > 21){
            statesToSet.dealerWin = true;
            statesToSet.money = money - bet;
        }
    }
    if(money === 0){
        this.endGame();
    }
    this.setState(statesToSet);
}

startNewGame = () =>{
    this.setState({
            gameStarted: false,
            deck: [],
            playerCards: [],
            dealerCards: [],
            playerScore: 0,
            dealerScore: 0,
            playerWin: false,
            dealerWin: false,
            draw: false
        });

}

getPlayerCard = () => {

    const { deck, playerCards, bet } = this.state;
    let { playerScore, playerWin, dealerWin, money } = this.state;
    const deckCards = deck.length > 0  ? deck : cards;
    const randomIndex = Math.floor(Math.random() * deckCards.length);
    playerScore += deckCards[randomIndex].cardValue;
    playerCards.push(deckCards[randomIndex]);

    if(playerScore === 21){
        playerWin = true;
        money = money + bet * 2;
    }
    if(playerScore > 21){
        dealerWin = true;
        money = money - bet;
    }

    this.setState({
        deck: deckCards,
        playerCards: playerCards,
        playerScore: playerScore,
        playerWin: playerWin,
        dealerWin: dealerWin,
        money: money
    });

}

endRound = () =>{
    this.getDealerCard();
}

endGame = () =>{
    const { playerName, money } = this.state;
    const highscores = JSON.parse(localStorage.getItem('highscores'));
    highscores.push({name: playerName, score: money});
    localStorage.setItem('highscores', JSON.stringify(highscores))
    this.setState({finish: true});
}

componentDidMount(){

    this.getRandomCards(4);
    const playerName = localStorage.getItem('name');
    this.setState({playerName: playerName})

}

componentDidUpdate(){
    if(this.state.deck.length === 0){
        this.getRandomCards();
    }
}


render(){
    const { gameStarted, bet, money, dealerScore, playerScore, dealerCards, playerCards, playerWin, dealerWin, draw, finish } = this.state;

    if(finish){
        return <Redirect to="/highscores"/>
    }
    if(gameStarted){
        return(
            <div className="col-md-12 col-xs-12">
                <DealersHand cards={dealerCards} />
                <div className="panel">
                    <h3>Dealer's score: {dealerScore}</h3>
                </div>
                <Hand cards={playerCards} />
                {draw || playerWin || dealerWin ? 
                <div className="game-status">
                    {dealerWin ?<div className="info lose">You lost.</div> : null}
                    {playerWin ?<div className="info win"> You won!</div> : null}
                    {draw ? <div className="info draw">Draw.</div> : null}
                    <div>
                        <div className="buttons">
                            <button className="game-button" onClick={this.startNewGame}>Play again</button>
                            <button className="game-button" onClick={this.endGame}>End game and save score</button>
                        </div>
                    </div>
                </div> 
                : null}
                <div className="panel">
                        <h3>Your score: {playerScore}</h3>
                </div>
                <div className="panel">

                    <button className="game-button" onClick={this.getPlayerCard} disabled={playerScore > 20 || playerWin || dealerWin || draw}>Get card</button>
                    <button className="game-button" onClick={this.endRound} disabled={playerScore > 20 || playerWin || dealerWin || draw}>End round</button>
                </div>
            </div>
        )
    }else{
        return(
            <Bet bet={bet} money={money} betLess={this.betLess} betMore={this.betMore} letsPlay={this.letsPlay} />
        )
    }

}
}
export default Game;

GitHub

GitHub Pages

Can anyone tell me what can I do better or what I did wrong?

\$\endgroup\$
3
\$\begingroup\$

The code in componentDidUpdate looks a little odd to me.

if(this.state.deck.length === 0){

You are checking if there aren't any cards, then drawing some cards. This works because you are initialising the deck within getPlayerCard. What I would do is put the deck initialisation within the startNewGame method instead.

getDealerCard and getPlayerCard are doing a bit too much; you could move the victory conditions to separate methods.

In componentDidMount, this.getRandomCards(4); takes in a parameter but the method doesn't use any parameters.

You have 3 variables in state which represent the victory state; playerWin, dealerWin, draw. These all cannot be true at the same time. It would be better to have one variable for the victory state; an option would be like an Enum in Typescript

Looking at the code in your repository, there's a bug in DealersHand.js. You are rendering the second card twice; once in the map function, then again when you make the decision to render it face-down or face-up. Instead, you just need to conditionally render it when the dealer has only 1 card.

{
    cards.length == 1
    &&
    <Card
    key="5"
    className={ "cards card-back" }
    />
}

The link on your ReadMe is also wrong. I used the link you provided in the question. I liked the game, but the lack of cards 2-8 took some adapting.

\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.