Freecodecamp Advanced Front End development project.
A Pen by Paulina Fischer on CodePen.
<div class="container-fluid text-center" id="container"> | |
<div class="row"> | |
<div class="col-md-12"> | |
<div class="container text-center"> | |
<br> | |
<button type="button" class="btn btn-success btn-lg animated fadeIn" data-toggle="modal" data-target="#myModal"><span class="glyphicon glyphicon-play" aria-hidden="true"></span></button> | |
<div class="modal fade animated swing" id="myModal" role="dialog"> | |
<div class="modal-dialog modal-sm"> | |
<div class="modal-content"> | |
<div class="modal-header"> | |
<button type="button" class="close" data-dismiss="modal">×</button> | |
<h4 class="modal-title">Selec your simbol!</h4> | |
</div> | |
<div class="modal-body"> | |
<div class = "selectSym"> | |
<button class="btn btn-danger animated rotateIn" onClick="selectSym('X')"><span class="glyphicon glyphicon-remove" aria-hidden="true"></span> | |
</button> | |
<button class="btn btn-danger animated bounce" onClick="selectSym('O')"><i class="fa fa-circle-o" aria-hidden="true"></i> | |
</button> | |
</div> | |
</div> | |
<div class="modal-footer"> | |
</div> | |
</div> | |
</div> | |
</div> | |
</div> | |
<br> | |
<button class="btn btn-warning" onClick="startGame()"><span class="glyphicon glyphicon-repeat" aria-hidden="true"></span></button></button> | |
</div> | |
</div> | |
<br><br><br><br> | |
<div class="container-fluid"> | |
<div class="row"> | |
<div class="col-md-2"><div class="jumotron"><h1 id="ti"><strong>TIC TAC TOE</strong></h1></div></div><div class="col-md-2"></div> | |
<div class="col-md-4"> | |
<table class="table animated fadeIn"> | |
<tr class="default"> | |
<td class="cell animated infinite pulse" id="0"></td> | |
<td class="cell animated infinite pulse" id="1"></td> | |
<td class="cell animated infinite pulse" id="2"></td> | |
</tr> | |
<tr class="default"> | |
<td class="cell animated infinite pulse" id="3"></td> | |
<td class="cell animated infinite pulse" id="4"></td> | |
<td class="cell animated infinite pulse" id="5"></td> | |
</tr> | |
<tr class="default"> | |
<td class="cell animated infinite pulse" id="6"></td> | |
<td class="cell animated infinite pulse" id="7"></td> | |
<td class="cell animated infinite pulse" id="8"></td> | |
</tr> | |
</table> | |
<div class="endgame well well-lg animated rubberBand"> | |
<div class="text"></div> | |
</div> | |
<div class="col-md-2"></div> | |
<div class="col-md-2"></div> | |
</div> | |
<div class="row"> | |
<div class="col-md-12 strong animated fadeIn"> <br><br><br> <p id ="yo">Created by: Paulina Fischer</p><br><p>Library from | |
<a href="https://www.youtube.com/watch?v=P2TcQ3h0ipQ&t=2699s" target="_blank">freeCodeCamp</a></p> | |
</div> | |
</div> | |
</div> |
let origBoard; | |
let huPlayer ='O'; | |
let aiPlayer = 'X'; | |
const winCombos =[ | |
[0, 1, 2], | |
[3, 4, 5], | |
[6, 7, 8], | |
[0, 4, 8], | |
[6, 4, 2], | |
[2, 5, 8], | |
[1, 4, 7], | |
[0, 3, 6] | |
]; | |
const cells = document.querySelectorAll('.cell'); | |
startGame(); | |
function selectSym(sym){ | |
huPlayer = sym; | |
aiPlayer = sym==='O' ? 'X' :'O'; | |
origBoard = Array.from(Array(9).keys()); | |
for (let i = 0; i < cells.length; i++) { | |
cells[i].addEventListener('click', turnClick, false); | |
} | |
if (aiPlayer === 'X') { | |
turn(bestSpot(),aiPlayer); | |
} | |
document.querySelector('.selectSym').style.display = "none"; | |
} | |
function startGame() { | |
document.querySelector('.endgame').style.display = "none"; | |
document.querySelector('.endgame .text').innerText =""; | |
document.querySelector('.selectSym').style.display = "block"; | |
for (let i = 0; i < cells.length; i++) { | |
cells[i].innerText = ''; | |
cells[i].style.removeProperty('background-color'); | |
} | |
} | |
function turnClick(square) { | |
if (typeof origBoard[square.target.id] ==='number') { | |
turn(square.target.id, huPlayer); | |
if (!checkWin(origBoard, huPlayer) && !checkTie()) | |
turn(bestSpot(), aiPlayer); | |
} | |
} | |
function turn(squareId, player) { | |
origBoard[squareId] = player; | |
document.getElementById(squareId).innerHTML = player; | |
let gameWon = checkWin(origBoard, player); | |
if (gameWon) gameOver(gameWon); | |
checkTie(); | |
} | |
function checkWin(board, player) { | |
let plays = board.reduce((a, e, i) => (e === player) ? a.concat(i) : a, []); | |
let gameWon = null; | |
for (let [index, win] of winCombos.entries()) { | |
if (win.every(elem => plays.indexOf(elem) > -1)) { | |
gameWon = {index: index, player: player}; | |
break; | |
} | |
} | |
return gameWon; | |
} | |
function gameOver(gameWon){ | |
for (let index of winCombos[gameWon.index]) { | |
document.getElementById(index).style.backgroundColor = | |
gameWon.player === huPlayer ? "#00CC89" : "#6CDEB9"; | |
} | |
for (let i=0; i < cells.length; i++) { | |
cells[i].removeEventListener('click', turnClick, false); | |
} | |
declareWinner(gameWon.player === huPlayer ? "You win!" : "You lose"); | |
} | |
function declareWinner(who) { | |
document.querySelector(".endgame").style.display = "block"; | |
document.querySelector(".endgame .text").innerText = who; | |
} | |
function emptySquares() { | |
return origBoard.filter((elm, i) => i===elm); | |
} | |
function bestSpot(){ | |
return minimax(origBoard, aiPlayer).index; | |
} | |
function checkTie() { | |
if (emptySquares().length === 0){ | |
for (cell of cells) { | |
cell.style.backgroundColor = "#FF5600"; | |
cell.removeEventListener('click',turnClick, false); | |
} | |
declareWinner("Tie game"); | |
return true; | |
} | |
return false; | |
} | |
function minimax(newBoard, player) { | |
var availSpots = emptySquares(newBoard); | |
if (checkWin(newBoard, huPlayer)) { | |
return {score: -10}; | |
} else if (checkWin(newBoard, aiPlayer)) { | |
return {score: 10}; | |
} else if (availSpots.length === 0) { | |
return {score: 0}; | |
} | |
var moves = []; | |
for (let i = 0; i < availSpots.length; i ++) { | |
var move = {}; | |
move.index = newBoard[availSpots[i]]; | |
newBoard[availSpots[i]] = player; | |
if (player === aiPlayer) | |
move.score = minimax(newBoard, huPlayer).score; | |
else | |
move.score = minimax(newBoard, aiPlayer).score; | |
newBoard[availSpots[i]] = move.index; | |
if ((player === aiPlayer && move.score === 10) || (player === huPlayer && move.score === -10)) | |
return move; | |
else | |
moves.push(move); | |
} | |
let bestMove, bestScore; | |
if (player === aiPlayer) { | |
bestScore = -1000; | |
for(let i = 0; i < moves.length; i++) { | |
if (moves[i].score > bestScore) { | |
bestScore = moves[i].score; | |
bestMove = i; | |
} | |
} | |
} else { | |
bestScore = 1000; | |
for(let i = 0; i < moves.length; i++) { | |
if (moves[i].score < bestScore) { | |
bestScore = moves[i].score; | |
bestMove = i; | |
} | |
} | |
} | |
return moves[bestMove]; | |
} | |
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.2.1/jquery.min.js"></script> | |
<script src="https://cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/3.3.7/js/bootstrap.min.js"></script> |
#container{ | |
background:#EE004C; | |
-webkit-animation-name:bgcolor; | |
-webkit-animation-duration:10s; | |
-webkit-animation-timing-function:linear; | |
-webkit-animation-delay:0s; | |
-webkit-animation-iteration-count:infinite; | |
-webkit-animation-direction:alternate; | |
-webkit-animation-play-state:running; | |
animation-name:bgcolor; | |
animation-duration:10s; | |
animation-timing-function:linear; | |
animation-delay:0s; | |
animation-iteration-count:infinite; | |
animation-direction:alternate; | |
animation-play-state:running; | |
} | |
@-webkit-keyframes bgcolor | |
{ | |
0% {background: #EE004C; left:0px; top:0px;} | |
25% {background: #B2385F; left:0px; top:0px;} | |
50% {background: #9b59b6; left:0px; top:0px;} | |
75% {background: #C96E40; left:0px; top:0px;} | |
100% {background: #EE004C; left:0px; top:0px;} | |
} | |
@keyframes bgcolor | |
{ | |
0% {background: #EE004C; left:0px; top:0px;} | |
25% {background: #B2385F; left:0px; top:0px;} | |
50% {background: #9b59b6; left:0px; top:0px;} | |
75% {background: #C96E40; left:0px; top:0px;} | |
100% {background: #EE004C; left:0px; top:0px;} | |
} | |
td { | |
border: 5px solid #6D0023; | |
width:100px; | |
height:100px; | |
text-align:center; | |
vertical-align:middle; | |
font-family: 'Finger Paint', cursive; | |
cursor: pointer; | |
font-size:50px; | |
color:#F4779F; | |
} | |
table tr:first-child td { | |
border-top: 0; | |
} | |
table tr:last-child td { | |
border-bottom: 0; | |
} | |
table tr td:first-child { | |
border-left: 0; | |
} | |
table tr td:last-child { | |
border-right: 0; | |
} | |
.well{ | |
position:relative; | |
top:-250px; | |
font-size:80px; | |
font-family: 'Finger Paint', cursive; | |
background-color:#B2F577; | |
color:#346E00; | |
border:none; | |
} | |
.jumbotron{ | |
width: 100%; | |
margin:0px auto; | |
} | |
h1{ | |
letter-spacing:5px; | |
font-size:65px; | |
color:#71EF00; | |
font-family: 'Finger Paint', cursive; | |
} | |
h4{font-family: 'Finger Paint', cursive; | |
color:#FFA97D; | |
} | |
.modal-content, .modal-body, .modal-header, .modal-title, .modal-footer {background-color:#FF5600; | |
border:none;} | |
#yo{color:whitesmoke; | |
font-family: 'Libre Franklin', sans-serif;} | |
.btn{ | |
width:100px; | |
height:40px; | |
color:#005237; | |
background-color:#00CC89; | |
border: #005237;} | |
.btn-danger{ | |
background-color:#7B2900; | |
color:#FFA97D; | |
} |
<link href="https://cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/3.3.7/css/bootstrap.min.css" rel="stylesheet" /> | |
<link href="https://cdnjs.cloudflare.com/ajax/libs/animate.css/3.5.2/animate.min.css" rel="stylesheet" /> |
Freecodecamp Advanced Front End development project.
A Pen by Paulina Fischer on CodePen.