class Matrix { constructor() { this.cases = Array(3).fill(null).map(() => Array(3).fill(0)); this.marked_case = 0; } is_full() { return this.marked_case === 9; } mark(row, col, player) { if (this.cases[row][col] === 0) { this.cases[row][col] = player; this.marked_case++; return true; } return false; } check_win(player) { const win_combinations = [ [[0, 0], [0, 1], [0, 2]], [[1, 0], [1, 1], [1, 2]], [[2, 0], [2, 1], [2, 2]], [[0, 0], [1, 0], [2, 0]], [[0, 1], [1, 1], [2, 1]], [[0, 2], [1, 2], [2, 2]], [[0, 0], [1, 1], [2, 2]], [[0, 2], [1, 1], [2, 0]], ]; return win_combinations.some(combination => combination.every(([row, col]) => this.cases[row][col] === player) ); } } class AI { constructor(level = 5, player = 2) { this.level = level; this.player = player; } random_move(matrix) { const available_moves = []; matrix.cases.forEach((row, i) => { row.forEach((cell, j) => { if (cell === 0) { available_moves.push([i, j]); } }); }); if (available_moves.length === 0) { return null; } const random_index = Math.floor(Math.random() * available_moves.length); return available_moves[random_index]; } minimax(matrix, depth, maximizingPlayer) { const winner = this.check_winner(matrix); if (winner !== 0) { return winner === this.player ? 10 - depth : depth - 10; } if (matrix.is_full()) { return 0; } if (depth >= this.level) { return 0; } const opponent = 3 - this.player; const currentPlayer = maximizingPlayer ? this.player : opponent; let bestScore = maximizingPlayer ? -Infinity : Infinity; for (let row = 0; row < 3; row++) { for (let col = 0; col < 3; col++) { if (matrix.cases[row][col] === 0) { matrix.mark(row, col, currentPlayer); const score = this.minimax(matrix, depth + 1, !maximizingPlayer); matrix.cases[row][col] = 0; matrix.marked_case--; bestScore = maximizingPlayer ? Math.max(bestScore, score) : Math.min(bestScore, score); } } } return bestScore; } check_winner(matrix) { for (let player = 1; player <= 2; player++) { if (matrix.check_win(player)) { return player; } } return 0; } move(matrix) { let bestScore = -Infinity; let bestMove = null; for (let row = 0; row < 3; row++) { for (let col = 0; col < 3; col++) { if (matrix.cases[row][col] === 0) { matrix.mark(row, col, this.player); const score = this.minimax(matrix, 1, false); matrix.cases[row][col] = 0; matrix.marked_case--; if (score > bestScore) { bestScore = score; bestMove = [row, col]; } } } } return bestMove; } } class Game { constructor() { this.matrix = new Matrix(); this.ai = new AI(); this.player = 1; this.gamemode = 'ai'; this.running = true; this.ai_starts = false; } updateBoard() { const cells = document.querySelectorAll('.cell'); this.matrix.cases.forEach((row, rowIndex) => { row.forEach((cell, cellIndex) => { const cellElement = cells[rowIndex * 3 + cellIndex]; cellElement.classList.remove('x', 'o'); if (cell === 1) { cellElement.classList.add('x'); } else if (cell === 2) { cellElement.classList.add('o'); } }); }); } displayMessage(messageId) { const messages = ['p1win', 'p2win', 'aiwin', 'draw']; messages.forEach((id) => { const element = document.getElementById(id); if (id === messageId) { element.style.display = 'block'; } else { element.style.display = 'none'; } }); } handleCellClick(row, col) { if (this.running && this.matrix.mark(row, col, this.player)) { if (this.matrix.check_win(this.player)) { this.displayMessage(this.player === 1 ? 'p1win' : 'p2win'); this.running = false; } else if (this.matrix.is_full()) { this.displayMessage('draw'); this.running = false; } else { this.player = 3 - this.player; if (this.gamemode === 'ai' && this.player === this.ai.player) { const [ai_row, ai_col] = this.ai.move(this.matrix); if (ai_row !== null && ai_col !== null) { this.matrix.mark(ai_row, ai_col, this.ai.player); if (this.matrix.check_win(this.ai.player)) { this.displayMessage('aiwin'); this.running = false; } else if (this.matrix.is_full()) { this.displayMessage('draw'); this.running = false; } } this.player = 3 - this.player; } } this.updateBoard(); } } setupEventListeners() { const cells = document.querySelectorAll('[data-cell]'); cells.forEach((cell, index) => { const row = Math.floor(index / 3); const col = index % 3; cell.addEventListener('click', () => this.handleCellClick(row, col)); }); } start() { this.running = true; this.matrix = new Matrix(); if (this.gamemode === 'ai' && this.ai_starts) { const [ai_row, ai_col] = this.ai.move(this.matrix); this.matrix.mark(ai_row, ai_col, this.ai.player); this.player = 3 - this.player; } this.updateBoard(); const messages = ['p1win', 'p2win', 'aiwin', 'draw']; messages.forEach((id) => { document.getElementById(id).style.display = 'none'; }); } } const cellElements = document.querySelectorAll('[data-cell]'); cellElements.forEach((cell, index) => { cell.addEventListener('click', () => { const row = Math.floor(index / 3); const col = index % 3; game.handleCellClick(row, col); }); }); const game = new Game(); game.start(); const resetButton = document.getElementById('reset'); resetButton.addEventListener('click', () => game.start()); const aiButton = document.getElementById('ai'); aiButton.addEventListener('click', () => { game.gamemode = game.gamemode === 'ai' ? 'player' : 'ai'; game.start(); });