# VBForums CodeBank > CodeBank - JavaScript >  [ES6] Tic-Tac-Toe

## dday9

I posted this in the game demos forum, but I feel like it belongs in the JavaScript codebank too.

Here is an example of a simple player versus computer Tic-Tac-Toe game: https://jsfiddle.net/9bj2rvn0/

Source:


```
<!DOCTYPE html>
<html>
    <head>
        <meta content="text/html;charset=utf-8" http-equiv="Content-Type" />
        <meta content="utf-8" http-equiv="encoding" />
        <meta content="Dday9" name="author" />
        <meta content="Play Tic-Tac-Toe online with the power of HTML5" name="description" />
        <meta content="tic-tac-toe, html5, free, online, game" name="keywords" />

        <title>Tic Tac Toe</title>

        <style>
            body {
                font-family: Helvetica, sans-serif;
            }
            table {
                margin: auto;
            }
            table tbody tr td {
                font-size: 4rem;
                height: 5rem;
                text-align: center;
                width: 5rem;
            }

            /* border utilities */
            .u-border {
                border: 1px solid black;
            }
            .u-border-bottom {
                border-bottom: 1px solid black;
            }
            .u-border-left {
                border-left: 1px solid black;
            }
            .u-border-right {
                border-right: 1px solid black;
            }
            .u-border-top {
                border-top: 1px solid black;
            }

            /* color utilities */
            .u-color-blue {
                color: #0d6efd;
            }
            .u-color-red {
                color: #dc3545;
            }
        </style>
    </head>

    <body>
        <table>
            <caption>
                Wins:
                <span id="wins">0</span>
                - Losses:
                <span id="losses">0</span>
            </caption>
            <tbody>
                <tr>
                    <td class="u-border-bottom u-border-right"></td>
                    <td class="u-border-bottom u-border-left u-border-right"></td>
                    <td class="u-border-bottom u-border-left"></td>
                </tr>
                <tr>
                    <td class="u-border-bottom u-border-right u-border-top"></td>
                    <td class="u-border"></td>
                    <td class="u-border-bottom u-border-left u-border-top"></td>
                </tr>
                <tr>
                    <td class="u-border-right u-border-top"></td>
                    <td class="u-border-left u-border-right u-border-top"></td>
                    <td class="u-border-left u-border-top"></td>
                </tr>
            </tbody>
        </table>
        <script>
            let availableCells = [];
            let losses = 0;
            let unavailableCells = [];
            let wins = 0;

            window.onload = function () {
                const table = document.getElementsByTagName("table")[0];
                const tableBody = table.getElementsByTagName("tbody")[0];
                const tableRows = tableBody.getElementsByTagName("tr");

                Array.from(tableRows).forEach((tableRow) => {
                    const cells = tableRow.getElementsByTagName("td");
                    Array.from(cells).forEach((cell) => (cell.onclick = cellClicked));
                });
                resetGame();
            };

            /**
             * <td> cell event handler
             */
            function cellClicked() {
                const coordinate = determineCoordinate(this);
                if (!coordinate) {
                    return;
                }

                const cell = availableCells.find((availableCell) => availableCell.x === coordinate.x && availableCell.y === coordinate.y);
                if (!cell) {
                    return;
                }

                // print the cross
                printCross(this);

                // update the available/unavailable cells
                availableCells = availableCells.filter((availableCell) => availableCell !== cell);
                cell.owner = "x";
                unavailableCells.push(cell);

                if (determineWin("x")) {
                    // user won
                    alert("You won!");
                    ++wins;
                    resetGame();
                } else if (!availableCells.length) {
                    // cat (draw)
                    alert("Cat");
                    resetGame();
                } else {
                    // computer's turn
                    playComputer();
                }
            }

            /**
             * gets the X/Y coordinate of a <td> respective to the overall <table>
             */
            function determineCoordinate(cell) {
                const table = document.getElementsByTagName("table")[0];
                const tableBody = table.getElementsByTagName("tbody")[0];
                const tableRows = tableBody.getElementsByTagName("tr");
                for (let y = 0; y < tableRows.length; y++) {
                    const cells = tableRows[y].getElementsByTagName("td");
                    for (let x = 0; x < cells.length; x++) {
                        if (cells[x] === cell) {
                            return { x, y };
                        }
                    }
                }

                return null;
            }

            function determineWin(owner) {
                const ownerCells = unavailableCells.filter((unavailableCell) => unavailableCell.owner === owner);

                if (ownerCells.length < 3) {
                    // no point in checking
                    return false;
                }
                if (ownerCells.filter((ownerCell) => ownerCell.x === 0).length === 3) {
                    // 1st column match
                    return true;
                }
                if (ownerCells.filter((ownerCell) => ownerCell.x === 1).length === 3) {
                    // 2nd column match
                    return true;
                }
                if (ownerCells.filter((ownerCell) => ownerCell.x === 2).length === 3) {
                    // 3nd column match
                    return true;
                }
                if (ownerCells.filter((ownerCell) => ownerCell.y === 0).length === 3) {
                    // 1st column match
                    return true;
                }
                if (ownerCells.filter((ownerCell) => ownerCell.y === 1).length === 3) {
                    // 2nd column match
                    return true;
                }
                if (ownerCells.filter((ownerCell) => ownerCell.y === 2).length === 3) {
                    // 3nd column match
                    return true;
                }
                if (ownerCells.filter((ownerCell) => (ownerCell.x === 0 && ownerCell.y === 0) || (ownerCell.x === 1 && ownerCell.y === 1) || (ownerCell.x === 2 && ownerCell.y === 2)).length === 3) {
                    // diagnoal top left to bottom right match
                    return true;
                }
                if (ownerCells.filter((ownerCell) => (ownerCell.x === 2 && ownerCell.y === 0) || (ownerCell.x === 1 && ownerCell.y === 1) || (ownerCell.x === 0 && ownerCell.y === 2)).length === 3) {
                    // diagnoal top right to bottom left match
                    return true;
                }

                return false;
            }

            function playComputer() {
                // get a random coordinate
                const randomCell = availableCells[Math.floor(Math.random() * availableCells.length)];
                const table = document.getElementsByTagName("table")[0];
                const tableBody = table.getElementsByTagName("tbody")[0];
                const tableRow = tableBody.getElementsByTagName("tr")[randomCell.y];
                const cell = tableRow.getElementsByTagName("td")[randomCell.x];

                // print the cross
                printCircle(cell);

                // update the available/unavailable cells
                availableCells = availableCells.filter((availableCell) => availableCell !== randomCell);
                randomCell.owner = "o";
                unavailableCells.push(randomCell);

                if (determineWin("o")) {
                    // player won
                    alert("CPU won :(");
                    ++losses;
                    resetGame();
                } else if (!availableCells.length) {
                    // cat (draw)
                    alert("Cat");
                    resetGame();
                }
            }

            /**
             * sets a <td>'s text to "O" and adds the red color class
             */
            function printCircle(cell) {
                cell.innerText = "O";
                cell.classList.add("u-color-red");
            }

            /**
             * sets a <td>'s text to "X" and adds the blue color class
             */
            function printCross(cell) {
                cell.innerText = "X";
                cell.classList.add("u-color-blue");
            }

            /**
             * updates the global variables as well as the DOM
             */
            function resetGame() {
                // update the win/loss ratio
                document.getElementById("losses").innerText = losses;
                document.getElementById("wins").innerText = wins;

                // reset the availableCells/unavailableCells
                availableCells = [];
                unavailableCells = [];
                const table = document.getElementsByTagName("table")[0];
                const tableBody = table.getElementsByTagName("tbody")[0];
                const tableRows = tableBody.getElementsByTagName("tr");
                for (let y = 0; y < tableRows.length; y++) {
                    const cells = tableRows[y].getElementsByTagName("td");
                    for (let x = 0; x < cells.length; x++) {
                        // clear the text of the <td> and add the cell to the availableCells
                        cells[x].innerText = "";
                        availableCells.push({ x, y });
                    }
                }
            }
        </script>
    </body>
</html>
```

----------

