Zual commited on
Commit
8ddaa9e
·
verified ·
1 Parent(s): d1a705c

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +106 -139
app.py CHANGED
@@ -1,119 +1,77 @@
1
  import streamlit as st
2
  import chess
 
3
  import os
4
  import git
5
  import sys
6
  import random
 
 
7
 
8
  # Configuration de la page
9
  st.set_page_config(page_title="Échecs contre IA", layout="wide")
10
 
11
  def render_chessboard():
12
- """Render un échiquier interactif avec chessboard.js"""
13
- from streamlit.components.v1 import html
 
 
 
 
 
14
 
15
- # Conversion de la position FEN pour JavaScript
16
- fen = st.session_state.board.fen()
17
- last_move = ''
18
- if st.session_state.board.move_stack:
19
- last_move = st.session_state.board.peek().uci()
20
-
21
- # Code JavaScript et HTML pour l'échiquier interactif
22
- board_html = f"""
23
- <html>
24
- <head>
25
- <link
26
- rel="stylesheet"
27
- href="https://cdnjs.cloudflare.com/ajax/libs/chessboard-js/1.0.0/chessboard-1.0.0.min.css"
28
- integrity="sha512-TU/clvRaSqKB43MX6dvJPgxm0ytgRrg/6tkbTPCFwOXG6Ej70nGCkcFkatrbcPHqR0mlPCy3WuYNg936BGvNOg=="
29
- crossorigin="anonymous"
30
- />
31
- <script
32
- src="https://code.jquery.com/jquery-3.6.0.min.js"
33
- integrity="sha256-/xUj+3OJU5yExlq6GSYGSHk7tPXikynS7ogEvDej/m4="
34
- crossorigin="anonymous">
35
- </script>
36
- <script
37
- src="https://cdnjs.cloudflare.com/ajax/libs/chessboard-js/1.0.0/chessboard-1.0.0.min.js"
38
- integrity="sha512-WfASs5HtTgTL/eZs0Td0JVJZ+8tNxF/MDNU99TzJI8D4jXrZdQZRO9G7EPIVQhvmb7yUEEH+AKY9PfGi4pqrw=="
39
- crossorigin="anonymous">
40
- </script>
41
- <script src="https://cdnjs.cloudflare.com/ajax/libs/chess.js/0.10.3/chess.min.js"></script>
42
- </head>
43
- <body>
44
- <div id="board" style="width: 400px; margin: auto;"></div>
45
- <script>
46
- var board = null;
47
- var game = new Chess('{fen}');
48
-
49
- function onDragStart (source, piece, position, orientation) {{
50
- // Permettre seulement le déplacement des pièces blanches
51
- if (game.turn() === 'b' ||
52
- game.game_over() ||
53
- (game.turn() === 'w' && piece.search(/^b/) !== -1)) {{
54
- return false;
55
- }}
56
- }}
57
-
58
- function onDrop (source, target) {{
59
- var move = game.move({{
60
- from: source,
61
- to: target,
62
- promotion: 'q'
63
- }});
64
-
65
- if (move === null) return 'snapback';
66
-
67
- // Envoyer le coup au serveur via Streamlit
68
- window.parent.postMessage({{
69
- type: 'move',
70
- move: move.san
71
- }}, '*');
72
- }}
73
 
74
- function onSnapEnd () {{
75
- board.position(game.fen());
76
- }}
 
 
 
 
 
 
 
77
 
78
- var config = {{
79
- draggable: true,
80
- position: '{fen}',
81
- onDragStart: onDragStart,
82
- onDrop: onDrop,
83
- onSnapEnd: onSnapEnd,
84
- pieceTheme: 'https://cdnjs.cloudflare.com/ajax/libs/chessboard-js/1.0.0/img/chesspieces/wikipedia/{{piece}}.png'
85
- }};
86
-
87
- board = Chessboard('board', config);
88
-
89
- // Marquer le dernier coup
90
- if ('{last_move}') {{
91
- var sourceSquare = '{last_move}'.slice(0, 2);
92
- var targetSquare = '{last_move}'.slice(2, 4);
93
- $("div[data-square='" + sourceSquare + "']").addClass('highlight-square');
94
- $("div[data-square='" + targetSquare + "']").addClass('highlight-square');
95
- }}
96
- </script>
97
- <style>
98
- .highlight-square {{
99
- box-shadow: inset 0 0 3px 3px yellow;
100
- }}
101
- </style>
102
- </body>
103
- </html>
104
- """
105
- html(board_html, height=450)
106
 
107
  def calculate_max_length(move_count):
108
- """
109
- Calcule le max_length optimal basé sur le nombre de coups joués
110
- """
111
- base_length = 10 # Longueur minimum pour un coup simple
112
- increment = 1 # Augmentation par coup
113
- max_length = 100 # Plafond maximum
114
-
115
- dynamic_length = base_length + (move_count * increment)
116
- return min(dynamic_length, max_length)
117
 
118
  # Setup du modèle
119
  @st.cache_resource
@@ -131,30 +89,20 @@ def setup_inference():
131
  )
132
  return ChessGenerator(config)
133
 
134
- # Initialisation
135
  try:
136
  generator = setup_inference()
137
  except Exception as e:
138
  st.error("Erreur lors de l'initialisation.")
139
  st.stop()
140
 
141
- # Initialisation de l'état
142
- if 'board' not in st.session_state:
143
- st.session_state.board = chess.Board()
144
- st.session_state.moves = []
145
- st.session_state.last_move = None
146
-
147
  def get_ai_move(prompt):
148
- """Obtient le coup de l'IA avec max_length dynamique"""
149
- print(f"\n=== Tour de l'IA ===")
150
  moves_count = len(st.session_state.moves)
151
-
152
  dynamic_max_length = calculate_max_length(moves_count)
153
  generator.config.max_length = dynamic_max_length
154
- print(f"max_length actuel: {dynamic_max_length} pour {moves_count} coups joués")
155
 
156
  try:
157
- if not prompt: # Premier coup
158
  response = generator.generate("1.")
159
  else:
160
  moves = prompt.split()
@@ -164,12 +112,12 @@ def get_ai_move(prompt):
164
  response = generator.generate(f"{last_moves} {next_move_num}")
165
  else:
166
  response = generator.generate(f"{last_moves}")
167
-
168
  moves = response[0].split() if isinstance(response, list) else response.split()
169
  next_move = moves[-1]
170
  if '.' in next_move and len(moves) > 1:
171
  next_move = moves[-2]
172
-
173
  try:
174
  move = st.session_state.board.parse_san(next_move)
175
  if move in st.session_state.board.legal_moves:
@@ -177,7 +125,6 @@ def get_ai_move(prompt):
177
  except ValueError:
178
  pass
179
 
180
- # En cas d'échec, jouer un coup légal aléatoire
181
  legal_moves = list(st.session_state.board.legal_moves)
182
  if legal_moves:
183
  random_move = random.choice(legal_moves)
@@ -196,9 +143,7 @@ def try_move(move_str):
196
  if move in st.session_state.board.legal_moves:
197
  st.session_state.board.push(move)
198
  st.session_state.moves.append(clean_move)
199
- st.session_state.last_move = clean_move
200
  return True
201
-
202
  return False
203
  except ValueError:
204
  return False
@@ -219,18 +164,21 @@ st.title("♟️ Échecs contre IA")
219
  col1, col2 = st.columns([2, 1])
220
 
221
  with col1:
222
- # Échiquier interactif
223
  render_chessboard()
224
 
225
- # Input texte comme fallback
226
  move = st.text_input(
227
- "Ou saisissez votre coup ici",
228
  key=f"move_input_{len(st.session_state.moves)}",
229
  placeholder="ex: e4, Nf3, O-O"
230
  )
231
 
 
 
 
232
  with col2:
233
- # Affichage du max_length actuel
234
  current_max_length = calculate_max_length(len(st.session_state.moves))
235
  st.info(f"Longueur de génération actuelle: {current_max_length} tokens")
236
 
@@ -243,7 +191,7 @@ with col2:
243
  # Instructions
244
  st.markdown("""
245
  **Comment jouer:**
246
- - Glissez et déposez les pièces pour jouer
247
  - Ou utilisez la notation algébrique :
248
  - Pion: e4, d5
249
  - Cavalier: Nf3, Nc6
@@ -258,25 +206,44 @@ with col2:
258
  if st.button("Nouvelle partie"):
259
  st.session_state.board = chess.Board()
260
  st.session_state.moves = []
261
- st.session_state.last_move = None
262
  st.rerun()
263
 
264
- # Gestion des messages JavaScript
265
- if st.session_state.get("js_message"):
266
- move = st.session_state.js_message["move"]
267
- st.session_state.js_message = None
268
- if try_move(move):
269
- game_str = get_game_string()
270
- with st.spinner("L'IA réfléchit..."):
271
- ai_move = get_ai_move(game_str)
272
- if ai_move and try_move(ai_move):
273
- if st.session_state.board.is_checkmate():
274
- st.success("Échec et mat!")
275
- elif st.session_state.board.is_game_over():
276
- st.info("Partie terminée!")
277
- else:
278
- st.error("Problème avec le coup de l'IA")
279
- st.rerun()
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
280
 
281
  # Gestion des coups via input texte
282
  if move:
 
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
+ import base64
9
+ from streamlit.components.v1 import html
10
 
11
  # Configuration de la page
12
  st.set_page_config(page_title="Échecs contre IA", layout="wide")
13
 
14
  def render_chessboard():
15
+ """Render un échiquier interactif en SVG"""
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
+ squares=get_legal_moves_squares() if st.session_state.show_hints else None,
21
+ )
22
 
23
+ # Style pour centrer l'échiquier et ajouter des styles supplémentaires
24
+ html_content = f"""
25
+ <div style="display: flex; justify-content: center; margin-bottom: 20px;">
26
+ <style>
27
+ .chess-board {{
28
+ cursor: pointer;
29
+ }}
30
+ .square.legal-move {{
31
+ fill: #afa !important;
32
+ opacity: 0.5;
33
+ }}
34
+ .square.selected {{
35
+ fill: #0af !important;
36
+ opacity: 0.5;
37
+ }}
38
+ .highlight {{
39
+ fill: #ff0 !important;
40
+ opacity: 0.5;
41
+ }}
42
+ </style>
43
+ {board_svg}
44
+ </div>
45
+ """
46
+ html(html_content, height=450)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
47
 
48
+ def get_legal_moves_squares():
49
+ """Obtenir les cases des coups légaux pour la pièce sélectionnée"""
50
+ squares = []
51
+ if st.session_state.selected_square:
52
+ legal_moves = st.session_state.board.legal_moves
53
+ from_square = chess.parse_square(st.session_state.selected_square)
54
+ for move in legal_moves:
55
+ if move.from_square == from_square:
56
+ squares.append(chess.square_name(move.to_square))
57
+ return squares
58
 
59
+ # Initialisation des variables de session
60
+ if 'board' not in st.session_state:
61
+ st.session_state.board = chess.Board()
62
+ if 'moves' not in st.session_state:
63
+ st.session_state.moves = []
64
+ if 'selected_square' not in st.session_state:
65
+ st.session_state.selected_square = None
66
+ if 'show_hints' not in st.session_state:
67
+ st.session_state.show_hints = True
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
68
 
69
  def calculate_max_length(move_count):
70
+ """Calcule le max_length optimal"""
71
+ base_length = 10
72
+ increment = 1
73
+ max_length = 100
74
+ return min(base_length + (move_count * increment), max_length)
 
 
 
 
75
 
76
  # Setup du modèle
77
  @st.cache_resource
 
89
  )
90
  return ChessGenerator(config)
91
 
 
92
  try:
93
  generator = setup_inference()
94
  except Exception as e:
95
  st.error("Erreur lors de l'initialisation.")
96
  st.stop()
97
 
 
 
 
 
 
 
98
  def get_ai_move(prompt):
99
+ """Obtient le coup de l'IA"""
 
100
  moves_count = len(st.session_state.moves)
 
101
  dynamic_max_length = calculate_max_length(moves_count)
102
  generator.config.max_length = dynamic_max_length
 
103
 
104
  try:
105
+ if not prompt:
106
  response = generator.generate("1.")
107
  else:
108
  moves = prompt.split()
 
112
  response = generator.generate(f"{last_moves} {next_move_num}")
113
  else:
114
  response = generator.generate(f"{last_moves}")
115
+
116
  moves = response[0].split() if isinstance(response, list) else response.split()
117
  next_move = moves[-1]
118
  if '.' in next_move and len(moves) > 1:
119
  next_move = moves[-2]
120
+
121
  try:
122
  move = st.session_state.board.parse_san(next_move)
123
  if move in st.session_state.board.legal_moves:
 
125
  except ValueError:
126
  pass
127
 
 
128
  legal_moves = list(st.session_state.board.legal_moves)
129
  if legal_moves:
130
  random_move = random.choice(legal_moves)
 
143
  if move in st.session_state.board.legal_moves:
144
  st.session_state.board.push(move)
145
  st.session_state.moves.append(clean_move)
 
146
  return True
 
147
  return False
148
  except ValueError:
149
  return False
 
164
  col1, col2 = st.columns([2, 1])
165
 
166
  with col1:
167
+ # Affichage de l'échiquier
168
  render_chessboard()
169
 
170
+ # Input texte comme méthode alternative
171
  move = st.text_input(
172
+ "Saisissez votre coup",
173
  key=f"move_input_{len(st.session_state.moves)}",
174
  placeholder="ex: e4, Nf3, O-O"
175
  )
176
 
177
+ # Option pour afficher les coups légaux
178
+ st.checkbox("Afficher les coups possibles", value=True, key="show_hints")
179
+
180
  with col2:
181
+ # Informations sur la partie
182
  current_max_length = calculate_max_length(len(st.session_state.moves))
183
  st.info(f"Longueur de génération actuelle: {current_max_length} tokens")
184
 
 
191
  # Instructions
192
  st.markdown("""
193
  **Comment jouer:**
194
+ - Cliquez sur une pièce puis sur la case de destination
195
  - Ou utilisez la notation algébrique :
196
  - Pion: e4, d5
197
  - Cavalier: Nf3, Nc6
 
206
  if st.button("Nouvelle partie"):
207
  st.session_state.board = chess.Board()
208
  st.session_state.moves = []
209
+ st.session_state.selected_square = None
210
  st.rerun()
211
 
212
+ # Gestion des clics sur l'échiquier (à implémenter avec st.experimental_get_query_params)
213
+ params = st.experimental_get_query_params()
214
+ if 'square' in params:
215
+ clicked_square = params['square'][0]
216
+ if st.session_state.selected_square is None:
217
+ # Premier clic - sélection de la pièce
218
+ piece = st.session_state.board.piece_at(chess.parse_square(clicked_square))
219
+ if piece and piece.color == st.session_state.board.turn:
220
+ st.session_state.selected_square = clicked_square
221
+ else:
222
+ # Deuxième clic - déplacement
223
+ from_square = chess.parse_square(st.session_state.selected_square)
224
+ to_square = chess.parse_square(clicked_square)
225
+ move = chess.Move(from_square, to_square)
226
+
227
+ if move in st.session_state.board.legal_moves:
228
+ # Appliquer le coup
229
+ st.session_state.board.push(move)
230
+ st.session_state.moves.append(st.session_state.board.san(move))
231
+ st.session_state.selected_square = None
232
+
233
+ # Tour de l'IA
234
+ with st.spinner("L'IA réfléchit..."):
235
+ ai_move = get_ai_move(get_game_string())
236
+ if ai_move and try_move(ai_move):
237
+ if st.session_state.board.is_checkmate():
238
+ st.success("Échec et mat!")
239
+ elif st.session_state.board.is_game_over():
240
+ st.info("Partie terminée!")
241
+ else:
242
+ st.error("Problème avec le coup de l'IA")
243
+ st.rerun()
244
+ else:
245
+ st.session_state.selected_square = None
246
+ st.rerun()
247
 
248
  # Gestion des coups via input texte
249
  if move: