This is my attempt at the Ultimate Tic-Tac-Toe code challenge.
It uses jQuery to build out the game grid and find the states of all the "buttons" (actually <div>
s) when calculating whether or not someone has won an individual board or the entire game.
This version follows the recommendation that a filled board that is a draw does not count for either player.
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" lang="en" xml:lang="en">
<head>
<meta http-equiv="Content-type" content="text/html;charset=UTF-8" />
<title>Ultimate Tic-Tac-Toe</title>
<script type="text/javascript" src="http://code.jquery.com/jquery-1.11.0.min.js"> </script>
<style type="text/css">
body { text-align: center; }
div { display: inline-block; }
.grid { padding: 5px; border: solid 1px #300; }
.current-grid { background-color: #ff0; }
.button { background-color: #eee; width: 25px; height: 25px; margin: 5px;
text-align: center; vertical-align: middle; font-size: 25px; }
.X-won { background-color: #cfc; }
.O-won { background-color: #cdf; }
.no-win { background-color: #ccc; }
.X-selected { color: #080; }
.O-selected { color: #008; }
#game { position: absolute; left: 0px; right: 0px; }
</style>
<script type="text/javascript">
<!--
var isXTurn = true;
var currentGrid = -1;
$(function() {
$('body').append('<div id="game"></div>');
for (var i = 0; i < 9; i++) {
$('#game').append('<div class="grid" id="grid' + i + '"></div>');
if (i % 3 == 2) {
$('#game').append('<br />');
}
for (var j = 0; j < 9; j++) {
$('#grid' + i).append('<div class="button" id="button' + i + '-' + j + '"></div>');
if (j % 3 == 2) {
$('#grid' + i).append('<br />');
}
}
}
$('.button').click(function() {
var parent = $(this).parent();
var me = isXTurn ? 'X' : 'O';
if ($(this).is('.X-selected, .O-selected') || parent.is('.X-won, .O-won') ||
(currentGrid >= 0 && parent.attr('id') != 'grid' + currentGrid)) {
return;
}
$(this).addClass(me + '-selected').html(me);
if (checkForWin($(this), ('.' + me + '-selected'))) {
parent.addClass(me + '-won');
if (checkForWin(parent, ('.' + me + '-won'))) {
window.alert(me + ' won!');
resetGame();
return;
}
else if ($('.grid.X-won, .grid.O-won, .grid.no-win').length == 9) {
window.alert('The game is a draw!');
resetGame();
return;
}
}
else if (parent.children('.X-selected, .O-selected').length == 9) {
parent.addClass('no-win');
}
currentGrid = +($(this).attr('id').slice(-1));
$('.grid').removeClass('current-grid');
if ($('#grid' + currentGrid).is('.X-won, .O-won, .no-win')) {
currentGrid = -1;
}
else {
$('#grid' + currentGrid).addClass('current-grid');
}
isXTurn = !isXTurn;
});
function checkForWin(elem, match) {
var index = +(elem.attr('id').slice(-1));
var prefix = '#' + (elem.hasClass('button') ? elem.attr('id').slice(0, 8) : 'grid');
// Check rows
if (elem.nextUntil('br').add(elem.prevUntil('br')).filter(match).length == 2) {
return true;
}
// Check columns
if ($(prefix + (index % 3)).add($(prefix + (index % 3 + 3))).add($(prefix + (index % 3 + 6))).filter(match).length == 3) {
return true;
}
// Check diagonals
if ($(prefix + 0).add($(prefix + 4)).add($(prefix + 8)).filter(match).length == 3) {
return true;
}
if ($(prefix + 2).add($(prefix + 4)).add($(prefix + 6)).filter(match).length == 3) {
return true;
}
return false;
}
});
function resetGame() {
isXTurn = true;
currentGrid = -1;
$('div').removeClass('X-won O-won no-win current-grid X-selected O-selected');
$('.button').html('');
}
//-->
</script>
</head>
<body>
<h1>Ultimate Tic-Tac-Toe!</h1>
<p><a href="#" onclick="resetGame()">Restart</a></p>
</body>
</html>
It also passes the W3C validators for HTML and CSS, which is a bonus warm fuzzy.