首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >使用随机数的反应严格模式

使用随机数的反应严格模式
EN

Stack Overflow用户
提问于 2022-08-29 18:55:47
回答 1查看 44关注 0票数 0

我试图创造一个游戏的Tic-Tac-脚趾与人工智能使用反应。我有一个函数,我的人工智能,复述随机行和列,以放置一块。然而,当使用严格模式时,AI会产生两个回合,因为随机数会再次生成。从我这样做的阅读来看,这表明我正在错误地更新我的董事会状态,但我不知道我哪里出了问题。下面是我把标记放在黑板上的代码。

代码语言:javascript
复制
const handlePlacePiece = (row: number, col: number) => {
    let currentPiece = board[row][col];
    if (currentPiece === "-") {
        const newBoard = Array.from(board);
        newBoard[row][col] = currentPlayer; // The current players mark either 'X' or 'O'
        setBoard(newBoard);
        setCurrentPlayer(currentPlayer === "X" ? "O" : "X");
    }
};

以下是我最初的董事会陈述:

代码语言:javascript
复制
const [board, setBoard] = useState([
    ["-", "-", "-"],
    ["-", "-", "-"],
    ["-", "-", "-"],
]);

这是我的人工智能功能:

代码语言:javascript
复制
export function easyAi(board: any) {
    let col = getRandomMove(); //Math.floor(Math.random() * 3);
    let row = getRandomMove();
    while (board[row][col] !== "-") {
        col = getRandomMove();
        row = getRandomMove(); 
    }
    return { row, col };
}

调用handlePlacePiece (这也是一个onClick,但这会产生正确的结果):

代码语言:javascript
复制
if (gameType === "AI") {
        if (currentPlayer === aiPiece) {
            const { row, col } = easyAi(board);
            handlePlacePiece(row, col);
        }
    }

关于GitHub:https://github.com/lukeypap/Tic-Tac-Toe-React/blob/master/src/components/Board/index.tsx的完整文件

如果你需要额外的细节,请告诉我,谢谢。

EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2022-08-30 07:10:36

问题

  1. “人工智能”的逻辑是在功能体中作为一种无意的副作用而正确。这意味着,在任何时候,由于任何原因,组件都会呈现它调用的代码。React.StrictMode两次运行某些函数,以帮助您使用检测意想不到的副作用。 if (gameType === "AI“& !gameOver) { if (checkDraw(board) x\x checkWinner(board)) {console.log(”将游戏设置为true");setGameOver(true);}console.log (currentPlayer === aiPiece & !gameOver) { const { row,col }= easyAi(board);handlePlacePiece(行);} React.StricMode 严格模式不能自动为您检测副作用,但它可以帮助您通过使其更具确定性来识别它们。这是通过有意地双重调用以下函数来实现的:
代码语言:javascript
复制
- Class component `constructor`, `render`, and `shouldComponentUpdate` methods
- Class component static `getDerivedStateFromProps` method
- _**Function component bodies**_ <--
- State updater functions (the first argument to `setState`)
- Functions passed to `useState`, `useMemo`, or `useReducer`
  1. handlePlacePiece回调正在变异board状态对象。正在更新的所有状态和嵌套状态都应该被浅层复制,以便创建新的引用。回调只创建外部board数组的浅表副本,但所有行数组仍然是对前一个状态的引用。 newBoard =Array.from(板);newBoardrow = currentPlayer;// <--突变!setBoard(...newBoard);

解决方案

使用功能状态更新从前一个值更新板状态,使用Array.prototype.map浅复制正在更新的行和列。

移动"AI“,将逻辑转换为useEffect挂钩。我还建议将游戏检查移到useEffect钩子中,以便在board状态更新时调用。

建议:

代码语言:javascript
复制
enum PIECE {
  X = "X",
  O = "O",
  EMPTY = "-",
}

interface props {
  gameType: "AI" | "HUMAN";
  selectedPiece: PIECE;
  startingPlayer: PIECE;
}

const index = ({ gameType, selectedPiece, startingPlayer }: props) => {
  const [board, setBoard] = useState(
    Array(3).fill(Array(3).fill(PIECE.EMPTY))
  );

  const [currentPlayer, setCurrentPlayer] = useState(startingPlayer);
  const [aiPiece, setAiPiece] = useState(
    selectedPiece === PIECE.O ? PIECE.X : PIECE.O
  );
  const [gameOver, setGameOver] = useState(false);
  const [checkingMove, setCheckingMove] = useState(false);

  const handlePlacePiece = (row: number, col: number) => {
    let mark = board[row][col];
    if (mark === PIECE.EMPTY) {
      setCheckingMove(true);
      setBoard((board) =>
        board.map((boardRow: PIECE[], i: number) =>
          i === row
            ? boardRow.map((boardCol: PIECE, j: number) =>
                j === col ? currentPlayer : boardCol
              )
            : boardRow
        )
      );
    }
  };

  useEffect(() => {
    const isWinner = checkWinner(board); // *
    const isDraw = checkDraw(board);

    if (isWinner || isDraw) {
      if (isWinner) {
        console.log(`Winner is: ${isWinner}`);
      } else if (isDraw) {
        console.log("Draw");
      }
      setGameOver(true);
    } else {
      setCurrentPlayer((current) => (current === PIECE.X ? PIECE.O : PIECE.X));
      setCheckingMove(false);
    }
  }, [board]);

  useEffect(() => {
    if (
      !checkingMove &&
      gameType === "AI" &&
      !gameOver &&
      currentPlayer === aiPiece
    ) {
      const { row, col } = easyAi(board);
      handlePlacePiece(row, col);
    }
  }, [checkingMove, currentPlayer, aiPiece, gameType, gameOver, board]);

  return (
    ...
  );
};

*注:更新了checkWinner实用程序以返回获奖作品。

代码语言:javascript
复制
export const checkWinner = (board: string[][]) => {
  //Rows
  if (
    board[0][0] == board[0][1] &&
    board[0][1] == board[0][2] &&
    board[0][0] != "-"
  ) {
    return board[0][0];
  }
  if (
    board[1][0] == board[1][1] &&
    board[1][1] == board[1][2] &&
    board[1][0] != "-"
  ) {
    return board[1][0];
  }
  if (
    board[2][0] == board[2][1] &&
    board[2][1] == board[2][2] &&
    board[2][0] != "-"
  ) {
    return board[2][0];
  }
  //Cols
  if (
    board[0][0] == board[1][0] &&
    board[1][0] == board[2][0] &&
    board[0][0] != "-"
  ) {
    return board[0][0];
  }
  if (
    board[0][1] == board[1][1] &&
    board[1][1] == board[2][1] &&
    board[0][1] != "-"
  ) {
    return board[0][1];
  }
  if (
    board[0][2] == board[1][2] &&
    board[1][2] == board[2][2] &&
    board[0][2] != "-"
  ) {
    return board[0][2];
  }
  //Diags
  if (
    board[0][0] == board[1][1] &&
    board[1][1] == board[2][2] &&
    board[0][0] != "-"
  ) {
    return board[0][0];
  }
  if (
    board[0][2] == board[1][1] &&
    board[1][1] == board[2][0] &&
    board[0][2] != "-"
  ) {
    return board[0][2];
  }
};
票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/73533469

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档