1
\$\begingroup\$

I've been working on a simple Tic Tac Toe game in JavaScript. It runs the way it should, but the Board.checkWin function (check every possible winning combo) could be better, it is very repetitive in its current state. Any ideas?

Here is my Cell class:

var Cell = function() {
this.value = "|_|";
};

Cell.prototype.setState = function(arg) {
    this.value = arg;
};

Cell.prototype.playable = function() {
    if (this.value == "|_|") {
        return true;
    } else {
        return false;
    }
};

Cell.prototype.render = function() {
    return this.value;
};

Here is my Board class:

var Board = function() {
    this.cells = [];
    this.currentPlayers = ["|X|","|O|","|X|","|O|","|X|","|O|","|X|", "|O|", "|X|"]; 
    this.winner = this.currentPlayers[1];
};

Board.prototype.startGame = function() {
    for (i = 0; i < 9; i++) {
        this.cells.push(new Cell);
    }
    return this.render();
};

Board.prototype.makePlay = function(position) {
    if (this.checkWin() == false) {

    if (position < this.cells.length) {
        var cell = this.cells[position];
        var currentPlayer = this.currentPlayers.shift();

        if (cell.playable() == true) {
        cell.setState(currentPlayer);
        }
    }   
    return this.render();
    }
};

Board.prototype.checkWin = function() {

for(var i = 0; i < this.cells.length; i++)
    if (this.cells[0].value == "|X|" && this.cells[1].value == "|X|" && this.cells[2].value == "|X|"    ||
        this.cells[0].value == "|O|" && this.cells[1].value == "|O|" && this.cells[2].value == "|O|" ||

        this.cells[3].value == "|X|" && this.cells[4].value == "|X|" && this.cells[5].value == "|X|" || 
        this.cells[3].value == "|O|" && this.cells[4].value == "|O|" && this.cells[5].value == "|O|" || 

        this.cells[6].value == "|X|" && this.cells[7].value == "|X|" && this.cells[8].value == "|X|" ||
        this.cells[6].value == "|O|" && this.cells[7].value == "|O|" && this.cells[8].value == "|O|" || 

        this.cells[0].value == "|X|" && this.cells[3].value == "|X|" && this.cells[6].value == "|X|" || 
        this.cells[0].value == "|O|" && this.cells[3].value == "|O|" && this.cells[6].value == "|O|" || 

        this.cells[1].value == "|X|" && this.cells[4].value == "|X|" && this.cells[7].value == "|X|" || 
        this.cells[1].value == "|O|" && this.cells[4].value == "|O|" && this.cells[7].value == "|O|" || 

        this.cells[2].value == "|X|" && this.cells[6].value == "|X|" && this.cells[8].value == "|X|" || 
        this.cells[2].value == "|O|" && this.cells[6].value == "|O|" && this.cells[8].value == "|O|" || 

        this.cells[0].value == "|X|" && this.cells[4].value == "|X|" && this.cells[8].value == "|X|" || 
        this.cells[0].value == "|O|" && this.cells[4].value == "|O|" && this.cells[8].value == "|O|" || 

        this.cells[6].value == "|X|" && this.cells[4].value == "|X|" && this.cells[2].value == "|X|" || 
        this.cells[6].value == "|O|" && this.cells[4].value == "|O|" && this.cells[2].value == "|O|")

        {
            return true;
        } else {
            return false;
    }
};

Board.prototype.render = function() {
    var boardArray = [];
    for (var i = 0; i < this.cells.length; i++) {
        boardArray.push(this.cells[i].value);
    }
    for (var j = 0; j < boardArray.length; j++) {
        var boardString = "TIC TAC TOE " + boardArray[0] + boardArray[1] + boardArray[2] + "\n ";
        boardString += " PICK A BOX " + boardArray[3] + boardArray[4] + boardArray[5] + " \n ";
        boardString += "   0 THRU 8 " + boardArray[6] + boardArray[7] + boardArray[8];
    }

    if (this.checkWin() == true) {
        return boardString + "\n   WE HAVE A WINNER!";
    } else {
    return boardString;     
    }
};
\$\endgroup\$
2
\$\begingroup\$

The most un-DRY code is checking if someone has won. You could add the following code to help you

// Row class

var Row = function{
    this.cells = [];
}

Row.prototype.allSame = function(){
    return this.cells[0] == this.cells[1] && this.cells[0] == this.cells[1];
}

// Expand the Board class
Board.prototype.getRow = function(num) {
    var row = new Row();

    // Horizontal rows
    if (num => 0 && num < 3) {
        row.cells.push(this.cells[3*num], this.cells[(3*num)+1], this.cells[(3*num)+2]);
        return row;
    }

    // Vertical rows
    if (num => 3 && num < 6) {
        row.cells.push(this.cells[num-3], this.cells[(num], this.cells[num+3]);
        return row;
    }

    // Diagonal rows
    if (num == 6) {
        row.cells.push(this.cells[0], this.cells[(5], this.cells[8]);
        return row;
    }

    if (num == 7) {
        row.cells.push(this.cells[2], this.cells[(5], this.cells[6]);
        return row;
    }

    return false;

};

Running on the assumtions that the first 3 horizontal rows are numbered from 0 to 2, the 3 columns from 3 to 5 and the 2 diagonals 6 and 7...

But I am not sure the amount of code you would save would be enough to make the change worth it, unless you are predicting adding bigger boards, beyond the classic 3x3.

\$\endgroup\$
0
\$\begingroup\$

The function checkWin can be written much shorter:

Board.prototype.checkWin = function() {
    var cells = this.cells;

    function three(a, b, c) {
        var symbol = cells[a].value;
        return (symbol === "|X|" || symbol === "|O|") &&
               cells[b].value === symbol &&
               cells[c].value === symbol;
    }

    return three(0, 1, 2) || three(3, 4, 5) || three(6, 7, 8) ||
           three(0, 3, 6) || three(1, 4, 7) || three(2, 5, 8) ||
           three(0, 4, 8) ||
           three(2, 4, 6);
    }
};

The helper function three checks a combination of three cells whether a player has won there.

\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy