# DFS: Depth First Search
import random
import tkinter as tk
import json
import time

class MazeGenerator:
    def __init__(self, width=10, height=10):
        self.width = width * 2 + 1  # Considera le pareti nel calcolo della larghezza
        self.height = height * 2 + 1  # Considera le pareti nel calcolo dell'altezza
        self.generate_maze()
        self.window = tk.Tk()
        self.window.title("Maze")
        self.canvas = tk.Canvas(self.window, width=self.width*10, height=self.height*10)
        self.canvas.pack()
        self.arrival_point = (self.width - 2, self.height - 2)  # Aggiorna il punto di arrivo
        self.backtrack = []

    def generate_maze(self):
        # Inizializza il labirinto con muri (True)
        self.maze = [[True for _ in range(self.width)] for _ in range(self.height)]
        
        # Definisci le direzioni (N, S, E, W)
        self.directions = [(-2, 0), (2, 0), (0, -2), (0, 2)]
        
        # Punto di partenza
        start_x, start_y = (1, 1)
        self.maze[start_y][start_x] = False
        self.stack = [(start_x, start_y)]

    def stack_iteration(self):
        if not self.stack:  # Check if the stack is empty
            return
        
        current_x, current_y = self.stack[-1]

        # Function to get the unvisited neighbors
        def get_unvisited_neighbors(x, y):
            time.sleep(0.005)
            neighbors = []
            if not (self.arrival_point == (x,y)):
                for dx, dy in self.directions:
                    nx, ny = x + dx, y + dy
                    if 1 <= nx < self.width - 1 and 1 <= ny < self.height - 1 and self.maze[ny][nx]:
                        neighbors.append((nx, ny))
            return neighbors

        neighbors = get_unvisited_neighbors(current_x, current_y)
        
        if neighbors:
            # Choose a random unvisited neighbor
            chosen_x, chosen_y = random.choice(neighbors)
            
            # Remove the wall between the current cell and the chosen cell
            self.maze[(current_y + chosen_y) // 2][(current_x + chosen_x) // 2] = False
            
            # Mark the chosen cell as visited
            self.maze[chosen_y][chosen_x] = False
            
            # Push the chosen cell to the stack
            self.stack.append((chosen_x, chosen_y))
        else:
            # Backtrack if no unvisited neighbors are found
            self.backtrack.append(self.stack.pop())

    def update_maze(self):
        self.stack_iteration()
        self.draw_maze()
        if self.stack:  # Continue updating only if there are cells left to visit
            self.window.after(10, self.update_maze)
        else:
            self.add_random_passages()
            self.draw_maze()
            with open('maze.json', 'w') as json_file:
                json.dump(self.maze, json_file)

    def add_random_passages(self):
        # Aggiungi passaggi casuali tra i corridoi
        for _ in range(30):
            x = random.randrange(1, self.width - 1, 2)
            y = random.randrange(1, self.height - 1, 2)
            print(x, y)
            self.maze[y][x] = False

    def draw_maze(self):
        self.canvas.delete("all")
        for i in range(self.height):
            for j in range(self.width):
                color = "black" if self.maze[i][j] else "white"
                # if (i, j) in self.backtrack:
                #     color="yellow"
                if (i, j) == self.arrival_point:
                    color = "green"  # Color the arrival point green
                elif (i, j) == (1 ,1):
                    color = "red"  # Color the arrival point green
                elif self.stack and (j, i) == self.stack[-1]:
                    color = "blue"  # Color the current position blue
                self.canvas.create_rectangle(j*10, i*10, (j+1)*10, (i+1)*10, fill=color)
                

    def run(self):
        self.update_maze()

        self.window.mainloop()

# Crea e avvia il generatore di labirinti
generator = MazeGenerator(15, 8)
generator.run()
