Skip to content

Instantly share code, notes, and snippets.

Created November 23, 2016 06:31
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save anonymous/15d7f2ecbace23a4b7de37ef8db0cfcd to your computer and use it in GitHub Desktop.
Save anonymous/15d7f2ecbace23a4b7de37ef8db0cfcd to your computer and use it in GitHub Desktop.
Tic-Tac-Toe // source https://jsbin.com/qototad
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=600, initial-scale=1">
<title>Tic-Tac-Toe</title>
<style id="jsbin-css">
html {
background: #f5f5f5;
}
/* The wrapper
* wraps the app
*/
.wrapper {
width: 80.3vw;
height: 90.3vw;
display: block;
margin-left: auto;
margin-right: auto;
margin-top: 10vw;
font-family: sans-serif;
}
/* The wrapper's intro.
* Here goes the title
* and the controls.
*/
.wrapper #intro {
text-align: center;
}
.wrapper #intro .title {
font-size: 12vw;
font-weight: bold;
display: inline-block;
}
.wrapper #intro .title .x,
.wrapper #intro .title .o {
opacity: 0;
float: left;
}
.wrapper #intro .title .x {
color: #e88;
}
.wrapper #intro .title .o {
color: #8be;
}
.wrapper #intro .message {
opacity: 0;
font-size: 5vw;
color: #999;
margin-top: -4px;
margin-bottom: 4px;
}
.wrapper #intro #restart {
background: none;
color: #e88;
border: none;
font-weight: bold;
text-transform: uppercase;
font-size: 5vw;
display: none;
cursor: pointer;
text-align: center;
width: 100%;
margin-top: -5px;
}
.wrapper #intro #restart.visible {
display: block;
}
/* tic-tac-toe blocks.
* People play here.
*/
.wrapper #tic-tac-toe div {
display: block;
float: left;
width: 25vw;
height: 25vw;
margin-left: 1.2vw;
margin-top: 1.2vw;
font-size: 22vw;
font-weight: bold;
text-align: center;
background: white;
color: #888;
cursor: pointer;
opacity: 0;
}
.wrapper #tic-tac-toe div.x {
color: #e88;
cursor: default;
}
.wrapper #tic-tac-toe div.o {
color: #8be;
cursor: default;
}
.wrapper #tic-tac-toe div.yellow {
background: #ffb;
}
.wrapper #tic-tac-toe div.showCursor:before {
background-image: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAgAAAAIACAMAAADDpiTIAAADAFBMVEX///8zMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMvIC5hAAAA/3RSTlMAAf3+AvsD/PkHBQT3+AkIERL69Q4L9iPsBvMMChQPSucQ8hntIQ3o8RYYHOtCF9sT5D8sNFEVKBtF6StM4yBP9DswJ10tNS7qHzk+Iirw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);
background-size: 12vw 12vw;
display: block;
width: 12vw;
height: 12vw;
content: '';
opacity: 0;
margin-left: 6.5vw;
margin-top: 6vw;
animation: click 5s 1s infinite;
}
@keyframes click {
0% {
opacity: 0;
}
3% {
opacity: 0.5;
}
15% {
margin-left: 6.5vw;
margin-top: 6vw;
}
20% {
margin-left: 6vw;
margin-top: 5.5vw;
}
25% {
margin-left: 6.5vw;
margin-top: 6vw;
}
30% {
margin-left: 6vw;
margin-top: 5.5vw;
}
35% {
margin-left: 6.5vw;
margin-top: 6vw;
}
47% {
opacity: 0.5;
}
50% {
opacity: 0;
}
}
/*
* Winner highlight
*/
.wrapper #winner {
display: none;
float: left;
margin-top: -80vw;
margin-bottom: -113px;
margin-left: -5vw;
width: 90vw;
height: 90vw;
font-size: 22vw;
text-align: center;
text-transform: uppercase;
padding-top: 17vw;
background: rgba(245, 245, 245, .8);
}
/* The author.
* Hi mom!
*/
.wrapper .author {
font-size: 3vw;
color: #999;
float: right;
margin-right: 5px;
margin-top: 2vw;
margin-bottom: 5vw;
}
.wrapper .author .hearts {
color: #e88;
}
.wrapper .author a {
text-decoration: none;
color: #8be;
}
.wrapper .author a:hover {
text-decoration: underline;
}
/*
* Misc - taken from elsewhere
* Sources:
* .noselect - https://stackoverflow.com/questions/826782/how-to-disable-text-selection-highlighting-using-css
*/
.noselect, .wrapper #tic-tac-toe div {
-webkit-touch-callout: none; /* iOS Safari */
-webkit-user-select: none; /* Chrome/Safari/Opera */
-khtml-user-select: none; /* Konqueror */
-moz-user-select: none; /* Firefox */
-ms-user-select: none; /* Internet Explorer/Edge */
user-select: none; /* Non-prefixed version, currently
not supported by any browser */
}
</style>
</head>
<body>
<div class='wrapper'>
<div id='intro'>
<div class='title'>
<div class='x'>Tic-</div>
<div class='o'>Tac-</div>
<div class='x'>Toe!</div>
</div>
<div class='message'>Click in the board</div>
<button id='restart'>Restart</button>
</div>
<div id='tic-tac-toe' class='.noselect'>
<div class=''></div>
<div class=''></div>
<div class=''></div>
<div class=''></div>
<div class=''></div>
<div class=''></div>
<div class=''></div>
<div class=''></div>
<div class=''></div>
</div>
<div id='winner'>
<!--
PLAYER
<b>X</b>
WINS!
-->
</div>
<div class='author'>
Made with
<span class='hearts'>&hearts;</span>
by
<a href='http://twitter.com/sadasant' target='_blank'>
@sadasant
</a>
</div>
</div>
<script id="jsbin-javascript">
window.onload = function() {
// Makes arrays
function makeArray(obj) {
return Array.prototype.slice.call(obj)
}
// Vanilla jQuery for the lazy
var $ = function() {
var args = makeArray(arguments);
var r = document.querySelectorAll.apply(document, args);
return r.length === 1 ? r[0] : r;
}
// Vanilla class functions
function addClass(el, className) {
removeClass(el, className)
el.className += ' ' + className
}
function removeClass(el, className) {
el.className = el.className.replace(className, '')
}
// Our main variables
var title = $('.wrapper #intro .title');
var message = $('.wrapper #intro .message');
var tictactoe = $('.wrapper #tic-tac-toe');
var blocks = $('.wrapper #tic-tac-toe div');
var restart = $('#restart');
var winner = $('#winner');
// Animated intro!
intro()
function intro() {
function show(el) {
el.style.opacity = 1;
}
function hide(el) {
el.style.opacity = 0;
}
var delayer = new Delayer();
var titleParts = makeArray(title.children);
var blocksArray = makeArray(blocks);
// Flushing
message.style.display = 'block'
winner.style.display = 'none'
hide(message)
removeClass(restart, 'visible')
titleParts.map(hide)
blocksArray.map(function(el) {
el.className = '';
el.innerText = '';
hide(el)
})
delayer.add(titleParts, show, 500)
delayer.add(blocksArray, show, 100)
delayer.add([blocks[0]], function(first) {
addClass(first, 'showCursor')
blocksArray.map(function(el) {
el.onclick = function() {
removeClass(first, 'showCursor')
message.style.display = 'none'
first.onclick = undefined
startGame(el)
}
})
}, 100)
delayer.add([message], show, 500)
delayer.run()
}
// Main game logic
var startsX = true;
function startGame(el) {
var player1 = {
str: startsX ? 'x' : 'o'
}
var player2 = {
str: !startsX ? 'x' : 'o',
}
var goesP1 = true;
var turns = 0;
addClass(restart, 'visible')
restart.onclick = function() {
intro()
}
var blocksArray = makeArray(blocks);
blocksArray.map(function(el) {
el.onclick = function() {
if (el.innerText) return
var player = goesP1 ? player1 : player2;
el.innerText = player.str.toUpperCase();
addClass(el, player.str);
goesP1 = !goesP1;
turns++
if (turns === 9) {
setTimeout(tie, 125);
} else
if (turns >= 5) {
setTimeout(function() {
checkWinner(player, el);
}, 125)
}
}
})
function checkWinner(player, el) {
var B = blocksArray;
var i = B.indexOf(el);
var str = player.str.toUpperCase()
function eqAt(a, b, c) {
return B[a].innerText === B[b].innerText && B[a].innerText === B[c].innerText;
}
var col = i % 3;
var row = i - col;
if (eqAt(row, row + 1, row + 2)) return won(player, row, row + 1, row + 2);
if (eqAt(col, col + 3, col + 6)) return won(player, col, col + 3, col + 6);
if (eqAt(0, 4, 8)) return won(player, 0, 4, 8)
if (eqAt(2, 4, 6)) return won(player, 2, 4, 6)
}
function won(player, a, b, c) {
addClass(blocksArray[a], 'yellow')
addClass(blocksArray[b], 'yellow')
addClass(blocksArray[c], 'yellow')
winner.style.display = 'block';
winner.style.color = player.str === 'x' ? '#e88' : '#8be';
winner.innerHTML = 'player <b>' + player.str + '</b> wins!'
blocksArray.map(function(el) {
el.onclick = undefined
})
}
function tie() {
winner.style.display = 'block';
winner.style.color = '#999';
winner.innerHTML = 'IT WAS<br>A TIE'
}
el.onclick()
}
// Delayer object
// adds animation *frames* into
// a strack, then replays them
function Delayer() {
var stack = []
this.add = function(arr, func, time) {
if (!(arr && arr.length)) {
throw 'Delayer.add error: invalid first argument, must be an array'
}
arr.map(function(el) {
stack.push({
el: el,
func: func,
timeout: time
})
})
}
var that = this
this.run = function() {
if (!stack.length) return
var current = stack.shift()
setTimeout(function() {
current.func(current.el)
that.run()
}, current.timeout)
}
}
}
</script>
<script id="jsbin-source-css" type="text/css">html {
background: #f5f5f5;
}
/* The wrapper
* wraps the app
*/
.wrapper {
width: 80.3vw;
height: 90.3vw;
display: block;
margin-left: auto;
margin-right: auto;
margin-top: 10vw;
font-family: sans-serif;
}
/* The wrapper's intro.
* Here goes the title
* and the controls.
*/
.wrapper #intro {
text-align: center;
}
.wrapper #intro .title {
font-size: 12vw;
font-weight: bold;
display: inline-block;
}
.wrapper #intro .title .x,
.wrapper #intro .title .o {
opacity: 0;
float: left;
}
.wrapper #intro .title .x {
color: #e88;
}
.wrapper #intro .title .o {
color: #8be;
}
.wrapper #intro .message {
opacity: 0;
font-size: 5vw;
color: #999;
margin-top: -4px;
margin-bottom: 4px;
}
.wrapper #intro #restart {
background: none;
color: #e88;
border: none;
font-weight: bold;
text-transform: uppercase;
font-size: 5vw;
display: none;
cursor: pointer;
text-align: center;
width: 100%;
margin-top: -5px;
}
.wrapper #intro #restart.visible {
display: block;
}
/* tic-tac-toe blocks.
* People play here.
*/
.wrapper #tic-tac-toe div {
display: block;
float: left;
width: 25vw;
height: 25vw;
margin-left: 1.2vw;
margin-top: 1.2vw;
font-size: 22vw;
font-weight: bold;
text-align: center;
background: white;
color: #888;
cursor: pointer;
opacity: 0;
}
.wrapper #tic-tac-toe div.x {
color: #e88;
cursor: default;
}
.wrapper #tic-tac-toe div.o {
color: #8be;
cursor: default;
}
.wrapper #tic-tac-toe div.yellow {
background: #ffb;
}
.wrapper #tic-tac-toe div.showCursor:before {
background-image: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAgAAAAIACAMAAADDpiTIAAADAFBMVEX///8zMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMvIC5hAAAA/3RSTlMAAf3+AvsD/PkHBQT3+AkIERL69Q4L9iPsBvMMChQPSucQ8hntIQ3o8RYYHOtCF9sT5D8sNFEVKBtF6StM4yBP9DswJ10tNS7qHzk+Iirw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);
background-size: 12vw 12vw;
display: block;
width: 12vw;
height: 12vw;
content: '';
opacity: 0;
margin-left: 6.5vw;
margin-top: 6vw;
animation: click 5s 1s infinite;
}
@keyframes click {
0% {
opacity: 0;
}
3% {
opacity: 0.5;
}
15% {
margin-left: 6.5vw;
margin-top: 6vw;
}
20% {
margin-left: 6vw;
margin-top: 5.5vw;
}
25% {
margin-left: 6.5vw;
margin-top: 6vw;
}
30% {
margin-left: 6vw;
margin-top: 5.5vw;
}
35% {
margin-left: 6.5vw;
margin-top: 6vw;
}
47% {
opacity: 0.5;
}
50% {
opacity: 0;
}
}
/*
* Winner highlight
*/
.wrapper #winner {
display: none;
float: left;
margin-top: -80vw;
margin-bottom: -113px;
margin-left: -5vw;
width: 90vw;
height: 90vw;
font-size: 22vw;
text-align: center;
text-transform: uppercase;
padding-top: 17vw;
background: rgba(245, 245, 245, .8);
}
/* The author.
* Hi mom!
*/
.wrapper .author {
font-size: 3vw;
color: #999;
float: right;
margin-right: 5px;
margin-top: 2vw;
margin-bottom: 5vw;
}
.wrapper .author .hearts {
color: #e88;
}
.wrapper .author a {
text-decoration: none;
color: #8be;
}
.wrapper .author a:hover {
text-decoration: underline;
}
/*
* Misc - taken from elsewhere
* Sources:
* .noselect - https://stackoverflow.com/questions/826782/how-to-disable-text-selection-highlighting-using-css
*/
.noselect, .wrapper #tic-tac-toe div {
-webkit-touch-callout: none; /* iOS Safari */
-webkit-user-select: none; /* Chrome/Safari/Opera */
-khtml-user-select: none; /* Konqueror */
-moz-user-select: none; /* Firefox */
-ms-user-select: none; /* Internet Explorer/Edge */
user-select: none; /* Non-prefixed version, currently
not supported by any browser */
}</script>
<script id="jsbin-source-javascript" type="text/javascript">window.onload = function() {
// Makes arrays
function makeArray(obj) {
return Array.prototype.slice.call(obj)
}
// Vanilla jQuery for the lazy
var $ = function() {
var args = makeArray(arguments);
var r = document.querySelectorAll.apply(document, args);
return r.length === 1 ? r[0] : r;
}
// Vanilla class functions
function addClass(el, className) {
removeClass(el, className)
el.className += ' ' + className
}
function removeClass(el, className) {
el.className = el.className.replace(className, '')
}
// Our main variables
var title = $('.wrapper #intro .title');
var message = $('.wrapper #intro .message');
var tictactoe = $('.wrapper #tic-tac-toe');
var blocks = $('.wrapper #tic-tac-toe div');
var restart = $('#restart');
var winner = $('#winner');
// Animated intro!
intro()
function intro() {
function show(el) {
el.style.opacity = 1;
}
function hide(el) {
el.style.opacity = 0;
}
var delayer = new Delayer();
var titleParts = makeArray(title.children);
var blocksArray = makeArray(blocks);
// Flushing
message.style.display = 'block'
winner.style.display = 'none'
hide(message)
removeClass(restart, 'visible')
titleParts.map(hide)
blocksArray.map(function(el) {
el.className = '';
el.innerText = '';
hide(el)
})
delayer.add(titleParts, show, 500)
delayer.add(blocksArray, show, 100)
delayer.add([blocks[0]], function(first) {
addClass(first, 'showCursor')
blocksArray.map(function(el) {
el.onclick = function() {
removeClass(first, 'showCursor')
message.style.display = 'none'
first.onclick = undefined
startGame(el)
}
})
}, 100)
delayer.add([message], show, 500)
delayer.run()
}
// Main game logic
var startsX = true;
function startGame(el) {
var player1 = {
str: startsX ? 'x' : 'o'
}
var player2 = {
str: !startsX ? 'x' : 'o',
}
var goesP1 = true;
var turns = 0;
addClass(restart, 'visible')
restart.onclick = function() {
intro()
}
var blocksArray = makeArray(blocks);
blocksArray.map(function(el) {
el.onclick = function() {
if (el.innerText) return
var player = goesP1 ? player1 : player2;
el.innerText = player.str.toUpperCase();
addClass(el, player.str);
goesP1 = !goesP1;
turns++
if (turns === 9) {
setTimeout(tie, 125);
} else
if (turns >= 5) {
setTimeout(function() {
checkWinner(player, el);
}, 125)
}
}
})
function checkWinner(player, el) {
var B = blocksArray;
var i = B.indexOf(el);
var str = player.str.toUpperCase()
function eqAt(a, b, c) {
return B[a].innerText === B[b].innerText && B[a].innerText === B[c].innerText;
}
var col = i % 3;
var row = i - col;
if (eqAt(row, row + 1, row + 2)) return won(player, row, row + 1, row + 2);
if (eqAt(col, col + 3, col + 6)) return won(player, col, col + 3, col + 6);
if (eqAt(0, 4, 8)) return won(player, 0, 4, 8)
if (eqAt(2, 4, 6)) return won(player, 2, 4, 6)
}
function won(player, a, b, c) {
addClass(blocksArray[a], 'yellow')
addClass(blocksArray[b], 'yellow')
addClass(blocksArray[c], 'yellow')
winner.style.display = 'block';
winner.style.color = player.str === 'x' ? '#e88' : '#8be';
winner.innerHTML = 'player <b>' + player.str + '</b> wins!'
blocksArray.map(function(el) {
el.onclick = undefined
})
}
function tie() {
winner.style.display = 'block';
winner.style.color = '#999';
winner.innerHTML = 'IT WAS<br>A TIE'
}
el.onclick()
}
// Delayer object
// adds animation *frames* into
// a strack, then replays them
function Delayer() {
var stack = []
this.add = function(arr, func, time) {
if (!(arr && arr.length)) {
throw 'Delayer.add error: invalid first argument, must be an array'
}
arr.map(function(el) {
stack.push({
el: el,
func: func,
timeout: time
})
})
}
var that = this
this.run = function() {
if (!stack.length) return
var current = stack.shift()
setTimeout(function() {
current.func(current.el)
that.run()
}, current.timeout)
}
}
}</script></body>
</html>
html {
background: #f5f5f5;
}
/* The wrapper
* wraps the app
*/
.wrapper {
width: 80.3vw;
height: 90.3vw;
display: block;
margin-left: auto;
margin-right: auto;
margin-top: 10vw;
font-family: sans-serif;
}
/* The wrapper's intro.
* Here goes the title
* and the controls.
*/
.wrapper #intro {
text-align: center;
}
.wrapper #intro .title {
font-size: 12vw;
font-weight: bold;
display: inline-block;
}
.wrapper #intro .title .x,
.wrapper #intro .title .o {
opacity: 0;
float: left;
}
.wrapper #intro .title .x {
color: #e88;
}
.wrapper #intro .title .o {
color: #8be;
}
.wrapper #intro .message {
opacity: 0;
font-size: 5vw;
color: #999;
margin-top: -4px;
margin-bottom: 4px;
}
.wrapper #intro #restart {
background: none;
color: #e88;
border: none;
font-weight: bold;
text-transform: uppercase;
font-size: 5vw;
display: none;
cursor: pointer;
text-align: center;
width: 100%;
margin-top: -5px;
}
.wrapper #intro #restart.visible {
display: block;
}
/* tic-tac-toe blocks.
* People play here.
*/
.wrapper #tic-tac-toe div {
display: block;
float: left;
width: 25vw;
height: 25vw;
margin-left: 1.2vw;
margin-top: 1.2vw;
font-size: 22vw;
font-weight: bold;
text-align: center;
background: white;
color: #888;
cursor: pointer;
opacity: 0;
}
.wrapper #tic-tac-toe div.x {
color: #e88;
cursor: default;
}
.wrapper #tic-tac-toe div.o {
color: #8be;
cursor: default;
}
.wrapper #tic-tac-toe div.yellow {
background: #ffb;
}
.wrapper #tic-tac-toe div.showCursor:before {
background-image: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAgAAAAIACAMAAADDpiTIAAADAFBMVEX///8zMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMvIC5hAAAA/3RSTlMAAf3+AvsD/PkHBQT3+AkIERL69Q4L9iPsBvMMChQPSucQ8hntIQ3o8RYYHOtCF9sT5D8sNFEVKBtF6StM4yBP9DswJ10tNS7qHzk+IirwLzPl7lUph0fgRms3JEBUJj3vHiU8Gk5cV8AyOHdyHdhSYzFLpnpBhH7M14XedeJ5YEnWbkR0YlbP4VNNuF7ZcVCCbd1zSMnmWdrfxJrVNlrRaFvSQ6Gog7S8vmeiZp6bcF+UrtzBZLbOWIu6imx/02nQs51vjXi3OpCsjJFll6uPk8uVp5LHfIGYsb3UpGHKo82gsHa5u4ayr3tqfcWOloDGn4mIqq2pnMO1yMKZpb8X8e1wAAAaJElEQVR4Xuzd+XcV1LnG8eeck5zMMwmBMEggJCFAZFZmAgqCBIMIyiQooyCgWOaIIlO1UKQCIjjU4Tos5YK2WpeAggtbxeGiAk51uHVste1Sq666Vp+udX+qLq7s8+ac5Oz3vJ+/4fvTfvbaG3Egt9/Fq6/Z9+h9fziyevyYrgEkEDP1T8cz+QPFi4dVIiGYnit281RCx7b8PgzdzKT/GcCfUP0LzQmYGW8k8zQ2zUqCTibvqSI6WL5DZQJmXS0dvV0DbUyz1+gu84/QxUxcyYjsyYEiZn4+I/R+GdQwKxi5sW2hhHmKEsHfQgXzBwqthQLmKMWWwHtmL+W4LwC/mX4FbIj3MuAzU7icDfO/afCYeYcN9VYJvGUWsuG25cFTpkU1o+Bge/jJbGZUPFYGH5m8sYyOutFQwI4A5Yp7wjsmN5NRU9odvjF/ZhRlXg3PmGWMpuQd8IoZzugKPgQNbAWWmwePmHJG3UXwhmnOGHgpCZ4wwxgLizPgB/NXxsShHHjBbGBs/KsjPGBKUhgjx85E/DOjGTO7ZyDumcsZOyvPR7wzMxlD23sgzpnVjKUOtyO+mfmMqZZdENfMf9FJQT5lsmYinpmL6GRB2yLKJM+CAhYARlVQJnQJvGcBbAIu6EyhaxC3zMfOAWBcNwo9CQUsAAysptCuJHjNXoW5FQDQ6W4K3ZcO/1kAyD1Oocez4T8LAIUPUOj7ZohDZgmdVOP/AGmfUuj91vCfBYDwvRRaXgX/WQAIvE6hCZPgKdsCHsN/2EKh8uFQwAKQT4hjr4ACFgAWBSkz+AbEFbOFTrbihy5MpUxWLyhgAeCWAsqk7EUcMSfpZCV+7PJayoTWQAELAFeNoNBSKGABYGg9hb4IIE6Yv9HJTpzC9FspdDgM/1kAqHyGQi+3gP8sALT7nEI3tUI8MAfoZAJOrdWHFLqtDfxnAaDF8xTaUAn/WQAIP0KhTVeiyZmldLIR/6/AKxTaOBX+swCAAxTqWwMFLAA8G6LMtCFoWuYvdFKPn7Q6hTIFF0MBCwALUymTOgVNyZygkwE4jbMHUyZlHRSwADByGmVCm6GABYAx5RQ6iSZjPqOTbji9yzZS6GgA/rMAULWAQh+E4T8LAL2foNCjaWgS5ho6qYOTNt9R6KNC+M8CQKvnKPT3XPjPAkD61xS6sysan7mWTrbDVdIeClWfB/9ZAMALFBrQB3HKAjgDEThBoRFz0cjMkRgEgP0hylRcCgUsAAxLpkzRdWhUZh6dlCMyg7Iok78eClgAuKclZYIvQgELABPHUmgtGo/5E530RcTOOYNCS6CABYDmOym0LwD/WQA463oKvZeBxmFW0ckISLReRqE30+A/CwDNfkOht0rgPwsA2fdTaFseGoFZSyedIZT+GoUOtof/LAAkvUGhx8oQc+ZXdFIMuS8pVDcaClgAuJZCxT2hgAWAp4OUKe2OuGB/B3dAg9yRTJnM/lDAAsCNmZRJ3gEFLABMLqVM8C7EkNlMJ2PRUOcWU2geFLAA0K+OQhdBAQsAZVsp9FISYsT8N51MQxS0f5tCizPgPwsAee9S6FAO/GcBoORBCs3piFgwz9JJLaIj5xMKHTsT/rMAkPEOhXbPQPSZNXRSgWgJvEqhlefDfxYA8DGFtveAAhYAVlGow+2IMnMznZQimh4OUqZlFyhgAWB2PmWyZkIBCwBtiyiTPAvRZPbTSUtE2agKyoQugQIWAC7oTKHPoIAFgHHdKPQkosZcQieDEX0Dqym0Kwn+swDQ6W4KfZMO/1kAyD1OocezERXmz3RSgJgofIBC3zeD/ywApH1Kofd7IwrM03RShBgJ30uh5VXwnwWAwOsUmjAJ/rMAgC0UKh+OhjJ30UkmYmg+hcZeAQUsACwKUmbwDVDAAsCFqZTJ6oUGMQ/RSRZi65YCyqTshQIWAC6vpUxoDRSwAHDVCAothZx5mE5SEXND6yn0RQD+swAw/VYKHQ4jtiyAfDSCymco9HILyJgX4ygAtPucQje1gv8sALT6kEK3tYGE+S2dJKNxtHieQhsq4T8LAOFHKLTpSvjPAkDgFQrVT0XEzCI6SUHjOUChvjVQwALAsyHK1A6BAhYAVqdQpmA8ImPW0UkQjWphKmVSp0ABCwBnD6ZMyjooYAFg5DTKhDYjAuaPdBJCYxtTTqGTUMACwGUTKHQ0AFdmNd2g8VUtoNAHYfjPAkDvJyj0aBr8ZwGgzXcU+qgQTszeeA4A2c9R6Hgu/GcBIP1rCt3ZFf6zAJC0h0LV5+H0zC/oJoCm8gKFBvSBAhYATlBoxFwoYAFgf4gyFZfiNMwwuklCExqWTJmi66CABYBBWZTJXw8FLADc05IywRfxU8wsugmjaU0cS6G1UMACQI8zKLQEcvr9mm4y0NSa76TQvgD8ZwHgrOsp9F4G/GcBoPUyCr2ZhlMzd9BNOuJAszkUeqsE/rMAkH0/hbblwX8WANJfo9DB9jgFs4NuWiA+JL1BocfK4D8LAPiSQnWjoYAFgCMUKu6JHzO/o5s0xI+ng5Qp7Q4FLADckUyZzP5QwALAjZmUSd6BHzCz6SYHcWVyKWWCd0EBCwDnFlNoHv6DWU832Ygz/eoo9BUUsABQtpVCLyXBfxYA2r9NocUZENDpQrpphfiTt41Ch3LgPwsAJQ9SaE5H+M8CQM4nFDp2JgwATKGbQsSljHcotHsG/GcBIPAqhVY2h/8sAGAFhbb3gMHP6aYEcWsVhTrcDgUsADwcpEzLLnBkAXREHJudT5msmUh0CzUEgLZFlEmeBQUsAIyqoEzoEiS2XnTTDPHtgs4U+gwKWAAY141CT0IBCwADqym0KwmJ65d00wZxr9PdFPomHf6zAJB7nEKPZ8N/FgAKH6DQ982QoAbRTTv4IO1TCr3fG/6zABC+l0LLq+A/CwCB1yk0YRIS0Uy6yYUvtlCofDgUsAAwn0JjRyLx3Eg3efDHoiBlBt8ABSwATEmlTFYvKGABYHwBZVL2IsH0p5sz4ZUhtZQJrYECFgBq+lJoKRSwADC0nkJfBJBArqab1vDN9E0UOhyG/ywAVD5DoZdbwH8WANp9TqGbWiFRtKWb3vBQqw8pdFs7+M8CQIvnKbShEv6zABB+hEKbpiMhXEc3lfBT4BUK1U+F/ywA4ACF+tZAP9xCN13hrWdDlKkdAgUsAKxOoUzBeChgAWBhKmVSp0C78XTTCT47ezBlUtZBAQsAI6dRJrQZClgAGF5OoZNQ7WK6aQ/PXTaBQkcD8J8FgKoFFPogDP9ZAOj9BIUeTYNaZ9PNDPivzXcU+qjQAoAC2c9R6HiuBaBB+jcUurMrdLqBbs6CCkl7KFR9ngWgwgsUGtAHGt1DN1XQ4gSFOs+1AFTYH6JMxaUWgArDkilTdB3U6UI3V0KRQVmUyZ9tAajQpSVlgi9aACpM7EChtdDlZ3QzHbr0OINCKywAFZrvpNC+gAWgwVnXU+i9DOgxmW7Ogzqtl1HozTQLQIOOcyj0VknCBTAQCmXfT6FteVCieyIHgPTXKHSwvQWgQdIbFNpaBhVG0U0ZlPqKQnWjLQAVjlCouKcFoMLTQcqUdof/LqWb86HXHcmUyexvAajQP5MyyTssABUml1ImeBc8dzndNIdq5xZT6IgFoMLoOgp9ZQGoULaVQi8lwWND6GYStGv/NoUWZ1gAGuRto9ChNHjr93RzGfQreZBC/whbABrkvEmhby0AFTLeodBT8NRIupmKhBB4lULzLAAdVlAmNNkC0GEVZXZ2hI+uoJuhSBgPBymyxwJQYnY+RdpaAEq0LaJEXUf4ZyLd9EEiGVVBiWstAC3mdqZA50ILQIs+3SiwCt65nW7GIcEMrGbkyrMtADU63c3I3QzfnEs3o5Fwco8zYv+0ABQp/IiRClVZAIqkfcpIrYFnetJNPySi8L2M0BwLQJXA64xMsNIC0GULI9MLfrmAbnogUc1nRJZaANosSmEEXrYA1JmSSncL4Je5dHMOEtj4AjpLybEA9BlSS2fnWAAK1fSlq5HwylV0MxyJbWg9Hf3MAlBp+iadNwNr6GYMElibqaMu3L+LbhZaADq0Gzpq/c1L9nzy7sYsRuLXFoDHcvt0X79mxbeH3q3PolAveGUM3dRAr7xxk2ev+fjw/cfqU9lwPS0AH/ybvTv9rqq84jj+u0NyM5GEBAIBEuZAMGAQQ4AQBpEhGgTEIApqZBJUUBkUnKkiImhFHBBRBEFGiwPKVBGVotYBRetSC3UeqlbFSh2K/fUFrBYhyr77nufecznP5x/Ii/PNWmedfZ/9+Ir7T9nwbNVDP04tz6KjCm0ALn7qZW3vWlu154n32mfRkDTEl76UuQTxypdX9sB9t/xzz/b1gxJo3nwbgBsEO3Z4YPGF376/feadCYyqTTaAmAkW9r5u8bzNS2fPbBJirFyG+NKbMuPgUsF2fTuPmbdx9UdbJU/dvJ42gCg99ROv37h606JWfrpKs9SjNICBcIGg4KnH2HLEmQ7xFAAW0O3W2gBM6k6X81cizpTF1QdO3810t+WwARi1hu42xAZgVkYXutkEH+JNf8r0gTt8QTebC8NsAMXZdK/6BTYA416le12M+HMaZe6FS1SG6FYLfDaAKPiOLpXQG1FgA7iXLvVnxKNSypwJ11hHV5rW0AYQHV3pRi2GIS71osz5cA3fdLpP1hTYAKLlYrrPGkSNDSC5Cd1mG+LV2fF46HkyXeZWRJMNILMH3cR/BtRsAOlQeJ4ukjQYcWwEZZ6DGd2mdUL4KkJ0jfbDoWYDOK09L4XC63SLpU2hZgMYWET2S1atNnKHVqMR54ZRpqe5u5mugcI7dIGEZ4qhZwOYmEOSXA+F2xlzSfu6Qc8GgA1Z3G8kFJYwttLeOAZHg3qUGQmnrfLzgO+gMIcxlL13TD4iYgO4gP+ToPlfSmnP2EiYtrqkEY4alZQ5B86q4kE+gcL1jLJTp419/esbOuQiYjaA4Ms8WFEGwlenNaOgxfT/LHvx6hkTjx+fC6fYAFJ/5i/NgMJGGhKov3DlpB1/2t14YKcUHO1aUuZkOCfjaR5iJhQ6ZdFBgaItK37+xwXXXHvJqFSYZAMoGOvQK8ZSRsrfZcnHu7Z9OGfICc1TER02gOLXnLpopTdVQq0WbXp34/UnDh3QJhGe140yx8EhoxayBqHxUNhOMX+TrR8t3TxvTOe+hUHEjg2g8grWqAoKbSnWIxMuYAMou5M1q58BhfcoNhk1sSooMxxO6FPf2YOVGyjWKhmxZgMY3oy/ahEUEk+n2OOIMRtA1zTHE3uWYtN8OJx1bvSuQrorgb/lUSjUPZVioxFLNoD7/fxNoQooXE6xH3A4azxl2kY+/j2SjVBoU4ti5yNmbABVgnFrIyj8gWJ7ESM2gOBXFFgFhdIApfzDcCjrGMo8AD2k7qLEQmi8TbGXEQs2gIxPKXMdFEZSLKcjos8G0HAlhT6Fxk8U+xqHsDqJ/zm1at9BKX89KMyiWFE6oswG0HwL5XZAIXgsxT5HdNkAWj5GObZuCIWnKPZYEL9gjaJMZ/Xp37D8EQrpRRQ7C1FkAxhYxPDc7IPCkxS7A79gNafMUOXp33BdC4W8HIqdjGixATTOYdi2Q2MnxZ5GlNgAzsti+AK9oFDPT6nAaTiI1cbYZTgv+anxCDReoNj3iAYbwJXUaZAPhTMpVqsNzLMBXBrlqxf/TbFP8H9WO8rcjnD4HqHabUEo3ESx6oYwywaQupp6vMn0CvG1MMoGkPwBI7HC9ArxG1NxgIVC5z/QNFzByJSZXiF+H8yxAWT+xAi9BY2rKbYextgA2ixhpLIzoZDZgGS4s02rI2UaQ6biWEbuShheIf4RzLABlJbTAacnQqEigWJ9sZ+VR5mJkBjXj464CBqTKLYaBtgAzmlNZ4yFxiUUyzoGjrMB3J5DpwyAxoqwr/m0iinTFUc0OIuOeQYaQyjWLB/OsgFc7Kdz0vJgeIX4h3CUDeBCOmoyNE6k2KBcWABqOzShuZXOKk+FQko5xa6BY2wAvjfotBtgeIX4X31wiA0g8X067kvA8Arxa2EBmQ4s2Ml9lAYMhMZmiq2EI2wAdTfRhKUwvUJ8IBxgA2j6DY1IageN9ym2DBaaUqY7fkW7rTTkMmh0oFioJSJlAzh3Pk1pkgKNJyj2Bqx8yvweNep1Fc1ZDI0pFOtRGxGxAZzQhQbdAZWpFHsTkbAB9DyFRp0PwyvEu2TA6+pQpgSHG5pNsyZBI/Fuiq2Bmg1gVhINyxoFjd9RbIIPSjaA3SHq+Cn2IDTqtqBYd3hcgfZXemsD1GkxchCl+iVD41KKLYCKDeBJKjXpjTcp9jA02tWi2EkInw3At4NKd9cDCmuZPsNzD8Uehbc1pMwsHCTxISpN7xTm9/qR0OgVoJR/BMJkA8h9gUpT8wAA4yj2ClTeNncS0QbQaDaV1tXBfj9QKmE8DK8QT+sIL6sb9obN/AVU+jEdBwymWBVU/kKxWyFnA0DhTCotS8EBSC2nVP10aFxEsfqN4GGNKDMY+42fQKV7grrD/I/D9ArxMyBlAxhxI5U242DFaZRaApX7KXZbImRsAANaOXXQ43uKTYFGej+KDYZ3pYfzM/2TqqkTOAOH6Euxz6ByGcX+BgkbQOce1EkYg8OMpZS/GzTysikgvxzfBlCSRJ1a3XG4EuNHuXdSbDk8K4My5+HhEHUatI3w5vfqujC9Qrw/jsAGMFc9/j0z4m3ST0HlFYo9BK9KpsyX+vEvapaZTanpULmXYknN4VW1KKMf//6atyjWGSrrKFYFrxpEKf34t2Zlxl/SulKsugAetYgGTc1zZqdTYBhMrxC/BR61kmL68W/NRlPseajMsCvEnXxV1o9/axa8jVKtC2B6hfhieNOrNGVZCo7gForNhekV4jPhTXMopx//1iy/AaXm+6DRtAHFOsOTRtCMzQ5/rW0MlR0U2wRvKqIJkyFRGqDUbKicm0CxAfCkpymgGP+KzKZUoBQqP1NsFzzpasrJx79CjSm2E6ZXiCeMhxcNoJh8/Cvlm0+pHvlQ+Zhi2+BJr1FIPv6Vm0uxC6EylGLNmsKLVlFIPv6VK2imuFLU2MfuC+BFdbIpJB//yr1IsdEwvUL8zlx40R4D41+xYQFKvQOYXiG+G150fMDA+FdsOcU6QGUexRb64EWTDIx/Tbyk7YNKwSkUmwgvqkgzMP6V8k2jVE5tqHxLsbHwpCoD41+xz41f9DMqiWJ94EV1uhgY/0rVPYVSNyYaf839FzxpsYHxr9g2is2CSlmAUqFKeNI+A+NfqZZ+Sq0DTK8QfxWelLzewPjXwEafE2B6hXh2MTypstrA+FeorfkjPFMp9gW8qbvfwPhXaIvxlU7n2RXiRzTHb2D8K7OGYn+HSuIVFFsFj7orZGD8K9KoBaXap0JlLsXmB+FRZ2UxfOV9oKD/VrcBxleIl8CruucwXCs6wgEVIUp9A50HqfgTntN/C8MSuDwRjthLseOh0i6NYs/BszK+ohyrb4JDjqPYuzC+QvwzeFjJqZSaWQnHbFVcKWpuhfjZ8LA2O5MocfpLKXDODIo9CZ0PKLYPntZtT4hHctWqFDgpo4hSTXKh0pNiaYXwttJlSfwt5U/lwmGfUGwMdL6h2H/bu7feqKo4jMPvbmemM6VVKtIDULAHhBSxtKAiqQqKBo2pRjFQjFTxAhRTBRRRjFHUSAOxaqUxSDxFqrVpDQpoiDEGDxHUWIOJiUY0jcZEhRtP0cS8XniJNP+9Z9Zhz/yfL7Dv1sUve72rX9+TW727nv+vcffiDHJuVtL4suc5FGucCJWZNrzghNnOo19ekYIRfxh/6SnxdMhBApWYd/vb9w5te25JumXTy8P9HT21MGYRxY6YvwOzOQHL1CZKJedHrBxL8mM/WMdKNsL4hPhxWKYyC0w/KYo5E+SfSMEy9bj5O1x7PN4MUg2nGd/0urKEUgdhm/qHYp2I5jdKXVMKy9QKih1CNJdRrA22qR2UKrkJ0azJj8UYvaH0K6JZ7/HD4qq0j1KNpyCSYBeF3oV16m6KfWL6z4OZsE6dnabUO4impo9CFbBODVJsNqL5gELzYJ26mmKjgNkJ8Wthn/qFUkXTEc0xytwH+9Rq09Ou8gnxh2GfGtdCqfaJ0WLghhKK3AEH1J0U+wmhpW7YSaluOKBqyyh1T4Bwpt62jHKz4YIaothyhFH18SSGcQtcUBdT7C/ItY4WMZzpcELtpVTxKsjUbH+ToY2HE6qbYl9A4tyfz2B45Qk4oVJbKVUvmCeeO1zGKF6BI2otxbZgbMG0AxTwKgSqikpKNQcYw5TnuxjZVXBFPZOThf/51zUyuhkBXFFzKfb9yYtvktn4Fu6oAUoVLxUU3ygWwx11UVaX+Kb2LmPWmuCOSmym1MI6QfEN70O4pHop1isovuHdCpdU3cIoWw412x9lbmyDW+o4xXoExTduB4BaSrGB/4rvn2Uk8+YAUAcodqmg+MbtAFBtFBsUFN+4HQAqaKYr9SvhnnqPrnTDA+r0erpxGF5QI3Ri7zh4Qa0spgN9TfCE2k/7kp3whXqK1pW/BW+ooIuWVXfCI6qDdjWvgk/U5HbatHMO/KI+o0VHMvCMqiqiLdUdAbyjfqQd6WN18JB6iFa8fj38pHbRvO9a4Su1j6at6QngLZV6kCalB9fBa2o9zTmrvwG+U1/RkK/3nQr/qXXFNKB4/3LEg3qJOTfh0/MQF2pWJXOr5f4KxIjqZS59/mwp4kUdZK6UHFqE2FGlA8yJme9fiDhS47uYvTe2nImYUlXV2RffBOJL3Zwu7OKrHrgxi+LbhNhTVS8WdvFVUzZEKb7nI2+o15KFXXxV64zCLr6qbuMkyhzNz+Krag9XFnbxVQ170hxTe54XX3X5R0/yZKqH2jLIe+qSx35I8wQtI3elUCDU5J6R0R1by0mSyQv+/n1k7YoA+eRf5cFlRxX8RB0AAAAASUVORK5CYII=);
background-size: 12vw 12vw;
display: block;
width: 12vw;
height: 12vw;
content: '';
opacity: 0;
margin-left: 6.5vw;
margin-top: 6vw;
animation: click 5s 1s infinite;
}
@keyframes click {
0% {
opacity: 0;
}
3% {
opacity: 0.5;
}
15% {
margin-left: 6.5vw;
margin-top: 6vw;
}
20% {
margin-left: 6vw;
margin-top: 5.5vw;
}
25% {
margin-left: 6.5vw;
margin-top: 6vw;
}
30% {
margin-left: 6vw;
margin-top: 5.5vw;
}
35% {
margin-left: 6.5vw;
margin-top: 6vw;
}
47% {
opacity: 0.5;
}
50% {
opacity: 0;
}
}
/*
* Winner highlight
*/
.wrapper #winner {
display: none;
float: left;
margin-top: -80vw;
margin-bottom: -113px;
margin-left: -5vw;
width: 90vw;
height: 90vw;
font-size: 22vw;
text-align: center;
text-transform: uppercase;
padding-top: 17vw;
background: rgba(245, 245, 245, .8);
}
/* The author.
* Hi mom!
*/
.wrapper .author {
font-size: 3vw;
color: #999;
float: right;
margin-right: 5px;
margin-top: 2vw;
margin-bottom: 5vw;
}
.wrapper .author .hearts {
color: #e88;
}
.wrapper .author a {
text-decoration: none;
color: #8be;
}
.wrapper .author a:hover {
text-decoration: underline;
}
/*
* Misc - taken from elsewhere
* Sources:
* .noselect - https://stackoverflow.com/questions/826782/how-to-disable-text-selection-highlighting-using-css
*/
.noselect, .wrapper #tic-tac-toe div {
-webkit-touch-callout: none; /* iOS Safari */
-webkit-user-select: none; /* Chrome/Safari/Opera */
-khtml-user-select: none; /* Konqueror */
-moz-user-select: none; /* Firefox */
-ms-user-select: none; /* Internet Explorer/Edge */
user-select: none; /* Non-prefixed version, currently
not supported by any browser */
}
window.onload = function() {
// Makes arrays
function makeArray(obj) {
return Array.prototype.slice.call(obj)
}
// Vanilla jQuery for the lazy
var $ = function() {
var args = makeArray(arguments);
var r = document.querySelectorAll.apply(document, args);
return r.length === 1 ? r[0] : r;
}
// Vanilla class functions
function addClass(el, className) {
removeClass(el, className)
el.className += ' ' + className
}
function removeClass(el, className) {
el.className = el.className.replace(className, '')
}
// Our main variables
var title = $('.wrapper #intro .title');
var message = $('.wrapper #intro .message');
var tictactoe = $('.wrapper #tic-tac-toe');
var blocks = $('.wrapper #tic-tac-toe div');
var restart = $('#restart');
var winner = $('#winner');
// Animated intro!
intro()
function intro() {
function show(el) {
el.style.opacity = 1;
}
function hide(el) {
el.style.opacity = 0;
}
var delayer = new Delayer();
var titleParts = makeArray(title.children);
var blocksArray = makeArray(blocks);
// Flushing
message.style.display = 'block'
winner.style.display = 'none'
hide(message)
removeClass(restart, 'visible')
titleParts.map(hide)
blocksArray.map(function(el) {
el.className = '';
el.innerText = '';
hide(el)
})
delayer.add(titleParts, show, 500)
delayer.add(blocksArray, show, 100)
delayer.add([blocks[0]], function(first) {
addClass(first, 'showCursor')
blocksArray.map(function(el) {
el.onclick = function() {
removeClass(first, 'showCursor')
message.style.display = 'none'
first.onclick = undefined
startGame(el)
}
})
}, 100)
delayer.add([message], show, 500)
delayer.run()
}
// Main game logic
var startsX = true;
function startGame(el) {
var player1 = {
str: startsX ? 'x' : 'o'
}
var player2 = {
str: !startsX ? 'x' : 'o',
}
var goesP1 = true;
var turns = 0;
addClass(restart, 'visible')
restart.onclick = function() {
intro()
}
var blocksArray = makeArray(blocks);
blocksArray.map(function(el) {
el.onclick = function() {
if (el.innerText) return
var player = goesP1 ? player1 : player2;
el.innerText = player.str.toUpperCase();
addClass(el, player.str);
goesP1 = !goesP1;
turns++
if (turns === 9) {
setTimeout(tie, 125);
} else
if (turns >= 5) {
setTimeout(function() {
checkWinner(player, el);
}, 125)
}
}
})
function checkWinner(player, el) {
var B = blocksArray;
var i = B.indexOf(el);
var str = player.str.toUpperCase()
function eqAt(a, b, c) {
return B[a].innerText === B[b].innerText && B[a].innerText === B[c].innerText;
}
var col = i % 3;
var row = i - col;
if (eqAt(row, row + 1, row + 2)) return won(player, row, row + 1, row + 2);
if (eqAt(col, col + 3, col + 6)) return won(player, col, col + 3, col + 6);
if (eqAt(0, 4, 8)) return won(player, 0, 4, 8)
if (eqAt(2, 4, 6)) return won(player, 2, 4, 6)
}
function won(player, a, b, c) {
addClass(blocksArray[a], 'yellow')
addClass(blocksArray[b], 'yellow')
addClass(blocksArray[c], 'yellow')
winner.style.display = 'block';
winner.style.color = player.str === 'x' ? '#e88' : '#8be';
winner.innerHTML = 'player <b>' + player.str + '</b> wins!'
blocksArray.map(function(el) {
el.onclick = undefined
})
}
function tie() {
winner.style.display = 'block';
winner.style.color = '#999';
winner.innerHTML = 'IT WAS<br>A TIE'
}
el.onclick()
}
// Delayer object
// adds animation *frames* into
// a strack, then replays them
function Delayer() {
var stack = []
this.add = function(arr, func, time) {
if (!(arr && arr.length)) {
throw 'Delayer.add error: invalid first argument, must be an array'
}
arr.map(function(el) {
stack.push({
el: el,
func: func,
timeout: time
})
})
}
var that = this
this.run = function() {
if (!stack.length) return
var current = stack.shift()
setTimeout(function() {
current.func(current.el)
that.run()
}, current.timeout)
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment