Last active
January 11, 2019 21:37
-
-
Save nicolechung/c84221d73235720dc908c4e9131b6c4c to your computer and use it in GitHub Desktop.
Tic Tac Toe (HTML, SASS, ES6 Javascript)
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
<html> | |
<body> | |
<h2>Click on a square to start</h2> | |
<div id="container"> | |
<div id="game-box"> | |
<div data-box="1" class="box"> </div> | |
<div data-box="2" class="box"> </div> | |
<div data-box="3" class="box"> </div> | |
<div data-box="4" class="box"> </div> | |
<div data-box="5" class="box"> </div> | |
<div data-box="6" class="box"> </div> | |
<div data-box="7" class="box"> </div> | |
<div data-box="8" class="box"> </div> | |
<div data-box="9" class="box"> </div> | |
</div> | |
<div id="won"> | |
<p id="won-message"></p> | |
<button id="reset">reset</button> | |
</div> | |
</div> | |
<script src="./index.js"></script> | |
</body> | |
</html> |
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
import './style.scss' | |
const el = document.getElementById('game-box') | |
el.addEventListener('click', handleClick); | |
const button = document.getElementById('reset') | |
button.addEventListener('click', reset); | |
let turn = 'x' | |
let xStyle = 'background-color: #7FDBFF' | |
let oStyle = 'background-color: #F012BE' | |
let turnStyle = xStyle | |
const WIN_LENGTH = 2 | |
let board | |
function reset() { | |
board = [ | |
{x:0, y: 0}, | |
{x:1, y: 0}, | |
{x:2, y: 0}, | |
{x:0, y: 1}, | |
{x:1, y: 1}, | |
{x:2, y: 1}, | |
{x:0, y: 2}, | |
{x:1, y: 2}, | |
{x:2, y: 2}, | |
] | |
const divs = document.getElementsByClassName('box'); | |
for (let i = 0; i < divs.length; i++) { | |
const div = divs[i] | |
div.innerHTML = '' | |
div.style = '' | |
} | |
const el = document.getElementById('won-message') | |
el.innerHTML = 'Start! (click)' | |
const wonBox = document.getElementById('won') | |
wonBox.classList.remove("bounceIn") | |
} | |
function toggleTurn() { | |
if (turn === 'x'){ | |
turn = 'o' | |
turnStyle = oStyle | |
} else { | |
turn = 'x' | |
turnStyle = xStyle | |
} | |
} | |
function handleClick(event) { | |
const box = event.target.dataset.box | |
if (score(turn, box)) { | |
const list = document.querySelectorAll(`[data-box='${box}']`) | |
const domElement = list[0] | |
domElement.style = turnStyle | |
domElement.innerHTML = turn | |
toggleTurn() | |
calculateScore() | |
} | |
} | |
function score(turn, box) { | |
const boxToScore = parseInt(box, 10) - 1 | |
if (!board[boxToScore].turn) { | |
board[boxToScore]= { | |
...board[boxToScore], | |
turn: turn | |
} | |
return true | |
} else { | |
alert('this box is taken') | |
return false | |
} | |
} | |
function calculateScore() { | |
const x = board.filter(item => item.turn === 'x') | |
const o = board.filter(item => item.turn === 'o') | |
const xWon = checkPlayerWon(x) | |
const oWon = checkPlayerWon(o) | |
if (xWon || oWon) { | |
let winner = '' | |
if (xWon) { | |
winner = 'x' | |
} else { | |
winner = 'o' | |
} | |
const el = document.getElementById('won-message') | |
el.innerHTML = winner + ' has won' | |
const wonBox = document.getElementById('won') | |
wonBox.classList.add("bounceIn") | |
setTimeout(reset, 2000) | |
} | |
} | |
function checkPlayerWon(player) { | |
return checkStraightWins(player, 'x') || checkStraightWins(player, 'y') || checkDiagonalWins(player) | |
} | |
function checkStraightWins(player, xy) { | |
const result = player.filter(item => item[xy] === 0).length > WIN_LENGTH || | |
player.filter(item => item[xy] === 1).length > WIN_LENGTH || | |
player.filter(item => item[xy] === WIN_LENGTH).length > WIN_LENGTH | |
return result | |
} | |
function checkDiagonalWins(player) { | |
const diagonal1 = [ | |
{ | |
x:0, y:0 | |
}, | |
{ | |
x:1, y:1 | |
}, | |
{ | |
x:2, y:2 | |
}, | |
] | |
const diagonal2 = [ | |
{ | |
x:2, y:0 | |
}, | |
{ | |
x:1, y:1 | |
}, | |
{ | |
x:0, y:2 | |
}, | |
] | |
const diagonal1Compare = arrayCompare(player, diagonal1) | |
const diagonal2Compare = arrayCompare(player, diagonal2) | |
const result = diagonal1Compare || diagonal2Compare | |
return result | |
} | |
function arrayCompare(player, win) { | |
const filtered = player.filter(player_item => { | |
return win.filter(win_item => { | |
return player_item.x == win_item.x && player_item.y == win_item.y | |
}).length > 0 | |
}) | |
return filtered.length > WIN_LENGTH | |
} | |
/* start game by resetting / initializing the board */ | |
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
h2 { | |
text-align: center; | |
font-family: 'Noto Sans', sans-serif; | |
margin: 30px auto 0; | |
color: #001f3f; | |
} | |
@-webkit-keyframes bounceIn { | |
from, | |
20%, | |
40%, | |
60%, | |
80%, | |
to { | |
-webkit-animation-timing-function: cubic-bezier(0.215, 0.61, 0.355, 1); | |
animation-timing-function: cubic-bezier(0.215, 0.61, 0.355, 1); | |
} | |
0% { | |
opacity: 0; | |
-webkit-transform: scale3d(0.3, 0.3, 0.3); | |
transform: scale3d(0.3, 0.3, 0.3); | |
} | |
20% { | |
-webkit-transform: scale3d(1.1, 1.1, 1.1); | |
transform: scale3d(1.1, 1.1, 1.1); | |
} | |
40% { | |
-webkit-transform: scale3d(0.9, 0.9, 0.9); | |
transform: scale3d(0.9, 0.9, 0.9); | |
} | |
60% { | |
opacity: 1; | |
-webkit-transform: scale3d(1.03, 1.03, 1.03); | |
transform: scale3d(1.03, 1.03, 1.03); | |
} | |
80% { | |
-webkit-transform: scale3d(0.97, 0.97, 0.97); | |
transform: scale3d(0.97, 0.97, 0.97); | |
} | |
to { | |
opacity: 1; | |
-webkit-transform: scale3d(1, 1, 1); | |
transform: scale3d(1, 1, 1); | |
} | |
} | |
@keyframes bounceIn { | |
from, | |
20%, | |
40%, | |
60%, | |
80%, | |
to { | |
-webkit-animation-timing-function: cubic-bezier(0.215, 0.61, 0.355, 1); | |
animation-timing-function: cubic-bezier(0.215, 0.61, 0.355, 1); | |
} | |
0% { | |
opacity: 0; | |
-webkit-transform: scale3d(0.3, 0.3, 0.3); | |
transform: scale3d(0.3, 0.3, 0.3); | |
} | |
20% { | |
-webkit-transform: scale3d(1.1, 1.1, 1.1); | |
transform: scale3d(1.1, 1.1, 1.1); | |
} | |
40% { | |
-webkit-transform: scale3d(0.9, 0.9, 0.9); | |
transform: scale3d(0.9, 0.9, 0.9); | |
} | |
60% { | |
opacity: 1; | |
-webkit-transform: scale3d(1.03, 1.03, 1.03); | |
transform: scale3d(1.03, 1.03, 1.03); | |
} | |
80% { | |
-webkit-transform: scale3d(0.97, 0.97, 0.97); | |
transform: scale3d(0.97, 0.97, 0.97); | |
} | |
to { | |
opacity: 1; | |
-webkit-transform: scale3d(1, 1, 1); | |
transform: scale3d(1, 1, 1); | |
} | |
} | |
#container { | |
display: flex; | |
width: 100%; | |
justify-content: center; | |
align-items: center; | |
font-family: 'Noto Sans', sans-serif; | |
} | |
#game-box { | |
display: flex; | |
margin: 50px 0; | |
grid-column-gap: 10px; | |
width: 180px; | |
border: 2px solid #001f3f; | |
flex-wrap: wrap; | |
& > div { | |
flex: 1; | |
min-width: 50px; | |
height: 50px; | |
font-size: 40px; | |
line-height: 39px; | |
text-align: center; | |
padding: 0; | |
cursor: pointer; | |
border: 2px solid #001f3f; | |
} | |
} | |
#won { | |
background-color: #FFDC00; | |
display: block; | |
width: 230px; | |
height: 160px; | |
margin: 0 20px; | |
text-align: center; | |
box-shadow: 0 0 1px rgba(0, 0, 0, 0); | |
&.bounceIn { | |
-webkit-animation-duration: 0.75s; | |
animation-duration: 0.75s; | |
-webkit-animation-name: bounceIn; | |
animation-name: bounceIn; | |
} | |
p { | |
font-size: 22px; | |
} | |
} | |
button { | |
margin: 30px auto; | |
padding: 5px 20px 10px; | |
display: block; | |
border: none; | |
background-color: #FF851B; | |
color: white; | |
font-size: 14px; | |
border-radius: 4px; | |
} | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment