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

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

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.
但如果我运行两个循环,就会出现这个错误。

  1. at Object.checkWinner (TTT.js:121)
  2. at <anonymous>:1:4

Googling this error wasnt helpful.
搜索这个错误并没有帮助。

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

  1. // create 2D array in console
  2. for (let i = 0; i < rows; i++) {
  3. board[i] = [];
  4. for (let j = 0; j < columns; j++) {
  5. board[i].push(Cell());
  6. }
  7. }
  8. // method for getting entire board for UI to render
  9. const getboard = () => board;
  10. const printBoard = () => {
  11. const boardWithCellValues = board.map((row) => row.map((cell) => cell.getValue()));
  12. console.log(boardWithCellValues);
  13. return boardWithCellValues;
  14. }
  15. // playMove function for checking available spaces and if move is valid,
  16. // add arguments
  17. // !!check that availableCells is working after changing intial value of indexes from 0
  18. const playMove = (row, column, player) => {
  19. const availableCells = board.filter((row) => row.map((cell) => cell.getValue().value = 0));
  20. // if statement for invalid move check goes here
  21. board[row][column].addToken(player);
  22. };
  23. return {
  24. getboard,
  25. printBoard,
  26. playMove,
  27. board
  28. }

})(); // may need to change this from IIFE!

// cell represents one square on board
function Cell() {
let value = 0; // initial value

  1. // accept move to change value of cell
  2. const addToken = (player) => {
  3. value = player;
  4. return value;
  5. }
  6. //retrieve current value of cell through closure
  7. const getValue = () => value;
  8. return {
  9. getValue,
  10. addToken
  11. }

}

// 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
}
];

  1. let activePlayer = players[0];
  2. const switchPlayerTurn = () => { // ternary operator
  3. activePlayer = activePlayer === players[0] ? players[1] : players[0];
  4. };
  5. const getActivePlayer = () => activePlayer;
  6. const printNewRound = () => {
  7. gameBoard.printBoard();
  8. console.log(`${getActivePlayer().name}'s turn`);
  9. };
  10. function checkLine (a,b,c) {
  11. return ((a != 0) && (a == b) && (a == c));
  12. }
  13. function checkWinner (bd) { // win logic function, what is bd in argument? the array?
  14. // check down
  15. for (r = 0; r < 3; r++)
  16. for (c = 0; c < 3; c++)
  17. if (checkLine(bd[r][c], bd[r+1][c], bd[r+2][c])) {
  18. return bd[r][c];
  19. }
  20. // check right, works but not if down check is enabled
  21. for (r = 0; r < 3; r++)
  22. for (c = 0; c < 3; c++)
  23. if (checkLine(bd[r][c], bd[r][c+1], bd[r][c+2])) {
  24. return bd[r][c];
  25. }
  26. return 0;
  27. };
  28. const playRound = (row, column) => {
  29. gameBoard.playMove(row, column, getActivePlayer().token);
  30. switchPlayerTurn();
  31. printNewRound();
  32. }
  33. return {
  34. activePlayer,
  35. switchPlayerTurn,
  36. getActivePlayer,
  37. players,
  38. printNewRound,
  39. playRound,
  40. checkWinner
  41. };

}

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:
我在底部有一些代码,可以在控制台中自动填充数组以显示玩家的标记,示例如下:

  1. (3) [Array(3), Array(3), Array(3)]
  2. 0: (3) [1, 1, 1]
  3. 1: (3) [2, 0, 0]
  4. 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.

  1. TTT.js:121 Uncaught TypeError: Cannot read properties of undefined (reading &#39;0&#39;)
  2. at Object.checkWinner (TTT.js:121)
  3. at &lt;anonymous&gt;:1:4

Googling this error wasnt helpful.

  1. const gameBoard = (() =&gt; {
  2. const rows = 3;
  3. const columns = 3;
  4. const board = [];
  5. // create 2D array in console
  6. for (let i = 0; i &lt; rows; i++) {
  7. board[i] = [];
  8. for (let j = 0; j &lt; columns; j++) {
  9. board[i].push(Cell());
  10. }
  11. }
  12. // method for getting entire board for UI to render
  13. const getboard = () =&gt; board;
  14. const printBoard = () =&gt; {
  15. const boardWithCellValues = board.map((row) =&gt; row.map((cell) =&gt; cell.getValue()));
  16. console.log(boardWithCellValues);
  17. return boardWithCellValues;
  18. }
  19. // playMove function for checking available spaces and if move is valid,
  20. // add arguments
  21. // !!check that availableCells is working after changing intial value of indexes from 0
  22. const playMove = (row, column, player) =&gt; {
  23. const availableCells = board.filter((row) =&gt; row.map((cell) =&gt; cell.getValue().value = 0));
  24. // if statement for invalid move check goes here
  25. board[row][column].addToken(player);
  26. };
  27. return {
  28. getboard,
  29. printBoard,
  30. playMove,
  31. board
  32. }
  33. })(); // may need to change this from IIFE!
  34. // cell represents one square on board
  35. function Cell() {
  36. let value = 0; // initial value
  37. // accept move to change value of cell
  38. const addToken = (player) =&gt; {
  39. value = player;
  40. return value;
  41. }
  42. //retrieve current value of cell through closure
  43. const getValue = () =&gt; value;
  44. return {
  45. getValue,
  46. addToken
  47. }
  48. }
  49. // GameController module/function. Controls flow of game, win logic
  50. // NOTE on switchplayer function: returns player two when called but when getActiveplayer
  51. // is called, still player one
  52. function gameController(
  53. playerOneName = &quot;Player One&quot;,
  54. playerTwoName = &quot;Player Two&quot;
  55. ) {
  56. const players = [
  57. {
  58. name : playerOneName,
  59. token : 1
  60. },
  61. {
  62. name : playerTwoName,
  63. token : 2
  64. }
  65. ];
  66. let activePlayer = players[0];
  67. const switchPlayerTurn = () =&gt; { // ternary operator
  68. activePlayer = activePlayer === players[0] ? players[1] : players[0];
  69. };
  70. const getActivePlayer = () =&gt; activePlayer;
  71. const printNewRound = () =&gt; {
  72. gameBoard.printBoard();
  73. console.log(`${getActivePlayer().name}&#39;s turn&#39;`);
  74. };
  75. function checkLine (a,b,c) {
  76. return ((a != 0) &amp;&amp; (a == b) &amp;&amp; (a == c));
  77. }
  78. function checkWinner (bd) { // win logic function, what is bd in argument? the array?
  79. // check down
  80. for (r = 0; r &lt; 3; r++)
  81. for (c = 0; c &lt; 3; c++)
  82. if (checkLine(bd[r][c], bd[r+1][c], bd[r+2][c])) {
  83. return bd[r][c];
  84. }
  85. // check right, works but not if down check is enabled
  86. for (r = 0; r &lt; 3; r++)
  87. for (c = 0; c &lt; 3; c++)
  88. if (checkLine(bd[r][c], bd[r][c+1], bd[r][c+2])) {
  89. return bd[r][c];
  90. }
  91. return 0;
  92. };
  93. const playRound = (row, column) =&gt; {
  94. gameBoard.playMove(row, column, getActivePlayer().token);
  95. switchPlayerTurn();
  96. printNewRound();
  97. }
  98. return {
  99. activePlayer,
  100. switchPlayerTurn,
  101. getActivePlayer,
  102. players,
  103. printNewRound,
  104. playRound,
  105. checkWinner
  106. }; // temporary, players will be included in future functions that
  107. // will be returned instead
  108. }
  109. const gc = gameController();
  110. // right check
  111. gc.playRound(0,0); //p1
  112. gc.playRound(1,0); //p2
  113. gc.playRound(0,1); //p1
  114. gc.playRound(2,2); //p2
  115. gc.playRound(0,2); //p1
  116. /*
  117. // down check
  118. gc.playRound(0,0); //p1
  119. gc.playRound(0,1); //p2
  120. gc.playRound(1,0); //p1
  121. gc.playRound(2,2); //p2
  122. gc.playRound(2,0); //p1
  123. */

I have some code at the bottom to automatically fill the array with player tokens in the console.
Example:

  1. (3) [Array(3), Array(3), Array(3)]
  2. 0: (3) [1, 1, 1]
  3. 1: (3) [2, 0, 0]
  4. 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 函数中确实存在一个逻辑错误。例如,在这里:

  1. for (r = 0; r &lt; 3; r++)
  2. for (c = 0; c &lt; 3; c++)
  3. if (checkLine(bd[r][c], bd[r+1][c], bd[r+2][c])) {
  4. return bd[r][c];
  5. }

注意到 if 语句会执行 3 x 3 = 9 次,但只有 3 列要检查。在外部循环的第二次迭代中,您将计算 r+2 作为索引,但它不存在,因此 bd[r+2][c] 会引发您引述的错误。外部循环不应该存在,而在你原本用 r 的地方,应该直接使用 0。所以:

  1. for (c = 0; c &lt; 3; c++)
  2. if (checkLine(bd[0][c], bd[1][c], bd[2][c])) {
  3. return bd[0][c];
  4. }

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

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

  1. for (r = 0; r &lt; 3; r++)
  2. if (checkLine(bd[r][0], bd[r][1], bd[r][2])) {
  3. return bd[r][0];
  4. }
英文:

Indeed, you have a logical error in your checkWinner function. For example here:

  1. for (r = 0; r &lt; 3; r++)
  2. for (c = 0; c &lt; 3; c++)
  3. if (checkLine(bd[r][c], bd[r+1][c], bd[r+2][c])) {
  4. return bd[r][c];
  5. }

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:

  1. for (c = 0; c &lt; 3; c++)
  2. if (checkLine(bd[0][c], bd[1][c], bd[2][c])) {
  3. return bd[0][c];
  4. }

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:

确定