doctorlinux commited on
Commit
cbeb866
·
verified ·
1 Parent(s): bbaffae

Upload 2 files

Browse files
Files changed (2) hide show
  1. app.py +196 -59
  2. requirements.txt +5 -5
app.py CHANGED
@@ -4,7 +4,7 @@ import chess.pgn
4
  import matplotlib.pyplot as plt
5
  import numpy as np
6
  import io
7
- import base64
8
  from io import BytesIO
9
 
10
  class AnalizadorAjedrez:
@@ -99,19 +99,26 @@ class AnalizadorAjedrez:
99
  jugadas = [d['jugada'] for d in self.datos_jugadas]
100
  evaluaciones = [d['evaluacion'] for d in self.datos_jugadas]
101
 
102
- ax1.plot(jugadas, evaluaciones, 'b-', linewidth=2, alpha=0.7)
103
- ax1.fill_between(jugadas, evaluaciones, alpha=0.3)
104
- ax1.axhline(y=0, color='black', linestyle='-', alpha=0.5)
105
- ax1.set_title('📊 EVALUACIÓN DE POSICIÓN', fontweight='bold')
 
 
 
 
 
106
  ax1.set_xlabel('Número de Jugada')
107
  ax1.set_ylabel('Ventaja para Blancas')
108
  ax1.grid(True, alpha=0.3)
 
109
 
110
  # 📈 2. ANÁLISIS DE MATERIAL
111
  material_data = [d['ventaja_material'] for d in self.datos_jugadas]
112
- ax2.plot(jugadas, material_data, 'r-', linewidth=2, alpha=0.7)
113
- ax2.axhline(y=0, color='black', linestyle='-', alpha=0.5)
114
- ax2.set_title('📈 VENTAJA MATERIAL', fontweight='bold')
 
115
  ax2.set_xlabel('Jugada')
116
  ax2.set_ylabel('Ventaja Material')
117
  ax2.grid(True, alpha=0.3)
@@ -120,9 +127,11 @@ class AnalizadorAjedrez:
120
  movilidad_b = [d['movilidad_blancas'] for d in self.datos_jugadas]
121
  movilidad_n = [d['movilidad_negras'] for d in self.datos_jugadas]
122
 
123
- ax3.plot(jugadas, movilidad_b, 'b-', label=f'{blancas}', linewidth=2)
124
- ax3.plot(jugadas, movilidad_n, 'r-', label=f'{negras}', linewidth=2)
125
- ax3.set_title('🎯 MOVILIDAD DE PIEZAS', fontweight='bold')
 
 
126
  ax3.set_xlabel('Jugada')
127
  ax3.set_ylabel('Movimientos Legales')
128
  ax3.legend()
@@ -135,12 +144,24 @@ class AnalizadorAjedrez:
135
  valores_n = [ultimo['material_negras'], ultimo['movilidad_negras']]
136
 
137
  x = np.arange(len(categorias))
138
- ax4.bar(x - 0.2, valores_b, 0.4, label=blancas, color='blue', alpha=0.7)
139
- ax4.bar(x + 0.2, valores_n, 0.4, label=negras, color='red', alpha=0.7)
140
- ax4.set_title('📋 COMPARACIÓN FINAL', fontweight='bold')
 
 
 
 
 
 
 
 
 
 
 
141
  ax4.set_xticks(x)
142
  ax4.set_xticklabels(categorias)
143
  ax4.legend()
 
144
 
145
  plt.tight_layout()
146
  return fig
@@ -151,113 +172,229 @@ class AnalizadorAjedrez:
151
  return "No hay datos para generar reporte"
152
 
153
  reporte = "🎯 ANÁLISIS DETALLADO DE LA PARTIDA\n"
154
- reporte += "=" * 40 + "\n"
155
 
156
  # Estadísticas básicas
157
  total_jugadas = len(self.datos_jugadas)
158
  eval_final = self.datos_jugadas[-1]['evaluacion']
159
 
160
- reporte += f" Total de jugadas: {total_jugadas}\n"
161
- reporte += f"• Evaluación final: {eval_final:.2f}\n"
 
162
 
163
  # Balance de material final
164
  mat_final = self.datos_jugadas[-1]['ventaja_material']
165
  if mat_final > 2:
166
- reporte += f"• Ventaja material final: +{mat_final} para Blancas\n"
167
  elif mat_final < -2:
168
- reporte += f"• Ventaja material final: +{abs(mat_final)} para Negras\n"
169
  else:
170
- reporte += "• Material equilibrado al final\n"
171
 
172
  # Jugador con mejor movilidad promedio
173
  mov_avg_b = np.mean([d['movilidad_blancas'] for d in self.datos_jugadas])
174
  mov_avg_n = np.mean([d['movilidad_negras'] for d in self.datos_jugadas])
175
 
 
176
  if mov_avg_b > mov_avg_n:
177
- reporte += f"• Mejor movilidad promedio: Blancas ({mov_avg_b:.1f} vs {mov_avg_n:.1f})\n"
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
178
  else:
179
- reporte += f"• Mejor movilidad promedio: Negras ({mov_avg_n:.1f} vs {mov_avg_b:.1f})\n"
180
 
181
  return reporte
182
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
183
  def analizar_y_mostrar(pgn_text):
184
  """Función que Gradio usará para la interfaz"""
185
  try:
186
  if not pgn_text.strip():
187
  return None, "❌ Por favor, pega una partida PGN válida"
188
 
 
 
 
189
  analizador = AnalizadorAjedrez()
190
- blancas, negras, resultado, error = analizador.analizar_partida(pgn_text)
191
 
192
- if error:
193
- return None, f"❌ {error}"
 
 
 
 
 
 
 
194
 
195
  # Generar gráficos
196
  fig = analizador.generar_graficos_gradio(blancas, negras)
197
 
198
  # Convertir figura a imagen para Gradio
199
  buf = BytesIO()
200
- fig.savefig(buf, format='png', dpi=100, bbox_inches='tight')
201
  buf.seek(0)
202
  plt.close(fig)
203
 
204
  # Generar reporte textual
205
  reporte = analizador.generar_reporte_textual()
206
- reporte = f"Partida: {blancas} vs {negras}\nResultado: {resultado}\n\n" + reporte
 
 
 
 
 
207
 
208
- return buf, reporte
209
 
210
  except Exception as e:
211
- return None, f"❌ Error inesperado: {str(e)}"
212
 
213
- # Interfaz de Gradio
214
- with gr.Blocks(theme=gr.themes.Soft()) as demo:
215
- gr.Markdown("# ♟️ Analizador de Partidas de Ajedrez")
216
- gr.Markdown("Pega cualquier partida en formato PGN y obtén un análisis completo con gráficos y estadísticas.")
 
 
 
 
 
217
 
218
  with gr.Row():
219
- with gr.Column():
 
220
  pgn_input = gr.Textbox(
221
  label="Pega tu partida PGN aquí",
222
- lines=15,
223
  placeholder="""[Event \"Mi Torneo\"]
224
  [White \"Jugador Blanco\"]
225
  [Black \"Jugador Negro\"]
226
  [Result \"1-0\"]
227
 
228
- 1. e4 e5 2. Nf3 Nc6 3. Bb5 a6 4. Ba4 Nf6 5. O-O Be7 6. Re1 b5 7. Bb3 d6 8. c3 O-O"""
 
 
 
 
 
229
  )
230
- btn_analizar = gr.Button("Analizar Partida", variant="primary")
231
 
232
- with gr.Column():
233
- image_output = gr.Image(label="Análisis Gráfico de la Partida", type="filepath")
234
- text_output = gr.Textbox(label="Reporte de Análisis", lines=8)
235
-
236
- # Ejemplos de PGN
237
- gr.Markdown("### 📋 Ejemplo de formato PGN:")
238
- gr.Examples(
239
- examples=[[
240
- """[Event "Ejemplo"]
241
- [Site "?"]
242
- [Date "2023.??.??"]
243
- [Round "?"]
244
- [White "Carlsen"]
245
- [Black "Caruana"]
246
  [Result "1-0"]
247
 
248
- 1. e4 e5 2. Nf3 Nc6 3. Bb5 a6 4. Ba4 Nf6 5. O-O Be7 6. Re1 b5 7. Bb3 d6 8. c3 O-O
249
- 9. h3 Nb8 10. d4 Nbd7 11. Nbd2 Bb7 12. Bc2 Re8 13. Nf1 Bf8 14. Ng3 g6 15. a4 c5
250
- 16. d5 c4 17. Bg5 h6 18. Be3 Nc5 19. Qd2 h5 20. Bh6 Nh7 21. g3 Bd7 22. Rf1 Qc7
251
- 23. Ne2 Rec8 24. Ng5 Nxg5 25. Bxg5 Bg7 26. f4 exf4 27. gxf4 f6 28. Bf3 Be5
252
- 29. fxe5 fxe5 30. Bg5 Qd7 31. e6 Qe7 32. Bf6 Qf8 33. e7 1-0"""]],
253
- inputs=pgn_input
254
- )
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
255
 
 
256
  btn_analizar.click(
257
  fn=analizar_y_mostrar,
258
  inputs=pgn_input,
259
  outputs=[image_output, text_output]
260
  )
 
 
 
 
 
 
261
 
262
  if __name__ == "__main__":
263
- demo.launch()
 
 
 
 
4
  import matplotlib.pyplot as plt
5
  import numpy as np
6
  import io
7
+ import re
8
  from io import BytesIO
9
 
10
  class AnalizadorAjedrez:
 
99
  jugadas = [d['jugada'] for d in self.datos_jugadas]
100
  evaluaciones = [d['evaluacion'] for d in self.datos_jugadas]
101
 
102
+ # Crear fondo coloreado para ventaja
103
+ ax1.axhspan(0.1, max(evaluaciones) if max(evaluaciones) > 0 else 0.1,
104
+ alpha=0.2, color='blue', label='Ventaja Blancas')
105
+ ax1.axhspan(min(evaluaciones) if min(evaluaciones) < 0 else -0.1, -0.1,
106
+ alpha=0.2, color='red', label='Ventaja Negras')
107
+
108
+ ax1.plot(jugadas, evaluaciones, 'b-', linewidth=2.5, alpha=0.8, marker='o', markersize=3)
109
+ ax1.axhline(y=0, color='black', linestyle='-', alpha=0.5, linewidth=1)
110
+ ax1.set_title('📊 EVALUACIÓN DE POSICIÓN', fontweight='bold', fontsize=14)
111
  ax1.set_xlabel('Número de Jugada')
112
  ax1.set_ylabel('Ventaja para Blancas')
113
  ax1.grid(True, alpha=0.3)
114
+ ax1.legend()
115
 
116
  # 📈 2. ANÁLISIS DE MATERIAL
117
  material_data = [d['ventaja_material'] for d in self.datos_jugadas]
118
+ ax2.bar(jugadas, material_data, alpha=0.7,
119
+ color=['blue' if x >= 0 else 'red' for x in material_data])
120
+ ax2.axhline(y=0, color='black', linestyle='-', alpha=0.5, linewidth=1)
121
+ ax2.set_title('📈 VENTAJA MATERIAL', fontweight='bold', fontsize=14)
122
  ax2.set_xlabel('Jugada')
123
  ax2.set_ylabel('Ventaja Material')
124
  ax2.grid(True, alpha=0.3)
 
127
  movilidad_b = [d['movilidad_blancas'] for d in self.datos_jugadas]
128
  movilidad_n = [d['movilidad_negras'] for d in self.datos_jugadas]
129
 
130
+ ax3.fill_between(jugadas, movilidad_b, alpha=0.3, color='blue')
131
+ ax3.fill_between(jugadas, movilidad_n, alpha=0.3, color='red')
132
+ ax3.plot(jugadas, movilidad_b, 'b-', label=f'{blancas}', linewidth=2.5)
133
+ ax3.plot(jugadas, movilidad_n, 'r-', label=f'{negras}', linewidth=2.5)
134
+ ax3.set_title('🎯 MOVILIDAD DE PIEZAS', fontweight='bold', fontsize=14)
135
  ax3.set_xlabel('Jugada')
136
  ax3.set_ylabel('Movimientos Legales')
137
  ax3.legend()
 
144
  valores_n = [ultimo['material_negras'], ultimo['movilidad_negras']]
145
 
146
  x = np.arange(len(categorias))
147
+ bar_width = 0.35
148
+
149
+ ax4.bar(x - bar_width/2, valores_b, bar_width, label=blancas,
150
+ color='blue', alpha=0.7, edgecolor='black')
151
+ ax4.bar(x + bar_width/2, valores_n, bar_width, label=negras,
152
+ color='red', alpha=0.7, edgecolor='black')
153
+
154
+ # Añadir valores encima de las barras
155
+ for i, v in enumerate(valores_b):
156
+ ax4.text(i - bar_width/2, v + 0.5, str(v), ha='center', va='bottom', fontweight='bold')
157
+ for i, v in enumerate(valores_n):
158
+ ax4.text(i + bar_width/2, v + 0.5, str(v), ha='center', va='bottom', fontweight='bold')
159
+
160
+ ax4.set_title('📋 COMPARACIÓN FINAL', fontweight='bold', fontsize=14)
161
  ax4.set_xticks(x)
162
  ax4.set_xticklabels(categorias)
163
  ax4.legend()
164
+ ax4.grid(True, alpha=0.3, axis='y')
165
 
166
  plt.tight_layout()
167
  return fig
 
172
  return "No hay datos para generar reporte"
173
 
174
  reporte = "🎯 ANÁLISIS DETALLADO DE LA PARTIDA\n"
175
+ reporte += "=" * 50 + "\n\n"
176
 
177
  # Estadísticas básicas
178
  total_jugadas = len(self.datos_jugadas)
179
  eval_final = self.datos_jugadas[-1]['evaluacion']
180
 
181
+ reporte += f"📊 **Estadísticas Básicas:**\n"
182
+ reporte += f" Total de jugadas: {total_jugadas}\n"
183
+ reporte += f" • Evaluación final: {eval_final:.2f}\n"
184
 
185
  # Balance de material final
186
  mat_final = self.datos_jugadas[-1]['ventaja_material']
187
  if mat_final > 2:
188
+ reporte += f" ⚖️ Ventaja material final: +{mat_final} para Blancas\n"
189
  elif mat_final < -2:
190
+ reporte += f" ⚖️ Ventaja material final: +{abs(mat_final)} para Negras\n"
191
  else:
192
+ reporte += " ⚖️ Material equilibrado al final\n"
193
 
194
  # Jugador con mejor movilidad promedio
195
  mov_avg_b = np.mean([d['movilidad_blancas'] for d in self.datos_jugadas])
196
  mov_avg_n = np.mean([d['movilidad_negras'] for d in self.datos_jugadas])
197
 
198
+ reporte += f"\n🎯 **Análisis de Movilidad:**\n"
199
  if mov_avg_b > mov_avg_n:
200
+ reporte += f" • Mejor movilidad promedio: 🏆 Blancas ({mov_avg_b:.1f} vs {mov_avg_n:.1f})\n"
201
+ else:
202
+ reporte += f" • Mejor movilidad promedio: 🏆 Negras ({mov_avg_n:.1f} vs {mov_avg_b:.1f})\n"
203
+
204
+ # Punto de mayor ventaja
205
+ max_ventaja_b = max([d['evaluacion'] for d in self.datos_jugadas])
206
+ min_ventaja_b = min([d['evaluacion'] for d in self.datos_jugadas])
207
+
208
+ reporte += f"\n📈 **Momentos Clave:**\n"
209
+ reporte += f" • Mayor ventaja de Blancas: +{max_ventaja_b:.1f}\n"
210
+ reporte += f" • Mayor ventaja de Negras: +{abs(min_ventaja_b):.1f}\n"
211
+
212
+ # Duración de la partida
213
+ if total_jugadas < 30:
214
+ reporte += f" • Partida rápida ({total_jugadas} jugadas)\n"
215
+ elif total_jugadas < 60:
216
+ reporte += f" • Partida de duración media ({total_jugadas} jugadas)\n"
217
  else:
218
+ reporte += f" Partida larga ({total_jugadas} jugadas)\n"
219
 
220
  return reporte
221
 
222
+ def limpiar_y_corregir_pgn(pgn_text):
223
+ """Limpia y corrige errores comunes en PGN automáticamente"""
224
+ correcciones = {
225
+ 'N75': 'Nf3', 'N76': 'Nf6', 'N15': 'Nf5', 'N16': 'Nf6',
226
+ 'Re6': 'Nc6', 'Re3': 'Ne3', 'Re4': 'Ne4',
227
+ 'Rel': 'Re1', 'Ral': 'Ra1', 'Rbl': 'Rb1', 'Rcl': 'Rc1', 'Rdl': 'Rd1',
228
+ 'Nba': 'Nb8', 'Nbc': 'Nbc6', 'Nbd': 'Nbd7',
229
+ 'Of8': 'Qf8', 'Oc7': 'Qc7', 'Od8': 'Qd8',
230
+ 'B6': 'Bf6', 'B7': 'Bb7', 'B5': 'Bb5',
231
+ 'ae': 'a6', 'af': 'a5'
232
+ }
233
+
234
+ # Aplicar correcciones
235
+ for error, correccion in correcciones.items():
236
+ pgn_text = pgn_text.replace(error, correccion)
237
+
238
+ # Corregir números de jugada mal formados
239
+ pgn_text = re.sub(r'(\d+)\.([A-Z])', r'\1. \2', pgn_text)
240
+
241
+ # Asegurar espacios después de puntos
242
+ pgn_text = re.sub(r'(\d+)\.(\S)', r'\1. \2', pgn_text)
243
+
244
+ return pgn_text
245
+
246
  def analizar_y_mostrar(pgn_text):
247
  """Función que Gradio usará para la interfaz"""
248
  try:
249
  if not pgn_text.strip():
250
  return None, "❌ Por favor, pega una partida PGN válida"
251
 
252
+ # Limpiar y corregir PGN automáticamente
253
+ pgn_limpio = limpiar_y_corregir_pgn(pgn_text)
254
+
255
  analizador = AnalizadorAjedrez()
256
+ blancas, negras, resultado, error = analizador.analizar_partida(pgn_limpio)
257
 
258
+ if "Error" in blancas:
259
+ # Intentar análisis con PGN original como fallback
260
+ try:
261
+ analizador = AnalizadorAjedrez()
262
+ blancas, negras, resultado, error = analizador.analizar_partida(pgn_text)
263
+ if "Error" in blancas:
264
+ return None, f"❌ No se pudo analizar el PGN.\n\n💡 **Sugerencias:**\n• Verifica que la notación sea correcta\n• Asegúrate de que los movimientos sigan formato estándar\n• Revisa que no haya caracteres especiales extraños\n\nError técnico: {error}"
265
+ except:
266
+ return None, f"❌ Error crítico en el PGN.\n\n📝 **Formato esperado:**\n```\n[Event \"Nombre\"]\n[White \"JugadorB\"]\n[Black \"JugadorN\"]\n\n1. e4 e5 2. Nf3 Nc6 3. Bb5 a6\n```"
267
 
268
  # Generar gráficos
269
  fig = analizador.generar_graficos_gradio(blancas, negras)
270
 
271
  # Convertir figura a imagen para Gradio
272
  buf = BytesIO()
273
+ fig.savefig(buf, format='png', dpi=120, bbox_inches='tight', facecolor='white')
274
  buf.seek(0)
275
  plt.close(fig)
276
 
277
  # Generar reporte textual
278
  reporte = analizador.generar_reporte_textual()
279
+ reporte_header = f"**♟️ PARTIDA ANALIZADA:**\n"
280
+ reporte_header += f"**Blancas:** {blancas}\n"
281
+ reporte_header += f"**Negras:** {negras}\n"
282
+ reporte_header += f"**Resultado:** {resultado}\n\n"
283
+
284
+ full_reporte = reporte_header + reporte
285
 
286
+ return buf, full_reporte
287
 
288
  except Exception as e:
289
+ return None, f"❌ Error inesperado: {str(e)}\n\nPor favor, verifica el formato de tu PGN."
290
 
291
+ # Interfaz de Gradio mejorada
292
+ with gr.Blocks(theme=gr.themes.Soft(primary_hue="blue", secondary_hue="slate")) as demo:
293
+ gr.Markdown("""
294
+ # ♟️ Analizador Avanzado de Partidas de Ajedrez
295
+
296
+ **Pega cualquier partida en formato PGN y obtén un análisis completo con gráficos y estadísticas detalladas.**
297
+
298
+ *El sistema corrige automáticamente errores comunes de notación.*
299
+ """)
300
 
301
  with gr.Row():
302
+ with gr.Column(scale=1):
303
+ gr.Markdown("### 📝 Ingresa tu partida")
304
  pgn_input = gr.Textbox(
305
  label="Pega tu partida PGN aquí",
306
+ lines=18,
307
  placeholder="""[Event \"Mi Torneo\"]
308
  [White \"Jugador Blanco\"]
309
  [Black \"Jugador Negro\"]
310
  [Result \"1-0\"]
311
 
312
+ 1. e4 e5 2. Nf3 Nc6 3. Bb5 a6 4. Ba4 Nf6 5. O-O Be7 6. Re1 b5 7. Bb3 d6 8. c3 O-O
313
+ 9. h3 Nb8 10. d4 Nbd7 11. Nbd2 Bb7 12. Bc2 Re8 13. Nf1 Bf8 14. Ng3 g6 15. a4 c5
314
+ 16. d5 c4 17. Bg5 h6 18. Be3 Nc5 19. Qd2 h5 20. Bh6 Nh7 21. g3 Bd7 22. Rf1 Qc7
315
+ 23. Ne2 Rec8 24. Ng5 Nxg5 25. Bxg5 Bg7 26. f4 exf4 27. gxf4 f6 28. Bf3 Be5
316
+ 29. fxe5 fxe5 30. Bg5 Qd7 31. e6 Qe7 32. Bf6 Qf8 33. e7 1-0""",
317
+ info="Puedes pegar PGNs con pequeños errores, el sistema los corregirá automáticamente."
318
  )
 
319
 
320
+ with gr.Row():
321
+ btn_analizar = gr.Button("🧠 Analizar Partida", variant="primary", size="lg")
322
+ btn_limpiar = gr.Button("🗑️ Limpiar", variant="secondary")
323
+
324
+ gr.Markdown("### 💡 Ejemplos rápidos:")
325
+ with gr.Row():
326
+ gr.Examples(
327
+ examples=[[
328
+ """[Event "Partida Rápida"]
329
+ [White "Aman"]
330
+ [Black "Boris"]
 
 
 
331
  [Result "1-0"]
332
 
333
+ 1. e4 e5 2. Nf3 Nc6 3. Bc4 Nf6 4. Ng5 d5 5. exd5 Nxd5 6. Nxf7 Kxf7 7. Qf3+ Ke6
334
+ 8. Nc3 Ne7 9. d4 c6 10. Bg5 h6 11. Bxe7 Bxe7 12. O-O-O Rf8 13. Qe4 Rxf2 14. d5+ Kd6
335
+ 15. Nxd5 cxd5 16. Rxd5+ Kc6 17. Qc4+ Kb6 18. Rb5+ Ka6 19. Qc6+ 1-0"""]],
336
+ inputs=pgn_input,
337
+ label="Ataque Legal"
338
+ )
339
+
340
+ with gr.Column(scale=1):
341
+ gr.Markdown("### 📊 Resultados del Análisis")
342
+ image_output = gr.Image(
343
+ label="Análisis Gráfico de la Partida",
344
+ type="filepath",
345
+ height=400
346
+ )
347
+ text_output = gr.Markdown(
348
+ label="Reporte de Análisis Detallado"
349
+ )
350
+
351
+ # Funcionalidades adicionales
352
+ gr.Markdown("---")
353
+ with gr.Accordion("📚 Guía de Formato PGN", open=False):
354
+ gr.Markdown("""
355
+ **Formato PGN Correcto:**
356
+ ```
357
+ [Event "Nombre del Torneo"]
358
+ [Site "Ciudad, País"]
359
+ [Date "2024.01.01"]
360
+ [Round "1"]
361
+ [White "Apellido, Nombre"]
362
+ [Black "Apellido, Nombre"]
363
+ [Result "1-0"]
364
+ [WhiteElo "2500"]
365
+ [BlackElo "2400"]
366
+
367
+ 1. e4 e5 2. Nf3 Nc6 3. Bb5 a6 4. Ba4 Nf6 5. O-O Be7 6. Re1 b5 7. Bb3 d6
368
+ 8. c3 O-O 9. h3 Nb8 10. d4 Nbd7 11. Nbd2 Bb7 12. Bc2 Re8 13. Nf1 Bf8
369
+ 14. Ng3 g6 15. a4 c5 16. d5 c4 17. Bg5 h6 18. Be3 Nc5 19. Qd2 h5
370
+ ...
371
+ 33. e7 1-0
372
+ ```
373
+
374
+ **Notación de Piezas:**
375
+ - Rey: **K** (King)
376
+ - Reina: **Q** (Queen)
377
+ - Torre: **R** (Rook)
378
+ - Alfil: **B** (Bishop)
379
+ - Caballo: **N** (Knight)
380
+ - Peón: (sin letra, ej: e4, d5)
381
+ """)
382
 
383
+ # Conectores de eventos
384
  btn_analizar.click(
385
  fn=analizar_y_mostrar,
386
  inputs=pgn_input,
387
  outputs=[image_output, text_output]
388
  )
389
+
390
+ btn_limpiar.click(
391
+ fn=lambda: [None, "### 📊 Reporte de Análisis\n\n*Los resultados aparecerán aquí después del análisis...*"],
392
+ inputs=[],
393
+ outputs=[image_output, text_output]
394
+ )
395
 
396
  if __name__ == "__main__":
397
+ demo.launch(
398
+ share=True,
399
+ show_error=True
400
+ )
requirements.txt CHANGED
@@ -1,5 +1,5 @@
1
- chess
2
- matplotlib
3
- numpy
4
- gradio
5
- pillow
 
1
+ chess==1.10.0
2
+ matplotlib==3.7.1
3
+ numpy==1.24.3
4
+ gradio==4.19.1
5
+ pillow==10.0.0