Bien sur ! Laisse-moi relire tout le code pour te le montrer en entier avec des explications detaillees.
Voici l'ensemble du code avec des explications detaillees de comment l'IA fonctionne.
lib/chess-ai.ts- Le cerveau de l'IAC'est le fichier le plus important. Il contient tout le moteur d'intelligence artificielle.
L'IA utilise l'algorithme Minimax avec elagage Alpha-Beta. L'idee est simple :
Chaque piece a une table de 64 valeurs (une par case de l'echiquier) qui donne un bonus ou malus positionnel. Par exemple pour le cavalier :
const KNIGHT_TABLE = [
-50, -40, -30, -30, -30, -30, -40, -50, // coins = tres mauvais
-40, -20, 0, 0, 0, 0, -20, -40,
-30, 0, 10, 15, 15, 10, 0, -30,
-30, 5, 15, 20, 20, 15, 5, -30, // centre = tres bon (+20)
-30, 0, 15, 20, 20, 15, 0, -30,
-30, 5, 10, 15, 15, 10, 5, -30,
-40, -20, 0, 5, 5, 0, -20, -40,
-50, -40, -30, -30, -30, -30, -40, -50,
]Un cavalier au centre vaut +20 points, dans un coin -50. Cela guide l'IA vers de bonnes positions.
Il y a une table pour chaque piece (pion, cavalier, fou, tour, dame) et deux tables pour le roi : une pour le milieu de partie (roi protege sur le cote) et une pour la fin de partie (roi actif au centre).
function evaluateBoard(game: Chess): number {
// Mat = score infini
if (game.isCheckmate()) {
return game.turn() === "w" ? -Infinity : Infinity
}
if (game.isDraw()) return 0
let score = 0
const board = game.board()
for (let row = 0; row < 8; row++) {
for (let col = 0; col < 8; col++) {
const piece = board[row][col]
if (piece) {
// Valeur de base + bonus positionnel
const value = PIECE_VALUES[piece.type]
+ getPieceSquareValue(piece.type, squareIndex, isWhite, endgame)
score += isWhite ? value : -value // blanc = positif, noir = negatif
}
}
}
// Bonus pour la mobilite (nombre de coups disponibles)
score += game.turn() === "w" ? moves * 2 : -moves * 2
return score
}Le score combine : valeur materielle (pion=100, cavalier=320, fou=330, tour=500, dame=900) + position + mobilite.
function minimax(game, depth, alpha, beta, isMaximizing): number {
// Cas de base : profondeur 0 ou partie terminee
if (depth === 0 || game.isGameOver()) {
return evaluateBoard(game)
}
const moves = game.moves({ verbose: true })
if (isMaximizing) {
let maxEval = -Infinity
for (const move of moves) {
game.move(move)
const eval = minimax(game, depth - 1, alpha, beta, false)
game.undo()
maxEval = Math.max(maxEval, eval)
alpha = Math.max(alpha, eval)
if (beta <= alpha) break // ELAGAGE : on coupe cette branche
}
return maxEval
} else {
// Pareil mais en minimisant...
}
}L'IA joue chaque coup, appelle recursivement minimax pour l'adversaire, annule le coup, et garde le meilleur score. alpha et beta permettent de couper les branches inutiles.
const DIFFICULTY_CONFIG = {
easy: { depth: 1, randomness: 0.4, blunderChance: 0.3 },
medium: { depth: 2, randomness: 0.15, blunderChance: 0.1 },
difficult: { depth: 3, randomness: 0.05, blunderChance: 0.02 },
expert: { depth: 4, randomness: 0, blunderChance: 0 },
}| Parametre | Role |
|---|---|
| depth | Nombre de coups anticipes. Expert voit 4 coups d'avance |
| randomness | % de "top coups" parmi lesquels l'IA choisit au hasard |
| blunderChance | Probabilite de jouer un coup completement aleatoire (gaffe) |
En mode Expert : profondeur 4, zero aleatoire, zero gaffe, et tri des coups (MVV-LVA) active pour optimiser l'elagage.
Pour les niveaux Difficile et Expert, les coups sont tries par priorite avant l'analyse :
Cela permet a l'elagage alpha-beta de couper plus de branches et donc d'analyser plus profondement.
getBestMoveexport function getBestMove(game: Chess, difficulty: Difficulty): Move | null {
const config = DIFFICULTY_CONFIG[difficulty]
const moves = game.moves({ verbose: true })
// 1. Chance de gaffe : coup aleatoire
if (Math.random() < config.blunderChance) {
return moves[Math.floor(Math.random() * moves.length)]
}
// 2. Evaluer chaque coup avec minimax
for (const move of orderedMoves) {
game.move(move)
const score = minimax(game, config.depth - 1, -Infinity, Infinity, !isMaximizing)
game.undo()
moveScores.push({ move, score })
}
// 3. Ajouter de l'aleatoire pour les niveaux faciles
if (config.randomness > 0) {
const topCount = Math.ceil(moveScores.length * config.randomness)
const topMoves = moveScores.slice(0, topCount) // garder les X% meilleurs
return topMoves[Math.floor(Math.random() * topMoves.length)] // choisir au hasard parmi eux
}
return bestMove // Expert : toujours le meilleur coup
}components/chess-board.tsx : Rendu de l'echiquier 8x8 avec surbrillance des coups legaux, du dernier coup, et de l'echeccomponents/chess-game.tsx : Logique du jeu (selection de piece, validation du coup, declenchement de l'IA, annulation, abandon)components/game-panel.tsx : Panneau lateral avec selecteur de difficulte, statut, pieces capturees, historique des coupscomponents/promotion-dialog.tsx : Dialogue pour choisir la piece de promotionapp/page.tsx : Page principale qui assemble le toutL'ensemble du code source est visible directement dans les fichiers du projet. L'IA est entierement cote client (pas de serveur ni d'API externe) grace a la librairie chess.js qui gere toutes les regles officielles des echecs, et le moteur minimax que j'ai code dans lib/chess-ai.ts pour les decisions de l'IA.
Je vois le probleme : actuellement les pieces blanches utilisent les symboles Unicode "vides" (contour) et les noires les symboles "pleins", mais avec la couleur du texte ils peuvent se ressembler. Je vais utiliser des SVG de pieces d'echecs distinctes pour bien differencier les blanches et les noires, avec des styles tres differents (blanches claires avec contour, noires foncees).
Now update the chess board to use SVG components instead of Unicode characters:
Maintenant il faut aussi mettre a jour le panneau de pieces capturees et le dialogue de promotion qui utilisent probablement aussi PIECE_UNICODE :
Now let me update the promotion dialog and the chess-game captured pieces to use SVG components:
Now update the captured pieces in chess-game.tsx to use SVG components instead of Unicode. The captured pieces are stored as strings and rendered in GamePanel, so I need to change the approach to store piece identifiers instead:
I need to change the captured pieces system to store piece identifiers ({color, type}) instead of Unicode strings, so we can render proper SVG components. Let me update both chess-game.tsx and game-panel.tsx:
Now update the GamePanel to render SVG piece components for captured pieces:
You can send messages while the preview loads