Beispiel:Tic-tac-toe-6.html
Aus SELFHTML-Wiki
<!doctype html>
<html lang="de">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<link rel="stylesheet" media="screen" href="./Beispiel:Grundlayout.css">
<title>Tic-Tac-Toe - 6</title>
<style>
.tic-tac-toe #gameboard {
width: 60vmin;
height: 60vmin;
display: grid;
grid-template-columns: repeat(3, 1fr);
gap: 0;
}
.tic-tac-toe button {
width: 20vmin;
height: 20vmin;
background: white;
border: 1px solid black;
margin: 0;
font: 0/0 transparent;
}
.tic-tac-toe [aria-label="x"] {
background-image: url('data:image/svg+xml,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20viewBox%3D%220%200%201%201%22%3E%3Cline%20x1%3D%220.1%22%20y1%3D%220.1%22%20x2%3D%220.9%22%20y2%3D%220.9%22%20stroke-width%3D%220.1%22%20stroke%3D%22red%22%2F%3E%3Cline%20x1%3D%220.1%22%20y1%3D%220.9%22%20x2%3D%220.9%22%20y2%3D%220.1%22%20stroke-width%3D%220.1%22%20stroke%3D%22red%22%2F%3E%3C%2Fsvg%3E');
}
.tic-tac-toe [aria-label="o"] {
background-image: url('data:image/svg+xml,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20viewBox%3D%220%200%201%201%22%3E%3Ccircle%20cx%3D%220.5%22%20cy%3D%220.5%22%20r%3D%220.4%22%20fill%3D%22none%22%20stroke-width%3D%220.1%22%20stroke%3D%22blue%22%2F%3E%3C%2Fsvg%3E');
}
.tic-tac-toe .highlighted {
background-color: yellow;
}
.warning {
color: red;
}
.success {
color: green;
background-color: yellow;
}
/* Dialog für "Neues Spiel?" */
#newgame-dialog {
display: none;
position: fixed;
inset: 0;
background: rgba(0,0,0,0.4);
justify-content: center;
align-items: center;
z-index: 10;
}
#newgame-dialog.visible {
display: flex;
}
#newgame-dialog > div {
background: white;
border: 1px solid black;
padding: 1.5em 2em;
text-align: center;
}
#newgame-dialog p {
margin: 0 0 1em;
}
#newgame-dialog button {
width: auto;
height: auto;
font: inherit;
padding: 0.4em 1.2em;
margin: 0 0.4em;
cursor: pointer;
}
</style>
<script>
'use strict';
document.addEventListener('DOMContentLoaded', function () {
const gameboard = document.querySelector('#gameboard');
const hint = document.querySelector('#hint');
const dialog = document.querySelector('#newgame-dialog');
const btnYes = document.querySelector('#btn-yes');
const btnNo = document.querySelector('#btn-no');
const players = ['x', 'o'];
let current = 0;
let winner = null;
let finished = false;
gameboard.addEventListener('click', markField);
function markField(e) {
if (finished) return;
const field = e.target;
if (field.tagName !== 'BUTTON') return;
field.setAttribute('aria-label', players[current]);
field.setAttribute('disabled', 'disabled');
current = 1 - current;
hint.textContent = 'Spieler ' + players[current] + ' ist am Zug.';
hint.className = '';
checkIfCompleted();
}
function checkIfCompleted() {
const fields = gameboard.querySelectorAll('button');
// Gewinner ermitteln
for (let i = 0; i < 3; i++) {
// 3 senkrecht
if (fields[i].getAttribute('aria-label') !== ''
&& fields[i].getAttribute('aria-label') === fields[3 + i].getAttribute('aria-label')
&& fields[3 + i].getAttribute('aria-label') === fields[6 + i].getAttribute('aria-label')
) {
winner = fields[i].getAttribute('aria-label');
highlightCells([fields[i], fields[3 + i], fields[6 + i]]);
}
// 3 waagrecht
if (fields[i * 3].getAttribute('aria-label') !== ''
&& fields[i * 3].getAttribute('aria-label') === fields[i * 3 + 1].getAttribute('aria-label')
&& fields[i * 3 + 1].getAttribute('aria-label') === fields[i * 3 + 2].getAttribute('aria-label')
) {
winner = fields[i * 3].getAttribute('aria-label');
highlightCells([fields[i * 3], fields[i * 3 + 1], fields[i * 3 + 2]]);
}
}
// diagonal links oben nach rechts unten
if (fields[0].getAttribute('aria-label') !== ''
&& fields[0].getAttribute('aria-label') === fields[4].getAttribute('aria-label')
&& fields[4].getAttribute('aria-label') === fields[8].getAttribute('aria-label')
) {
winner = fields[0].getAttribute('aria-label');
highlightCells([fields[0], fields[4], fields[8]]);
}
// diagonal rechts oben nach links unten
if (fields[2].getAttribute('aria-label') !== ''
&& fields[2].getAttribute('aria-label') === fields[4].getAttribute('aria-label')
&& fields[4].getAttribute('aria-label') === fields[6].getAttribute('aria-label')
) {
winner = fields[2].getAttribute('aria-label');
highlightCells([fields[2], fields[4], fields[6]]);
}
// alle Felder belegt?
const full = Array.from(fields).every(f => f.hasAttribute('disabled'));
// Spiel vorbei?
if (winner || full) {
finished = true;
if (winner) {
hint.textContent = 'Das Spiel ist zu Ende, weil Spieler ' + winner + ' gewonnen hat!';
hint.className = 'success';
} else {
hint.textContent = 'Das Spiel endet unentschieden, weil alle Felder belegt sind.';
hint.className = 'warning';
}
dialog.classList.add('visible');
}
}
function highlightCells(cells) {
cells.forEach(cell => cell.classList.add('highlighted'));
}
function resetGame() {
const fields = gameboard.querySelectorAll('button');
fields.forEach(field => {
field.setAttribute('aria-label', '');
field.removeAttribute('disabled');
field.classList.remove('highlighted');
field.style.backgroundImage = '';
});
current = 0;
winner = null;
finished = false;
hint.textContent = 'Zum Spielen bitte abwechselnd in die Spielfelder klicken/tappen!';
hint.className = '';
dialog.classList.remove('visible');
}
btnYes.addEventListener('click', resetGame);
btnNo.addEventListener('click', () => dialog.classList.remove('visible'));
});
</script>
</head>
<body>
<h1>Tic-Tac-Toe 6 (Spielende 2)</h1>
<div class="tic-tac-toe" aria-describedby="hint">
<p id="hint">Zum Spielen bitte abwechselnd in die Spielfelder klicken/tappen!</p>
<div id="gameboard">
<button aria-label=""></button>
<button aria-label=""></button>
<button aria-label=""></button>
<button aria-label=""></button>
<button aria-label=""></button>
<button aria-label=""></button>
<button aria-label=""></button>
<button aria-label=""></button>
<button aria-label=""></button>
</div>
</div>
<div id="newgame-dialog" role="dialog" aria-modal="true" aria-labelledby="dialog-text">
<div>
<p id="dialog-text">Neues Spiel?</p>
<button id="btn-yes">Ja</button>
<button id="btn-no">Nein</button>
</div>
</div>
</body>
</html>