import gradio as gr import chess import chess.engine import tempfile import os from PIL import Image, ImageDraw import requests import io # Configuración BOARD_SIZE = 400 SQUARE_SIZE = BOARD_SIZE // 8 class ChessGame: def __init__(self): self.board = chess.Board() self.selected_square = None self.valid_moves = [] self.game_over = False self.player_turn = True def create_board_image(self): """Crear imagen del tablero con las piezas""" # Colores light_square = (238, 238, 210) dark_square = (118, 150, 86) highlight = (186, 202, 68) # Crear imagen img = Image.new('RGB', (BOARD_SIZE, BOARD_SIZE), color='white') draw = ImageDraw.Draw(img) # Dibujar tablero for row in range(8): for col in range(8): color = light_square if (row + col) % 2 == 0 else dark_square x1 = col * SQUARE_SIZE y1 = row * SQUARE_SIZE x2 = x1 + SQUARE_SIZE y2 = y1 + SQUARE_SIZE draw.rectangle([x1, y1, x2, y2], fill=color) # Dibujar piezas (usaremos emojis como texto) piece_chars = { 'r': '♜', 'n': '♞', 'b': '♝', 'q': '♛', 'k': '♚', 'p': '♟', 'R': '♖', 'N': '♘', 'B': '♗', 'Q': '♕', 'K': '♔', 'P': '♙' } for square in chess.SQUARES: piece = self.board.piece_at(square) if piece: col = chess.square_file(square) row = 7 - chess.square_rank(square) x = col * SQUARE_SIZE + SQUARE_SIZE // 2 y = row * SQUARE_SIZE + SQUARE_SIZE // 2 # Usar emoji para la pieza piece_char = piece_chars[piece.symbol()] draw.text((x-10, y-15), piece_char, fill='black', font_size=30) return img def get_move_suggestion(self): """Obtener sugerencia de Stockfish usando API""" try: # Usar API de stockfish.js como fallback fen = self.board.fen() url = f"https://stockfish.online/api/s/v2.php?fen={fen}&depth=10" response = requests.get(url) if response.status_code == 200: data = response.json() if 'bestmove' in data: return data['bestmove'] except: pass # Fallback: elegir el primer movimiento legal legal_moves = list(self.board.legal_moves) return str(legal_moves[0]) if legal_moves else None def make_move(self, move_uci): """Realizar movimiento""" try: move = chess.Move.from_uci(move_uci) if move in self.board.legal_moves: self.board.push(move) self.player_turn = False return True except: pass return False def ai_move(self): """Movimiento de la IA""" if not self.player_turn and not self.board.is_game_over(): best_move = self.get_move_suggestion() if best_move: self.board.push(chess.Move.from_uci(best_move)) self.player_turn = True def get_game_status(self): """Obtener estado del juego""" if self.board.is_checkmate(): return "¡Jaque mate! " + ("Ganaste" if self.player_turn else "Stockfish gana") elif self.board.is_stalemate(): return "Tablas por ahogado" elif self.board.is_insufficient_material(): return "Tablas por material insuficiente" elif self.board.is_check(): return "¡Jaque!" else: return "Tu turno" if self.player_turn else "Pensando..." # Instancia global del juego game = ChessGame() def update_interface(): """Actualizar la interfaz completa""" board_img = game.create_board_image() status = game.get_game_status() # Generar lista de movimientos legales legal_moves = [str(move) for move in game.board.legal_moves] return board_img, status, "\n".join(legal_moves[:10]) # Mostrar primeros 10 movimientos def handle_move(move_input): """Manejar movimiento del jugador""" if game.player_turn and not game.board.is_game_over(): if game.make_move(move_input): # Movimiento de la IA después de un breve delay game.ai_move() return update_interface() def handle_suggestion(): """Obtener sugerencia de movimiento""" if game.player_turn: suggestion = game.get_move_suggestion() return suggestion if suggestion else "No hay sugerencias disponibles" return "Es el turno de Stockfish" def reset_game(): """Reiniciar juego""" global game game = ChessGame() return update_interface() # Crear interfaz Gradio with gr.Blocks(theme=gr.themes.Soft(), title="Ajedrez con Stockfish") as demo: gr.Markdown(""" # ♟️ Ajedrez con Stockfish Juega contra Stockfish, uno de los motores de ajedrez más fuertes del mundo. """) with gr.Row(): with gr.Column(): board_image = gr.Image(label="Tablero", interactive=False) status_text = gr.Textbox(label="Estado del Juego", interactive=False) with gr.Column(): move_input = gr.Textbox( label="Ingresa tu movimiento (ej: e2e4)", placeholder="Formato: casilla_origen casilla_destino" ) with gr.Row(): submit_btn = gr.Button("Realizar Movimiento", variant="primary") suggest_btn = gr.Button("Sugerencia") reset_btn = gr.Button("Nuevo Juego") suggestion_text = gr.Textbox(label="Sugerencia de Stockfish", interactive=False) legal_moves_text = gr.Textbox( label="Movimientos Legales (primeros 10)", lines=10, interactive=False ) # Conexiones de eventos submit_btn.click( fn=handle_move, inputs=move_input, outputs=[board_image, status_text, legal_moves_text] ) suggest_btn.click( fn=handle_suggestion, outputs=suggestion_text ) reset_btn.click( fn=reset_game, outputs=[board_image, status_text, legal_moves_text] ) # Inicializar interfaz demo.load( fn=update_interface, outputs=[board_image, status_text, legal_moves_text] ) # Para Hugging Face Spaces if __name__ == "__main__": demo.launch(share=True)