Created
April 23, 2013 06:38
-
-
Save Fauntleroy/5441300 to your computer and use it in GitHub Desktop.
Tic Tac Toe
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<div id="game"> | |
<table id="board"> | |
<tr> | |
<td></td> | |
<td></td> | |
<td></td> | |
</tr> | |
<tr> | |
<td></td> | |
<td></td> | |
<td></td> | |
</tr> | |
<tr> | |
<td></td> | |
<td></td> | |
<td></td> | |
</tr> | |
</table> | |
<button id="reset">Reset</button> | |
</div> | |
<script src="//ajax.googleapis.com/ajax/libs/jquery/2.0.0/jquery.min.js"></script> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
~function(){ | |
var PLAYER = 'o', | |
AI = 'x'; | |
var $board, | |
$reset, | |
turn = PLAYER, | |
gameover = false, | |
paths = [[[0,0],[1,1],[2,2]], | |
[[0,2],[1,1],[2,0]], | |
[[0,0],[0,1],[0,2]], | |
[[1,0],[1,1],[1,2]], | |
[[2,0],[2,1],[2,2]], | |
[[0,0],[1,0],[2,0]], | |
[[0,1],[1,1],[2,1]], | |
[[0,2],[1,2],[2,2]]], | |
board = [[ null, null, null ], | |
[ null, null, null ], | |
[ null, null, null ]]; | |
// occupy a cell with the specified player's livery | |
var setCell = function( position, player ){ | |
board[ position[0] ][ position[1] ] = player; | |
var $cell = $board.find('tr:eq('+ position[0] +') > td:eq('+ position[1] +')'); | |
$cell.addClass( player ); | |
}; | |
// start the next turn | |
var nextTurn = function(){ | |
var status = checkStatus(); | |
turn = ( turn === AI )? PLAYER: AI; | |
if( turn === AI && status ){ | |
setTimeout( aiMove, 750 ); | |
} | |
}; | |
// do the next step in the game | |
var checkStatus = function(){ | |
var possible_ai_scores = findScoringPaths( AI ); | |
var possible_player_scores = findScoringPaths( PLAYER ); | |
var ai_scores = findScoringPaths( AI, 3 ); | |
var player_scores = findScoringPaths( PLAYER, 3 ); | |
if( ai_scores.length > 0 ){ | |
endGame( 'victory', AI ); | |
return false; | |
} | |
else if( player_scores.length > 0 ){ | |
endGame( 'victory', PLAYER ); | |
return false; | |
} | |
else if( possible_ai_scores.length + possible_player_scores.length === 0 ){ | |
endGame('draw'); | |
return false; | |
} | |
return true; | |
}; | |
// display an endgame message and update game status | |
var endGame = function( status, player ){ | |
if( status === 'victory' ){ | |
alert( player +' is victorious!' ); | |
} | |
else if( status === 'draw' ){ | |
alert( PLAYER +' and '+ AI +' failed to best one another' ); | |
} | |
gameover = true; | |
}; | |
// a simple, brutish AI move | |
var aiMove = function(){ | |
// find scoring paths, weight | |
var possible_scores = findScoringPaths( AI ); | |
var imminent_scores = $.grep( possible_scores, function( path, i ){ | |
return path.score === 2; | |
}); | |
// find enemy scoring paths, weight | |
var possible_opponent_scores = findScoringPaths( PLAYER ); | |
var imminent_opponent_scores = $.grep( possible_opponent_scores, function( path, i ){ | |
return path.score === 2; | |
}); | |
if( !board[1][1] ){ | |
setCell( [1,1], AI ); | |
} | |
else if( imminent_scores.length > 0 ){ | |
var cell = firstEmptyCell( imminent_scores[0].path ); | |
setCell( cell, AI ); | |
} | |
else if( imminent_opponent_scores.length > 0 ){ | |
var cell = firstEmptyCell( imminent_opponent_scores[0].path ); | |
setCell( cell, AI ); | |
} | |
else if( possible_opponent_scores.length > 0 ){ | |
var cell = firstEmptyCell( possible_opponent_scores[0].path ); | |
setCell( cell, AI ); | |
} | |
else if( possible_scores.length > 0 ){ | |
var cell = firstEmptyCell( possible_scores[0].path ); | |
setCell( cell, AI ); | |
} | |
// initiate the next turn | |
nextTurn(); | |
}; | |
// find possible scoring paths for specified player | |
// sort scoring paths by score | |
// limit scoring paths to a certain score | |
var findScoringPaths = function( player, minscore ){ | |
minscore = minscore || 0; | |
var possible_scores = [], | |
opponent = ( player === PLAYER )? AI: PLAYER; | |
for( var i in paths ){ | |
var path = paths[i], | |
score = 0, | |
blocked = false; | |
for( var ii in path ){ | |
var cell = board[ path[ii][0] ][ path[ii][1] ]; | |
if( cell === opponent ){ | |
blocked = true; | |
break; | |
} | |
else if( cell === player ){ | |
score++; | |
} | |
} | |
if( !blocked && score >= minscore ){ | |
possible_scores.push({ | |
path: path, | |
score: score | |
}); | |
} | |
} | |
// sort paths by score chance | |
possible_scores.sort( function( a, b ){ | |
return b.score - a.score; | |
}); | |
return possible_scores; | |
}; | |
// find the first empty cell in a path | |
var firstEmptyCell = function( path ){ | |
var cell; | |
for( var i in path ){ | |
if( !board[ path[i][0] ][ path[i][1] ] ){ | |
cell = path[i]; | |
break; | |
} | |
} | |
return cell; | |
}; | |
// reset the status of the game | |
var reset = function(){ | |
board = [[ null, null, null ], | |
[ null, null, null ], | |
[ null, null, null ]]; | |
turn = PLAYER; | |
$board.find('td').removeClass('x o'); | |
gameover = false; | |
}; | |
// simple bindings to make the game work | |
$(function(){ | |
$board = $('#board'); | |
$reset = $('#reset'); | |
$board.on( 'click', 'td:not(.x,.o)', function( e ){ | |
if( gameover || turn !== PLAYER ) return; | |
var $cell = $(this); | |
var $row = $cell.parent(); | |
var position = [ $row.index(), $cell.index() ]; | |
// set square | |
setCell( position, PLAYER ); | |
// use turn | |
nextTurn(); | |
}); | |
$reset.on( 'click', reset ); | |
}); | |
}(); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
body { | |
font: sans-serif; | |
} | |
#board { | |
margin: 15px; | |
padding: 0; | |
border-spacing: 2px; | |
background: rgb( 220, 220, 220 ); | |
-webkit-perspective: 1000; | |
} | |
#board tr td { | |
width: 100px; | |
height: 100px; | |
margin: 0; | |
padding: 0; | |
background: rgb( 235, 235, 235 ); | |
font-size: 85px; | |
font-weight: bold; | |
text-align: center; | |
border: rgb( 204, 204, 204 ) 2px solid; | |
-webkit-transform-style: preserve-3d; | |
-webkit-transition: 250ms; | |
box-shadow: inset 0px 0px 15px 5px rgba( 0, 0, 0, 0.025 ); | |
} | |
#board tr td:hover:not(.x):not(.o) { | |
background: rgb( 255, 255, 255 ); | |
box-shadow: inset 0px 0px 25px 5px rgba( 0, 0, 0, 0.045 ), 0px 0px 30px 5px rgba( 255, 255, 255, 0.65 ), 0px 5px 15px 0px rgba(0, 0, 0, 0.5); | |
cursor: pointer; | |
-webkit-transform: rotateX( 5deg ) scale(1.05) translateZ(10px); | |
position: relative; | |
z-index: 99; | |
} | |
#board tr td.x, | |
#board tr td.o { | |
background: rgb( 250, 250, 250 ); | |
-webkit-transform: rotateX( 180deg ); | |
} | |
#board tr td.x { | |
color: #F00; | |
} | |
#board tr td.x:after { | |
content: "\00D7"; | |
} | |
#board tr td.o { | |
color: #00F; | |
} | |
#board tr td.o:after { | |
content: "\25CB"; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment