File size: 6,759 Bytes
5c1db90
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
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)