Skip to content

Instantly share code, notes, and snippets.

@bruno-de-queiroz
Created September 3, 2014 01:15
Show Gist options
  • Select an option

  • Save bruno-de-queiroz/856fb7a3917e068d7735 to your computer and use it in GitHub Desktop.

Select an option

Save bruno-de-queiroz/856fb7a3917e068d7735 to your computer and use it in GitHub Desktop.
A Pen by Bruno de Queiroz.
<div id="container">
<p id="result" class="hide"></p>
<table celpadding="0" celspacing="0">
<tr>
<td id="pos-0" onclick="TicTacToe.play(0)"></td>
<td id="pos-1" onclick="TicTacToe.play(1)"></td>
<td id="pos-2" onclick="TicTacToe.play(2)"></td>
</tr>
<tr>
<td id="pos-3" onclick="TicTacToe.play(3)"></td>
<td id="pos-4" onclick="TicTacToe.play(4)"></td>
<td id="pos-5" onclick="TicTacToe.play(5)"></td>
</tr>
<tr>
<td id="pos-6" onclick="TicTacToe.play(6)"></td>
<td id="pos-7" onclick="TicTacToe.play(7)"></td>
<td id="pos-8" onclick="TicTacToe.play(8)"></td>
</tr>
</table>
<div id="victory"></div>
<button onclick="TicTacToe.reset()">Reset</button>
</div>
window.TicTacToe = (function() {
var _board, _victories, _moves, _finished = false, _players, _victory, _victoryElement, _containerElement, _resultElement;
_containerElement = document.getElementById( 'container' );
_victoryElement = document.getElementById( 'victory' );
_resultElement = document.getElementById('result');
_board = '000000000'.split('');
_victories = [ '048', '147', '246' , '345', '012' , '258' , '678' , '036' ];
_players = {
user :[],
ai: []
};
function _diff( a1, a2, log ){
var k = 0, i = 0, diff = [];
for( i = 0 ; i < a2.length ; i++ ){
if( a1.indexOf( a2[ i ] ) == -1 ){
diff.push( a2[ i ] );
}
}
return diff;
}
function _isPossible( n ){
return _board[ n ] == '0';
}
function _has( key ){
var i=0, j=_victories.length;
for( ; i < j ; i++ ){
if ( key == _victories[ i ] ){
_victory = _victories[ i ];
return true;
}
}
return null;
}
function _hasWinner( next ){
_find( _players.ai, _has , function( result ){
if ( result === true ){
return next( 'computer' );
}
return _find( _players.user, _has, function( result ){
if ( result === true ){
return next( 'user' );
}
return next();
});
});
}
function _find( a, condition, next ){
var i=0,j,l,b,c,d,e,result,len = a.length;
a.sort();
for( ; i < len; i++ ){
b = a[ i ];
if( a[ i + 3] ){
e = a[i] + '' + a[i+1] + '' + a[i+2] + '' + a[i+3];
result = condition.call(this, e );
if ( result != null ){
return next( result );
}
}
for( j = i+1; j < len; j++ ){
c = b + '' + a[ j ];
for( l = len -1; l > j; l-- ){
d = c + '' + a[ l ];
result = condition.call(this, d );
if ( result != null ){
return next( result );
}
}
result = condition.call(this, c );
if ( result != null ){
return next( result );
}
}
result = condition( b );
if ( result != null ){
return next( result );
}
}
return next();
}
function _mark( n, u, log ){
if( n > 8 ) {
return false;
}
if( !_isPossible( n ) ){
return false;
}
_board[ n ] = u;
_players[ u == '1' ? 'user' : 'ai' ].push( n + '');
return _draw();
}
function _write( msg ){
_resultElement.className = msg != '' ? '' : 'hide';
_resultElement.innerHTML = msg;
}
function _draw() {
_hasWinner( function( winner ){
var msg = "Game ended.";
if( winner ){
_write( msg + " Winner: " + winner );
_containerElement.className = winner;
return _finished = true;
}
if( _board.join('').indexOf(0) == -1 ){
_containerElement.className = '';
_write( msg );
return _finished = true;
}
});
var i=0, el, klass;
for( ; i< _board.length; i++ ){
switch( _board[ i ]){
case '1':
klass = 'user';
break;
case '2':
klass = 'computer';
break;
default :
klass = '';
}
el = document.getElementById( 'pos-' + i );
el.className = klass;
}
if( _victory != null ){
_victoryElement.className = 'won-' + _victory;
}
return true;
}
function _calculate( player, threshold, max, next, log ){
var i = 0, k = 0, l = 0, user = player, _d, diff = [];
for( ; i < _victories.length; i++ ){
_d = _diff( user, _victories[ i ].split(''), log );
if( diff.length == max ){
break;
}
if( _d.length == threshold ){
for( k = 0; k < _d.length; k++ ){
if( diff.indexOf( _d[ k ] == -1 ) ){
diff.push(_d[ k ]);
}
}
}
}
return next( diff );
}
function _verify( moves ){
for( i = 0; i < moves.length; i++ ){
if( _isPossible( moves[ i ] ) ){
return moves[ i ];
}
}
return null;
}
function _verifyPossible( moves ){
var possibles = [];
for( i = 0; i < moves.length; i++ ){
if( _isPossible( moves[ i ] ) ){
possibles.push(moves[ i ]);
}
}
return possibles;
}
function _getNextRandom(){
var random = Math.floor((Math.random() * 8 ));
return _isPossible( random ) ? random : _getNextRandom();
}
function _simulate( moves, next ){
var tempUserA, tempUserB, move, i, j;
tempUserA = _players.user.slice(0);
tempUserB = _players.user.slice(0);
for( i = 2; i <= moves.length; i+=2 ){
move = moves[ i - 2 ];
nmove = moves[ i - 1 ];
if( _isPossible( move ) && _isPossible( nmove )){
if( nmove ){
tempUserA.push( nmove );
return _calculate( tempUserA, 1, 3, function( m ){
m = _verifyPossible( m );
if( m.length < 2 ){
return next( move );
} else {
tempUserB.push( move );
return _calculate( tempUserB, 1, 3, function( v ){
v = _verifyPossible( v );
if( v.length < 2 ){
return next( nmove );
} else {
moves.splice( i - 2, 2 );
return _simulate( moves, next );
}
});
}
});
} else {
return next()
}
}
}
return next();
}
function _ai(){
var move;
if( !_finished ){
// Verifica se pode ganhar
_calculate( _players.ai, 1, 3, function( finish ){
if( finish != null ){
move = _verify( finish );
if( move ){
return _mark( move, '2' );
}
}
// Verifica se o usuario pode ganhar
_calculate( _players.user, 1, 3, function( defend ) {
if( defend != null ){
move = _verify( defend );
if( move ){
return _mark( move, '2' );
}
}
// Preve a jogada do usuario para determinar a propria jogada
if( _players.user.length == 1 ){
if( _players.user[ 0 ] != 4 )
move = 4;
else {
var corners = [ '0', '2', '6', '8' ];
move = corners[ Math.floor( Math.random() * (corners.length-1) ) ];
}
return _mark( move, '2' );
}
_calculate( _players.ai, 2, 8, function( moves ){
if( moves != null ){
_simulate( moves, function( move ){
if( move != null ){
return _mark( move, '2' );
}
return _mark( _getNextRandom(), '2' );
})
}
});
});
});
}
}
function _play( n ){
if( !_finished ){
if( _mark( n , '1' ) ){
_ai();
}
}
}
function _reset(){
_finished = false;
_players = { user: [], ai: [] };
_board = '000000000'.split('');
_write('');
_draw();
_victory = null;
_victoryElement.className = '';
_containerElement.className = '';
}
_draw();
return {
play: _play,
reset: _reset
}
})();
#container { position:absolute; top:50%; margin-top:-170px; margin-left:-150px; left:50%; }
table { width:300px; height:300px; margin:0; padding:0; font-family: 'arial'; border:collapsed;}
table tr td { width: 100px; height:100px; background:#efefef; text-align:center; position:relative; text-align:center; -webkit-transition:opacity .2s ease-in-out; cursor:pointer; }
table tr td::before, table tr td::after { opacity: 0; }
table tr td:hover { opacity:0.5; -webkit-transition:opacity .2s ease-in-out; }
table tr td.user { }
table tr td.user::before { content:''; border-top:6px solid rgb(79, 130, 206); width:80px; transform:rotate(45deg); left:8px; position:absolute; -webkit-transition:all .2s ease-in-out; opacity:1; }
table tr td.user::after { content:''; border-top:6px solid rgb(79, 130, 206); width:80px; position:absolute; left:8px; transform:rotate(-45deg); -webkit-transition:all .2s ease-in-out; opacity:1;}
table tr td.computer { text-align:center;}
table tr td.computer::before { position:absolute; content: ''; display:inline-block; width:60px; height:60px; border-radius:80px; border:6px solid rgb(245, 74, 74); left:12px; top:15px; -webkit-transition:all .2s ease-in-out; opacity:1;}
button { display:block; margin:10px auto; padding:5px 10px 10px 10px; border-radius:5px; cursor:pointer; border:none; box-shadow: inset 0 -5px 0 rgba(100, 184, 167, 1); background:rgb(175, 219, 204); text-shadow:0 1px 0 white; color:rgb(40, 122, 99);}
button:active { padding: 10px 10px 5px 10px; box-shadow:inset 0 5px 0 white; }
button:focus { outline:none; }
#result.hide { display:none; }
#result { position:absolute; left:0; top:-70px; right:0; text-align:center; font-family: 'Arial';
background: rgb(253, 246, 61);
padding: 10px 0;
color: rgb(189, 153, 41);
font-weight: bold;
border-top: 2px solid white;
border-bottom: 2px solid white;
box-shadow: 0 2px 0 rgb(253, 246, 61), 0 -2px 0 rgb(253, 246, 61);
text-shadow: -1px -1px 0 rgb(241, 247, 197);
}
#victory { width:6px; background:black; position:absolute; left:0; height:300px; top:0; display:none; }
#victory[class^="won-"] { display:block; }
#victory.won-246 { transform: rotate(44deg); left:150px; }
#victory.won-048 { transform: rotate(-44deg); left:143px; }
#victory.won-012 { transform: rotate(90deg); left:147px; top:-97px; }
#victory.won-345 { transform: rotate(90deg); left:147px; top:6px; }
#victory.won-678 { transform: rotate(90deg); left:147px; top:107px; }
#victory.won-036 { left:47px; top:4px; }
#victory.won-147 { left:146px; top:4px; }
#victory.won-258 { left:244px; top:4px; }
.user #victory { background:rgb(79, 130, 206);}
.computer #victory { background:rgb(245, 74, 74);}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment