JSFiddle - React, Tailwind, and code Playground
HTML
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<link rel="stylesheet" href="./static/css/main.css" />
<script src="./static/js/main.js" defer></script>
<link rel="apple-touch-icon" sizes="180x180" href="../../public/images/favicon/apple-touch-icon.png">
<link rel="icon" type="image/png" sizes="32x32" href="../../public/images/favicon/favicon-32x32.png">
<link rel="icon" type="image/png" sizes="16x16" href="../../public/images/favicon/favicon-16x16.png">
<link rel="manifest" href="../../public/images/favicon/site.webmanifest">
<link rel="mask-icon" href="../../public/images/favicon/safari-pinned-tab.svg" color="#5bbad5">
<link rel="shortcut icon" href="../../public/images/favicon/favicon.ico">
<meta name="msapplication-TileColor" content="#da532c">
<meta name="msapplication-config" content="../../public/images/favicon/browserconfig.xml">
<meta name="theme-color" content="#ffffff">
<title>ThinkTap</title>
</head>
<h1>ThinkTap</h1>
<body>
<div id="game">
<div class="grid-cell" data-value="0"></div>
<div class="grid-cell" data-value="1"></div>
<div class="grid-cell" data-value="2"></div>
<div class="grid-cell" data-value="3"></div>
<div class="grid-cell" data-value="4"></div>
<div class="grid-cell" data-value="5"></div>
<div class="grid-cell" data-value="6"></div>
<div class="grid-cell" data-value="7"></div>
<div class="grid-cell" data-value="8"></div>
</div>
<div class="game-over">
<span class="game-over-text"></span>
<button class="restart">opnieuw spelen</button>
</div>
<div class="scoreboard">
<div class="score-x-score">X: 0</div>
<div class="score-o-score">O: 0</div>
</div>
<button class="reset"...
CSS
h1 {
color: white;
text-align: center;
font-family: Dongle;
font-weight: bold;
font-size: 5rem;
}
#game {
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
display: grid;
grid-template-columns: repeat(3, auto);
background-color: white;
border-radius: 1rem;
}
.scoreboard {
border: solid white;
color: white;
text-align: center;
font-family: sans-serif;
font-weight: bold;
font-size: 2rem;
width: 8rem;
float:right;
margin-right: 3rem;
background-color: black;
border-radius: 1rem;
}
.score-x-score {
border-bottom: solid white;
}
.grid-cell {
border: 0.063rem solid #000;
width: 6rem;
height: 6rem;
cursor: pointer;
display: flex;
justify-content: center;
align-items: center;
font-size: 1.75rem;
}
.grid-cell:not(.disabled):hover {
background: #C1DDFF;
}
.grid-cell:not(.disabled):first-child:hover {
border-top-left-radius: 1rem;
}
.grid-cell:not(.disabled):nth-child(3):hover {
border-top-right-radius: 1rem;
}
.grid-cell:not(.disabled):nth-last-child(3):hover {
border-bottom-left-radius: 1rem;
}
.grid-cell:not(.disabled):last-child:hover {
border-bottom-right-radius: 1rem;
}
.grid-cell:nth-child(-n + 3) {
border-top: none;
}
.grid-cell:nth-child(3n + 1) {
border-left: none;
}
.grid-cell:nth-child(3n + 3) {
border-right: none;
}
.grid-cell:nth-last-of-type(-n + 3) {
border-bottom: none;
}
.disabled {
cursor: not-allowed;
}
.x::after {
content: '❌';
}
.o::after {
content: '⭕';
}
.game-over {
border-radius: 1rem;
display: none;
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
box-shadow: rgb(0 0 0 / 50%) 0 0 0 9999px;
}
.game-over-text {
position: absolute;
top: -12rem;
font-size:4rem;
font-family: Dongle;
font-weight: bold;
text-align: center;
padding-left: 6rem;
transform: translateX(-30%);
color: white;
}
button {
appearance: button;
background-color: #1899D6;
border: solid...
JavaScript
const game = {
xTurn: true,
xState: [],
oState: [],
winningStates: [
// Rij
['0', '1', '2'],
['3', '4', '5'],
['6', '7', '8'],
// kolomen
['0', '3', '6'],
['1', '4', '7'],
['2', '5', '8'],
// diagonaal
['0', '4', '8'],
['2', '4', '6']
]
}
let scores = {
X: 0,
O: 0
};
const updateScoreboard = () => {
document.querySelector('.score-x-score').textContent = `X: ${scores.X}`;
document.querySelector('.score-o-score').textContent = `O: ${scores.O}`;
};
document.addEventListener('click', event => {
const target = event.target;
const isCell = target.classList.contains('grid-cell');
const isDisabled = target.classList.contains('disabled');
if (isCell && !isDisabled) {
const cellValue = target.dataset.value;
game.xTurn === true ?
game.xState.push(cellValue) :
game.oState.push(cellValue)
target.classList.add('disabled')
target.classList.add(game.xTurn ? 'x' : 'o');
game.xTurn = !game.xTurn;
if (!document.querySelectorAll('.grid-cell:not(.disabled)').length) {
document.querySelector('.game-over').classList.add('visible')
document.querySelector('.game-over-text').textContent = 'Gelijk!'
}
game.winningStates.forEach(winningState => {
const xWins = winningState.every(state => game.xState.includes(state))
const oWins = winningState.every(state => game.oState.includes(state))
if (xWins || oWins) {
document.querySelectorAll('.grid-cell').forEach(cell => cell.classList.add('disabled'))
document.querySelector('.game-over').classList.add('visible')
document.querySelector('.game-over-text').textContent = xWins ?
'❌ wint!' :
'⭕ wint!'
if (xWins) {
scores.X++;
...