Home > database >  useState in while cause infinite loop
useState in while cause infinite loop

Time:12-24

I trying to make Blackjack game in React. A bot has got 2 cards at start. If user stands, and bots card value is less than 17, it should draw addictional card, but then program cause infinite loop. This is my code:

  const [playerCards, setPlayerCards] = useState<Card[]>([]);
  const shuffledDeck = shuffleDeck(deck);
  const [dealerCards, setDealerCards] = useState<Card[]>([]);
const shuffleDeck = (deck: Card[]): Card[] => {
  for (let i = deck.length - 1; i > 0; i--) {
    const j = Math.floor(Math.random() * (i   1));
    [deck[i], deck[j]] = [deck[j], deck[i]];
  }
  return deck;
};
  const handleStand = () => {
    if (gameState === 'playing') {
      console.log(shuffledDeck[playerCards.length   dealerCards.length]);
      while(getHandValue(dealerCards) < 17) {
        setDealerCards([
          ...dealerCards,
          shuffledDeck[playerCards.length   dealerCards.length],
        ]);
      }
    }
    let dealerHandValue = getHandValue(dealerCards);
    const playerHandValue = getHandValue(playerCards);
    if (dealerHandValue > 21 || dealerHandValue < playerHandValue) {
      setGameState('won');
      setPlayerBalance(playerBalance   currentBet);
    } else if (dealerHandValue > playerHandValue) {
      setGameState('lost');
      setPlayerBalance(playerBalance - currentBet);
    } else {
      setGameState('tied');
    }
  };
const getHandValue = (cards: Card[]): number => {
  let value = 0;
  let numAces = 0;
  for (const card of cards) {
    if (card.rank === Rank.Ace) {
      numAces  ;
    } else if (card.rank === 'J' || card.rank === 'K' || card.rank === 'Q') {
      value  = 10;
    } else {
      value  = Number(card.rank);
    }
  }
  while (numAces > 0) {
    if (value   11 > 21) {
      value  = 1;
    } else {
      value  = 11;
    }
    numAces--;
  }
  return value;
};

The goal is to make bot draw a cards until value of his cards will be at least 17.

CodePudding user response:

As discussed in the comments, using setDealerCards inside the while loop can be problematic. Setting the state causes a re-render to the component and may trigger the function again depending on it's use. Another problem may be that since React schedules it's updates you may not get the most updated state every time you set the state again in the while loop.

So this might help

  const handleStand = () => {
    let newDealerCards = [...dealerCards];
    if (gameState === 'playing') {
      while(getHandValue(newDealerCards) < 17) {
             newDealerCards = 
             [...newDealerCards, shuffledDeck[playerCards.length   newDealerCards.length]];
      }
      setDealerCards(newDealerCards);
    }
    let dealerHandValue = getHandValue(newDealerCards);
    const playerHandValue = getHandValue(playerCards);
    if (dealerHandValue > 21 || dealerHandValue < playerHandValue) {
      setGameState('won');
      setPlayerBalance(playerBalance   currentBet);
    } else if (dealerHandValue > playerHandValue) {
      setGameState('lost');
      setPlayerBalance(playerBalance - currentBet);
    } else {
      setGameState('tied');
    }
  };

We make the new newDealerCards variable to spread dealerCards state, we then do the while loop with your condition and update newDealerCards accordingly. When we're done, only then we set the state again with the updated variable we made and thus we avoid calling setDealerCards multiple times inside the while loop.

  • Related