You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

201 lines
5.9 KiB

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();