I'm having a bug on my tictactoe game coded in html/css/javascript (with jquery).

Most of the times the game works properly but in some cases (seems it doesn't depend on the positions of the pieces on the board or the sequence of the moves, I haven't managed to figure out the cases where it breaks as it is quite random) it gives wrong winner numbers (sometimes even shows a win alert when anyone should win) and it changes the expected pieces (it puts a player 1 piece when player 2 is playing and instead).

Every time this bug happens, it shows the alert of the winner (wrong winner always) and when the game resets the last clicked position doesn't reset.

I've already checked that the function WhoWins(board) works properly.

JAVASCRIPT:

const NO_WINNER = 0;
const PL1 = 1;
const PL2 = 2;
const FREE = 0;
const PIECEPL1 = 'X';
const PIECEPL2 = 'O';

$(document).ready(function() {
    TicTacToe();
});

// **** ACTION ****
function TicTacToe() {
    console.log("Game start");
    // Initialization of variables
    var moves = 0;
    var board = [[FREE, FREE, FREE],[FREE, FREE, FREE],[FREE, FREE, FREE]];
    var winner = NO_WINNER;
    $( ".square" ).html( "" ); // Reset of board
    $( "#pnum" ).html( PL1 ); // Player 1 starts
    StartMove(moves, board);
}

// **** ACTION ****
// PRE: moves is integer, board is integer 3x3 matrix.
// POST: The game has been updated.
function StartMove(moves, board) {
    console.log("Move " + moves);
    // We wait for a click on some square
    $( ".square" ).each(function() {
        $( this ).on("click", function() {
            var id = $( this ).attr( "id" );
            // [id[1]][id[2]] is the position of the clicked square in the board
            var i = id[1];
            var j = id[2];
            if (board[i][j] == FREE) { // We update the board only if the clicked position isn't already marked
                if (moves%2 == 0) { // Player 1 is playing
                    $( '#' + id ).html(PIECEPL1);
                    board[i][j] = PL1;
                }
                else { // Player 2 is playing
                    $( '#' + id ).html(PIECEPL2);
                    board[i][j] = PL2;
                }
                ++moves;
                winner = WhoWins(board);
                // We check the situation of the game
                if (moves == 9 && winner == NO_WINNER) {
                    alert( "Draw!" );
                    TicTacToe(); // We start a new game
                }
                else if (winner == NO_WINNER) {
                    $( "#pnum" ).html(moves%2 + 1); // We write the number of next move's player (We add one not because it's the next move but because the players are numbered 1,2 and not 0,1)
                    StartMove(moves, board); // We start the next move
                }
                else {
                    alert( "The winner is Player " + winner );
                    TicTacToe(); // We start a new game 
                }
            }
        });
    });
}

// **** FUNCTION ****
// PRE: board is integer 3x3 matrix.
// POST: Returns integer 0 if there is no winner, integer 1 if player 1 wins or integer 2 if player 2 wins
function WhoWins(board) {
    // We check for row equality
    if (board[0][0] != FREE && board[0][0] == board[0][1] && board[0][0] == board[0][2]) return board[0][0];
    if (board[1][0] != FREE && board[1][0] == board[1][1] && board[1][0] == board[1][2]) return board[1][0];
    if (board[2][0] != FREE && board[2][0] == board[2][1] && board[2][0] == board[2][2]) return board[2][0];
    // We check for columns equality
    if (board[0][0] != FREE && board[0][0] == board[1][0] && board[0][0] == board[2][0]) return board[0][0];        
    if (board[0][1] != FREE && board[0][1] == board[1][1] && board[0][1] == board[2][1]) return board[0][1];
    if (board[0][2] != FREE && board[0][2] == board[1][2] && board[0][2] == board[2][2]) return board[0][2];
    // We check for diagonal equality
    if (board[0][0] != FREE && board[0][0] == board[1][1] && board[0][0] == board[2][2]) return board[0][0];
    if (board[0][2] != FREE && board[0][2] == board[1][1] && board[0][2] == board[2][0]) return board[0][2];
    return NO_WINNER;
}

HTML:

<!DOCTYPE html>
<html>
    <head>
        <script type = "text/javascript" src = "jquery-2.1.0.min.js"> </script>
        <script type = "text/javascript" src = "tictactoe.js"> </script>
        <link rel = "stylesheet" type = "text/css" href = "tictactoe.css">
        <title> Tic-tac-toe </title>
    </head>
    <body>
        <header></header>
        <div id = "board">
            <div class = "square" id = "p00"></div> <!-- It's important for the id to not change, as it identifies the position of the square in the board -->
            <div class = "square" id = "p01"></div>
            <div class = "square" id = "p02"></div>
            <div class = "square" id = "p10"></div>
            <div class = "square" id = "p11"></div>
            <div class = "square" id = "p12"></div>
            <div class = "square" id = "p20"></div>
            <div class = "square" id = "p21"></div>
            <div class = "square" id = "p22"></div>
        </div>
        <p>Player&nbsp; <span id = "pnum"></span></p>
    </body>
</html>

CSS:

body { background-color: black }

#board {
    width: 914px;
    height: 914px;
    display: inline-block;
}

.square {
    border: dotted white 3px;
    width: 300px;
    height: 300px;
    display: inline-block;
    vertical-align: top;
    margin-right: -4px; 
    border-radius: 20%;
    text-align: center;
    line-height: 310px;
    font-family: Arial;
    font-size: 2000%;
    color: white;
}

p {
    color: white;
    font-size: 80px;
    display: inline-block;
    position: absolute;
    margin-left: 30px;
    top: -60px;
    font-family: Arial;
}
有帮助吗?

解决方案

Every time you call your StartMove() function you apply a new click event listener. Therefore, with each new game an additional click event is attached to the element. You don't want this, so remove (unbind) the click events before re-applying them.

I.E replace this:

$( this ).on("click", function() {...

with this:

$( this ).unbind("click").on("click", function() {...

Because you're new I also made you a jsFiddle so that you're more familiar with it for next time you post a question ;-)

许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top