Skip to content

Instantly share code, notes, and snippets.

@Jean13
Created January 26, 2016 03:41
Show Gist options
  • Save Jean13/ea69fdb18a349b42be03 to your computer and use it in GitHub Desktop.
Save Jean13/ea69fdb18a349b42be03 to your computer and use it in GitHub Desktop.
Jean's Space Tic Tac Toe
html
h1 Jean's
h2 Space<br>Tic Tac Toe
body
.container
.board.clearfix
.row
#0.square
#1.square
#2.square
.row
#3.square
#4.square
#5.square
.row
#6.square
#7.square
#8.square
.modal-container
.modal.choose-modal
h3 Select Your Tool
.button-area
span.x-marker X
span.o-marker O
.modal.end-game-modal
h3
p Tough Luck!
.button-area
span Play Again

Jean's Space Tic Tac Toe

A simple game of Tic Tac Toe built using JavaScript. Try to beat the computer... it will destroy you!

A Pen by Jean on CodePen.

License.

var cpuIcon = 'X';
var playerIcon = 'O';
var AIMove;
var liveBoard = [1, -1, -1, -1, 1, 1, 1, -1, -1];
var winningLines = [
[0, 1, 2],
[3, 4, 5],
[6, 7, 8],
[0, 3, 6],
[1, 4, 7],
[2, 5, 8],
[0, 4, 8],
[2, 4, 6]
];
function renderBoard(board) {
board.forEach(function(el, i) {
var squareId = '#' + i.toString();
if (el === -1) {
$(squareId).text(playerIcon);
} else if (el === 1) {
$(squareId).text(cpuIcon);
}
});
$('.square:contains(X)').addClass('x-marker');
$('.square:contains(O)').addClass('o-marker');
}
function animateWinLine() {
var idxOfArray = winningLines.map(function(winLines) {
return winLines.map(function(winLine) {
return liveBoard[winLine];
}).reduce(function(prev, cur) {
return prev + cur;
});
});
var squaresToAnimate = winningLines[idxOfArray.indexOf(Math.abs(3))];
squaresToAnimate.forEach(function(el) {
$('#' + el).fadeIn(200).fadeOut(200).fadeIn(200).fadeOut(200).fadeIn(200).fadeIn(200).fadeOut(200).fadeIn(200).fadeOut(200).fadeIn(200);
});
}
function chooseMarker() {
$('.modal-container').css('display', 'block');
$('.choose-modal').addClass('animated bounceInUp');
$('.button-area span').click(function() {
var marker = $(this).text();
playerIcon = (marker === 'X' ? 'X' : 'O');
cpuIcon = (marker === 'X' ? 'O' : 'X');
$('.choose-modal').addClass('animated bounceOutDown');
setTimeout(function() {
$('.modal-container').css('display', 'none');
$('.choose-modal').css('display', 'none');
startNewGame();
}, 700);
$('.button-area span').off();
});
}
function endGameMessage() {
var result = checkVictory(liveBoard);
$('.end-game-modal h3').text(result === 'win' ? 'You Lost' : "It's a draw");
$('.modal-container').css('display', 'block');
$('.end-game-modal').css('display', 'block').removeClass('animated bounceOutDown').addClass('animated bounceInUp');
$('.button-area span').click(function() {
$('.end-game-modal').removeClass('animated bounceInUp').addClass('animated bounceOutDown');
setTimeout(function() {
$('.modal-container').css('display', 'none');
startNewGame();
}, 700);
$('.button-area span').off();
});
}
function startNewGame() {
liveBoard = [0, 0, 0, 0, 0, 0, 0, 0, 0];
$('.square').text("").removeClass('o-marker x-marker');
renderBoard(liveBoard);
playerTakeTurn();
}
function playerTakeTurn() {
$('.square:empty').hover(function() {
$(this).text(playerIcon).css('cursor', 'pointer');
}, function() {
$(this).text('');
});
$('.square:empty').click(function() {
$(this).css('cursor', 'default');
liveBoard[parseInt($(this).attr('id'))] = -1;
renderBoard(liveBoard);
if (checkVictory(liveBoard)) {
setTimeout(endGameMessage, (checkVictory(liveBoard) === 'win') ? 700 : 100);
} else {
setTimeout(aiTakeTurn, 100);
}
$('.square').off();
});
}
function aiTakeTurn() {
miniMax(liveBoard, 'aiPlayer');
liveBoard[AIMove] = 1;
renderBoard(liveBoard);
if (checkVictory(liveBoard)) {
animateWinLine();
setTimeout(endGameMessage, checkVictory(liveBoard) === 'win' ? 700 : 100);
} else {
playerTakeTurn();
}
}
function checkVictory(board) {
var squaresInPlay = board.reduce(function(prev, cur) {
return Math.abs(prev) + Math.abs(cur);
});
var outcome = winningLines.map(function(winLines) {
return winLines.map(function(winLine) {
return board[winLine];
}).reduce(function(prev, cur) {
return prev + cur;
});
}).filter(function(winLineTotal) {
return Math.abs(winLineTotal) === 3;
});
if (outcome[0] === 3) {
return 'win';
} else if (outcome[0] === -3) {
return 'lose';
} else if (squaresInPlay === 9) {
return 'draw';
} else {
return false;
}
}
function availableMoves(board) {
return board.map(function(el, i) {
if (!el) {
return i;
}
}).filter(function(e) {
return (typeof e !== "undefined");
});
}
//AI: minimax algorithm
function miniMax(state, player) {
var rv = checkVictory(state);
if (rv === 'win') {
return 10;
}
if (rv === 'lose') {
return -10;
}
if (rv === 'draw') {
return 0;
}
var moves = [];
var scores = [];
availableMoves(state).forEach(function(square) {
state[square] = (player === 'aiPlayer') ? 1 : -1;
scores.push(miniMax(state, (player === 'aiPlayer') ? 'opponent' : 'aiPlayer'));
moves.push(square);
state[square] = 0;
});
if (player === 'aiPlayer') {
AIMove = moves[scores.indexOf(Math.max.apply(Math, scores))];
return Math.max.apply(Math, scores);
} else {
AIMove = moves[scores.indexOf(Math.min.apply(Math, scores))];
return Math.min.apply(Math, scores);
}
}
renderBoard(liveBoard);
chooseMarker();
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.0.0-alpha1/jquery.min.js"></script>
@import url(https://fonts.googleapis.com/css?family=Cinzel|Philosopher|Kreon|Merriweather|Electrolize|Orbitron|Geo);
$someBlue: #6666ff;
$brightGreen: #06cd51;
$someWhite: #fff;
$someRed: #6f0101;
$darkBlue: #5e3669;
$someYellow: #eeda76;
html {
//overflow: hidden;
}
h1 {
font-family: 'Cinzel';
font-size: 30px;
text-align: center;
color: white;
padding: 1%;
margin-top: -1.5%;
}
h2 {
font-family: 'Philosopher';
font-size: 34px;
text-align: center;
color: white;
font-weight: bold;
margin-top: -2%;
text-shadow: 1px 1px 8px grey;
}
body {
background-image: url('http://mynoise.net/Data/SPACESHIP/fb.jpg');
}
.container {
position: absolute;
left: 50%;
top: 50%;
transform: translate(-50%, -50%);
margin-top: 3%;
}
.clearfix:after {
content: "";
display: table;
clear: both;
}
p {
font-weight: 400;
}
h3 {
font-weight: 700;
text-transform: uppercase;
margin: 0 0 10px 0;
text-align: center;
font-family: 'Electrolize';
color: $someRed;
text-shadow: 1px 1px 8px red;
}
.board {
position: relative;
width: 22em;
font-family: 'Electrolize';
font-weight: 700;
margin: 0 auto;
color: $brightGreen;
font-weight: bold;
text-shadow: 1px 1px 8px green;
box-shadow: 1px 1px 8px grey;
}
.row {
float: left;
}
.row:first-child .square {
border-top: 0;
}
.square {
color: #605B56 ;
border-color: #605B56;
font-size: 6em;
width: 1.2em;
height: 1.2em;
line-height: 1.2em;
float: left;
border-style: solid;
border-width: 1px 1px 0 0;
text-align: center;
cursor: default;
}
.square:last-child {
border-right: 0px;
}
.x-marker {
color: $brightGreen;
}
.o-marker {
color: $brightGreen;
}
.modal-container{
position: absolute;
left: 50%;
top: 50%;
transform: translate(-50%, -50%);
width: 70%;
display: none;
}
.modal {
font-family: 'Electrolize';
text-align: center;
background-color: grey;
font-size: 1em;
height: 100%;
padding: 30px;
opacity: 0.8;
box-shadow: 1px 1px 8px grey;
border: solid;
border-color: grey;
}
.end-game-modal {
display: none;
}
.choose-modal span{
line-height: 1.5em;
width: 1.5em;
height: 1.5em;
font-size: 2.5em;
border: solid;
border-radius: 5%;
}
.end-game-modal span {
color: $someYellow;
text-transform: uppercase;
line-height: 1.5em;
font-size: 1.3em;
padding: 0.2em 0.4em;
text-shadow: 1px 1px 8px yellow;
}
.button-area span {
display: inline-block;
background-color: hsla(30, 10%, 10%, 0.35);
margin: 0.2em 0.2em 0 0.2em;
border-radius: 5%;
border: solid;
}
.button-area span:hover {
cursor: pointer;
background-color: hsla(30, 10%, 10%, 0.95);
}
@media screen and (max-width: 500px){
.container {
top: 40px;
-moz-transform: scale(0.6);
-ms-transform: scale(0.6);
-o-transform: scale(0.6);
-webkit-transform: scale(0.6);
transform: scale(0.6);
-o-transform-origin: 0 0;
-ms-transform-origin: 0 0;
-webkit-transform-origin: 0 0;
-moz-transform-origin: 0 0;
transform-origin: 0 0;
left: 50%;
margin-left: -100px;
margin-top: 5%;
}
}
<link href="https://cdnjs.cloudflare.com/ajax/libs/animate.css/3.4.0/animate.min.css" rel="stylesheet" />
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment