Beispiel:Tic-tac-toe-6.html

Aus SELFHTML-Wiki
Wechseln zu: Navigation, Suche
<!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>