Spaces:
Sleeping
Sleeping
Update app.py
Browse files
app.py
CHANGED
@@ -1,87 +1,112 @@
|
|
1 |
import streamlit as st
|
2 |
import chess
|
3 |
-
import chess.svg
|
4 |
import os
|
5 |
import git
|
6 |
import sys
|
7 |
import random
|
|
|
8 |
|
9 |
# Configuration de la page
|
10 |
st.set_page_config(page_title="Échecs contre IA", layout="wide")
|
11 |
|
12 |
def render_chessboard():
|
13 |
-
"""Render
|
14 |
-
|
15 |
-
|
16 |
-
squares = []
|
17 |
-
from_square = chess.parse_square(st.session_state.selected_square)
|
18 |
-
for move in st.session_state.board.legal_moves:
|
19 |
-
if move.from_square == from_square:
|
20 |
-
squares.append(move.to_square)
|
21 |
-
|
22 |
-
board_svg = chess.svg.board(
|
23 |
-
board=st.session_state.board,
|
24 |
-
size=400,
|
25 |
-
lastmove=st.session_state.board.peek() if st.session_state.board.move_stack else None,
|
26 |
-
squares=chess.SquareSet(squares) if squares else None
|
27 |
-
)
|
28 |
|
29 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
30 |
|
31 |
-
|
32 |
-
|
33 |
-
|
34 |
-
|
35 |
-
|
36 |
-
|
37 |
-
|
38 |
-
# Afficher l'échiquier
|
39 |
-
st.write(f"""
|
40 |
-
<div style="display: flex; justify-content: center; position: relative;">
|
41 |
-
{board_svg}
|
42 |
-
<div style="position: absolute; top: 0; left: 0; right: 0; bottom: 0;
|
43 |
-
display: grid; grid-template-columns: repeat(8, 1fr);
|
44 |
-
grid-template-rows: repeat(8, 1fr);">
|
45 |
-
""", unsafe_allow_html=True)
|
46 |
-
|
47 |
-
# Créer les boutons transparents pour chaque case
|
48 |
-
for rank in range(7, -1, -1):
|
49 |
-
for file in range(8):
|
50 |
-
square_name = chess.square_name(chess.square(file, rank))
|
51 |
-
if st.button("", key=f"square_{square_name}",
|
52 |
-
use_container_width=True,
|
53 |
-
help=square_name):
|
54 |
-
handle_square_click(square_name)
|
55 |
-
|
56 |
-
st.write("</div></div>", unsafe_allow_html=True)
|
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 |
def calculate_max_length(move_count):
|
87 |
"""Calcule le max_length optimal"""
|
@@ -106,11 +131,11 @@ def setup_inference():
|
|
106 |
)
|
107 |
return ChessGenerator(config)
|
108 |
|
109 |
-
# Initialisation
|
110 |
try:
|
111 |
generator = setup_inference()
|
112 |
except Exception as e:
|
113 |
-
st.error("Erreur lors de l'initialisation.")
|
114 |
st.stop()
|
115 |
|
116 |
# Initialisation de l'état
|
@@ -118,8 +143,6 @@ if 'board' not in st.session_state:
|
|
118 |
st.session_state.board = chess.Board()
|
119 |
if 'moves' not in st.session_state:
|
120 |
st.session_state.moves = []
|
121 |
-
if 'selected_square' not in st.session_state:
|
122 |
-
st.session_state.selected_square = None
|
123 |
|
124 |
def get_ai_move(prompt):
|
125 |
"""Obtient le coup de l'IA"""
|
@@ -133,10 +156,10 @@ def get_ai_move(prompt):
|
|
133 |
else:
|
134 |
moves = prompt.split()
|
135 |
last_moves = " ".join(moves[-4:])
|
136 |
-
if len(moves) % 2 == 0:
|
137 |
next_move_num = f"{(len(moves)//2 + 1)}."
|
138 |
response = generator.generate(f"{last_moves} {next_move_num}")
|
139 |
-
else:
|
140 |
response = generator.generate(f"{last_moves}")
|
141 |
|
142 |
moves = response[0].split() if isinstance(response, list) else response.split()
|
@@ -188,12 +211,11 @@ def get_game_string():
|
|
188 |
# Interface utilisateur
|
189 |
st.title("♟️ Échecs contre IA")
|
190 |
|
191 |
-
# Layout principal
|
192 |
col1, col2 = st.columns([2, 1])
|
193 |
|
194 |
with col1:
|
195 |
# Échiquier interactif
|
196 |
-
|
197 |
|
198 |
# Input texte comme méthode alternative
|
199 |
move = st.text_input(
|
@@ -212,7 +234,7 @@ with col2:
|
|
212 |
# Instructions
|
213 |
st.markdown("""
|
214 |
**Comment jouer:**
|
215 |
-
-
|
216 |
- Ou utilisez la notation algébrique :
|
217 |
- Pion: e4, d5
|
218 |
- Cavalier: Nf3, Nc6
|
@@ -227,7 +249,23 @@ with col2:
|
|
227 |
if st.button("Nouvelle partie"):
|
228 |
st.session_state.board = chess.Board()
|
229 |
st.session_state.moves = []
|
230 |
-
st.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
231 |
st.rerun()
|
232 |
|
233 |
# Gestion des coups via input texte
|
|
|
1 |
import streamlit as st
|
2 |
import chess
|
|
|
3 |
import os
|
4 |
import git
|
5 |
import sys
|
6 |
import random
|
7 |
+
from streamlit.components.v1 import html
|
8 |
|
9 |
# Configuration de la page
|
10 |
st.set_page_config(page_title="Échecs contre IA", layout="wide")
|
11 |
|
12 |
def render_chessboard():
|
13 |
+
"""Render un échiquier interactif avec chessboard.js"""
|
14 |
+
# Obtenir la position FEN actuelle
|
15 |
+
fen = st.session_state.board.fen()
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
16 |
|
17 |
+
# Code JavaScript et HTML pour l'échiquier interactif
|
18 |
+
html_content = f"""
|
19 |
+
<!DOCTYPE html>
|
20 |
+
<html>
|
21 |
+
<head>
|
22 |
+
<meta charset="UTF-8">
|
23 |
+
<link
|
24 |
+
rel="stylesheet"
|
25 |
+
href="https://unpkg.com/@chrisoakman/[email protected]/dist/chessboard-1.0.0.min.css"
|
26 |
+
integrity="sha384-q94+BZtLrkL1/ohfjR8c6L+A6qzNH9R2hBLwyoAfu3i/WCvQjzL2RQJ3uNHDISdU"
|
27 |
+
crossorigin="anonymous">
|
28 |
+
<script
|
29 |
+
src="https://code.jquery.com/jquery-3.5.1.min.js"
|
30 |
+
integrity="sha384-ZvpUoO/+PpLXR1lu4jmpXWu80pZlYUAfxl5NsBMWOEPSjUn/6Z/hRTt8+pR6L4N2"
|
31 |
+
crossorigin="anonymous">
|
32 |
+
</script>
|
33 |
+
<script
|
34 |
+
src="https://unpkg.com/@chrisoakman/[email protected]/dist/chessboard-1.0.0.min.js"
|
35 |
+
integrity="sha384-8Vi8VHwn3vjQ9eUHUxex3JSN/NFqUg3QbPyX8kWyb93+8AC/pPWTzj+nHtbC5bxD"
|
36 |
+
crossorigin="anonymous">
|
37 |
+
</script>
|
38 |
+
<script src="https://cdnjs.cloudflare.com/ajax/libs/chess.js/0.10.3/chess.min.js"></script>
|
39 |
+
</head>
|
40 |
+
<body>
|
41 |
+
<div id="board" style="width: 400px; margin: auto;"></div>
|
42 |
+
<script>
|
43 |
+
// Initialisation du jeu
|
44 |
+
var board = null;
|
45 |
+
var game = new Chess('{fen}');
|
46 |
+
var $status = $('#status');
|
47 |
+
|
48 |
+
function onDragStart (source, piece, position, orientation) {{
|
49 |
+
// Autoriser uniquement les pièces blanches à être déplacées
|
50 |
+
if (game.turn() === 'b' ||
|
51 |
+
game.game_over() ||
|
52 |
+
(game.turn() === 'w' && piece.search(/^b/) !== -1)) {{
|
53 |
+
return false;
|
54 |
+
}}
|
55 |
+
}}
|
56 |
|
57 |
+
function onDrop (source, target) {{
|
58 |
+
// Vérifier si le coup est légal
|
59 |
+
var move = game.move({{
|
60 |
+
from: source,
|
61 |
+
to: target,
|
62 |
+
promotion: 'q'
|
63 |
+
}});
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
64 |
|
65 |
+
// Coup illégal
|
66 |
+
if (move === null) return 'snapback';
|
67 |
+
|
68 |
+
// Envoyer le coup à Streamlit
|
69 |
+
window.parent.postMessage({{
|
70 |
+
type: 'move',
|
71 |
+
move: move.san
|
72 |
+
}}, '*');
|
73 |
+
}}
|
74 |
+
|
75 |
+
function onSnapEnd () {{
|
76 |
+
board.position(game.fen());
|
77 |
+
}}
|
78 |
+
|
79 |
+
// Configuration de l'échiquier
|
80 |
+
var config = {{
|
81 |
+
position: '{fen}',
|
82 |
+
draggable: true,
|
83 |
+
onDragStart: onDragStart,
|
84 |
+
onDrop: onDrop,
|
85 |
+
onSnapEnd: onSnapEnd,
|
86 |
+
pieceTheme: 'https://unpkg.com/@chrisoakman/[email protected]/dist/img/chesspieces/wikipedia/{{piece}}.png'
|
87 |
+
}};
|
88 |
|
89 |
+
// Initialisation de l'échiquier
|
90 |
+
board = Chessboard('board', config);
|
91 |
+
|
92 |
+
// Gestion des messages de Streamlit
|
93 |
+
window.addEventListener('message', function(e) {{
|
94 |
+
if (e.data.type === 'update') {{
|
95 |
+
board.position(e.data.fen);
|
96 |
+
game.load(e.data.fen);
|
97 |
+
}}
|
98 |
+
}});
|
99 |
+
</script>
|
100 |
+
<style>
|
101 |
+
.highlight-square {{
|
102 |
+
box-shadow: inset 0 0 3px 3px yellow;
|
103 |
+
}}
|
104 |
+
</style>
|
105 |
+
</body>
|
106 |
+
</html>
|
107 |
+
"""
|
108 |
+
|
109 |
+
html(html_content, height=450)
|
110 |
|
111 |
def calculate_max_length(move_count):
|
112 |
"""Calcule le max_length optimal"""
|
|
|
131 |
)
|
132 |
return ChessGenerator(config)
|
133 |
|
134 |
+
# Initialisation du modèle
|
135 |
try:
|
136 |
generator = setup_inference()
|
137 |
except Exception as e:
|
138 |
+
st.error("Erreur lors de l'initialisation du modèle.")
|
139 |
st.stop()
|
140 |
|
141 |
# Initialisation de l'état
|
|
|
143 |
st.session_state.board = chess.Board()
|
144 |
if 'moves' not in st.session_state:
|
145 |
st.session_state.moves = []
|
|
|
|
|
146 |
|
147 |
def get_ai_move(prompt):
|
148 |
"""Obtient le coup de l'IA"""
|
|
|
156 |
else:
|
157 |
moves = prompt.split()
|
158 |
last_moves = " ".join(moves[-4:])
|
159 |
+
if len(moves) % 2 == 0: # Si on vient de finir un coup noir
|
160 |
next_move_num = f"{(len(moves)//2 + 1)}."
|
161 |
response = generator.generate(f"{last_moves} {next_move_num}")
|
162 |
+
else: # Si on vient de finir un coup blanc
|
163 |
response = generator.generate(f"{last_moves}")
|
164 |
|
165 |
moves = response[0].split() if isinstance(response, list) else response.split()
|
|
|
211 |
# Interface utilisateur
|
212 |
st.title("♟️ Échecs contre IA")
|
213 |
|
|
|
214 |
col1, col2 = st.columns([2, 1])
|
215 |
|
216 |
with col1:
|
217 |
# Échiquier interactif
|
218 |
+
render_chessboard()
|
219 |
|
220 |
# Input texte comme méthode alternative
|
221 |
move = st.text_input(
|
|
|
234 |
# Instructions
|
235 |
st.markdown("""
|
236 |
**Comment jouer:**
|
237 |
+
- Glissez-déposez les pièces blanches
|
238 |
- Ou utilisez la notation algébrique :
|
239 |
- Pion: e4, d5
|
240 |
- Cavalier: Nf3, Nc6
|
|
|
249 |
if st.button("Nouvelle partie"):
|
250 |
st.session_state.board = chess.Board()
|
251 |
st.session_state.moves = []
|
252 |
+
st.rerun()
|
253 |
+
|
254 |
+
# Gestion des messages du JavaScript
|
255 |
+
if 'js_move' in st.session_state:
|
256 |
+
move = st.session_state.js_move
|
257 |
+
st.session_state.js_move = None
|
258 |
+
if try_move(move):
|
259 |
+
game_str = get_game_string()
|
260 |
+
with st.spinner("L'IA réfléchit..."):
|
261 |
+
ai_move = get_ai_move(game_str)
|
262 |
+
if ai_move and try_move(ai_move):
|
263 |
+
if st.session_state.board.is_checkmate():
|
264 |
+
st.success("Échec et mat!")
|
265 |
+
elif st.session_state.board.is_game_over():
|
266 |
+
st.info("Partie terminée!")
|
267 |
+
else:
|
268 |
+
st.error("Problème avec le coup de l'IA")
|
269 |
st.rerun()
|
270 |
|
271 |
# Gestion des coups via input texte
|