From b0c8148005d3713c7eaa24c0a52332ddeed738bc Mon Sep 17 00:00:00 2001 From: letuaillon Date: Tue, 25 Apr 2023 11:00:27 +0200 Subject: [PATCH] translate to html/css/js --- script.js | 200 +++++++++++++++++++++++++++++++++++++++++++++++ script1.js | 136 ++++++++++++++++++++++++++++++++ style.css | 48 ++++++++++++ style1.css | 50 ++++++++++++ tictactoe.html | 27 +++++++ tictactoeAI.html | 14 ++++ 6 files changed, 475 insertions(+) create mode 100644 script.js create mode 100644 script1.js create mode 100644 style.css create mode 100644 style1.css create mode 100644 tictactoe.html create mode 100644 tictactoeAI.html diff --git a/script.js b/script.js new file mode 100644 index 0000000..3ac75cf --- /dev/null +++ b/script.js @@ -0,0 +1,200 @@ +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, maximizing) { + const caseStatus = matrix.winner(); + + if (caseStatus === 1) return { value: 1, move: null }; + if (caseStatus === 2) return { value: -1, move: null }; + if (matrix.isFull()) return { value: 0, move: null }; + + let bestValue; + let bestMove = null; + const emptyCases = matrix.getEmptyCases(); + + if (maximizing) { + bestValue = -Infinity; + + for (const [row, col] of emptyCases) { + const tempMatrix = matrix.clone(); + tempMatrix.markCase(row, col, 1); + + const { value } = this.minimax(tempMatrix, false); + + if (value > bestValue) { + bestValue = value; + bestMove = [row, col]; + } + } + } else { + bestValue = Infinity; + + for (const [row, col] of emptyCases) { + const tempMatrix = matrix.clone(); + tempMatrix.markCase(row, col, this.player); + + const { value } = this.minimax(tempMatrix, true); + + if (value < bestValue) { + bestValue = value; + bestMove = [row, col]; + } + } + } + + return { value: bestValue, move: bestMove }; + } + + evaluate(mainMatrix) { + if (this.level === 0) { + const emptyCases = mainMatrix.getEmptyCases(); + const randomIndex = Math.floor(Math.random() * emptyCases.length); + return emptyCases[randomIndex]; + } else { + const { move } = this.minimax(mainMatrix, false); + return move; + } + } + + + move(matrix) { + if (this.level === 0) { + return this.random_move(matrix); + } else { + return this.evaluate(matrix); + } + } +} + +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 gameBoard = document.getElementById('game-board'); + gameBoard.innerHTML = ''; + + this.matrix.cases.forEach((row, rowIndex) => { + const rowElement = document.createElement('div'); + rowElement.classList.add('row'); + + row.forEach((cell, cellIndex) => { + const cellElement = document.createElement('div'); + cellElement.classList.add('cell'); + cellElement.dataset.mark = cell; + cellElement.addEventListener('click', () => this.handleCellClick(rowIndex, cellIndex)); + rowElement.appendChild(cellElement); + }); + + gameBoard.appendChild(rowElement); + }); + } + + handleCellClick(row, col) { + if (this.running && this.matrix.mark(row, col, this.player)) { + if (this.matrix.check_win(this.player)) { + alert(`Le joueur ${this.player} a gagné !`); + this.running = false; + } else if (this.matrix.is_full()) { + alert("Match nul !"); + 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)) { + alert(`L'IA a gagné !`); + this.running = false; + } else if (this.matrix.is_full()) { + alert("Match nul !"); + this.running = false; + } + } + this.player = 3 - this.player; + } + } + this.updateBoard(); + } + } + + 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 game = new Game(); +game.start(); + diff --git a/script1.js b/script1.js new file mode 100644 index 0000000..1339d6c --- /dev/null +++ b/script1.js @@ -0,0 +1,136 @@ +const cells = document.querySelectorAll('.cell'); +const resetButton = document.querySelector('#reset'); +const aiButton = document.querySelector('#toggle-ai'); + +let board = Array.from({ length: 9 }, () => 0); +let currentPlayer = 1; +let aiEnabled = true; +let gameMode = 'ai'; +let running = true; + +function handleClick(e) { + const cell = e.target; + const index = cells.findIndex(c => c === cell); + + if (board[index] !== 0 || !running) { + return; + } + + makeMove(index); + + if (checkWinner(board) !== 0 || board.every(cell => cell !== 0)) { + running = false; + } + + if (running && gameMode === 'ai' && currentPlayer === 2) { + const { move } = minimax(board, false); + makeMove(move); + + if (checkWinner(board) !== 0 || board.every(cell => cell !== 0)) { + running = false; + } + } +} + +function makeMove(index) { + board[index] = currentPlayer; + cells[index].textContent = currentPlayer === 1 ? 'X' : 'O'; + currentPlayer = 3 - currentPlayer; +} + +function isRunning() { + return !checkWinner(board) && board.some(cell => cell === 0); +} + +function checkWinner(tempBoard) { + const winningCombinations = [ + [0, 1, 2], + [3, 4, 5], + [6, 7, 8], + [0, 3, 6], + [1, 4, 7], + [2, 5, 8], + [0, 4, 8], + [2, 4, 6], + ]; + + for (const combination of winningCombinations) { + const [a, b, c] = combination; + if (tempBoard[a] !== 0 && tempBoard[a] === tempBoard[b] && tempBoard[a] === tempBoard[c]) { + return tempBoard[a]; + } + } + + return 0; +} + +function checkGameOver() { + const winner = checkWinner(board); + if (winner !== 0) { + alert(`Le joueur ${winner} a gagné !`); + } else if (!isRunning()) { + alert('Match nul !'); + } +} + +function resetBoard() { + board = Array.from({ length: 9 }, () => 0); + currentPlayer = 1; + running = true; + cells.forEach(cell => (cell.textContent = '')); +} + +function toggleAi() { + aiEnabled = !aiEnabled; + gameMode = aiEnabled ? 'ai' : '1v1'; +} + +function minimax(tempBoard, maximizing) { + const winner = checkWinner(tempBoard); + + if (winner !== 0) { + return { eval: winner === 1 ? 1 : -1, move: null }; + } else if (!tempBoard.some(cell => cell === 0)) { + return { eval: 0, move: null }; + } + + let bestEval, bestMove; + + if (maximizing) { + bestEval = -Infinity; + + for (let i = 0; i < tempBoard.length; i++) { + if (tempBoard[i] === 0) { + const newBoard = [...tempBoard]; + newBoard[i] = 1; + + const eval = minimax(newBoard, false).eval; + if (eval > bestEval) { + bestEval = eval; + bestMove = i; + } + } + } + } else { + bestEval = Infinity; + + for (let i = 0; i < tempBoard.length; i++) { + if (tempBoard[i] === 0) { + const newBoard = [...tempBoard]; + newBoard[i] = 2; + + const eval = minimax(newBoard, true).eval; + if (eval < bestEval) { + bestEval = eval; + bestMove = i; + } + } + } + } + + return { eval: bestEval, move: bestMove }; +} + +cells.forEach(cell => cell.addEventListener('click', handleClick)); +resetButton.addEventListener('click', resetBoard); +aiButton.addEventListener('click', toggleAi); diff --git a/style.css b/style.css new file mode 100644 index 0000000..4ccf8d6 --- /dev/null +++ b/style.css @@ -0,0 +1,48 @@ +body { + font-family: Arial, sans-serif; + display: flex; + flex-direction: column; + align-items: center; + background-color: #f0f0f0; +} + +h1 { + margin-bottom: 1rem; +} + +#game-board { + display: flex; + flex-direction: column; + width: 300px; + height: 300px; + background-color: white; + border: 1px solid black; +} + +.row { + display: flex; + flex-direction: row; + height: 33.33%; +} + +.cell { + display: flex; + justify-content: center; + align-items: center; + width: 33.33%; + height: 100%; + border: 1px solid black; + cursor: pointer; +} + +.cell[data-mark="1"]::before { + content: "X"; + font-size: 2rem; + color: #2196F3; +} + +.cell[data-mark="2"]::before { + content: "O"; + font-size: 2rem; + color: #F44336; +} diff --git a/style1.css b/style1.css new file mode 100644 index 0000000..3962ed1 --- /dev/null +++ b/style1.css @@ -0,0 +1,50 @@ +body { + display: flex; + justify-content: center; + align-items: center; + height: 100vh; + margin: 0; + background-color: #1E2125; + font-family: "Arial", sans-serif; +} + +.container { + display: flex; + flex-direction: column; + align-items: center; +} + +.grid { + display: grid; + grid-template-columns: repeat(3, 100px); + grid-template-rows: repeat(3, 100px); + gap: 15px; + margin-bottom: 25px; +} + +.cell { + width: 100px; + height: 100px; + display: flex; + justify-content: center; + align-items: center; + background-color: #2C3036; + color: #FFFFFF; + font-size: 24px; + font-weight: bold; + cursor: pointer; +} + +button { + padding: 10px 20px; + background-color: #1E2125; + color: #FFFFFF; + border: 2px solid #FFFFFF; + font-size: 16px; + cursor: pointer; + margin: 5px; +} + +button:hover { + background-color: #2C3036; +} diff --git a/tictactoe.html b/tictactoe.html new file mode 100644 index 0000000..1eb890d --- /dev/null +++ b/tictactoe.html @@ -0,0 +1,27 @@ + + + + + + Tic Tac Toe - IA + + + +
+
+
+
+
+
+
+
+
+
+
+
+ + +
+ + + diff --git a/tictactoeAI.html b/tictactoeAI.html new file mode 100644 index 0000000..99dfded --- /dev/null +++ b/tictactoeAI.html @@ -0,0 +1,14 @@ + + + + + + Jeu de Morpion + + + +

Jeu de Morpion

+
+ + +