Skip to content

Instantly share code, notes, and snippets.

@RemLampa
Created January 13, 2017 09:09
Show Gist options
  • Save RemLampa/8e43d898f28af7332c134dace84c0e16 to your computer and use it in GitHub Desktop.
Save RemLampa/8e43d898f28af7332c134dace84c0e16 to your computer and use it in GitHub Desktop.
Tic-Tac-Toe
<h1 id="title" class="text-primary">Tic Tac Toe</h1>
<div id="options" class="modal fade" role="dialog" tabindex="-1">
<div class="modal-dialog" role="document">
<div class="modal-content">
<div class="modal-header">
<h4 class="modal-title">Choose Your Side</h4>
</div>
<div class="modal-body">
<p class="lead text-center">Choose: "X" or "O"</p>
<p class="text-center">Default is "X".</p>
</div>
<div class="modal-footer">
<button id="x-button" type="button" class="btn btn-lg btn-primary" data-dismiss="modal">X</button>
<button id="o-button" type="button" class="btn btn-lg btn-danger" data-dismiss="modal">O</button>
</div>
</div>
</div>
</div>
<div id="toss-coin" class="modal fade" role="dialog" tabindex="-1">
<div class="modal-dialog" role="document">
<div class="modal-content">
<div class="modal-header">
<h4 class="modal-title">Toss Coin!</h4>
</div>
<div class="modal-body">
<p class="lead text-center"></p>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-lg btn-primary" data-dismiss="modal">Ok</button>
</div>
</div>
</div>
</div>
<div id="winDialog" class="modal fade" role="dialog" tabindex="-1">
<div class="modal-dialog" role="document">
<div class="modal-content">
<div class="modal-header">
<h4 class="modal-title"></h4>
</div>
<div class="modal-body">
<p class="lead text-center"></p>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-lg btn-danger" data-dismiss="modal">Reset</button>
</div>
</div>
</div>
</div>
<div class="container-fixed">
<div class="row">
<div id="cell-1" class="col-xs-4">
<div class="middle-align"></div>
</div>
<div id="cell-2" class="col-xs-4">
<div class="middle-align"></div>
</div>
<div id="cell-3" class="col-xs-4">
<div class="middle-align"></div>
</div>
</div>
<div class="row">
<div id="cell-4" class="col-xs-4">
<div class="middle-align"></div>
</div>
<div id="cell-5" class="col-xs-4">
<div class="middle-align"></div>
</div>
<div id="cell-6" class="col-xs-4">
<div class="middle-align"></div>
</div>
</div>
<div class="row">
<div id="cell-7" class="col-xs-4">
<div class="middle-align"></div>
</div>
<div id="cell-8" class="col-xs-4">
<div class="middle-align"></div>
</div>
<div id="cell-9" class="col-xs-4">
<div class="middle-align"></div>
</div>
</div>
</div>
$(document).ready(function() {
var playerCells = [],
aiCells = [],
remaining = 9,
winCells = -1,
player = 'X',
ai = 'O',
firstMove = 'ai';
// AI decision function
var aiPick = function(ai) {
var choice = -1,
choiceCell = '';
// first move with highest chance of winning is middle or corner cells
if (aiCells.length === 0 && playerCells.length === 0) {
choice = [1,3,5,7,9][Math.floor(Math.random()*5)];
} else if (aiCells.length === 1 && aiCells[0] !== 5 && [1,3,7,9].indexOf(playerCells[0]) !== -1) {
// always pick corners for second turn if first turn of both players are corners
while (choice === -1 || $('#cell-' + choice + ' div').html() !== '') {
choice = [1,3,7,9][Math.floor(Math.random() * 4)];
}
console.log('ai\'s second turn. pick a corner!');
} else {
choice = findWinCell(aiCells);
}
if (choice === -1) {
choice = findWinCell(playerCells);
if (choice === -1) {
// find best move
var blankCellArray = [];
patterns.forEach(function(pattern, patternIndex, patternArray) {
var blankCells = [];
if (pattern.every(function(cell, cellIndex, cellArray) {
return playerCells.indexOf(cell) === -1;
})) {
pattern.forEach(function(cell, cellIndex, cellArray) {
if (aiCells.indexOf(cell) === -1 && $('#cell-' + cell + ' div').html() === '') {
blankCells.push(cell);
}
});
if (blankCells.length === 2) {
blankCellArray.push(blankCells);
}
};
});
if (blankCellArray.length > 0) {
choice = blankCellArray[Math.floor(Math.random() * blankCellArray.length)][Math.floor(Math.random() * 2)];
console.log(blankCellArray, choice);
}
if (choice === -1) {
choice = Math.floor((Math.random() * 9) + 1);
}
}
}
choiceCell = '#cell-' + choice;
if ($(choiceCell).find('div').html() === '') {
$(choiceCell).find('div').html(ai);
aiCells.push(choice);
aiCells.sort();
winCells = checkWin(aiCells);
if (winCells === -1) {
remaining--;
if (remaining === 0) {
resetBoard('draw', [1, 2, 3, 4, 5, 6, 7, 8, 9]);
return;
}
$('.col-xs-4').each(function(index) {
if ($(this).find('div').html() === '') {
$(this).addClass('clickable');
}
});
} else {
resetBoard('ai', winCells);
}
} else {
aiPick(ai);
}
};
// find a winning cell
var findWinCell = function(cells) {
var missingCell = -1;
patterns.some(function(pattern, patternIndex, patternArray) {
var missing = [];
pattern.forEach(function(cell, cellIndex, cellArray) {
if (cells.indexOf(cell) === -1) {
missing.push(cell);
}
});
if (missing.length === 1 && $('#cell-' + missing[0] + ' div').html() === '') {
missingCell = missing[0];
return true;
} else {
return false;
}
});
return missingCell;
};
// winning patterns
var patterns = [
[1, 2, 3],
[4, 5, 6],
[7, 8, 9],
[1, 4, 7],
[2, 5, 8],
[3, 6, 9],
[1, 5, 9],
[3, 5, 7]
].sort();
// check for win
var checkWin = function(cells) {
var winIndex = -1;
patterns.some(function(pattern, patternIndex, array) {
if (pattern.every(function(cell, index, patternArray) {
return cells.indexOf(cell) != -1;
})) {
winIndex = pattern;
return true;
}
});
return winIndex;
};
// reset board
var resetBoard = function(side, array) {
if (side === 'ai') {
$('#winDialog .lead').html('You lose.');
} else if (side === 'player') {
$('#winDialog .lead').html('You win.');
} else {
$('#winDialog .lead').html('It\'s a draw!');
}
array.forEach(function(element, index, array) {
$('#cell-' + element + ' div').addClass('blinking');
});
var blinkInterval = setInterval(function() {
$('.blinking').fadeOut(250);
$('.blinking').fadeIn(250);
}, 500);
setTimeout(function() {
clearInterval(blinkInterval);
$('#winDialog').modal('show');
}, 1500);
$('#winDialog').on('hidden.bs.modal', function(event) {
winCells = -1;
remaining = 9;
aiCells = [];
playerCells = [];
$('.col-xs-4 div').html('');
$('.blinking').removeClass('blinking');
$('.clickable').removeClass('clickable');
if (firstMove === 'ai') {
aiPick(ai);
}
setTimeout(function() {
$('.col-xs-4').addClass('clickable');
}, 500);
});
};
// for implementation? (but first player always wins/draws)
var tossCoin = function() {
$('#toss-coin').modal('show');
if (Math.floor(Math.random() * 2) === 0) {
firstMove = 'ai';
$('#toss-coin p').html('AI goes first!');
$('#toss-coin').on('hidden.bs.modal', function(event) {
aiPick(ai);
});
} else {
firstMove = 'player';
$('#toss-coin p').html('You go first!');
}
};
$('#x-button').click(function() {
player = 'X';
ai = 'O';
if (firstMove === 'ai') {
aiPick(ai);
}
//tossCoin();
});
$('#o-button').click(function() {
player = 'O';
ai = 'X';
if (firstMove === 'ai') {
aiPick(ai);
}
//tossCoin();
});
$('#options').modal('show');
$('.col-xs-4').addClass('clickable');
$('.col-xs-4').click(function(event) {
if ($(this).hasClass('clickable')) {
$('.col-xs-4').removeClass('clickable');
$(this).find('div').html(player);
playerCells.push(parseInt($(this).attr('id').substr(-1)));
playerCells.sort();
winCells = checkWin(playerCells);
if (winCells === -1) {
remaining--;
if (remaining > 0) {
setTimeout(function() {
aiPick(ai);
}, 750);
}
if (remaining === 0) {
resetBoard('draw', [1, 2, 3, 4, 5, 6, 7, 8, 9]);
return;
}
} else {
resetBoard('player', winCells);
}
}
});
});
<script src="//cdnjs.cloudflare.com/ajax/libs/jquery/2.1.3/jquery.min.js"></script>
<script src="//maxcdn.bootstrapcdn.com/bootstrap/3.3.5/js/bootstrap.min.js"></script>
#title {
text-align: center;
}
.modal-body {
text-align: center;
}
.modal-footer {
text-align: center;
}
.container-fixed {
margin: 50px auto;
width: 750px;
}
.col-xs-4 {
text-align: center;
border: 1px black solid;
height: 250px;
width: 250px;
display: table;
margin: 0;
padding: 0;
}
.clickable {
cursor: pointer;
}
.middle-align {
margin: 0;
padding: 0;
font-size: 100px;
display: table-cell;
vertical-align: middle;
}
.blinking {
color: #FF0000;
}
<link href="//maxcdn.bootstrapcdn.com/bootstrap/3.3.5/css/bootstrap.min.css" rel="stylesheet" />
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment