se bloquea al resolver: ""import pygame
import sys
import random
from collections import deque
import heapq

# Configuración de Pygame
pygame.init()

# Constantes
TILE_SIZE = 100
GRID_SIZE = 4
WINDOW_HEIGHT = TILE_SIZE * GRID_SIZE + 50  # Espacio extra para el botón
WINDOW_WIDTH = TILE_SIZE * GRID_SIZE
FPS = 30  # Frames por segundo

# Colores
BACKGROUND_COLOR = (255, 255, 255)
TILE_COLOR = (0, 102, 204)
TEXT_COLOR = (255, 255, 255)
BUTTON_COLOR = (0, 204, 102)

# Inicializar pantalla
screen = pygame.display.set_mode((WINDOW_WIDTH, WINDOW_HEIGHT))
pygame.display.set_caption('Puzzle 15')

# Fuente
font = pygame.font.Font(None, 72)
button_font = pygame.font.Font(None, 48)

def create_initial_board():
    numbers = list(range(1, GRID_SIZE * GRID_SIZE))
    numbers.append(0)
    random.shuffle(numbers)
    board = [numbers[i:i + GRID_SIZE] for i in range(0, len(numbers), GRID_SIZE)]
    return board

def draw_board(board, solve_button):
    screen.fill(BACKGROUND_COLOR)
    for row in range(GRID_SIZE):
        for col in range(GRID_SIZE):
            value = board[row][col]
            if value != 0:
                x = col * TILE_SIZE
                y = row * TILE_SIZE
                pygame.draw.rect(screen, TILE_COLOR, (x, y, TILE_SIZE, TILE_SIZE))
                text = font.render(str(value), True, TEXT_COLOR)
                text_rect = text.get_rect(center=(x + TILE_SIZE // 2, y + TILE_SIZE // 2))
                screen.blit(text, text_rect)
    
    # Dibujar botón de resolver
    pygame.draw.rect(screen, BUTTON_COLOR, solve_button)
    button_text = button_font.render('Resolver', True, TEXT_COLOR)
    button_rect = button_text.get_rect(center=solve_button.center)
    screen.blit(button_text, button_rect)

def find_empty_tile(board):
    for row in range(GRID_SIZE):
        for col in range(GRID_SIZE):
            if board[row][col] == 0:
                return (row, col)
    return None

def is_valid_move(empty_tile, click_pos):
    empty_row, empty_col = empty_tile
    click_row, click_col = click_pos
    return (abs(empty_row - click_row) == 1 and empty_col == click_col) or (abs(empty_col - click_col) == 1 and empty_row == click_row)

def swap_tiles(board, tile1, tile2):
    board[tile1[0]][tile1[1]], board[tile2[0]][tile2[1]] = board[tile2[0]][tile2[1]], board[tile1[0]][tile1[1]]

def is_solved(board):
    correct = list(range(1, GRID_SIZE * GRID_SIZE)) + [0]
    flat_board = sum(board, [])
    return correct == flat_board

def get_neighbors(position):
    row, col = position
    neighbors = [
        (row + 1, col), (row - 1, col),
        (row, col + 1), (row, col - 1)
    ]
    valid_neighbors = [(r, c) for r, c in neighbors if 0 <= r < GRID_SIZE and 0 <= c < GRID_SIZE]
    return valid_neighbors

def manhattan_distance(board):
    distance = 0
    for row in range(GRID_SIZE):
        for col in range(GRID_SIZE):
            value = board[row][col]
            if value != 0:
                target_row, target_col = divmod(value - 1, GRID_SIZE)
                distance += abs(row - target_row) + abs(col - target_col)
    return distance

def a_star_solve(start_board):
    def board_to_tuple(board):
        return tuple(tuple(row) for row in board)

    start_state = board_to_tuple(start_board)
    goal_state = board_to_tuple([[i + 1 if i < GRID_SIZE * GRID_SIZE - 1 else 0 for i in range(j * GRID_SIZE, (j + 1) * GRID_SIZE)] for j in range(GRID_SIZE)])
    
    open_set = []
    heapq.heappush(open_set, (0, start_state))
    came_from = {}
    g_score = {start_state: 0}
    f_score = {start_state: manhattan_distance(start_board)}
    
    while open_set:
        current_f, current_state = heapq.heappop(open_set)
        current_board = [list(row) for row in current_state]
        
        if current_state == goal_state:
            return reconstruct_path(came_from, current_state)
        
        for neighbor_pos in get_neighbors(find_empty_tile(current_board)):
            new_board = [row[:] for row in current_board]
            swap_tiles(new_board, find_empty_tile(new_board), neighbor_pos)
            neighbor_state = board_to_tuple(new_board)
            tentative_g_score = g_score[current_state] + 1
            
            if neighbor_state not in g_score or tentative_g_score < g_score[neighbor_state]:
                came_from[neighbor_state] = current_state
                g_score[neighbor_state] = tentative_g_score
                f_score[neighbor_state] = tentative_g_score + manhattan_distance(new_board)
                heapq.heappush(open_set, (f_score[neighbor_state], neighbor_state))
    
    return None

def reconstruct_path(came_from, current):
    total_path = [current]
    while current in came_from:
        current = came_from[current]
        total_path.append(current)
    return total_path[::-1]

# Main loop
def main():
    clock = pygame.time.Clock()
    board = create_initial_board()
    solve_button = pygame.Rect(0, WINDOW_HEIGHT - 50, WINDOW_WIDTH, 50)
    
    while True:
        for event in pygame.event.get():
            if event.type == pygame.QUIT:
                pygame.quit()
                sys.exit()
            elif event.type == pygame.MOUSEBUTTONDOWN:
                mouse_pos = pygame.mouse.get_pos()
                if solve_button.collidepoint(mouse_pos):
                    solution = a_star_solve(board)
                    if solution:
                        for state in solution:
                            board = [list(row) for row in state]
                            draw_board(board, solve_button)
                            pygame.display.flip()
                            pygame.time.wait(500)  # Esperar 500 ms entre movimientos
                else:
                    click_row, click_col = mouse_pos[1] // TILE_SIZE, mouse_pos[0] // TILE_SIZE
                    empty_tile = find_empty_tile(board)
                    if is_valid_move(empty_tile, (click_row, click_col)):
                        swap_tiles(board, empty_tile, (click_row, click_col))
        
        draw_board(board, solve_button)
        pygame.display.flip()
        clock.tick(FPS)

if __name__ == '__main__':
    main()""