撤消和显示历史按钮不起作用,不知道bug在哪里

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

我想要一个显示历史记录按钮,在您重新启动游戏时显示最新的比赛,以及一个撤消按钮来撤消 1 个步骤。但显示不正确,撤消按钮总是显示“没有可撤消的动作”

我尝试检查控制台日志,但我不知道错误在哪里

这是我的js代码:

javascript tic-tac-toe
1个回答
0
投票
document.addEventListener('DOMContentLoaded', function () {
    const dimensionButton = document.getElementById('dimension-button');
    const dimensionElement = document.getElementById('dimension');
    const statusElement = document.getElementById('status');
    const restartButton = document.getElementById('restart-btn');
    const singlePlayerToggle = document.getElementById('single-player-toggle');
    const boardElement = document.getElementById('board');
    const historyBtn = document.getElementById('history-button');
    const undoButton = document.getElementById('undo-btn');

    let dimension = 10;

    dimensionButton.textContent = `${dimension}x${dimension}`;

    let singlePlayerMode = false;
    let squares = Array(dimension).fill(Array(dimension).fill(null));
    let xIsNext = true;
    let theWinner = null;
    let winningLine = [];
    const dimensions = [10, 12, 16, 20];
    let dimensionIndex = 0; 

    dimensionButton.addEventListener('click', function () {
        stopTimer();
        dimensionIndex = (dimensionIndex + 1) % dimensions.length;
        dimension = dimensions[dimensionIndex];
        dimensionButton.textContent = `${dimension}x${dimension}`;
        restartGame();
    });
    //restartButton.addEventListener('click', restartGame);

    restartButton.addEventListener('click', function () {
        stopTimer(); // Stop the timer before restarting the game
        restartGame();
    });

    undoButton.addEventListener('click', function () {
        undoLastMove();
    });    

    historyBtn.addEventListener('click', function () {
        console.log("History button clicked");
        stopTimer();
        displayLatestMatchMoves();
    });    

    singlePlayerToggle.addEventListener('click', function () {
        stopTimer();
        toggleSinglePlayerMode();
        restartGame();
        if (singlePlayerMode && !xIsNext) {
            makeComputerMove();
        }
    });
    

    //UPDATE TIMING (10s each turn)
    const timingElement = document.querySelector('.timing');
    let timer;

    function startTimer() {
        resetTimer();
        let timeLeft = 10;
        timingElement.textContent = `Time left: ${timeLeft}s`;
    
        timer = setInterval(() => {
        if (theWinner) {
            clearInterval(timer);
            timingElement.textContent = '';
            return;
        }

        //if (!xIsNext) return;
    
        timeLeft--;
        timingElement.textContent = `Time left: ${timeLeft}s`;
    
        if (timeLeft === 0) {
            clearInterval(timer);
            if (singlePlayerMode && !xIsNext) {
                makeComputerMove();
            } else {
                xIsNext = !xIsNext;
                updateStatus();
            }
            //updateStatus();
            timingElement.textContent = '';
        }
        }, 1000);
    }  

    function resetTimer() {
        clearInterval(timer);
        timingElement.textContent = '';
    }

    function stopTimer(forceStop = false) {
        if (forceStop) {
            clearInterval(timer); // Clear the interval to stop the timer
            timingElement.textContent = ''; // Clear the timing display
        } else {
            // Do nothing if forceStop is false
        }
    }
        

    function handleClick(row, col) {
        //update
        console.log("Clicked on row:", row, "column:", col);

        resetTimer();
        if (theWinner || squares[row][col]) return;

        const newSquares = squares.map((row) => [...row]);
        newSquares[row][col] = xIsNext ? 'X' : 'O';
        squares = newSquares;
        //squares = newSquares;
        xIsNext = !xIsNext;

        const winner = calculateWinner(newSquares, row, col);
        if (winner) {
            theWinner = winner;
            winningLine = findWinningLine(newSquares, row, col, winner);
        }

        //update match moves
        currentMatchMoves.push([row, col]);
        console.log("Current match moves:", currentMatchMoves);

        renderBoard();
        updateStatus();
        //update
        startTimer();

        if (singlePlayerMode && !theWinner && !xIsNext) {
            makeComputerMove();
        } else {
            startTimer();
        }

        if (theWinner) {
            recordMatchHistory();
        }
        recordMatchHistory();
        console.log("Move recorded:", row, col);
    }

    function calculateWinner(currentSquares, row, col) {
        const currentPlayer = currentSquares[row][col];

        // Check horizontally
        let count = 1;
        let leftCol = col - 1;
        while (leftCol >= 0 && currentSquares[row][leftCol] === currentPlayer) {
        count++;
        leftCol--;
        }
        let rightCol = col + 1;
        while (rightCol < dimension && currentSquares[row][rightCol] === currentPlayer) {
        count++;
        rightCol++;
        }
        if (count >= 5) {
        return currentPlayer;
        }

        // Check vertically
        count = 1;
        let topRow = row - 1;
        while (topRow >= 0 && currentSquares[topRow][col] === currentPlayer) {
        count++;
        topRow--;
        }
        let bottomRow = row + 1;
        while (bottomRow < dimension && currentSquares[bottomRow][col] === currentPlayer) {
        count++;
        bottomRow++;
        }
        if (count >= 5) {
        return currentPlayer;
        }

        // Check diagonally (top-left to bottom-right)
        count = 1;
        let topLeftRow = row - 1;
        let topLeftCol = col - 1;
        while (topLeftRow >= 0 && topLeftCol >= 0 && currentSquares[topLeftRow][topLeftCol] === currentPlayer) {
        count++;
        topLeftRow--;
        topLeftCol--;
        }
        let bottomRightRow = row + 1;
        let bottomRightCol = col + 1;
        while (bottomRightRow < dimension && bottomRightCol < dimension && currentSquares[bottomRightRow][bottomRightCol] === currentPlayer) {
        count++;
        bottomRightRow++;
        bottomRightCol++;
        }
        if (count >= 5) {
        return currentPlayer;
        }

        // Check diagonally (top-right to bottom-left)
        count = 1;
        let topRightRow = row - 1;
        let topRightCol = col + 1;
        while (topRightRow >= 0 && topRightCol < dimension && currentSquares[topRightRow][topRightCol] === currentPlayer) {
        count++;
        topRightRow--;
        topRightCol++;
        }
        let bottomLeftRow = row + 1;
        let bottomLeftCol = col - 1;
        while (bottomLeftRow < dimension && bottomLeftCol >= 0 && currentSquares[bottomLeftRow][bottomLeftCol] === currentPlayer) {
        count++;
        bottomLeftRow++;
        bottomLeftCol--;
        }
        if (count >= 5) {
        return currentPlayer;
        }

        return null;
    }

    function findWinningLine(currentSquares, row, col, winner) {
        const currentPlayer = currentSquares[row][col];
        const lines = [];

        // Check horizontally
        let leftCol = col - 1;
        while (leftCol >= 0 && currentSquares[row][leftCol] === currentPlayer) {
        lines.push([row, leftCol]);
        leftCol--;
        }
        lines.push([row, col]);
        let rightCol = col + 1;
        while (rightCol < dimension && currentSquares[row][rightCol] === currentPlayer) {
        lines.push([row, rightCol]);
        rightCol++;
        }
        if (lines.length >= 5) {
        return lines;
        }

        // Check vertically
        let topRow = row - 1;
        while (topRow >= 0 && currentSquares[topRow][col] === currentPlayer) {
        lines.push([topRow, col]);
        topRow--;
        }
        lines.push([row, col]);
        let bottomRow = row + 1;
        while (bottomRow < dimension && currentSquares[bottomRow][col] === currentPlayer) {
        lines.push([bottomRow, col]);
        bottomRow++;
        }
        if (lines.length >= 5) {
        return lines;
        }

        // Check diagonally (top-left to bottom-right)
        let topLeftRow = row - 1;
        let topLeftCol = col - 1;
        while (topLeftRow >= 0 && topLeftCol >= 0 && currentSquares[topLeftRow][topLeftCol] === currentPlayer) {
        lines.push([topLeftRow, topLeftCol]);
        topLeftRow--;
        topLeftCol--;
        }
        lines.push([row, col]);
        let bottomRightRow = row + 1;
        let bottomRightCol = col + 1;
        while (bottomRightRow < dimension && bottomRightCol < dimension && currentSquares[bottomRightRow][bottomRightCol] === currentPlayer) {
        lines.push([bottomRightRow, bottomRightCol]);
        bottomRightRow++;
        bottomRightCol++;
        }
        if (lines.length >= 5) {
        return lines;
        }

        // Check diagonally (top-right to bottom-left)
        let topRightRow = row - 1;
        let topRightCol = col + 1;
        while (topRightRow >= 0 && topRightCol < dimension && currentSquares[topRightRow][topRightCol] === currentPlayer) {
        lines.push([topRightRow, topRightCol]);
        topRightRow--;
        topRightCol++;
        }
        lines.push([row, col]);
        let bottomLeftRow = row + 1;
        let bottomLeftCol = col - 1;
        while (bottomLeftRow < dimension && bottomLeftCol >= 0 && currentSquares[bottomLeftRow][bottomLeftCol] === currentPlayer) {
        lines.push([bottomLeftRow, bottomLeftCol]);
        bottomLeftRow++;
        bottomLeftCol--;
        }
        if (lines.length >= 5) {
        return lines;
        }

        return [];
    }

    function renderBoard() {
        boardElement.innerHTML = '';
        for (let row = 0; row < dimension; row++) {
            const rowElement = document.createElement('div');
            rowElement.className = 'board-row';
    
            for (let col = 0; col < dimension; col++) {
                const value = squares[row][col];
                const isWinningSquare = winningLine.some(([winRow, winCol]) => winRow === row && winCol === col);
    
                const squareButton = document.createElement('button');
                squareButton.className = 'square';
                squareButton.style.backgroundColor = isWinningSquare ? 'yellow' : 'white';
                squareButton.style.color = value === 'X' ? 'blue' : 'red';
                squareButton.style.fontWeight = isWinningSquare ? 'bold' : 'normal';
                squareButton.textContent = value;
                squareButton.addEventListener('click', () => {
                    if (!singlePlayerMode || (singlePlayerMode && xIsNext)) {
                        handleClick(row, col);
                    }
                });
    
                rowElement.appendChild(squareButton);
            }
    
            boardElement.appendChild(rowElement);
        }
    }    

    function updateStatus() {
        if (theWinner) {
        statusElement.textContent = `Chiến thắng: ${theWinner}`;
        } else {
        statusElement.textContent = `Người chơi: ${xIsNext ? 'X' : 'O'}`;
        }
    }

    function restartGame() {
        squares = Array(dimension).fill(Array(dimension).fill(null));
        xIsNext = true; 
        theWinner = null;
        winningLine = [];
        currentMatchMoves = [];

        renderBoard();
        updateStatus();
        //recordMatchHistory();

        if (singlePlayerMode && !xIsNext) {
            makeComputerMove();
        }
    }

    function makeComputerMove() {
        //update
        console.log("makeComputerMove called");
        console.log("singlePlayerMode:", singlePlayerMode);
        console.log("xIsNext:", xIsNext);
        console.log("theWinner:", theWinner);

        if (!singlePlayerMode || theWinner) {
            console.log("Exiting makeComputerMove early");
            return;
        }

        const availableMoves = [];
        const humanPlayer = xIsNext ? 'X' : 'O';
        const computerPlayer = xIsNext ? 'O' : 'X';

        squares.forEach((row, rowIndex) => {
        row.forEach((col, colIndex) => {
            if (!squares[rowIndex][colIndex]) {
                availableMoves.push([rowIndex, colIndex]);
            }
        });
        });

        if (availableMoves.length > 0) {
        // Check if the computer can win in the next move
        for (let i = 0; i < availableMoves.length; i++) {
            const [row, col] = availableMoves[i];
            const newSquares = squares.map((row) => [...row]);
            newSquares[row][col] = computerPlayer;

            if (calculateWinner(newSquares, row, col) === computerPlayer) {
                console.log("Computer winning move:", row, col);
                handleClick(row, col);
                return;
            }
        }

        // Check if the human player can win in the next move
        for (let i = 0; i < availableMoves.length; i++) {
            const [row, col] = availableMoves[i];
            const newSquares = squares.map((row) => [...row]);
            newSquares[row][col] = humanPlayer;

            if (calculateWinner(newSquares, row, col) === humanPlayer) {
                console.log("Human winning move:", row, col);
                handleClick(row, col);
                return;
            }
        }

        // Random move for normal difficulty
        const randomIndex = Math.floor(Math.random() * availableMoves.length);
        const [row, col] = availableMoves[randomIndex];

        // Choose a winning move for hard difficulty
        if (availableMoves.length >= 3) {
            for (let i = 0; i < availableMoves.length; i++) {
            const [row, col] = availableMoves[i];
            const newSquares = squares.map((row) => [...row]);
            newSquares[row][col] = computerPlayer;

            if (isWinningMove(newSquares, computerPlayer)) {
                handleClick(row, col);
                return;
            }
            }
        }

        console.log("Computer random move:", row, col);
        handleClick(row, col);
        }
    }

    function isWinningMove(currentSquares, player) {
        for (let row = 0; row < dimension; row++) {
        for (let col = 0; col < dimension; col++) {
            if (!currentSquares[row][col]) {
            const newSquares = currentSquares.map((row) => [...row]);
            newSquares[row][col] = player;
            if (calculateWinner(newSquares, row, col) === player) {
                return true;
            }
            }
        }
        }
        return false;
    }

    function toggleSinglePlayerMode() {
        singlePlayerMode = !singlePlayerMode;
        if (singlePlayerMode) {
        singlePlayerToggle.innerHTML = '&#x1F4BB;';
        } else {
        singlePlayerToggle.innerHTML = '&#x1F477; ';
        }
    }
    renderBoard();
    updateStatus();

    //UNDO BUTTON
    function undoLastMove() {
        console.log("Undo button clicked");
        if (currentMatchMoves.length > 0) {
            // Remove the last move from the current match moves
            const [lastMoveRow, lastMoveCol] = currentMatchMoves.pop();
            // Reset the game state to the state before the last move
            squares[lastMoveRow][lastMoveCol] = null;
            xIsNext = !xIsNext;
            // Re-render the board and update the status
            renderBoard();
            updateStatus();
            stopTimer(true); // Stop the timer after undoing the move
        } else {
            alert("No moves to undo");
        }
    }                    
    
    //update history function
    let matchHistory = [];
    let currentMatchMoves = [];

    function recordMatchHistory() {
        console.log("Recording match history");
        console.log("Current match moves:", currentMatchMoves);
        if (currentMatchMoves.length > 0) {
            // Check if the current match moves are already in the match history
            const isDuplicate = matchHistory.some(historyMoves =>
                JSON.stringify(historyMoves) === JSON.stringify(currentMatchMoves)
            );
    
            // If the current match moves are not a duplicate, record them
            if (!isDuplicate) {
                matchHistory.push([...currentMatchMoves]); // Push a copy of currentMatchMoves
                console.log("Match history:", matchHistory);
            }
    
            // Reset current match moves after recording
            currentMatchMoves = [];
        }
    }                                 
    
    function displayLatestMatchMoves() {
        console.log("Displaying latest match moves...");
        if (matchHistory.length > 0) {
            const latestMatchMoves = matchHistory[matchHistory.length - 1];
            console.log("Latest match moves:", latestMatchMoves);
            // Replay the latest match moves
            replayMatchMoves(latestMatchMoves);
        } else {
            alert("No match history available");
        }
    }
    
    function replayMatchMoves(moves) {
        // Reset the game state before replaying the moves
        squares = Array.from({ length: dimension }, () => Array.from({ length: dimension }, () => null));
        xIsNext = true; 
        theWinner = null;
        winningLine = [];
    
        moves.forEach((move, index) => {
            const [row, col] = move;
            console.log("Replaying move:", row, col); // Log each move being replayed
            squares[row][col] = xIsNext ? 'X' : 'O'; // Update the squares array directly
            xIsNext = !xIsNext; // Toggle the player after each move
    
            // Update xIsNext based on the number of moves replayed
            if (index === moves.length - 1) {
                // If it's the last move, the next player depends on the total number of moves
                xIsNext = moves.length % 2 === 0;
            }
        });
    
        // Render the board after all moves are replayed
        renderBoard();
        // Update the status after replaying all moves
        updateStatus();
    }    
  
});

这是我的js代码

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