index.html

5.65 KB
21/03/2025 14:01
HTML
<!DOCTYPE html>
<html lang="en">

<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Tic Tac Toe vs AI</title>
  <style>
    .board {
      display: grid;
      grid-template-columns: repeat(3, 100px);
      gap: 5px;
      width: 310px;
      margin: 20px auto;
    }

    .cell {
      width: 100px;
      height: 100px;
      background: #f0f0f0;
      display: flex;
      align-items: center;
      justify-content: center;
      font-size: 40px;
      cursor: pointer;
      user-select: none;
    }

    .cell:hover {
      background: #e0e0e0;
    }

    .message {
      text-align: center;
      font-size: 24px;
      margin: 20px;
    }

    button {
      display: block;
      margin: 10px auto;
      padding: 10px 20px;
      font-size: 16px;
    }
  </style>
</head>

<body>
  <div class="message" id="message">Your turn (X)</div>
  <div class="board" id="board"></div>
  <button id="reset">Reset Game</button>

  <script>
    // Game Module: จัดการตรรกะของเกมและ AI
    const Game = {
      board: Array(9).fill(null),
      humanPlayer: 'X',
      aiPlayer: 'O',
      gameOver: false,

      init: function() {
        this.board = Array(9).fill(null);
        this.gameOver = false;
      },

      makeMove: function(index, player) {
        if (!this.gameOver && !this.board[index]) {
          this.board[index] = player;
          if (this.checkWin()) {
            this.gameOver = true;
            return `${player} wins!`;
          }
          if (this.board.every(cell => cell)) {
            this.gameOver = true;
            return "It's a tie!";
          }
          return null;
        }
        return null;
      },

      checkWin: function() {
        const winPatterns = [
          [0, 1, 2], [3, 4, 5], [6, 7, 8], // Rows
          [0, 3, 6], [1, 4, 7], [2, 5, 8], // Columns
          [0, 4, 8], [2, 4, 6]             // Diagonals
        ];
        return winPatterns.some(pattern => {
          const [a, b, c] = pattern;
          return this.board[a] && this.board[a] === this.board[b] && this.board[a] === this.board[c];
        });
      },

      getEmptyCells: function() {
        return this.board.reduce((acc, val, idx) => {
          if (!val) acc.push(idx);
          return acc;
        }, []);
      },

      minimax: function(depth, isMaximizing) {
        if (this.checkWin()) {
          return isMaximizing ? -10 + depth : 10 - depth;
        }
        if (this.board.every(cell => cell)) {
          return 0;
        }

        if (isMaximizing) {
          let bestScore = -Infinity;
          const emptyCells = this.getEmptyCells();
          for (let i of emptyCells) {
            this.board[i] = this.aiPlayer;
            const score = this.minimax(depth + 1, false);
            this.board[i] = null;
            bestScore = Math.max(score, bestScore);
          }
          return bestScore;
        } else {
          let bestScore = Infinity;
          const emptyCells = this.getEmptyCells();
          for (let i of emptyCells) {
            this.board[i] = this.humanPlayer;
            const score = this.minimax(depth + 1, true);
            this.board[i] = null;
            bestScore = Math.min(score, bestScore);
          }
          return bestScore;
        }
      },

      aiMove: function() {
        let bestScore = -Infinity;
        let bestMove;
        const emptyCells = this.getEmptyCells();

        for (let i of emptyCells) {
          this.board[i] = this.aiPlayer;
          const score = this.minimax(0, false);
          this.board[i] = null;
          if (score > bestScore) {
            bestScore = score;
            bestMove = i;
          }
        }
        return this.makeMove(bestMove, this.aiPlayer);
      }
    };

    // UI Module: จัดการการแสดงผลและการโต้ตอบ
    const UI = {
      boardElement: document.getElementById('board'),
      messageElement: document.getElementById('message'),
      resetButton: document.getElementById('reset'),

      init: function() {
        this.renderBoard();
        this.addEventListeners();
      },

      renderBoard: function() {
        this.boardElement.innerHTML = '';
        Game.board.forEach((value, index) => {
          const cell = document.createElement('div');
          cell.className = 'cell';
          cell.textContent = value || '';
          cell.dataset.index = index;
          this.boardElement.appendChild(cell);
        });
      },

      updateMessage: function(message) {
        this.messageElement.textContent = message;
      },

      addEventListeners: function() {
        this.boardElement.addEventListener('click', (e) => {
          const index = e.target.dataset.index;
          if (index !== undefined && !Game.gameOver) {
            const humanResult = Game.makeMove(index, Game.humanPlayer);
            if (humanResult) {
              this.renderBoard();
              this.updateMessage(humanResult);
            } else if (!Game.gameOver) {
              this.renderBoard();
              this.updateMessage("AI's turn (O)");
              setTimeout(() => {
                const aiResult = Game.aiMove();
                this.renderBoard();
                this.updateMessage(aiResult || "Your turn (X)");
              }, 500); // Delay เพื่อให้ดูเป็นธรรมชาติ
            }
          }
        });
        this.resetButton.addEventListener('click', () => {
          Game.init();
          this.renderBoard();
          this.updateMessage("Your turn (X)");
        });
      }
    };

    // Initialize the game
    Game.init();
    UI.init();
  </script>
</body>

</html>