Zual commited on
Commit
c7b5e31
·
verified ·
1 Parent(s): 7678641

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +193 -62
app.py CHANGED
@@ -5,33 +5,144 @@ 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_board():
13
- """Rendre l'échiquier en SVG avec mise en évidence des coups légaux"""
14
- # Déterminer les cases à mettre en évidence
15
- squares = None
16
- last_move = None
17
-
18
- if st.session_state.board.move_stack:
19
- last_move = st.session_state.board.peek()
20
-
21
- # Créer le SVG
22
  board_svg = chess.svg.board(
23
  board=st.session_state.board,
24
  size=400,
25
- lastmove=last_move,
26
- check=st.session_state.board.king(st.session_state.board.turn) if st.session_state.board.is_check() else None
27
  )
28
 
29
- # On utilise unsafe_allow_html=True car on sait que le SVG est sûr (généré par python-chess)
30
- st.write(board_svg, unsafe_allow_html=True)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
31
 
32
- # Setup du modèle
33
  @st.cache_resource
34
  def setup_inference():
 
35
  if not os.path.exists('chess'):
36
  git.Repo.clone_from('https://github.com/l-pommeret/chess.git', 'chess')
37
  if 'chess' not in sys.path:
@@ -45,25 +156,12 @@ def setup_inference():
45
  )
46
  return ChessGenerator(config)
47
 
48
- # Initialisation
49
- try:
50
- generator = setup_inference()
51
- except Exception as e:
52
- st.error(f"Erreur lors de l'initialisation: {str(e)}")
53
- st.stop()
54
-
55
- # Initialisation de l'état
56
- if 'board' not in st.session_state:
57
- st.session_state.board = chess.Board()
58
- if 'moves' not in st.session_state:
59
- st.session_state.moves = []
60
-
61
- def calculate_max_length(move_count):
62
- """Calcule le max_length optimal"""
63
- base_length = 10
64
- increment = 1
65
- max_length = 100
66
- return min(base_length + (move_count * increment), max_length)
67
 
68
  def get_ai_move(prompt):
69
  """Obtient le coup de l'IA"""
@@ -76,18 +174,20 @@ def get_ai_move(prompt):
76
  response = generator.generate("1.")
77
  else:
78
  moves = prompt.split()
79
- last_moves = " ".join(moves[-4:])
80
- if len(moves) % 2 == 0:
 
81
  next_move_num = f"{(len(moves)//2 + 1)}."
82
  response = generator.generate(f"{last_moves} {next_move_num}")
83
- else:
84
  response = generator.generate(f"{last_moves}")
85
 
86
  moves = response[0].split() if isinstance(response, list) else response.split()
87
  next_move = moves[-1]
88
  if '.' in next_move and len(moves) > 1:
89
  next_move = moves[-2]
90
-
 
91
  try:
92
  move = st.session_state.board.parse_san(next_move)
93
  if move in st.session_state.board.legal_moves:
@@ -95,17 +195,18 @@ def get_ai_move(prompt):
95
  except ValueError:
96
  pass
97
 
98
- # En cas d'échec, jouer un coup légal aléatoire
99
  legal_moves = list(st.session_state.board.legal_moves)
100
  if legal_moves:
101
  random_move = random.choice(legal_moves)
102
  return st.session_state.board.san(random_move)
 
103
  except Exception as e:
104
- st.error(f"Erreur lors de la génération du coup de l'IA: {str(e)}")
105
  return None
106
 
107
  def try_move(move_str):
108
- """Applique un coup au plateau"""
109
  try:
110
  clean_move = move_str.split('.')[-1].strip()
111
  move = st.session_state.board.parse_san(clean_move)
@@ -119,7 +220,7 @@ def try_move(move_str):
119
  return False
120
 
121
  def get_game_string():
122
- """Renvoie la notation de la partie"""
123
  result = []
124
  for i in range(0, len(st.session_state.moves), 2):
125
  move_num = i//2 + 1
@@ -128,11 +229,23 @@ def get_game_string():
128
  result.append(st.session_state.moves[i+1])
129
  return " ".join(result)
130
 
131
- def display_legal_moves():
132
- """Affiche les coups légaux possibles"""
133
- legal_moves = [st.session_state.board.san(move) for move in st.session_state.board.legal_moves]
134
- st.text("Coups légaux possibles:")
135
- st.code(", ".join(legal_moves))
 
 
 
 
 
 
 
 
 
 
 
 
136
 
137
  # Interface utilisateur
138
  st.title("♟️ Échecs contre IA")
@@ -140,22 +253,18 @@ st.title("♟️ Échecs contre IA")
140
  col1, col2 = st.columns([2, 1])
141
 
142
  with col1:
143
- # Échiquier
144
  render_board()
145
 
146
- # Input du coup
147
  move = st.text_input(
148
- "Votre coup",
149
  key=f"move_input_{len(st.session_state.moves)}",
150
  placeholder="ex: e4, Nf3, O-O"
151
  )
152
-
153
- # Afficher les coups légaux si demandé
154
- if st.checkbox("Afficher les coups possibles"):
155
- display_legal_moves()
156
 
157
  with col2:
158
- # Historique et état de la partie
159
  st.subheader("Partie en cours")
160
  game_str = get_game_string()
161
  if game_str:
@@ -164,13 +273,15 @@ with col2:
164
  # Instructions
165
  st.markdown("""
166
  **Comment jouer:**
167
- - Pion: e4, d5
168
- - Cavalier: Nf3, Nc6
169
- - Fou: Bc4, Be7
170
- - Tour: Ra1, Rd8
171
- - Dame: Qd1, Qh4
172
- - Roi: Ke2, Kg8
173
- - Roque: O-O ou O-O-O
 
 
174
  """)
175
 
176
  # Nouvelle partie
@@ -179,7 +290,27 @@ with col2:
179
  st.session_state.moves = []
180
  st.rerun()
181
 
182
- # Logique du jeu
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
183
  if move:
184
  if try_move(move):
185
  game_str = get_game_string()
 
5
  import git
6
  import sys
7
  import random
8
+ from streamlit.components.v1 import html
9
 
10
  # Configuration de la page
11
  st.set_page_config(page_title="Échecs contre IA", layout="wide")
12
 
13
  def render_board():
14
+ """Rendre l'échiquier interactif"""
15
+ # Générer le SVG de l'échiquier
 
 
 
 
 
 
 
16
  board_svg = chess.svg.board(
17
  board=st.session_state.board,
18
  size=400,
19
+ lastmove=st.session_state.board.peek() if st.session_state.board.move_stack else None,
 
20
  )
21
 
22
+ # Code HTML/JS pour rendre l'échiquier interactif
23
+ html_content = f"""
24
+ <style>
25
+ #chess-board {{
26
+ user-select: none;
27
+ position: relative;
28
+ width: 400px;
29
+ margin: auto;
30
+ }}
31
+ .dragging {{
32
+ opacity: 0.8;
33
+ cursor: grabbing !important;
34
+ }}
35
+ .piece {{
36
+ cursor: grab;
37
+ }}
38
+ .square {{
39
+ cursor: pointer;
40
+ }}
41
+ .highlight {{
42
+ fill: yellow;
43
+ opacity: 0.5;
44
+ }}
45
+ .last-move {{
46
+ fill: #aaf;
47
+ opacity: 0.5;
48
+ }}
49
+ </style>
50
+
51
+ <div id="chess-board">
52
+ {board_svg}
53
+ </div>
54
+
55
+ <script>
56
+ (function() {{
57
+ const board = document.querySelector('#chess-board');
58
+ let draggedPiece = null;
59
+ let startSquare = null;
60
+ let isDragging = false;
61
+ let dragStartX = 0;
62
+ let dragStartY = 0;
63
+ let originalTransform = null;
64
+
65
+ // Convertir les coordonnées en notation algébrique
66
+ function getSquareFromCoords(x, y) {{
67
+ const boardRect = board.getBoundingClientRect();
68
+ const squareSize = boardRect.width / 8;
69
+ const file = Math.floor((x - boardRect.left) / squareSize);
70
+ const rank = 7 - Math.floor((y - boardRect.top) / squareSize);
71
+ if (file >= 0 && file < 8 && rank >= 0 && rank < 8) {{
72
+ return String.fromCharCode(97 + file) + (rank + 1);
73
+ }}
74
+ return null;
75
+ }}
76
+
77
+ // Déplacer la pièce
78
+ function movePiece(piece, x, y) {{
79
+ const deltaX = x - dragStartX;
80
+ const deltaY = y - dragStartY;
81
+ piece.style.transform = `translate(${{deltaX}}px, ${{deltaY}}px)`;
82
+ }}
83
+
84
+ // Début du glissement
85
+ board.addEventListener('mousedown', function(e) {{
86
+ const piece = e.target.closest('.piece');
87
+ if (piece && piece.classList.contains('white')) {{
88
+ isDragging = true;
89
+ draggedPiece = piece;
90
+ dragStartX = e.clientX;
91
+ dragStartY = e.clientY;
92
+ startSquare = getSquareFromCoords(e.clientX, e.clientY);
93
+ originalTransform = window.getComputedStyle(piece).transform;
94
+
95
+ piece.classList.add('dragging');
96
+ e.preventDefault();
97
+ }}
98
+ }});
99
+
100
+ // Glissement
101
+ document.addEventListener('mousemove', function(e) {{
102
+ if (isDragging && draggedPiece) {{
103
+ movePiece(draggedPiece, e.clientX, e.clientY);
104
+ }}
105
+ }});
106
+
107
+ // Fin du glissement
108
+ document.addEventListener('mouseup', function(e) {{
109
+ if (isDragging && draggedPiece) {{
110
+ const endSquare = getSquareFromCoords(e.clientX, e.clientY);
111
+
112
+ // Réinitialiser la position de la pièce
113
+ draggedPiece.style.transform = originalTransform;
114
+ draggedPiece.classList.remove('dragging');
115
+
116
+ // Envoyer le coup si valide
117
+ if (startSquare && endSquare && startSquare !== endSquare) {{
118
+ window.parent.postMessage({{
119
+ type: 'chess_move',
120
+ from: startSquare,
121
+ to: endSquare
122
+ }}, '*');
123
+ }}
124
+
125
+ isDragging = false;
126
+ draggedPiece = null;
127
+ startSquare = null;
128
+ }}
129
+ }});
130
+ }})();
131
+ </script>
132
+ """
133
+
134
+ html(html_content, height=450)
135
+
136
+ def calculate_max_length(move_count):
137
+ """Calcule le max_length optimal"""
138
+ base_length = 10
139
+ increment = 1
140
+ max_length = 100
141
+ return min(base_length + (move_count * increment), max_length)
142
 
 
143
  @st.cache_resource
144
  def setup_inference():
145
+ """Initialise le modèle d'IA"""
146
  if not os.path.exists('chess'):
147
  git.Repo.clone_from('https://github.com/l-pommeret/chess.git', 'chess')
148
  if 'chess' not in sys.path:
 
156
  )
157
  return ChessGenerator(config)
158
 
159
+ def initialize_state():
160
+ """Initialise ou réinitialise l'état du jeu"""
161
+ if 'board' not in st.session_state:
162
+ st.session_state.board = chess.Board()
163
+ if 'moves' not in st.session_state:
164
+ st.session_state.moves = []
 
 
 
 
 
 
 
 
 
 
 
 
 
165
 
166
  def get_ai_move(prompt):
167
  """Obtient le coup de l'IA"""
 
174
  response = generator.generate("1.")
175
  else:
176
  moves = prompt.split()
177
+ last_moves = " ".join(moves[-4:]) # Garder seulement les 2 derniers coups
178
+
179
+ if len(moves) % 2 == 0: # Tour des blancs
180
  next_move_num = f"{(len(moves)//2 + 1)}."
181
  response = generator.generate(f"{last_moves} {next_move_num}")
182
+ else: # Tour des noirs
183
  response = generator.generate(f"{last_moves}")
184
 
185
  moves = response[0].split() if isinstance(response, list) else response.split()
186
  next_move = moves[-1]
187
  if '.' in next_move and len(moves) > 1:
188
  next_move = moves[-2]
189
+
190
+ # Vérifier si le coup est légal
191
  try:
192
  move = st.session_state.board.parse_san(next_move)
193
  if move in st.session_state.board.legal_moves:
 
195
  except ValueError:
196
  pass
197
 
198
+ # Si le coup n'est pas légal, jouer un coup aléatoire
199
  legal_moves = list(st.session_state.board.legal_moves)
200
  if legal_moves:
201
  random_move = random.choice(legal_moves)
202
  return st.session_state.board.san(random_move)
203
+
204
  except Exception as e:
205
+ st.error(f"Erreur lors de la génération du coup: {str(e)}")
206
  return None
207
 
208
  def try_move(move_str):
209
+ """Tente d'appliquer un coup"""
210
  try:
211
  clean_move = move_str.split('.')[-1].strip()
212
  move = st.session_state.board.parse_san(clean_move)
 
220
  return False
221
 
222
  def get_game_string():
223
+ """Obtient la notation de la partie"""
224
  result = []
225
  for i in range(0, len(st.session_state.moves), 2):
226
  move_num = i//2 + 1
 
229
  result.append(st.session_state.moves[i+1])
230
  return " ".join(result)
231
 
232
+ def handle_move(move_from, move_to):
233
+ """Gère un coup joué via l'interface graphique"""
234
+ move = chess.Move.from_uci(f"{move_from}{move_to}")
235
+ if move in st.session_state.board.legal_moves:
236
+ san_move = st.session_state.board.san(move)
237
+ if try_move(san_move):
238
+ return True
239
+ return False
240
+
241
+ # Initialisation
242
+ try:
243
+ generator = setup_inference()
244
+ except Exception as e:
245
+ st.error(f"Erreur d'initialisation: {str(e)}")
246
+ st.stop()
247
+
248
+ initialize_state()
249
 
250
  # Interface utilisateur
251
  st.title("♟️ Échecs contre IA")
 
253
  col1, col2 = st.columns([2, 1])
254
 
255
  with col1:
256
+ # Échiquier interactif
257
  render_board()
258
 
259
+ # Input texte alternatif
260
  move = st.text_input(
261
+ "Ou saisissez votre coup ici",
262
  key=f"move_input_{len(st.session_state.moves)}",
263
  placeholder="ex: e4, Nf3, O-O"
264
  )
 
 
 
 
265
 
266
  with col2:
267
+ # Informations de la partie
268
  st.subheader("Partie en cours")
269
  game_str = get_game_string()
270
  if game_str:
 
273
  # Instructions
274
  st.markdown("""
275
  **Comment jouer:**
276
+ - Glissez et déposez les pièces blanches
277
+ - Ou utilisez la notation algébrique :
278
+ - Pion: e4, d5
279
+ - Cavalier: Nf3, Nc6
280
+ - Fou: Bc4, Be7
281
+ - Tour: Ra1, Rd8
282
+ - Dame: Qd1, Qh4
283
+ - Roi: Ke2, Kg8
284
+ - Roque: O-O ou O-O-O
285
  """)
286
 
287
  # Nouvelle partie
 
290
  st.session_state.moves = []
291
  st.rerun()
292
 
293
+ # Gestion des coups (glisser-déposer et texte)
294
+ if st.session_state.get("chess_move"):
295
+ move_data = st.session_state.chess_move
296
+ st.session_state.chess_move = None
297
+ if handle_move(move_data["from"], move_data["to"]):
298
+ game_str = get_game_string()
299
+ # Tour de l'IA
300
+ with st.spinner("L'IA réfléchit..."):
301
+ ai_move = get_ai_move(game_str)
302
+ if ai_move and try_move(ai_move):
303
+ if st.session_state.board.is_checkmate():
304
+ st.success("Échec et mat!")
305
+ elif st.session_state.board.is_game_over():
306
+ st.info("Partie terminée!")
307
+ else:
308
+ st.error("Problème avec le coup de l'IA")
309
+ st.rerun()
310
+ else:
311
+ st.error("Coup invalide")
312
+
313
+ # Gestion des coups via input texte
314
  if move:
315
  if try_move(move):
316
  game_str = get_game_string()