TicTacToe - the pragmatic way
Tags: javascript, html, css
Published: 2023-11-08 08:58:14

```html
<!DOCTYPE html>
<html lang="de">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0"> 
  <title>Document</title>
  <style>
    html{
      font-family: system-ui, sans-serif;
    }
    body{
      display:flex;
      flex-direction:column;
      align-items: center;
      width: 360px;
      margin:auto;
    }
    table{
      border-spacing:0px; 
      border-collapse: collapse;
    }
    td{
      box-sizing: border-box;
      display: inline-grid;
      place-items: center;
      width:100px;
      height:100px;
      background:blue;
      font-weight:bold;
      font-size: 4em;
      cursor:pointer;
      user-select: none;  
      margin:2px;
      }
    td:hover{
      background: silver;
    }
    button{
      margin: 1em 0;
      font-size:2em;
      padding: 0.25em 1em;
      font-weight:bold;
    }
    ::backdrop {
      opacity: 0.75;
      backdrop-filter: blur(3px);
    }
  </style>
</head>
<body>
  <h1>TicTacToe</h1>
  <table id=board></table>
  <button>new Game</button>
  <dialog id=dialog>
    <h2 id=winner></h2>
    <form method="dialog">
      <button>OK</button>
    </form>
  </dialog>
  <script>
    var player = "X"
    const clearBoard = () => board.innerHTML = '<tr><td><td><td>'.repeat(3)
    clearBoard()
    board.onclick = (el, cell=el.target) => {
      if (cell.tagName == 'TD' && cell.innerText == ''){
        cell.innerText = player
        cell.style.background = "silver"
        let vert = diaglr = diagrl = ''
        for (let i=0; i<3; i++){
          let row = board.rows[i].cells
          vert += row[cell.cellIndex].textContent
          diaglr += row[i].textContent
          diagrl += row[2-i].textContent
        }
        if ([cell.parentNode.textContent, vert, diaglr, diagrl].includes(player.repeat(3))){
          winner.textContent=`Winner player "${player}" !`
          dialog.showModal()
        } else {
          if(board.textContent.length==9){
            winner.textContent="The game ends in a tie"
            dialog.showModal()
          }
        }
        player = player === 'X' ? 'O' : 'X'
      } 
    }
    document.querySelectorAll('button').forEach( 
      el => el.addEventListener('click', () => 
      clearBoard()))
  </script>
</body>
</html>
```


This HTML and JavaScript code represents a simple implementation of the Tic-Tac-Toe game. Let me explain the code step by step:

### HTML Part:

```html
<!DOCTYPE html>
<html lang="de">
<head>
  <!-- Meta tags for character set and viewport settings -->
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0"> 
  <title>Document</title>
  <!-- Internal CSS styles for the document -->
  <style>
    /* CSS styles for various HTML elements */
  </style>
</head>
<body>
  <!-- Game title and game board rendered as a table -->
  <h1>TicTacToe</h1>
  <table id=board></table>
  <!-- Button to start a new game and a dialog box for displaying game results -->
  <button>new Game</button>
  <dialog id=dialog>
    <h2 id=winner></h2>
    <!-- Form inside the dialog box with an OK button -->
    <form method="dialog">
      <button>OK</button>
    </form>
  </dialog>
  <script>
    // JavaScript code for game logic
  </script>
</body>
</html>
```

### CSS Part:

- The CSS styles define the appearance of various HTML elements, including the game board cells, buttons, and dialog box. It sets the layout, colors, and interactions for the Tic-Tac-Toe game.

### JavaScript Part:

1. **Initialization:**
   - `var player = "X"` initializes the current player as "X".
   - `const clearBoard = () => board.innerHTML = '<tr><td><td><td>'.repeat(3)` clears the game board by resetting the inner HTML of the table to three rows with three empty cells each.

2. **Event Handling:**
   - `board.onclick` handles click events on the game board. It checks if a clicked cell is empty and sets it to the current player ("X" or "O"). It then checks for winning conditions in rows, columns, and diagonals. If a player wins, a dialog is displayed with the winner's message. If the game ends in a tie, a tie message is displayed.

   - `document.querySelectorAll('button').forEach(...)` adds a click event listener to all buttons in the document. When a button is clicked, it calls the `clearBoard` function to reset the game board.



```javascript
// Initialize the current player as "X"
var player = "X";

// Function to clear the game board by resetting HTML content
const clearBoard = () => board.innerHTML = '<tr><td><td><td>'.repeat(3);

// Clear the board when the page loads
clearBoard();

// Event handler for clicks on the game board
board.onclick = (el, cell = el.target) => {
  // Check if the clicked element is a cell and is empty
  if (cell.tagName == 'TD' && cell.innerText == '') {
    // Set the cell text to the current player ("X" or "O")
    cell.innerText = player;
    cell.style.background = "silver";

    // Variables to store values of current row, column, and diagonals
    let vert = diaglr = diagrl = '';

    // Loop through rows to check for winning conditions
    for (let i = 0; i < 3; i++) {
      let row = board.rows[i].cells;
      vert += row[cell.cellIndex].textContent; // Vertical
      diaglr += row[i].textContent; // Diagonal from top-left to bottom-right
      diagrl += row[2 - i].textContent; // Diagonal from top-right to bottom-left
    }

    // Check if any of the winning conditions are met
    if ([cell.parentNode.textContent, vert, diaglr, diagrl].includes(player.repeat(3))) {
      // Display winner message in the dialog box
      winner.textContent = `Winner player "${player}" !`;
      dialog.showModal();
    } else {
      // If the board is full and there is no winner, display a tie message
      if (board.textContent.length == 9) {
        winner.textContent = "The game ends in a tie";
        dialog.showModal();
      }
    }
    
    // Switch players for the next turn
    player = player === 'X' ? 'O' : 'X';
  }
};

// Event listener for all buttons to start a new game
document.querySelectorAll('button').forEach(
  el => el.addEventListener('click', () =>
    clearBoard())
);
```

### Overall Summary:

This code creates a functional Tic-Tac-Toe game. Players can click on the cells to make their moves, and the game checks for win or draw conditions after each move. The game interface includes a "new Game" button to reset the board and a dialog box to display the game result messages. The styling is kept minimal, focusing on the game functionality.