@import url('https://fonts.googleapis.com/css?family=Permanent+Marker');
html {
box-sizing: border-box;
font-size: 10px;
}
*, *:before, *:after {
box-sizing: inherit;
}
body {
align-items: center;
display: flex;
flex-direction: column;
font-family: 'Permanent Marker';
height: 100vh;
justify-content: center;
}
#score {
display: flex;
margin-bottom: 4rem;
width: 50vh;
// display isn't necessary for pseudo elements if parent is flex
// nice
&::before {
// here's a reason for all the dataset changes in js
// free UI updates with state changes
content: 'x: ' attr(data-x-score);
font-size: 3rem;
width: 50%;
}
&::after {
content: 'o: ' attr(data-o-score);
font-size: 3rem;
text-align: right;
width: 50%;
}
}
#container {
border: 1px solid black;
display: flex;
flex-wrap: wrap;
height: 50vh;
min-height: 200px;
min-width: 200px;
width: 50vh;
&::before {
font-size: 3rem;
position: absolute;
text-align: center;
transform: translate3d(0, -110%, 0);
width: 50vh;
}
// more dataset changes in js causing UI changes
&[data-message="x"]::before {
content: 'x turn';
}
&[data-message="o"]::before {
content: 'o turn';
}
&[data-message="winner"]::before {
color: green;
content: 'winner!';
}
&[data-message="tie"]::before {
color: red;
content: 'tie!';
}
// sometimes sub-pixel math causes gaps between borders
// a more clever border layout would solve that
.square {
align-items: center;
background-color: white;
border: 1px solid black;
cursor: pointer;
display: flex;
height: 33.33%;
justify-content: center;
overflow: hidden;
transition: background-color 0.25s 0.25s;
width: 33.33%;
&:hover {
// but a more clever border layout would makes this hard to handle, compromise
border-color: green;
}
&::before {
content: '';
transform:...
JavaScript
console.clear();
// this makes heavy use of dataset attributes to control display and state changes
// basic HTML to insert into body
document.body.insertAdjacentHTML('afterbegin', '<div id="score"></div>');
document.body.insertAdjacentHTML('beforeend', '<div id="container"></div><div id="panel"><button id="aiBtn"></button><button id="resetBtn">reset</button></div>');
const $score = document.querySelector('#score');
const $container = document.querySelector('#container');
const $aiBtn = document.querySelector('#aiBtn');
// possible winning choices
const wins = [[0,1,2],[3,4,5],[6,7,8],[0,3,6],[1,4,7],[2,5,8],[0,4,8],[2,4,6]];
// various lets for creating board and keeping track of play
let squaresHTML = '';
let plays = [null, null, null, null, null, null, null, null, null];
let winner = null;
let score = {x: 0, o: 0};
let hasAI;
// after every click we check for winner
let checkForWin = () => {
let winRow;
// compare current plays against possible win combinations
// this does rip through entire wins array without breaking on match, but it's only 8 items
// could change it to for loop to have break, but bah
wins.forEach((element) => {
if (plays[element[0]] && plays[element[0]] === plays[element[1]] && plays[element[1]] === plays[element[2]]) {
// if winner is found id the winning player
winner = plays[element[0]];
// id the winning row to highlight
winRow = element;
}
});
if (winner) {
// update message and score
$container.dataset.message = 'winner';
score[winner]++;
$score.dataset.xScore = score.x;
$score.dataset.oScore = score.o;
winRow.forEach((element) => {
// highlight winning row
$container.childNodes[element].classList.add('win');
});
} else {
// no win so switch players in message
$container.dataset.message = $container.dataset.message === 'x' ? 'o' : 'x';
}
};
// AI always assumes player is X
// idea: look for wins
// idea: choose certain move based on...
Please Whitelist JSFiddle in your content blocker.
Help keep JSFiddle free for always by one of two ways:
Whitelist JSFiddle in your content blocker (two clicks)
Go PRO and get access to additional PRO features →
Join the 4+ million users, and keep the JSFiddle dream alive.
Ad-free
All ads in the editor and listing pages are turned completely off.
Use pre-released features
You get to try and use features (like the Palette Color Generator) months before everyone else.
Fiddle collections
Sort and categorize your Fiddles into multiple collections.
Private collections and fiddles
You can make as many Private Fiddles, and Private Collections as you wish!
Console
Debug your Fiddle with a minimal built-in JavaScript console.