我试图创造一个游戏的Tic-Tac-脚趾与人工智能使用反应。我有一个函数,我的人工智能,复述随机行和列,以放置一块。然而,当使用严格模式时,AI会产生两个回合,因为随机数会再次生成。从我这样做的阅读来看,这表明我正在错误地更新我的董事会状态,但我不知道我哪里出了问题。下面是我把标记放在黑板上的代码。
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");
}
};以下是我最初的董事会陈述:
const [board, setBoard] = useState([
["-", "-", "-"],
["-", "-", "-"],
["-", "-", "-"],
]);这是我的人工智能功能:
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,但这会产生正确的结果):
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的完整文件
如果你需要额外的细节,请告诉我,谢谢。
发布于 2022-08-30 07:10:36
问题
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
严格模式不能自动为您检测副作用,但它可以帮助您通过使其更具确定性来识别它们。这是通过有意地双重调用以下函数来实现的:- 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`handlePlacePiece回调正在变异board状态对象。正在更新的所有状态和嵌套状态都应该被浅层复制,以便创建新的引用。回调只创建外部board数组的浅表副本,但所有行数组仍然是对前一个状态的引用。
newBoard =Array.from(板);newBoardrow = currentPlayer;// <--突变!setBoard(...newBoard);解决方案
使用功能状态更新从前一个值更新板状态,使用Array.prototype.map浅复制正在更新的行和列。
移动"AI“,将逻辑转换为useEffect挂钩。我还建议将游戏检查移到useEffect钩子中,以便在board状态更新时调用。
建议:
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实用程序以返回获奖作品。
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];
}
};https://stackoverflow.com/questions/73533469
复制相似问题