File size: 9,522 Bytes
7bc796e
8dc0e70
7bc796e
 
 
8dc0e70
44bedb5
8a91eec
8dc0e70
44bedb5
 
 
8dc0e70
44bedb5
 
 
 
8a91eec
44bedb5
 
8dc0e70
 
7bc796e
44bedb5
 
 
 
34d1909
44bedb5
 
 
34d1909
44bedb5
 
34d1909
44bedb5
 
34d1909
 
 
44bedb5
 
 
 
 
8dc0e70
34d1909
44bedb5
 
 
 
 
 
 
 
 
 
 
 
 
8a91eec
44bedb5
 
 
34d1909
44bedb5
 
 
7bc796e
 
9f671a2
7bc796e
8dc0e70
44bedb5
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
8a91eec
44bedb5
34d1909
44bedb5
 
 
 
 
8a91eec
34d1909
44bedb5
 
34d1909
44bedb5
 
 
 
 
8a91eec
44bedb5
 
 
 
 
8a91eec
44bedb5
34d1909
44bedb5
 
 
 
 
 
 
 
34d1909
44bedb5
 
 
 
 
 
8a91eec
44bedb5
34d1909
44bedb5
 
 
 
34d1909
44bedb5
34d1909
44bedb5
 
 
34d1909
44bedb5
 
 
34d1909
44bedb5
34d1909
44bedb5
34d1909
44bedb5
 
34d1909
44bedb5
 
 
34d1909
44bedb5
 
 
 
 
34d1909
 
44bedb5
34d1909
8a91eec
8dc0e70
34d1909
44bedb5
 
8dc0e70
7bc796e
8dc0e70
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
<!DOCTYPE html>
<html lang="fr">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Jeu d'Échecs</title>
    <!-- Tailwind CSS via CDN -->
    <script src="https://cdn.tailwindcss.com"></script>
    <style>
        /* Pour une meilleure interaction avec le SVG */
        .chess-board svg {
            cursor: default; /* Ou 'pointer' sur les pièces si on gère les clics SVG */
        }
        .square { /* Styles pour les cases si on n'utilise pas SVG pour le rendu cliquable */
            width: 40px; height: 40px;
            display: flex; align-items: center; justify-content: center;
            border: 1px solid #ccc;
        }
        .selected-square {
            background-color: rgba(255, 255, 0, 0.5) !important;
        }
    </style>
</head>
<body class="bg-gray-100 flex flex-col items-center justify-center min-h-screen p-4">

    <div class="bg-white p-6 rounded-lg shadow-xl w-full max-w-3xl">
        <h1 class="text-3xl font-bold text-center text-gray-700 mb-6">Jeu d'Échecs</h1>

        <div class="controls mb-4 flex flex-wrap gap-2 justify-center">
            <button id="newGameHuman" class="bg-blue-500 hover:bg-blue-700 text-white font-bold py-2 px-4 rounded">
                Nouvelle Partie (Humain vs Humain)
            </button>
            <button id="newGameAIWhite" class="bg-green-500 hover:bg-green-700 text-white font-bold py-2 px-4 rounded">
                Nouvelle Partie (Jouer Blancs vs IA)
            </button>
            <button id="newGameAIBlack" class="bg-gray-700 hover:bg-gray-900 text-white font-bold py-2 px-4 rounded">
                Nouvelle Partie (Jouer Noirs vs IA)
            </button>
        </div>

        <div class="game-area flex flex-col md:flex-row gap-4 items-start">
            <!-- Échiquier (rendu par chess.svg) -->
            <div id="boardDisplay" class="chess-board mx-auto md:mx-0 border-2 border-gray-500" style="width: 350px; height: 350px;">
                <!-- Le SVG de l'échiquier sera injecté ici -->
                {{ initial_board_svg|safe if initial_board_svg else "Chargement de l'échiquier..." }}
            </div>

            <!-- Informations et contrôles de la partie -->
            <div class="info-panel flex-grow p-4 bg-gray-50 rounded-md shadow">
                <h2 class="text-xl font-semibold mb-2">Informations</h2>
                <p id="turnInfo" class="mb-1">Tour: Chargement...</p>
                <p id="statusInfo" class="mb-3 font-medium">Statut: Chargement...</p>

                <h3 class="text-lg font-semibold mb-1">Jouer un coup (ex: e2e4):</h3>
                <div class="move-input flex gap-2 mb-3">
                    <input type="text" id="moveInput" placeholder="e.g., e2e4"
                           class="flex-grow p-2 border border-gray-300 rounded focus:outline-none focus:ring-2 focus:ring-blue-500">
                    <button id="submitMove" class="bg-indigo-500 hover:bg-indigo-700 text-white font-bold py-2 px-3 rounded">
                        Jouer
                    </button>
                </div>
                <p class="text-xs text-gray-500 mb-3">
                    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).
                </p>

                <h3 class="text-lg font-semibold mb-1">Derniers coups:</h3>
                <p id="playerMoveInfo" class="text-sm"></p>
                <p id="aiMoveInfo" class="text-sm"></p>
            </div>
        </div>
    </div>

    <script>
        const boardDisplay = document.getElementById('boardDisplay');
        const turnInfo = document.getElementById('turnInfo');
        const statusInfo = document.getElementById('statusInfo');
        const moveInput = document.getElementById('moveInput');
        const playerMoveInfo = document.getElementById('playerMoveInfo');
        const aiMoveInfo = document.getElementById('aiMoveInfo');

        let currentFen = "{{ initial_fen }}"; // FEN initial passé par Flask
        let selectedSquare = null; // Pour une interaction de clic sur le plateau (non implémenté visuellement ici)

        async function updateBoard(data) {
            if (data.error) {
                statusInfo.textContent = `Erreur: ${data.error}`;
                if (data.board_svg) boardDisplay.innerHTML = data.board_svg; // Mettre à jour même en cas d'erreur de coup
                return;
            }
            currentFen = data.fen;
            boardDisplay.innerHTML = data.board_svg; // chess.svg fournit le plateau
            turnInfo.textContent = `Tour: ${data.turn}`;
            statusInfo.textContent = `Statut: ${data.status}`;
            moveInput.value = '';

            playerMoveInfo.textContent = data.player_move_san ? `Votre coup: ${data.player_move_san}` : "";
            aiMoveInfo.textContent = data.ai_move_san ? `Coup IA: ${data.ai_move_san}` : "";

            if (data.game_over) {
                moveInput.disabled = true;
                document.getElementById('submitMove').disabled = true;
                // On pourrait ajouter une alerte ou un modal
                setTimeout(() => alert(`Partie terminée ! ${data.status}`), 100);
            } else {
                moveInput.disabled = false;
                document.getElementById('submitMove').disabled = false;
            }
        }

        async function submitMove() {
            const move = moveInput.value.trim().toLowerCase();
            if (!move.match(/^[a-h][1-8][a-h][1-8]([qrbn])?$/)) { // Validation basique du format UCI
                statusInfo.textContent = "Format de coup invalide (ex: e2e4, e7e8q).";
                return;
            }

            playerMoveInfo.textContent = ""; // Clear previous move info
            aiMoveInfo.textContent = "";

            try {
                const response = await fetch('/move', {
                    method: 'POST',
                    headers: { 'Content-Type': 'application/json' },
                    body: JSON.stringify({ move: move })
                });
                const data = await response.json();
                updateBoard(data);
            } catch (error) {
                console.error('Erreur lors de la soumission du coup:', error);
                statusInfo.textContent = 'Erreur de communication avec le serveur.';
            }
        }

        async function startNewGame(mode, playerPlaysWhite = true) {
            playerMoveInfo.textContent = "";
            aiMoveInfo.textContent = "";
            try {
                const response = await fetch('/new_game', {
                    method: 'POST',
                    headers: { 'Content-Type': 'application/json' },
                    body: JSON.stringify({ mode: mode, player_color_white: playerPlaysWhite})
                });
                const data = await response.json();
                updateBoard(data);
                statusInfo.textContent = `Nouvelle partie commencée. ${mode === 'ai' ? (playerPlaysWhite ? 'Vous jouez les Blancs.' : 'L\'IA joue les Blancs.') : 'Humain vs Humain.'}`;
            } catch (error) {
                console.error('Erreur lors du démarrage de la nouvelle partie:', error);
                statusInfo.textContent = 'Erreur de communication avec le serveur.';
            }
        }

        document.getElementById('submitMove').addEventListener('click', submitMove);
        moveInput.addEventListener('keypress', function(event) {
            if (event.key === 'Enter') {
                submitMove();
            }
        });

        document.getElementById('newGameHuman').addEventListener('click', () => startNewGame('human'));
        document.getElementById('newGameAIWhite').addEventListener('click', () => startNewGame('ai', true));
        document.getElementById('newGameAIBlack').addEventListener('click', () => startNewGame('ai', false));

        // Initialiser l'état au chargement de la page (si une partie est en cours via session)
        async function initializeBoardState() {
            if (boardDisplay.innerHTML.includes("Chargement")) { // Si le SVG n'a pas été injecté par le serveur
                try {
                    const response = await fetch('/get_board_state');
                    const data = await response.json();
                    updateBoard(data);
                } catch (error) {
                    console.error('Erreur de récupération de l\'état initial:', error);
                    statusInfo.textContent = 'Erreur de chargement de la partie.';
                }
            } else { // Le SVG est déjà là, il faut juste mettre à jour les infos de statut
                 try {
                    const response = await fetch('/get_board_state'); // Récupérer le statut actuel
                    const data = await response.json();
                    turnInfo.textContent = `Tour: ${data.turn}`;
                    statusInfo.textContent = `Statut: ${data.status}`;
                    if (data.game_over) {
                        moveInput.disabled = true;
                        document.getElementById('submitMove').disabled = true;
                    }
                } catch (error) {
                     console.error('Erreur de récupération de l\'état initial (infos):', error);
                }
            }
        }

        window.onload = initializeBoardState;

    </script>
</body>
</html>