import tkinter as tk
from tkinter import messagebox
import random
import time

# Define the pieces
PIECES = {
    'line': {
        'chars': ['─', '│', '─', '│'],
        'connections': [
            [0, 1, 0, 1],  # 0°, horizontal
            [1, 0, 1, 0],  # 90°, vertical
            [0, 1, 0, 1],  # 180°, horizontal
            [1, 0, 1, 0],  # 270°, vertical
        ]
    },
    'curve': {
        'chars': ['└', '┌', '┐', '┘'],
        'connections': [
            [1, 1, 0, 0],  # 0°, conecta Arriba y Derecha
            [0, 1, 1, 0],  # 90°, conecta Derecha y Abajo
            [0, 0, 1, 1],  # 180°, conecta Abajo y Izquierda
            [1, 0, 0, 1],  # 270°, conecta Izquierda y Arriba
        ]
    },
    't': {
        'chars': ['┬', '┤', '┴', '├'],
        'connections': [
            [1, 1, 0, 1],  # 0°, conecta Arriba, Derecha, Izquierda
            [1, 1, 1, 0],  # 90°, conecta Arriba, Derecha, Abajo
            [0, 1, 1, 1],  # 180°, conecta Derecha, Abajo, Izquierda
            [1, 0, 1, 1],  # 270°, conecta Arriba, Abajo, Izquierda
        ]
    },
    'cross': {
        'chars': ['┼', '┼', '┼', '┼'],
        'connections': [
            [1, 1, 1, 1],
            [1, 1, 1, 1],
            [1, 1, 1, 1],
            [1, 1, 1, 1],
        ]
    }
}

class PipePuzzleApp:
    def __init__(self, root):
        self.root = root
        self.root.title("Pipe Puzzle Game")
        self.board_size = 5
        self.board = [[None for _ in range(self.board_size)] for _ in range(self.board_size)]
        self.buttons = [[None for _ in range(self.board_size)] for _ in range(self.board_size)]
        self.init_ui()
        self.generate_board()

    def init_ui(self):
        self.frame = tk.Frame(self.root)
        self.frame.pack()

        for i in range(self.board_size):
            for j in range(self.board_size):
                btn = tk.Button(self.frame, text="", width=5, height=2, command=lambda i=i, j=j: self.rotate_piece(i, j))
                btn.grid(row=i, column=j)
                self.buttons[i][j] = btn

        self.solve_frame = tk.Frame(self.root)
        self.solve_frame.pack()

        tk.Button(self.solve_frame, text="DFS", command=self.solve_dfs).pack(side=tk.LEFT)
        tk.Button(self.solve_frame, text="BFS", command=self.solve_bfs).pack(side=tk.LEFT)
        tk.Button(self.solve_frame, text="A*", command=self.solve_a_star).pack(side=tk.LEFT)
        tk.Button(self.solve_frame, text="GA", command=self.solve_ga).pack(side=tk.LEFT)

    def generate_board(self):
        for i in range(self.board_size):
            for j in range(self.board_size):
                piece_type = random.choice(list(PIECES.keys()))
                piece = PIECES[piece_type]
                rotation = random.randint(0, 3)
                self.board[i][j] = {'type': piece_type, 'rotation': rotation}
                self.update_button(i, j)

    def update_button(self, i, j):
        piece = self.board[i][j]
        char = PIECES[piece['type']]['chars'][piece['rotation']]
        self.buttons[i][j].config(text=char)

    def rotate_piece(self, i, j):
        self.board[i][j]['rotation'] = (self.board[i][j]['rotation'] + 1) % 4
        self.update_button(i, j)
        self.check_flow()

    def check_flow(self):
        # Resetea el color de todos los botones
        for i in range(self.board_size):
            for j in range(self.board_size):
                self.buttons[i][j].config(bg='SystemButtonFace')

        # Comienza a verificar el flujo desde la posición (0, 0)
        visited = [[False for _ in range(self.board_size)] for _ in range(self.board_size)]
        self.dfs_flow(0, 0, visited)

    def dfs_flow(self, i, j, visited):
        if i < 0 or i >= self.board_size or j < 0 or j >= self.board_size:
            return
        if visited[i][j]:
            return

        # Marca esta celda como visitada
        visited[i][j] = True

        # Colorea la celda actual como parte del flujo
        self.buttons[i][j].config(bg='lightblue')

        # Obtiene las conexiones de la pieza actual
        piece = self.board[i][j]
        connections = PIECES[piece['type']]['connections'][piece['rotation']]

        # Verifica en cada dirección si el flujo puede continuar
        directions = [(i-1, j, 0, 2), (i, j+1, 1, 3), (i+1, j, 2, 0), (i, j-1, 3, 1)]
        for ni, nj, cur_dir, opp_dir in directions:
            if 0 <= ni < self.board_size and 0 <= nj < self.board_size:
                neighbor_piece = self.board[ni][nj]
                neighbor_connections = PIECES[neighbor_piece['type']]['connections'][neighbor_piece['rotation']]
                if connections[cur_dir] == 1 and neighbor_connections[opp_dir] == 1:
                    self.dfs_flow(ni, nj, visited)

    def solve_dfs(self):
        messagebox.showinfo("Solve", "Solving with DFS...")
        # Implement DFS algorithm here
        # Placeholder for demonstration
        time.sleep(1)
        messagebox.showinfo("Result", "DFS Solution Found!")

    def solve_bfs(self):
        messagebox.showinfo("Solve", "Solving with BFS...")
        # Implement BFS algorithm here
        # Placeholder for demonstration
        time.sleep(1)
        messagebox.showinfo("Result", "BFS Solution Found!")

    def solve_a_star(self):
        messagebox.showinfo("Solve", "Solving with A*...")
        # Implement A* algorithm here
        # Placeholder for demonstration
        time.sleep(1)
        messagebox.showinfo("Result", "A* Solution Found!")

    def solve_ga(self):
        messagebox.showinfo("Solve", "Solving with Genetic Algorithm...")
        # Implement Genetic Algorithm here
        # Placeholder for demonstration
        time.sleep(1)
        messagebox.showinfo("Result", "GA Solution Found!")

if __name__ == "__main__":
    root = tk.Tk()
    app = PipePuzzleApp(root)
    root.mainloop()