无法结束我的井字游戏并宣布平局。

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

Can't get my Tic-Tac-Toe Game to end and announce a Tie

问题

我离完成这个井字游戏非常接近了。游戏已经可以正常进行并宣布赢家,但是我无法让它在游戏结束时宣布平局。

我尝试在我的getWinner()函数中实现一个返回,但它在仅有一次点击后就结束了游戏。我在这里漏掉了什么?我认为我的for循环有问题,但是我想不出来。

我尝试在循环之外的地方结束函数,但它会过早地结束游戏。

以下是你的代码,我只翻译了你的问题部分,其他内容保持原样:

/*----- state variables -----*/
let board; //包含9个方格的数组
let turn; // 1 或 -1
let winner; //null = 没有赢家; 1 或 -1 = 赢家; 'T' = 平局

/*----- cached elements  -----*/
const message = document.querySelector('h1');
const resetButton = document.querySelector('button');

/*----- event listeners -----*/
document.getElementById('board').addEventListener('click', handleClick);
resetButton.addEventListener('click', init);

/*----- functions -----*/
init();
//初始化游戏状态并调用render()
function init() {
  board = [0, 0, 0, 0, 0, 0, 0, 0, 0];
  turn = 1;
  winner = null;
  render();
}

//在DOM中显示所有状态
function render() {
  renderBoard();
  renderMessage();
}

//渲染游戏棋盘
function renderBoard() {
  board.forEach(function(boardArr, boardIdx) {
    const squareId = `box-${boardIdx}`;
    const squareEl = document.getElementById(squareId);
    //为玩家选择设置样式
    squareEl.style.backgroundColor = COLORS[boardArr];
    squareEl.innerHTML = MARK[boardArr];
    squareEl.style.display = 'flex';
    squareEl.style.justifyContent = 'center';
    squareEl.style.alignItems = 'center';
    squareEl.style.fontSize = '19vmin';
  });
}

//显示轮到谁和赢家
function renderMessage() {
  if (winner === 'T') {
    message.innerHTML = '平局!游戏结束!';
  } else if (winner) {
    message.innerHTML = `玩家 ${MARK[winner]} 获胜!`;
  } else {
    message.innerHTML = `轮到玩家 ${MARK[turn]}`;
  }
}

//获取点击方格的索引
function handleClick(event) {
  const boxIdx = parseInt(event.target.id.replace('box-', ''));
  //如果点击了方格外部、方格已被填充或已有赢家,则不进行操作
  if (isNaN(boxIdx) || board[boxIdx] || winner)
    return;
  //更新游戏状态为当前轮次的值
  board[boxIdx] = turn;
  //切换玩家轮次
  turn *= -1;
  // 检查是否有赢家
  winner = getWinner();
  render();
}

//检查游戏状态是否有赢家。1(X)或-1(O),'T'表示平局,null表示尚无赢家
function getWinner() {
  for (let i = 0; i < COMBOS.length; i++) {
    if (Math.abs(board[COMBOS[i][0]] + board[COMBOS[i][1]] + board[COMBOS[i][2]]) === 3) {
      return board[COMBOS[i][0]];
    } else if (board.includes(null)) {
      return null;
    }
  }
  //返回 'T';
  //当我实现这个时,游戏在仅有一次移动后就结束了。
}
英文:

I am so close to finishing this Tic-Tac-Toe game. It plays through and announces the winner but I can't get it to announce if there is a tie at the end of the game if there is no winner.

I tried to implement a return in my getWinner() function but it ends the game after just one click. What am I missing here? I'm thinking something is wrong with my for loop but can't figure it out.

I tried ending my function with a return outside of the loop but it ends the game prematurely.

<!-- begin snippet: js hide: false console: true babel: false -->

<!-- language: lang-js -->

/*----- constants -----*/
//Display of background color for the selected box. Player 1 is 1, pink and X. Player 2 is -1, green and O
const COLORS = {
&#39;0&#39;: &#39;white&#39;,
&#39;1&#39;: &#39;pink&#39;,
&#39;-1&#39;: &#39;lightgreen&#39;
};
//Display for selected box. X or O
const MARK = {
&#39;0&#39;: &#39;&#39;,
&#39;1&#39;: &#39;X&#39;,
&#39;-1&#39;: &#39;O&#39;
};
//Winning combos to win the math
const COMBOS = [
[0, 1, 2],
[3, 4, 5],
[6, 7, 8],
[6, 4, 2],
[0, 4, 8],
[0, 3, 6],
[1, 4, 7],
[2, 5, 8]
];
/*----- state variables -----*/
let board; //array of 9 boxes
let turn; // 1 or -1
let winner; //null = no winner; 1 or -1 winner; &#39;T&#39; = Tie
/*----- cached elements  -----*/
const message = document.querySelector(&#39;h1&#39;);
const resetButton = document.querySelector(&#39;button&#39;);
/*----- event listeners -----*/
document.getElementById(&#39;board&#39;).addEventListener(&#39;click&#39;, handleClick);
resetButton.addEventListener(&#39;click&#39;, init);
/*----- functions -----*/
init();
//Initializes state and calls render()
function init() {
board = [0, 0, 0, 0, 0, 0, 0, 0, 0];
turn = 1;
winner = null;
render();
}
//Visualizes all state in the DOM
function render() {
renderBoard();
renderMessage();
}
//Iterate over the squares in the board
function renderBoard() {
board.forEach(function(boardArr, boardIdx) {
const squareId = `box-${boardIdx}`;
const squareEl = document.getElementById(squareId);
//styles for player selection
squareEl.style.backgroundColor = COLORS[boardArr];
squareEl.innerHTML = MARK[boardArr];
squareEl.style.display = &#39;flex&#39;;
squareEl.style.justifyContent = &#39;center&#39;;
squareEl.style.alignItems = &#39;center&#39;;
squareEl.style.fontSize = &#39;19vmin&#39;;
});
}
//Display whose turn it is and the winner
function renderMessage() {
if (winner === &#39;T&#39;) {
message.innerHTML = &#39;Tie Game! Game Over!&#39;;
} else if (winner) {
message.innerHTML = `Player ${MARK[winner]} Wins!`;
} else {
message.innerHTML = `Player ${MARK[turn]}&#39;s Turn`;
}
}
//Get index of the clicked box
function handleClick(event) {
const boxIdx = parseInt(event.target.id.replace(&#39;box-&#39;, &#39;&#39;));
//if statement in case someone clicks outside box, the box is filled or there is a winner
if (isNaN(boxIdx) || board[boxIdx] || winner)
return;
//update state of board with the current turn value
board[boxIdx] = turn;
//switch player turn
turn *= -1;
// check for a winner
winner = getWinner();
render();
}
//Check for a winner in the state. 1(X) or -1(O), &#39;T&#39; for Tie, null for no winner yet
//Got really stuck on this section. Had to peak at the solution and research Math.abs function
function getWinner() {
for (let i = 0; i &lt; COMBOS.length; i++) {
if (Math.abs(board[COMBOS[i][0]] + board[COMBOS[i][1]] + board[COMBOS[i][2]]) === 3) {
return board[COMBOS[i][0]];
} else if (board.includes(null)) {
return null;
}
}
//return &#39;T&#39;; 
//When I implement this, the game ends after just one move.
}

<!-- language: lang-css -->

* {
box-sizing: border-box;
}
body {
height: 100vh;
margin: 0;
font-family: &#39;Raleway&#39;, sans-serif;
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
}
header {
margin-top: 5vmin;
font-size: 10vmin;
color: darkslategrey;
}
h1 {
color: slategrey;
}
#board {
display: grid;
grid-template-columns: repeat(3, 20vmin);
grid-template-rows: repeat(3, 20vmin);
}
#board&gt;div {
border: 0.5vmin solid slategrey;
}
button {
margin-top: 5vmin;
margin-bottom: 5vmin;
padding: 2vmin;
font-size: 3vmin;
border-radius: 4vmin;
border: 0.5vmin solid lightslategrey;
background-color: aliceblue;
color: darkslategrey;
}
button:hover {
color: azure;
background-color: cadetblue;
}

<!-- language: lang-html -->

&lt;link href=&quot;https://fonts.googleapis.com/css2?family=Raleway:wght@100&amp;display=swap&quot; rel=&quot;stylesheet&quot;&gt;
&lt;header&gt;Tic-Tac-Toe&lt;/header&gt;
&lt;h1&gt;X&#39;s Turn&lt;/h1&gt;
&lt;section id=&quot;board&quot;&gt;
&lt;div id=&quot;box-0&quot;&gt;&lt;/div&gt;
&lt;div id=&quot;box-1&quot;&gt;&lt;/div&gt;
&lt;div id=&quot;box-2&quot;&gt;&lt;/div&gt;
&lt;div id=&quot;box-3&quot;&gt;&lt;/div&gt;
&lt;div id=&quot;box-4&quot;&gt;&lt;/div&gt;
&lt;div id=&quot;box-5&quot;&gt;&lt;/div&gt;
&lt;div id=&quot;box-6&quot;&gt;&lt;/div&gt;
&lt;div id=&quot;box-7&quot;&gt;&lt;/div&gt;
&lt;div id=&quot;box-8&quot;&gt;&lt;/div&gt;
&lt;/section&gt;
&lt;button&gt;Reset Match&lt;/button&gt;

<!-- end snippet -->

答案1

得分: 1

一个解决方法是添加一个记录点击字段次数的计数器。然后,你可以在你的getWinner函数中检查这个计数器是否达到平局条件。只有当所有字段都被点击且没有赢家时,这个条件才会成立。

示例代码如下:

function getWinner() {
  for (let i = 0; i < COMBOS.length; i++) {
    if (Math.abs(board[COMBOS[i][0]] + board[COMBOS[i][1]] + board[COMBOS[i][2]]) === 3) {
      return board[COMBOS[i][0]];
    } else if (board.includes(null)) {
      return null;
    }
  }
  if (filledFields >= 9) {
    return 'T';
  }
}

希望这对你有所帮助 无法结束我的井字游戏并宣布平局。

英文:

one way for a solution could be to add a counter of the clicked fields. Then you could check in your getWinner function this counter at your tie line. This line then should only hit if all fields have been clicked an no winner is found.

Like so:

function getWinner() {
for (let i = 0; i &lt; COMBOS.length; i++) {
if (Math.abs(board[COMBOS[i][0]] + board[COMBOS[i][1]] + board[COMBOS[i][2]]) === 3) {
return board[COMBOS[i][0]];
} else if (board.includes(null)) {
return null;
}
}
if(filledFields &gt;= 9)
{
return &#39;T&#39;;
}
}

Hope this helps 无法结束我的井字游戏并宣布平局。

答案2

得分: 0

你可以数一下board数组中剩下的零的数量。当没有零剩下时,使用以下代码判断平局:

if (board.filter(x => x == 0).length == 0) return 'T';

这段代码的作用是检查board数组中是否没有剩余的零,如果没有,就返回字符'T'表示平局。

英文:

You can count the number of zeros remaining in the board array. When there are none left, it's tie using if (board.filter(x =&gt; x == 0).length == 0) return &#39;T&#39;:

<!-- begin snippet: js hide: false console: true babel: false -->

<!-- language: lang-js -->

/*----- constants -----*/
//Display of background color for the selected box. Player 1 is 1, pink and X. Player 2 is -1, green and O
const COLORS = {
&#39;0&#39;: &#39;white&#39;,
&#39;1&#39;: &#39;pink&#39;,
&#39;-1&#39;: &#39;lightgreen&#39;
};
//Display for selected box. X or O
const MARK = {
&#39;0&#39;: &#39;&#39;,
&#39;1&#39;: &#39;X&#39;,
&#39;-1&#39;: &#39;O&#39;
};
//Winning combos to win the math
const COMBOS = [
[0, 1, 2],
[3, 4, 5],
[6, 7, 8],
[6, 4, 2],
[0, 4, 8],
[0, 3, 6],
[1, 4, 7],
[2, 5, 8]
];
/*----- state variables -----*/
let board; //array of 9 boxes
let turn; // 1 or -1
let winner; //null = no winner; 1 or -1 winner; &#39;T&#39; = Tie
/*----- cached elements  -----*/
const message = document.querySelector(&#39;h1&#39;);
const resetButton = document.querySelector(&#39;button&#39;);
/*----- event listeners -----*/
document.getElementById(&#39;board&#39;).addEventListener(&#39;click&#39;, handleClick);
resetButton.addEventListener(&#39;click&#39;, init);
/*----- functions -----*/
init();
//Initializes state and calls render()
function init() {
board = [0, 0, 0, 0, 0, 0, 0, 0, 0];
turn = 1;
winner = null;
render();
}
//Visualizes all state in the DOM
function render() {
renderBoard();
renderMessage();
}
//Iterate over the squares in the board
function renderBoard() {
board.forEach(function(boardArr, boardIdx) {
const squareId = `box-${boardIdx}`;
const squareEl = document.getElementById(squareId);
//styles for player selection
squareEl.style.backgroundColor = COLORS[boardArr];
squareEl.innerHTML = MARK[boardArr];
squareEl.style.display = &#39;flex&#39;;
squareEl.style.justifyContent = &#39;center&#39;;
squareEl.style.alignItems = &#39;center&#39;;
squareEl.style.fontSize = &#39;19vmin&#39;;
});
}
//Display whose turn it is and the winner
function renderMessage() {
if (winner === &#39;T&#39;) {
message.innerHTML = &#39;Tie Game! Game Over!&#39;;
} else if (winner) {
message.innerHTML = `Player ${MARK[winner]} Wins!`;
} else {
message.innerHTML = `Player ${MARK[turn]}&#39;s Turn`;
}
}
//Get index of the clicked box
function handleClick(event) {
const boxIdx = parseInt(event.target.id.replace(&#39;box-&#39;, &#39;&#39;));
//if statement in case someone clicks outside box, the box is filled or there is a winner
if (isNaN(boxIdx) || board[boxIdx] || winner)
return;
//update state of board with the current turn value
board[boxIdx] = turn;
//switch player turn
turn *= -1;
// check for a winner
winner = getWinner();
render();
}
//Check for a winner in the state. 1(X) or -1(O), &#39;T&#39; for Tie, null for no winner yet
//Got really stuck on this section. Had to peak at the solution and research Math.abs function
function getWinner() {
for (let i = 0; i &lt; COMBOS.length; i++) {
if (Math.abs(board[COMBOS[i][0]] + board[COMBOS[i][1]] + board[COMBOS[i][2]]) === 3) {
return board[COMBOS[i][0]];
} else if (board.includes(null)) {
return null;
}
if (board.filter(x =&gt; x == 0).length == 0) return &#39;T&#39;;
}
//return &#39;T&#39;; 
//When I implement this, the game ends after just one move.
}

<!-- language: lang-css -->

* {
box-sizing: border-box;
}
body {
height: 100vh;
margin: 0;
font-family: &#39;Raleway&#39;, sans-serif;
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
}
header {
margin-top: 5vmin;
font-size: 10vmin;
color: darkslategrey;
}
h1 {
color: slategrey;
}
#board {
display: grid;
grid-template-columns: repeat(3, 20vmin);
grid-template-rows: repeat(3, 20vmin);
}
#board&gt;div {
border: 0.5vmin solid slategrey;
}
button {
margin-top: 5vmin;
margin-bottom: 5vmin;
padding: 2vmin;
font-size: 3vmin;
border-radius: 4vmin;
border: 0.5vmin solid lightslategrey;
background-color: aliceblue;
color: darkslategrey;
}
button:hover {
color: azure;
background-color: cadetblue;
}

<!-- language: lang-html -->

&lt;link href=&quot;https://fonts.googleapis.com/css2?family=Raleway:wght@100&amp;display=swap&quot; rel=&quot;stylesheet&quot;&gt;
&lt;header&gt;Tic-Tac-Toe&lt;/header&gt;
&lt;h1&gt;X&#39;s Turn&lt;/h1&gt;
&lt;section id=&quot;board&quot;&gt;
&lt;div id=&quot;box-0&quot;&gt;&lt;/div&gt;
&lt;div id=&quot;box-1&quot;&gt;&lt;/div&gt;
&lt;div id=&quot;box-2&quot;&gt;&lt;/div&gt;
&lt;div id=&quot;box-3&quot;&gt;&lt;/div&gt;
&lt;div id=&quot;box-4&quot;&gt;&lt;/div&gt;
&lt;div id=&quot;box-5&quot;&gt;&lt;/div&gt;
&lt;div id=&quot;box-6&quot;&gt;&lt;/div&gt;
&lt;div id=&quot;box-7&quot;&gt;&lt;/div&gt;
&lt;div id=&quot;box-8&quot;&gt;&lt;/div&gt;
&lt;/section&gt;
&lt;button&gt;Reset Match&lt;/button&gt;

<!-- end snippet -->

huangapple
  • 本文由 发表于 2023年6月13日 03:00:18
  • 转载请务必保留本文链接:https://go.coder-hub.com/76459573.html
匿名

发表评论

匿名网友

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

确定