Tic Tac Toe

by Bill Withers

HTML

<script src="https://raw.github.com/LeaVerou/prefixfree/master/prefixfree.min.js"></script>
<p class="score" id="X">0</p>
<p class="score" id="O">0</p>
<div id="ttt">
    <ol>
        <li></li> <li></li> <li></li>
        
        <li></li> <li></li> <li></li>
        
        <li></li> <li></li> <li></li>
    </ol>
</div>

CSS

body {font-family: sans-serif;}
#ttt {background: #f9f9f9; margin: 40px auto; width: 300px; height: 300px; padding: 5px 0 2px 5px; border: 1px solid #eee; box-shadow: 0px 15px 10px -15px rgba(0,0,0,0.2);}
#ttt li {float: left; width: 97px; height: 97px; border: 1px solid #ddd; background: #fff;}
#ttt li[class] {text-shadow: 0 2px 1px rgba(255,255,255,1), 0 -2px 1px rgba(0,0,0,0.05);}

#ttt .X, #X {background: #d9f4ff;}
#ttt .O, #O {background: #ffedd9;}
.X:before, .O:before { display: block; text-align: center; font-size: 62px; width: 97px; line-height: 97px;}
#X:before, #O:before { color: #777; margin-right: 10px;}
.score {padding: 5px; font-family: Consolas, monospace; font-weight: bold; font-size: 22px;}
.X:before, #X:before {content: "X";}
.O:before, #O:before {content: "O";}

JavaScript

(function TicTacToe() {
    var board = $('#ttt'),
        boxes = board.find('li'),
        map = { X: '', O: '' },
        players = {
            X: { score: 0 },
            O: { score: 0 }
        },
        active = 'X',
        turns = 0,
        wins = ['012', '345', '678', '036', '147', '258', '048', '246'];

    function turn() {
        ++turns;
        var box = $(this),
            a = map[active];
        box.addClass(active);
        map[active] += box.index();
        map[active] = map[active].split('').sort().join('');

        checkTurn();
    }

    function checkTurn() {
        var over = false;
        $.each(wins, function(i, win) {
            var winning = new RegExp('.?' + win[0] + '.?' + win[1] + '.?' + win[2] + '.?');
            if (winning.test(map[active])) over = true;
        });

        if (over) { // matched a winning combination
            gameOver(active);
        } else {
            if (turns === 9) { // tie
                gameOver();
            } else { // prepare next turn
                active = (active === 'X') ? 'O' : 'X';
            }
        }
    }

    function gameOver(winner) {
        if (winner) {
            alert(winner + ', you Won! :-D');
            $('#' + active).text(++players[active].score);
        } else {
            alert('Well, it\'s a tie.');
        }
        newGame();
    }

    function newGame() {
        map['X'] = '';
        map['O'] = '';
        turns = 0;
        boxes.removeAttr('class');
    }

    function init() {
        board.delegate('li:not([class])', 'click', turn);
    }

    $(init);
})();