为什么在这个井字游戏逻辑函数中运行多个循环会导致错误?

huangapple go评论70阅读模式
英文:

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 &#39;0&#39;)
    at Object.checkWinner (TTT.js:121)
    at &lt;anonymous&gt;:1:4

Googling this error wasnt helpful.

const gameBoard = (() =&gt; {
    const rows = 3;
    const columns = 3;
    const board = [];

    // create 2D array in console
    for (let i = 0; i &lt; rows; i++) {
        board[i] = [];
        for (let j = 0; j &lt; columns; j++) {
            board[i].push(Cell());
        }
    }

    // method for getting entire board for UI to render
    const getboard = () =&gt; board;

    const printBoard = () =&gt; {
        const boardWithCellValues = board.map((row) =&gt; row.map((cell) =&gt; 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) =&gt; {
        const availableCells = board.filter((row) =&gt; row.map((cell) =&gt; 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) =&gt; {
        value = player;
        return value;
    }

    //retrieve current value of cell through closure
    const getValue = () =&gt; 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 = &quot;Player One&quot;,
    playerTwoName = &quot;Player Two&quot;
) {

    

    const players = [
        {
            name : playerOneName,
            token : 1
        },
        {
            name : playerTwoName,
            token : 2
        }
    ];

    
    let activePlayer = players[0];
    

    const switchPlayerTurn = () =&gt; {  // ternary operator
        activePlayer = activePlayer === players[0] ? players[1] : players[0];
    };


    const getActivePlayer = () =&gt; activePlayer;

    const printNewRound = () =&gt; {
        gameBoard.printBoard();
        console.log(`${getActivePlayer().name}&#39;s turn&#39;`);
    };

    function checkLine (a,b,c) {
        return ((a != 0) &amp;&amp; (a == b) &amp;&amp; (a == c));
    }

    function checkWinner (bd) {      // win logic function, what is bd in argument? the array?
        
            // check down
            
            for (r = 0; r &lt; 3; r++)
                for (c = 0; c &lt; 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 &lt; 3; r++)
                for (c = 0; c &lt; 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) =&gt; {
        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 &lt; 3; r++)
    for (c = 0; c &lt; 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 &lt; 3; c++)
    if (checkLine(bd[0][c], bd[1][c], bd[2][c])) {
        return bd[0][c]; 
    }

我猜你现在可以解决函数下一部分的类似错误了。

以防万一,这里有一个提示:

for (r = 0; r &lt; 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 &lt; 3; r++)
    for (c = 0; c &lt; 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 &lt; 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>

huangapple
  • 本文由 发表于 2023年6月1日 02:55:44
  • 转载请务必保留本文链接:https://go.coder-hub.com/76376517.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定