英文:
Why does running multiple loops in this tic tac toe game logic function result in an error?
问题
I am working on the logic for checking for a winner in a Tic Tac Toe game.
我正在研究在井字棋游戏中检查赢家的逻辑。
I copied the logic from here:
我从这里复制了逻辑:
https://stackoverflow.com/questions/33181356/connect-four-game-checking-for-wins-js
This win check logic was for a connect four game, so i modified it.
这个胜利检查逻辑是为四子连珠游戏设计的,所以我进行了修改。
If i just run a single loop, for example, the loop checking for down wins, it runs as expected.
如果我只运行一个循环,例如,检查向下赢的循环,它会按预期运行。
but if i run both loops, i get this error.
但如果我运行两个循环,就会出现这个错误。
at Object.checkWinner (TTT.js:121)
at <anonymous>:1:4
Googling this error wasnt helpful.
搜索这个错误并没有帮助。
const gameBoard = (() => {
const rows = 3;
const columns = 3;
const board = [];
// create 2D array in console
for (let i = 0; i < rows; i++) {
board[i] = [];
for (let j = 0; j < columns; j++) {
board[i].push(Cell());
}
}
// method for getting entire board for UI to render
const getboard = () => board;
const printBoard = () => {
const boardWithCellValues = board.map((row) => row.map((cell) => cell.getValue()));
console.log(boardWithCellValues);
return boardWithCellValues;
}
// playMove function for checking available spaces and if move is valid,
// add arguments
// !!check that availableCells is working after changing intial value of indexes from 0
const playMove = (row, column, player) => {
const availableCells = board.filter((row) => row.map((cell) => cell.getValue().value = 0));
// if statement for invalid move check goes here
board[row][column].addToken(player);
};
return {
getboard,
printBoard,
playMove,
board
}
})(); // may need to change this from IIFE!
// cell represents one square on board
function Cell() {
let value = 0; // initial value
// accept move to change value of cell
const addToken = (player) => {
value = player;
return value;
}
//retrieve current value of cell through closure
const getValue = () => value;
return {
getValue,
addToken
}
}
// GameController module/function. Controls flow of game, win logic
// NOTE on switchplayer function: returns player two when called but when getActiveplayer
// is called, still player one
function gameController(
playerOneName = "Player One",
playerTwoName = "Player Two"
) {
const players = [
{
name: playerOneName,
token: 1
},
{
name: playerTwoName,
token: 2
}
];
let activePlayer = players[0];
const switchPlayerTurn = () => { // ternary operator
activePlayer = activePlayer === players[0] ? players[1] : players[0];
};
const getActivePlayer = () => activePlayer;
const printNewRound = () => {
gameBoard.printBoard();
console.log(`${getActivePlayer().name}'s turn`);
};
function checkLine (a,b,c) {
return ((a != 0) && (a == b) && (a == c));
}
function checkWinner (bd) { // win logic function, what is bd in argument? the array?
// check down
for (r = 0; r < 3; r++)
for (c = 0; c < 3; c++)
if (checkLine(bd[r][c], bd[r+1][c], bd[r+2][c])) {
return bd[r][c];
}
// check right, works but not if down check is enabled
for (r = 0; r < 3; r++)
for (c = 0; c < 3; c++)
if (checkLine(bd[r][c], bd[r][c+1], bd[r][c+2])) {
return bd[r][c];
}
return 0;
};
const playRound = (row, column) => {
gameBoard.playMove(row, column, getActivePlayer().token);
switchPlayerTurn();
printNewRound();
}
return {
activePlayer,
switchPlayerTurn,
getActivePlayer,
players,
printNewRound,
playRound,
checkWinner
};
}
const gc = gameController();
// right check
gc.playRound(0,0); //p1
gc.playRound(1,0); //p2
gc.playRound(0,1); //p1
gc.playRound(2,2); //p2
gc.playRound(0,2); //p1
/*
// down check
gc.playRound(0,0); //p1
gc.playRound(0,1); //p2
gc.playRound(1,0); //p1
gc.playRound(2,2); //p2
gc.playRound(2,0); //p1
*/
I have some code at the bottom to automatically fill the array with player tokens in the console.
Example:
我在底部有一些代码,可以在控制台中自动填充数组以显示玩家的标记,示例如下:
(3) [Array(3), Array(3), Array(3)]
0: (3) [1, 1, 1]
1: (3) [2, 0, 0]
2: (3) [0, 0, 2]
Again, these loops work on there own. but if i were to run both on the example above, with the down check supposed to run first, then right check to run next, it results in the above error.
Why am i unable to run both loops?
再次说明,这些循环单独运行是正常的。但如果我在上面的示例中同时运行这两个循环,首先运行向下检查,然后运行向右检查,就会导致上述错误。
为什么我不能同时运行这两个循环?
英文:
I am working on the logic for checking for a winner in a Tic Tac Toe game.
I copied the logic from here:
https://stackoverflow.com/questions/33181356/connect-four-game-checking-for-wins-js
This win check logic was for a connect four game, so i modified it.
If i just run a single loop, for example, the loop checking for down wins, it runs as expected.
but if i run both loops, i get this error.
TTT.js:121 Uncaught TypeError: Cannot read properties of undefined (reading '0')
at Object.checkWinner (TTT.js:121)
at <anonymous>:1:4
Googling this error wasnt helpful.
const gameBoard = (() => {
const rows = 3;
const columns = 3;
const board = [];
// create 2D array in console
for (let i = 0; i < rows; i++) {
board[i] = [];
for (let j = 0; j < columns; j++) {
board[i].push(Cell());
}
}
// method for getting entire board for UI to render
const getboard = () => board;
const printBoard = () => {
const boardWithCellValues = board.map((row) => row.map((cell) => cell.getValue()));
console.log(boardWithCellValues);
return boardWithCellValues;
}
// playMove function for checking available spaces and if move is valid,
// add arguments
// !!check that availableCells is working after changing intial value of indexes from 0
const playMove = (row, column, player) => {
const availableCells = board.filter((row) => row.map((cell) => cell.getValue().value = 0));
// if statement for invalid move check goes here
board[row][column].addToken(player);
};
return {
getboard,
printBoard,
playMove,
board
}
})(); // may need to change this from IIFE!
// cell represents one square on board
function Cell() {
let value = 0; // initial value
// accept move to change value of cell
const addToken = (player) => {
value = player;
return value;
}
//retrieve current value of cell through closure
const getValue = () => value;
return {
getValue,
addToken
}
}
// GameController module/function. Controls flow of game, win logic
// NOTE on switchplayer function: returns player two when called but when getActiveplayer
// is called, still player one
function gameController(
playerOneName = "Player One",
playerTwoName = "Player Two"
) {
const players = [
{
name : playerOneName,
token : 1
},
{
name : playerTwoName,
token : 2
}
];
let activePlayer = players[0];
const switchPlayerTurn = () => { // ternary operator
activePlayer = activePlayer === players[0] ? players[1] : players[0];
};
const getActivePlayer = () => activePlayer;
const printNewRound = () => {
gameBoard.printBoard();
console.log(`${getActivePlayer().name}'s turn'`);
};
function checkLine (a,b,c) {
return ((a != 0) && (a == b) && (a == c));
}
function checkWinner (bd) { // win logic function, what is bd in argument? the array?
// check down
for (r = 0; r < 3; r++)
for (c = 0; c < 3; c++)
if (checkLine(bd[r][c], bd[r+1][c], bd[r+2][c])) {
return bd[r][c];
}
// check right, works but not if down check is enabled
for (r = 0; r < 3; r++)
for (c = 0; c < 3; c++)
if (checkLine(bd[r][c], bd[r][c+1], bd[r][c+2])) {
return bd[r][c];
}
return 0;
};
const playRound = (row, column) => {
gameBoard.playMove(row, column, getActivePlayer().token);
switchPlayerTurn();
printNewRound();
}
return {
activePlayer,
switchPlayerTurn,
getActivePlayer,
players,
printNewRound,
playRound,
checkWinner
}; // temporary, players will be included in future functions that
// will be returned instead
}
const gc = gameController();
// right check
gc.playRound(0,0); //p1
gc.playRound(1,0); //p2
gc.playRound(0,1); //p1
gc.playRound(2,2); //p2
gc.playRound(0,2); //p1
/*
// down check
gc.playRound(0,0); //p1
gc.playRound(0,1); //p2
gc.playRound(1,0); //p1
gc.playRound(2,2); //p2
gc.playRound(2,0); //p1
*/
I have some code at the bottom to automatically fill the array with player tokens in the console.
Example:
(3) [Array(3), Array(3), Array(3)]
0: (3) [1, 1, 1]
1: (3) [2, 0, 0]
2: (3) [0, 0, 2]
Again, these loops work on there own. but if i were to run both on the example above, with the down check supposed to run first, then right check to run next, it results in the above error.
Why am i unable to run both loops?
答案1
得分: 1
在你的 checkWinner
函数中确实存在一个逻辑错误。例如,在这里:
for (r = 0; r < 3; r++)
for (c = 0; c < 3; c++)
if (checkLine(bd[r][c], bd[r+1][c], bd[r+2][c])) {
return bd[r][c];
}
注意到 if
语句会执行 3 x 3 = 9 次,但只有 3 列要检查。在外部循环的第二次迭代中,您将计算 r+2
作为索引,但它不存在,因此 bd[r+2][c]
会引发您引述的错误。外部循环不应该存在,而在你原本用 r
的地方,应该直接使用 0。所以:
for (c = 0; c < 3; c++)
if (checkLine(bd[0][c], bd[1][c], bd[2][c])) {
return bd[0][c];
}
我猜你现在可以解决函数下一部分的类似错误了。
以防万一,这里有一个提示:
for (r = 0; r < 3; r++)
if (checkLine(bd[r][0], bd[r][1], bd[r][2])) {
return bd[r][0];
}
英文:
Indeed, you have a logical error in your checkWinner
function. For example here:
for (r = 0; r < 3; r++)
for (c = 0; c < 3; c++)
if (checkLine(bd[r][c], bd[r+1][c], bd[r+2][c])) {
return bd[r][c];
}
Realise how the if
statement is executed 3 x 3 = 9 times, yet there are only 3 columns to check. In the second iteration of the outer loop, you'll evaluate r+2
as an index, but it doesn't exist, and so bd[r+2][c]
will raise the error you quoted. The outer loop shouldn't be there, and where you have r
, it should just be 0. So:
for (c = 0; c < 3; c++)
if (checkLine(bd[0][c], bd[1][c], bd[2][c])) {
return bd[0][c];
}
I guess you can now solve the similar error in the next part of your function.
Just in case, a spoiler:
>! <code>for (r = 0; r < 3; r++)
>! if (checkLine(bd[r][0], bd[r][1], bd[r][2])) {
>! return bd[r][0];
>! }</code>
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论