回合确实切换,新选择的位置被添加到playerTwo数组中,但它也被添加到playerOne中。我已经移动了部分代码,但这并不能解决问题。
const gameBoard = (() => {
const board = ['topLeft', 'topMiddle', 'topRight',
'middleLeft', 'middle', 'middleRight',
'bottomLeft', 'bottomMiddle', 'bottomRight'
];
return board
})();
// gameBoard[0] returns 'topLeft', gameBoard[1] returns topMiddle, and so on...
const createPlayer = (name, marker) => {
let score = 0;
const getScore = () => score;
const giveScore = () => score++;
let choices = [];
const pickSpot = function(spot){
const pickedSpot = gameBoard[spot];
choices.push(pickedSpot);
};
return {name, choices, marker, pickSpot, getScore, giveScore};
}
const gameOn = (() => {
const playerOne = createPlayer('Fred', 'X');
const playerTwo = createPlayer('Barney', 'O');
let playerOneChoices = playerOne.choices;
let playerTwoChoices = playerTwo.choices;
const winConditions = {
one : ['topLeft', 'topMiddle', 'topRight'],
two: ['middleLeft', 'middle', 'middleRight'],
three: ['bottomLeft', 'bottomMiddle', 'bottomRight'],
four: ['topLeft', 'middleLeft', 'bottomLeft'],
five: ['topMiddle', 'middle', 'bottomMiddle'],
six: ['topRight', 'middleRight', 'bottomRight'],
seven: ['topLeft', 'middle', 'bottomRight'],
eight: ['topRight', 'middle', 'bottomLeft']
};
const checkWinCondition = () => {
//makes it so two players can't have the same spot picked at the same time
function noRepeats(firstPick, repeatPick){
repeatPick.filter(element => {
if(firstPick.includes(element) === true){
repeatPick.splice(repeatPick.indexOf(element), 1);
}
})
}
noRepeats(playerTwoChoices, playerOneChoices);
noRepeats(playerOneChoices, playerTwoChoices);
//checks the players' picks to determine if someone wins the game
const vals = Object.keys(winConditions).map(key => winConditions[key]);
for(let x of vals) {
const playerOneCheck = x.every(e => playerOneChoices.includes(e));
const playerTwoCheck = x.every(e => playerTwoChoices.includes(e));
if(playerOneCheck === true) {
playerOne.giveScore();
playerOneChoices.length = 0;
playerTwoChoices.length = 0;
alert(`${playerOne.name} just won the game! His score is now ${playerOne.getScore()}!`);
} else if(playerTwoCheck === true) {
playerTwo.giveScore();
playerOneChoices.length = 0;
playerTwoChoices.length = 0;
alert(`${playerTwo.name} just won the game! His score is now ${playerTwo.getScore()}!`);
} else if(playerOneChoices.length === 5 && playerTwoChoices.length === 4){
playerOneChoices.length = 0;
playerTwoChoices.length = 0;
alert(`It's a tie! Neither ${playerOne.name} nor ${playerTwo.name} gain any points this round!`)
}
}
}
const topLeft = document.querySelector('.top-left');
const topMiddle = document.querySelector('.top-middle');
const topRight = document.querySelector('.top-right');
const middleLeft = document.querySelector('.middle-left');
const middle = document.querySelector('.middle');
const middleRight = document.querySelector('.middle-right');
const bottomLeft = document.querySelector('.bottom-left');
const bottomMiddle = document.querySelector('.bottom-middle');
const bottomRight = document.querySelector('.bottom-right');
const allSquares = document.querySelectorAll('.grid-container > div');
//variables for chaning turn
const players = [playerOne, playerTwo];
let turn = 0;
//picks corresponding spot on the board for the player that has a turn
const playerTurn = () => {
let currentPlayer = players[turn];
topLeft.addEventListener('click', () => currentPlayer.pickSpot(0));
topMiddle.addEventListener('click', () => currentPlayer.pickSpot(1));
topRight.addEventListener('click', () => currentPlayer.pickSpot(2));
middleLeft.addEventListener('click', () => currentPlayer.pickSpot(3));
middle.addEventListener('click', () => currentPlayer.pickSpot(4));
middleRight.addEventListener('click', () => currentPlayer.pickSpot(5));
bottomLeft.addEventListener('click', () => currentPlayer.pickSpot(6));
bottomMiddle.addEventListener('click', () => currentPlayer.pickSpot(7));
bottomRight.addEventListener('click', () => currentPlayer.pickSpot(8));
//changes player turn
turn++;
if(turn === players.length){
turn = 0;
}
checkWinCondition()
}
playerTurn()
//plays a new turn after any spot is picked
for(let e of allSquares){
e.addEventListener('click', playerTurn)
}
return {playerOne, playerTwo, playerOneChoices, playerTwoChoices}
})()
在我看来,这是事件侦听器没有“更新”回合值或其他内容的问题,但我不知道如何修复它。
您面临的问题是由于当前实现中添加事件侦听器的方式造成的。具体来说,每次调用playerTurn() 时,您都会向相同的DOM 元素添加更多的事件侦听器。这些事件侦听器是“堆叠”的,这意味着每次单击一个方块时,它都会触发当前回合和上一回合的多个处理程序,从而导致两个玩家的数组都被更新。
问题:每回合添加多个事件监听器 每次您单击一个方块时,都会添加一个新的侦听器,但不会删除以前的侦听器,因此两个玩家可能会将其选定的点推入同一个数组中。
解决方案:每个方格使用一个事件侦听器并正确管理转弯 您不必每次都添加新的事件侦听器,而是可以为每个方块添加一次事件侦听器,并管理该单个事件侦听器内的轮流切换。这样,只有正确的玩家动作才会被触发。
以下是修改代码来解决此问题的方法:
主要变化:
仅添加事件监听器一次。
在事件监听器内部, 确定轮到哪个玩家并处理逻辑 选择地点并在那里切换转弯。
const gameOn = (() => { const playerOne = createPlayer('Fred', 'X'); const playerTwo = createPlayer('巴尼', 'O'); 让playerOneChoices =playerOne.choices; 让playerTwoChoices =playerTwo.choices;
const winConditions = {
one: ['topLeft', 'topMiddle', 'topRight'],
two: ['middleLeft', 'middle', 'middleRight'],
three: ['bottomLeft', 'bottomMiddle', 'bottomRight'],
four: ['topLeft', 'middleLeft', 'bottomLeft'],
five: ['topMiddle', 'middle', 'bottomMiddle'],
six: ['topRight', 'middleRight', 'bottomRight'],
seven: ['topLeft', 'middle', 'bottomRight'],
eight: ['topRight', 'middle', 'bottomLeft']
};
const checkWinCondition = () => {
const vals = Object.keys(winConditions).map(key => winConditions[key]);
for (let x of vals) {
const playerOneCheck = x.every(e => playerOneChoices.includes(e));
const playerTwoCheck = x.every(e => playerTwoChoices.includes(e));
if (playerOneCheck === true) {
playerOne.giveScore();
playerOneChoices.length = 0;
playerTwoChoices.length = 0;
alert(`${playerOne.name} just won the game! His score is now ${playerOne.getScore()}!`);
} else if (playerTwoCheck === true) {
playerTwo.giveScore();
playerOneChoices.length = 0;
playerTwoChoices.length = 0;
alert(`${playerTwo.name} just won the game! His score is now ${playerTwo.getScore()}!`);
} else if (playerOneChoices.length === 5 && playerTwoChoices.length === 4) {
playerOneChoices.length = 0;
playerTwoChoices.length = 0;
alert(`It's a tie! Neither ${playerOne.name} nor ${playerTwo.name} gain any points this round!`);
}
}
};
const allSquares = document.querySelectorAll('.grid-container > div');
// Variables for changing turns
const players = [playerOne, playerTwo];
let turn = 0;
// Single event listener per square
allSquares.forEach((square, index) => {
square.addEventListener('click', () => {
let currentPlayer = players[turn];
// Pick the corresponding spot for the current player
currentPlayer.pickSpot(index);
// Check for win conditions
checkWinCondition();
// Change turn
turn = (turn + 1) % players.length;
}, { once: true }); // Add the listener only once for each square
});
return { playerOne, playerTwo, playerOneChoices, playerTwoChoices };
})();
变更说明: 每个方块单个事件侦听器:我们不是每次都重新添加事件侦听器,而是使用 forEach 向每个方块添加一个侦听器。这确保每个方块只有一个事件侦听器。
监听器内部的转弯处理:转弯切换逻辑在单个事件监听器内部处理。我们用 let currentPlayer =players[turn]; 检查现在轮到谁了然后使用turn = (turn + 1) %players.length;更新回合。
{once: true}:此选项确保每个事件侦听器只会为每个方块触发一次,使其无法再点击(因为玩家只能选择一个位置一次)。
现在,每次方形单击都会正确地将所选位置添加到正确的玩家选择中,并正确处理回合,而无需添加多个事件侦听器!