Docfile commited on
Commit
44bedb5
·
verified ·
1 Parent(s): 0356fb2

Update templates/index.html

Browse files
Files changed (1) hide show
  1. templates/index.html +138 -386
templates/index.html CHANGED
@@ -4,439 +4,191 @@
4
  <meta charset="UTF-8">
5
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
6
  <title>Jeu d'Échecs</title>
 
7
  <script src="https://cdn.tailwindcss.com"></script>
8
  <style>
9
- .chess-board {
10
- display: grid;
11
- grid-template-columns: repeat(8, 1fr);
12
- grid-template-rows: repeat(8, 1fr);
13
- aspect-ratio: 1;
14
- max-width: 600px;
15
- margin: 0 auto;
16
- border: 4px solid #8B4513;
17
  }
18
-
19
- .chess-square {
20
- display: flex;
21
- align-items: center;
22
- justify-content: center;
23
- font-size: 2.5rem;
24
- cursor: pointer;
25
- transition: all 0.2s;
26
- user-select: none;
27
  }
28
-
29
- .chess-square.light {
30
- background-color: #F0D9B5;
31
- }
32
-
33
- .chess-square.dark {
34
- background-color: #B58863;
35
- }
36
-
37
- .chess-square.selected {
38
- background-color: #7fc97f !important;
39
- box-shadow: inset 0 0 0 3px #4CAF50;
40
- }
41
-
42
- .chess-square.legal-move {
43
- background-color: #90EE90 !important;
44
- }
45
-
46
- .chess-square:hover {
47
- opacity: 0.8;
48
- }
49
-
50
- .piece-white { color: white; text-shadow: 1px 1px 1px black; }
51
- .piece-black { color: black; text-shadow: 1px 1px 1px white; }
52
-
53
- .status-bar {
54
- background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
55
  }
56
  </style>
57
  </head>
58
- <body class="bg-gray-100 min-h-screen">
59
- <div class="container mx-auto px-4 py-8">
60
- <!-- Header -->
61
- <div class="text-center mb-8">
62
- <h1 class="text-4xl font-bold text-gray-800 mb-4">♔ Jeu d'Échecs ♛</h1>
63
- <div class="status-bar text-white px-6 py-4 rounded-lg shadow-lg">
64
- <div id="game-status" class="text-xl font-semibold">
65
- Choisissez un mode de jeu pour commencer
66
- </div>
67
- <div id="current-player" class="text-sm mt-1 opacity-90"></div>
68
- </div>
69
- </div>
70
 
71
- <!-- Game Controls -->
72
- <div class="flex flex-wrap justify-center gap-4 mb-8">
73
- <button id="btn-human-mode" class="px-6 py-3 bg-blue-600 hover:bg-blue-700 text-white rounded-lg font-semibold transition-colors shadow-lg">
74
- 🤝 Mode Humain vs Humain
75
  </button>
76
- <button id="btn-ai-mode" class="px-6 py-3 bg-purple-600 hover:bg-purple-700 text-white rounded-lg font-semibold transition-colors shadow-lg">
77
- 🤖 Mode vs IA
78
  </button>
79
- <button id="btn-reset" class="px-6 py-3 bg-green-600 hover:bg-green-700 text-white rounded-lg font-semibold transition-colors shadow-lg">
80
- 🔄 Nouvelle Partie
81
  </button>
82
  </div>
83
 
84
- <!-- Chess Board -->
85
- <div class="flex justify-center mb-8">
86
- <div class="bg-white p-6 rounded-xl shadow-2xl">
87
- <div id="chess-board" class="chess-board">
88
- <!-- Le plateau sera généré par JavaScript -->
89
- </div>
90
  </div>
91
- </div>
92
 
93
- <!-- Game Info -->
94
- <div class="grid md:grid-cols-2 gap-6 max-w-4xl mx-auto">
95
- <!-- Moves History -->
96
- <div class="bg-white rounded-lg shadow-lg p-6">
97
- <h3 class="text-xl font-bold text-gray-800 mb-4">📝 Historique des coups</h3>
98
- <div id="moves-history" class="max-h-60 overflow-y-auto text-sm">
99
- <p class="text-gray-500 italic">Aucun coup joué</p>
 
 
 
 
 
 
100
  </div>
101
- </div>
 
 
102
 
103
- <!-- Game Instructions -->
104
- <div class="bg-white rounded-lg shadow-lg p-6">
105
- <h3 class="text-xl font-bold text-gray-800 mb-4">ℹ️ Instructions</h3>
106
- <ul class="text-sm text-gray-600 space-y-2">
107
- <li><strong>Mode Humain:</strong> Deux joueurs alternent sur le même appareil</li>
108
- <li><strong>Mode IA:</strong> Jouez contre l'intelligence artificielle</li>
109
- <li><strong>Comment jouer:</strong> Cliquez sur une pièce puis sur la case de destination</li>
110
- <li><strong>Cases vertes:</strong> Coups légaux possibles</li>
111
- </ul>
112
- <div class="mt-4 text-xs text-gray-500">
113
- <p>🔴 Cases rouges = sélection | 🟢 Cases vertes = coups possibles</p>
114
- </div>
115
  </div>
116
  </div>
117
  </div>
118
 
119
  <script>
120
- class ChessGame {
121
- constructor() {
122
- this.gameState = null;
123
- this.selectedSquare = null;
124
- this.legalMoves = [];
125
- this.initializeBoard();
126
- this.setupEventListeners();
127
- }
128
-
129
- initializeBoard() {
130
- const board = document.getElementById('chess-board');
131
- board.innerHTML = '';
132
-
133
- for (let row = 0; row < 8; row++) {
134
- for (let col = 0; col < 8; col++) {
135
- const square = document.createElement('div');
136
- square.className = `chess-square ${(row + col) % 2 === 0 ? 'light' : 'dark'}`;
137
- square.dataset.square = this.getSquareName(row, col);
138
- square.addEventListener('click', (e) => this.handleSquareClick(e));
139
- board.appendChild(square);
140
- }
141
- }
142
- }
143
-
144
- getSquareName(row, col) {
145
- const files = 'abcdefgh';
146
- const ranks = '87654321';
147
- return files[col] + ranks[row];
148
- }
149
-
150
- getSquareFromName(squareName) {
151
- const files = 'abcdefgh';
152
- const ranks = '87654321';
153
- const col = files.indexOf(squareName[0]);
154
- const row = ranks.indexOf(squareName[1]);
155
- return { row, col };
156
- }
157
-
158
- pieceToUnicode(piece) {
159
- const pieces = {
160
- 'K': '♔', 'Q': '♕', 'R': '♖', 'B': '♗', 'N': '♘', 'P': '♙',
161
- 'k': '♚', 'q': '♛', 'r': '♜', 'b': '♝', 'n': '♞', 'p': '♟'
162
- };
163
- return pieces[piece] || '';
164
  }
 
165
 
166
- updateBoard() {
167
- if (!this.gameState) return;
168
-
169
- // Parse FEN pour obtenir la position des pièces
170
- const fenParts = this.gameState.fen.split(' ');
171
- const position = fenParts[0];
172
- const rows = position.split('/');
173
-
174
- const squares = document.querySelectorAll('.chess-square');
175
- squares.forEach(square => {
176
- square.textContent = '';
177
- square.className = square.className.replace(/piece-(white|black)/, '');
178
- });
179
-
180
- rows.forEach((row, rowIndex) => {
181
- let colIndex = 0;
182
- for (let char of row) {
183
- if (char >= '1' && char <= '8') {
184
- colIndex += parseInt(char);
185
- } else {
186
- const squareName = this.getSquareName(rowIndex, colIndex);
187
- const square = document.querySelector(`[data-square="${squareName}"]`);
188
- if (square) {
189
- square.textContent = this.pieceToUnicode(char);
190
- square.classList.add(char === char.toUpperCase() ? 'piece-white' : 'piece-black');
191
- }
192
- colIndex++;
193
- }
194
- }
195
- });
196
- }
197
-
198
- updateGameStatus() {
199
- const statusEl = document.getElementById('game-status');
200
- const playerEl = document.getElementById('current-player');
201
-
202
- if (!this.gameState) {
203
- statusEl.textContent = 'Choisissez un mode de jeu pour commencer';
204
- playerEl.textContent = '';
205
- return;
206
- }
207
-
208
- if (this.gameState.game_over) {
209
- if (this.gameState.winner === 'draw') {
210
- statusEl.textContent = '🤝 Match nul !';
211
- } else {
212
- const winner = this.gameState.winner === 'white' ? 'Blancs' : 'Noirs';
213
- statusEl.textContent = `🏆 ${winner} gagnent !`;
214
- }
215
- playerEl.textContent = 'Partie terminée';
216
- } else {
217
- const currentPlayer = this.gameState.current_player === 'white' ? 'Blancs' : 'Noirs';
218
- const modeText = this.gameState.mode === 'ai' ? 'vs IA' : 'Humain vs Humain';
219
- statusEl.textContent = `🎮 ${modeText}`;
220
- playerEl.textContent = `Au tour des ${currentPlayer}`;
221
- }
222
  }
223
 
224
- updateMovesHistory() {
225
- const historyEl = document.getElementById('moves-history');
226
-
227
- if (!this.gameState || this.gameState.moves_history.length === 0) {
228
- historyEl.innerHTML = '<p class="text-gray-500 italic">Aucun coup joué</p>';
229
- return;
230
- }
231
 
232
- let historyHtml = '<div class="grid grid-cols-2 gap-2 text-sm">';
233
- this.gameState.moves_history.forEach((move, index) => {
234
- const moveNumber = Math.floor(index / 2) + 1;
235
- const isWhite = index % 2 === 0;
236
-
237
- if (isWhite) {
238
- historyHtml += `<div class="font-semibold">${moveNumber}. ${move}</div>`;
239
- } else {
240
- historyHtml += `<div class="pl-4">${move}</div>`;
241
- }
242
  });
243
- historyHtml += '</div>';
244
- historyEl.innerHTML = historyHtml;
245
-
246
- // Scroll vers le bas
247
- historyEl.scrollTop = historyEl.scrollHeight;
248
- }
249
-
250
- async handleSquareClick(event) {
251
- const square = event.target;
252
- const squareName = square.dataset.square;
253
-
254
- if (!this.gameState || this.gameState.game_over) return;
255
-
256
- // Si aucune pièce n'est sélectionnée
257
- if (!this.selectedSquare) {
258
- if (square.textContent && this.canSelectPiece(square)) {
259
- this.selectSquare(square);
260
- }
261
- return;
262
- }
263
-
264
- // Si on clique sur la même case
265
- if (this.selectedSquare === square) {
266
- this.deselectSquare();
267
- return;
268
- }
269
-
270
- // Si on clique sur une autre pièce de la même couleur
271
- if (square.textContent && this.canSelectPiece(square)) {
272
- this.selectSquare(square);
273
- return;
274
- }
275
-
276
- // Tentative de coup
277
- const fromSquare = this.selectedSquare.dataset.square;
278
- const toSquare = squareName;
279
- const move = fromSquare + toSquare;
280
-
281
- await this.makeMove(move);
282
- }
283
-
284
- canSelectPiece(square) {
285
- if (!square.textContent) return false;
286
-
287
- const isWhitePiece = square.classList.contains('piece-white');
288
- const isCurrentPlayerWhite = this.gameState.current_player === 'white';
289
-
290
- return isWhitePiece === isCurrentPlayerWhite;
291
- }
292
-
293
- selectSquare(square) {
294
- this.deselectSquare();
295
- this.selectedSquare = square;
296
- square.classList.add('selected');
297
- this.highlightLegalMoves(square.dataset.square);
298
- }
299
-
300
- deselectSquare() {
301
- if (this.selectedSquare) {
302
- this.selectedSquare.classList.remove('selected');
303
- this.selectedSquare = null;
304
- }
305
- this.clearHighlights();
306
  }
 
307
 
308
- highlightLegalMoves(fromSquare) {
309
- this.clearHighlights();
310
-
311
- if (!this.gameState.legal_moves) return;
312
-
313
- const movesFromSquare = this.gameState.legal_moves.filter(move =>
314
- move.startsWith(fromSquare)
315
- );
316
-
317
- movesFromSquare.forEach(move => {
318
- const toSquare = move.substring(2, 4);
319
- const square = document.querySelector(`[data-square="${toSquare}"]`);
320
- if (square) {
321
- square.classList.add('legal-move');
322
- }
323
  });
 
 
 
 
 
 
324
  }
 
325
 
326
- clearHighlights() {
327
- document.querySelectorAll('.legal-move').forEach(square => {
328
- square.classList.remove('legal-move');
329
- });
330
  }
 
331
 
332
- async makeMove(move) {
333
- try {
334
- const response = await fetch('/api/make_move', {
335
- method: 'POST',
336
- headers: {
337
- 'Content-Type': 'application/json'
338
- },
339
- body: JSON.stringify({ move })
340
- });
341
-
342
- const data = await response.json();
343
-
344
- if (data.success) {
345
- this.gameState = data.game_state;
346
- this.updateDisplay();
347
- this.deselectSquare();
348
-
349
- // Si l'IA a joué un coup
350
- if (data.ai_move) {
351
- setTimeout(() => {
352
- console.log('IA a joué:', data.ai_move);
353
- }, 500);
354
- }
355
- } else {
356
- alert('Coup invalide: ' + data.error);
357
- }
358
- } catch (error) {
359
- console.error('Erreur lors du coup:', error);
360
- alert('Erreur de connexion');
361
- }
362
- }
363
 
364
- async startNewGame(mode) {
 
 
365
  try {
366
- const response = await fetch('/api/new_game', {
367
- method: 'POST',
368
- headers: {
369
- 'Content-Type': 'application/json'
370
- },
371
- body: JSON.stringify({ mode })
372
- });
373
-
374
  const data = await response.json();
375
-
376
- if (data.success) {
377
- this.gameState = data.game_state;
378
- this.updateDisplay();
379
- this.deselectSquare();
380
- } else {
381
- alert('Erreur lors de la création de la partie');
382
- }
383
  } catch (error) {
384
- console.error('Erreur:', error);
385
- alert('Erreur de connexion');
386
  }
387
- }
388
-
389
- async resetGame() {
390
- if (!this.gameState) return;
391
-
392
- try {
393
- const response = await fetch('/api/reset_game', {
394
- method: 'POST',
395
- headers: {
396
- 'Content-Type': 'application/json'
397
- }
398
- });
399
-
400
  const data = await response.json();
401
-
402
- if (data.success) {
403
- this.gameState = data.game_state;
404
- this.updateDisplay();
405
- this.deselectSquare();
406
  }
407
  } catch (error) {
408
- console.error('Erreur:', error);
409
- alert('Erreur de connexion');
410
  }
411
  }
412
-
413
- updateDisplay() {
414
- this.updateBoard();
415
- this.updateGameStatus();
416
- this.updateMovesHistory();
417
- }
418
-
419
- setupEventListeners() {
420
- document.getElementById('btn-human-mode').addEventListener('click', () => {
421
- this.startNewGame('human');
422
- });
423
-
424
- document.getElementById('btn-ai-mode').addEventListener('click', () => {
425
- this.startNewGame('ai');
426
- });
427
-
428
- document.getElementById('btn-reset').addEventListener('click', () => {
429
- if (confirm('Êtes-vous sûr de vouloir recommencer la partie ?')) {
430
- this.resetGame();
431
- }
432
- });
433
- }
434
  }
435
 
436
- // Initialiser le jeu quand la page est chargée
437
- document.addEventListener('DOMContentLoaded', () => {
438
- new ChessGame();
439
- });
440
  </script>
441
  </body>
442
  </html>
 
4
  <meta charset="UTF-8">
5
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
6
  <title>Jeu d'Échecs</title>
7
+ <!-- Tailwind CSS via CDN -->
8
  <script src="https://cdn.tailwindcss.com"></script>
9
  <style>
10
+ /* Pour une meilleure interaction avec le SVG */
11
+ .chess-board svg {
12
+ cursor: default; /* Ou 'pointer' sur les pièces si on gère les clics SVG */
 
 
 
 
 
13
  }
14
+ .square { /* Styles pour les cases si on n'utilise pas SVG pour le rendu cliquable */
15
+ width: 40px; height: 40px;
16
+ display: flex; align-items: center; justify-content: center;
17
+ border: 1px solid #ccc;
 
 
 
 
 
18
  }
19
+ .selected-square {
20
+ background-color: rgba(255, 255, 0, 0.5) !important;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
21
  }
22
  </style>
23
  </head>
24
+ <body class="bg-gray-100 flex flex-col items-center justify-center min-h-screen p-4">
25
+
26
+ <div class="bg-white p-6 rounded-lg shadow-xl w-full max-w-3xl">
27
+ <h1 class="text-3xl font-bold text-center text-gray-700 mb-6">Jeu d'Échecs</h1>
 
 
 
 
 
 
 
 
28
 
29
+ <div class="controls mb-4 flex flex-wrap gap-2 justify-center">
30
+ <button id="newGameHuman" class="bg-blue-500 hover:bg-blue-700 text-white font-bold py-2 px-4 rounded">
31
+ Nouvelle Partie (Humain vs Humain)
 
32
  </button>
33
+ <button id="newGameAIWhite" class="bg-green-500 hover:bg-green-700 text-white font-bold py-2 px-4 rounded">
34
+ Nouvelle Partie (Jouer Blancs vs IA)
35
  </button>
36
+ <button id="newGameAIBlack" class="bg-gray-700 hover:bg-gray-900 text-white font-bold py-2 px-4 rounded">
37
+ Nouvelle Partie (Jouer Noirs vs IA)
38
  </button>
39
  </div>
40
 
41
+ <div class="game-area flex flex-col md:flex-row gap-4 items-start">
42
+ <!-- Échiquier (rendu par chess.svg) -->
43
+ <div id="boardDisplay" class="chess-board mx-auto md:mx-0 border-2 border-gray-500" style="width: 350px; height: 350px;">
44
+ <!-- Le SVG de l'échiquier sera injecté ici -->
45
+ {{ initial_board_svg|safe if initial_board_svg else "Chargement de l'échiquier..." }}
 
46
  </div>
 
47
 
48
+ <!-- Informations et contrôles de la partie -->
49
+ <div class="info-panel flex-grow p-4 bg-gray-50 rounded-md shadow">
50
+ <h2 class="text-xl font-semibold mb-2">Informations</h2>
51
+ <p id="turnInfo" class="mb-1">Tour: Chargement...</p>
52
+ <p id="statusInfo" class="mb-3 font-medium">Statut: Chargement...</p>
53
+
54
+ <h3 class="text-lg font-semibold mb-1">Jouer un coup (ex: e2e4):</h3>
55
+ <div class="move-input flex gap-2 mb-3">
56
+ <input type="text" id="moveInput" placeholder="e.g., e2e4"
57
+ class="flex-grow p-2 border border-gray-300 rounded focus:outline-none focus:ring-2 focus:ring-blue-500">
58
+ <button id="submitMove" class="bg-indigo-500 hover:bg-indigo-700 text-white font-bold py-2 px-3 rounded">
59
+ Jouer
60
+ </button>
61
  </div>
62
+ <p class="text-xs text-gray-500 mb-3">
63
+ Alternative: cliquez sur la case de départ puis la case d'arrivée sur un échiquier interactif (non implémenté ici, utilisez l'input).
64
+ </p>
65
 
66
+ <h3 class="text-lg font-semibold mb-1">Derniers coups:</h3>
67
+ <p id="playerMoveInfo" class="text-sm"></p>
68
+ <p id="aiMoveInfo" class="text-sm"></p>
 
 
 
 
 
 
 
 
 
69
  </div>
70
  </div>
71
  </div>
72
 
73
  <script>
74
+ const boardDisplay = document.getElementById('boardDisplay');
75
+ const turnInfo = document.getElementById('turnInfo');
76
+ const statusInfo = document.getElementById('statusInfo');
77
+ const moveInput = document.getElementById('moveInput');
78
+ const playerMoveInfo = document.getElementById('playerMoveInfo');
79
+ const aiMoveInfo = document.getElementById('aiMoveInfo');
80
+
81
+ let currentFen = "{{ initial_fen }}"; // FEN initial passé par Flask
82
+ let selectedSquare = null; // Pour une interaction de clic sur le plateau (non implémenté visuellement ici)
83
+
84
+ async function updateBoard(data) {
85
+ if (data.error) {
86
+ statusInfo.textContent = `Erreur: ${data.error}`;
87
+ if (data.board_svg) boardDisplay.innerHTML = data.board_svg; // Mettre à jour même en cas d'erreur de coup
88
+ return;
89
+ }
90
+ currentFen = data.fen;
91
+ boardDisplay.innerHTML = data.board_svg; // chess.svg fournit le plateau
92
+ turnInfo.textContent = `Tour: ${data.turn}`;
93
+ statusInfo.textContent = `Statut: ${data.status}`;
94
+ moveInput.value = '';
95
+
96
+ playerMoveInfo.textContent = data.player_move_san ? `Votre coup: ${data.player_move_san}` : "";
97
+ aiMoveInfo.textContent = data.ai_move_san ? `Coup IA: ${data.ai_move_san}` : "";
98
+
99
+ if (data.game_over) {
100
+ moveInput.disabled = true;
101
+ document.getElementById('submitMove').disabled = true;
102
+ // On pourrait ajouter une alerte ou un modal
103
+ setTimeout(() => alert(`Partie terminée ! ${data.status}`), 100);
104
+ } else {
105
+ moveInput.disabled = false;
106
+ document.getElementById('submitMove').disabled = false;
 
 
 
 
 
 
 
 
 
 
 
107
  }
108
+ }
109
 
110
+ async function submitMove() {
111
+ const move = moveInput.value.trim().toLowerCase();
112
+ if (!move.match(/^[a-h][1-8][a-h][1-8]([qrbn])?$/)) { // Validation basique du format UCI
113
+ statusInfo.textContent = "Format de coup invalide (ex: e2e4, e7e8q).";
114
+ return;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
115
  }
116
 
117
+ playerMoveInfo.textContent = ""; // Clear previous move info
118
+ aiMoveInfo.textContent = "";
 
 
 
 
 
119
 
120
+ try {
121
+ const response = await fetch('/move', {
122
+ method: 'POST',
123
+ headers: { 'Content-Type': 'application/json' },
124
+ body: JSON.stringify({ move: move })
 
 
 
 
 
125
  });
126
+ const data = await response.json();
127
+ updateBoard(data);
128
+ } catch (error) {
129
+ console.error('Erreur lors de la soumission du coup:', error);
130
+ statusInfo.textContent = 'Erreur de communication avec le serveur.';
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
131
  }
132
+ }
133
 
134
+ async function startNewGame(mode, playerPlaysWhite = true) {
135
+ playerMoveInfo.textContent = "";
136
+ aiMoveInfo.textContent = "";
137
+ try {
138
+ const response = await fetch('/new_game', {
139
+ method: 'POST',
140
+ headers: { 'Content-Type': 'application/json' },
141
+ body: JSON.stringify({ mode: mode, player_color_white: playerPlaysWhite})
 
 
 
 
 
 
 
142
  });
143
+ const data = await response.json();
144
+ updateBoard(data);
145
+ statusInfo.textContent = `Nouvelle partie commencée. ${mode === 'ai' ? (playerPlaysWhite ? 'Vous jouez les Blancs.' : 'L\'IA joue les Blancs.') : 'Humain vs Humain.'}`;
146
+ } catch (error) {
147
+ console.error('Erreur lors du démarrage de la nouvelle partie:', error);
148
+ statusInfo.textContent = 'Erreur de communication avec le serveur.';
149
  }
150
+ }
151
 
152
+ document.getElementById('submitMove').addEventListener('click', submitMove);
153
+ moveInput.addEventListener('keypress', function(event) {
154
+ if (event.key === 'Enter') {
155
+ submitMove();
156
  }
157
+ });
158
 
159
+ document.getElementById('newGameHuman').addEventListener('click', () => startNewGame('human'));
160
+ document.getElementById('newGameAIWhite').addEventListener('click', () => startNewGame('ai', true));
161
+ document.getElementById('newGameAIBlack').addEventListener('click', () => startNewGame('ai', false));
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
162
 
163
+ // Initialiser l'état au chargement de la page (si une partie est en cours via session)
164
+ async function initializeBoardState() {
165
+ if (boardDisplay.innerHTML.includes("Chargement")) { // Si le SVG n'a pas été injecté par le serveur
166
  try {
167
+ const response = await fetch('/get_board_state');
 
 
 
 
 
 
 
168
  const data = await response.json();
169
+ updateBoard(data);
 
 
 
 
 
 
 
170
  } catch (error) {
171
+ console.error('Erreur de récupération de l\'état initial:', error);
172
+ statusInfo.textContent = 'Erreur de chargement de la partie.';
173
  }
174
+ } else { // Le SVG est déjà là, il faut juste mettre à jour les infos de statut
175
+ try {
176
+ const response = await fetch('/get_board_state'); // Récupérer le statut actuel
 
 
 
 
 
 
 
 
 
 
177
  const data = await response.json();
178
+ turnInfo.textContent = `Tour: ${data.turn}`;
179
+ statusInfo.textContent = `Statut: ${data.status}`;
180
+ if (data.game_over) {
181
+ moveInput.disabled = true;
182
+ document.getElementById('submitMove').disabled = true;
183
  }
184
  } catch (error) {
185
+ console.error('Erreur de récupération de l\'état initial (infos):', error);
 
186
  }
187
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
188
  }
189
 
190
+ window.onload = initializeBoardState;
191
+
 
 
192
  </script>
193
  </body>
194
  </html>