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

Upload 2 files

Browse files
Files changed (2) hide show
  1. app.py +229 -18
  2. requirements.txt +2 -2
app.py CHANGED
@@ -7,15 +7,192 @@ import io
7
  import base64
8
  from io import BytesIO
9
 
10
- # (Aquí va toda la clase AnalizadorAjedrez que te pasé antes)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
11
 
12
  def analizar_y_mostrar(pgn_text):
13
  """Función que Gradio usará para la interfaz"""
14
  try:
 
 
 
15
  analizador = AnalizadorAjedrez()
16
- blancas, negras, resultado = analizador.analizar_partida(pgn_text)
17
 
18
- # Generar gráficos y convertirlos a base64 para mostrar en Gradio
 
 
 
19
  fig = analizador.generar_graficos_gradio(blancas, negras)
20
 
21
  # Convertir figura a imagen para Gradio
@@ -26,27 +203,61 @@ def analizar_y_mostrar(pgn_text):
26
 
27
  # Generar reporte textual
28
  reporte = analizador.generar_reporte_textual()
 
29
 
30
  return buf, reporte
31
 
32
  except Exception as e:
33
- return None, f"❌ Error: {str(e)}"
34
 
35
  # Interfaz de Gradio
36
- demo = gr.Interface(
37
- fn=analizar_y_mostrar,
38
- inputs=gr.Textbox(
39
- label="Pega tu partida PGN aquí",
40
- lines=10,
41
- placeholder="[Event 'Mi Partida']\n[White 'Yo']\n[Black 'Rival']\n\n1. e4 e5 2. Nf3 Nc6 ..."
42
- ),
43
- outputs=[
44
- gr.Image(label="Análisis Gráfico de la Partida"),
45
- gr.Textbox(label="Reporte de Análisis")
46
- ],
47
- title="♟️ Analizador de Partidas de Ajedrez",
48
- description="Pega cualquier partida en formato PGN y obtén un análisis completo con gráficos y estadísticas."
49
- )
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
50
 
51
  if __name__ == "__main__":
52
  demo.launch()
 
7
  import base64
8
  from io import BytesIO
9
 
10
+ class AnalizadorAjedrez:
11
+ def __init__(self):
12
+ self.datos_jugadas = []
13
+ plt.style.use('default')
14
+
15
+ def analizar_partida(self, pgn_string):
16
+ """Analiza una partida completa desde PGN"""
17
+ try:
18
+ pgn = io.StringIO(pgn_string)
19
+ game = chess.pgn.read_game(pgn)
20
+
21
+ if game is None:
22
+ return "Error", "Error", "Error", "No se pudo leer el PGN"
23
+
24
+ # Metadatos
25
+ blancas = game.headers.get("White", "Anónimo")
26
+ negras = game.headers.get("Black", "Anónimo")
27
+ resultado = game.headers.get("Result", "*")
28
+
29
+ # Analizar cada jugada
30
+ tablero = game.board()
31
+ self.datos_jugadas = []
32
+
33
+ jugada_num = 0
34
+ for move in game.mainline_moves():
35
+ tablero.push(move)
36
+ jugada_num += 1
37
+ analisis = self._evaluar_posicion(tablero, jugada_num)
38
+ self.datos_jugadas.append(analisis)
39
+
40
+ return blancas, negras, resultado, ""
41
+
42
+ except Exception as e:
43
+ return "Error", "Error", "Error", f"Error procesando PGN: {str(e)}"
44
+
45
+ def _evaluar_posicion(self, tablero, jugada_num):
46
+ """Evalúa una posición específica del tablero"""
47
+ # Valor material (puntos estándar)
48
+ valores = {'p': 1, 'n': 3, 'b': 3, 'r': 5, 'q': 9, 'k': 0}
49
+
50
+ material_blancas = 0
51
+ material_negras = 0
52
+
53
+ for square, pieza in tablero.piece_map().items():
54
+ valor = valores.get(pieza.symbol().lower(), 0)
55
+ if pieza.color == chess.WHITE:
56
+ material_blancas += valor
57
+ else:
58
+ material_negras += valor
59
+
60
+ ventaja_material = material_blancas - material_negras
61
+
62
+ # Movilidad
63
+ movilidad_blancas = len(list(tablero.legal_moves))
64
+ tablero.turn = not tablero.turn
65
+ movilidad_negras = len(list(tablero.legal_moves))
66
+ tablero.turn = not tablero.turn
67
+
68
+ ventaja_movilidad = movilidad_blancas - movilidad_negras
69
+
70
+ # Evaluación compuesta
71
+ evaluacion = ventaja_material + (ventaja_movilidad * 0.1)
72
+
73
+ return {
74
+ 'jugada': jugada_num,
75
+ 'evaluacion': evaluacion,
76
+ 'material_blancas': material_blancas,
77
+ 'material_negras': material_negras,
78
+ 'ventaja_material': ventaja_material,
79
+ 'movilidad_blancas': movilidad_blancas,
80
+ 'movilidad_negras': movilidad_negras,
81
+ 'es_blancas': jugada_num % 2 == 1
82
+ }
83
+
84
+ def generar_graficos_gradio(self, blancas, negras):
85
+ """Genera todos los gráficos para Gradio"""
86
+ if not self.datos_jugadas:
87
+ # Crear gráfico vacío si no hay datos
88
+ fig, ax = plt.subplots(figsize=(10, 6))
89
+ ax.text(0.5, 0.5, 'No hay datos para mostrar',
90
+ horizontalalignment='center', verticalalignment='center',
91
+ transform=ax.transAxes, fontsize=16)
92
+ ax.set_xlim(0, 1)
93
+ ax.set_ylim(0, 1)
94
+ return fig
95
+
96
+ fig, ((ax1, ax2), (ax3, ax4)) = plt.subplots(2, 2, figsize=(15, 12))
97
+
98
+ # 📊 1. GRÁFICO DE EVALUACIÓN DE POSICIÓN
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)
118
+
119
+ # 🎯 3. MOVILIDAD
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()
129
+ ax3.grid(True, alpha=0.3)
130
+
131
+ # 📋 4. ESTADÍSTICAS FINALES
132
+ ultimo = self.datos_jugadas[-1]
133
+ categorias = ['Material', 'Movilidad']
134
+ valores_b = [ultimo['material_blancas'], ultimo['movilidad_blancas']]
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
147
+
148
+ def generar_reporte_textual(self):
149
+ """Genera un análisis textual de la partida"""
150
+ if not self.datos_jugadas:
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
 
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()
requirements.txt CHANGED
@@ -1,5 +1,5 @@
1
  chess
2
  matplotlib
3
  numpy
4
- seaborn
5
- gradio
 
1
  chess
2
  matplotlib
3
  numpy
4
+ gradio
5
+ pillow