即使在 tic tac toe 游戏中轮到玩家二后,事件侦听器也会添加到玩家一

问题描述 投票:0回答:1

回合确实切换,新选择的位置被添加到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}
})()

在我看来,这是事件侦听器没有“更新”回合值或其他内容的问题,但我不知道如何修复它。

javascript oop dom
1个回答
0
投票

您面临的问题是由于当前实现中添加事件侦听器的方式造成的。具体来说,每次调用playerTurn() 时,您都会向相同的DOM 元素添加更多的事件侦听器。这些事件侦听器是“堆叠”的,这意味着每次单击一个方块时,它都会触发当前回合和上一回合的多个处理程序,从而导致两个玩家的数组都被更新。

问题:每回合添加多个事件监听器 每次您单击一个方块时,都会添加一个新的侦听器,但不会删除以前的侦听器,因此两个玩家可能会将其选定的点推入同一个数组中。

解决方案:每个方格使用一个事件侦听器并正确管理转弯 您不必每次都添加新的事件侦听器,而是可以为每个方块添加一次事件侦听器,并管理该单个事件侦听器内的轮流切换。这样,只有正确的玩家动作才会被触发。

以下是修改代码来解决此问题的方法:

主要变化:

  1. 仅添加事件监听器一次。

  2. 在事件监听器内部, 确定轮到哪个玩家并处理逻辑 选择地点并在那里切换转弯。

    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}:此选项确保每个事件侦听器只会为每个方块触发一次,使其无法再点击(因为玩家只能选择一个位置一次)。

现在,每次方形单击都会正确地将所选位置添加到正确的玩家选择中,并正确处理回合,而无需添加多个事件侦听器!

© www.soinside.com 2019 - 2024. All rights reserved.