parent
2ba106d939
commit
1334779dc2
@ -0,0 +1,170 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
"""
|
||||
Created on Sun May 11 10:32:04 2025
|
||||
|
||||
@author: Lenovo
|
||||
"""
|
||||
|
||||
import numpy as np
|
||||
import random
|
||||
import tkinter as tk
|
||||
from datetime import datetime
|
||||
from tkinter import simpledialog, filedialog
|
||||
from PIL import ImageGrab
|
||||
|
||||
|
||||
class Maze:
|
||||
def __init__(self, size=8, obstacle_prob=0.3):
|
||||
self.size = size
|
||||
self.obstacle_prob = obstacle_prob
|
||||
self.maze = self.generate_maze()
|
||||
self.path = []
|
||||
|
||||
def generate_maze(self):
|
||||
maze = np.zeros((self.size, self.size), dtype=int)
|
||||
for i in range(self.size):
|
||||
for j in range(self.size):
|
||||
if random.random() < self.obstacle_prob:
|
||||
maze[i][j] = 1
|
||||
maze[0][0] = 0
|
||||
maze[self.size - 1][self.size - 1] = 0
|
||||
return maze.tolist()
|
||||
|
||||
def is_valid_move(self, x, y):
|
||||
return 0 <= x < self.size and 0 <= y < self.size and self.maze[x][y] == 0
|
||||
|
||||
def solve_maze(self, strategy):
|
||||
self.path = []
|
||||
solver = strategy(self)
|
||||
return solver.solve()
|
||||
|
||||
|
||||
class DepthFirstSearchSolver:
|
||||
def __init__(self, maze):
|
||||
self.maze = maze
|
||||
self.path = []
|
||||
|
||||
def solve(self):
|
||||
if self.dfs(0, 0):
|
||||
return self.path
|
||||
else:
|
||||
return None
|
||||
|
||||
def dfs(self, x, y):
|
||||
if (x, y) == (self.maze.size - 1, self.maze.size - 1):
|
||||
self.path.append((x, y))
|
||||
return True
|
||||
|
||||
directions = [(-1, 0), (1, 0), (0, -1), (0, 1), (-1, -1), (-1, 1), (1, -1), (1, 1)]
|
||||
self.maze.maze[x][y] = 2 # Mark as visited (Previously path)
|
||||
self.path.append((x, y))
|
||||
|
||||
for d in directions:
|
||||
next_x, next_y = x + d[0], y + d[1]
|
||||
if self.maze.is_valid_move(next_x, next_y) and self.maze.maze[next_x][next_y] == 0:
|
||||
if self.dfs(next_x, next_y):
|
||||
return True
|
||||
|
||||
self.path.pop()
|
||||
return False
|
||||
|
||||
|
||||
class MazeApp:
|
||||
def __init__(self, root, maze_size=8, obstacle_prob=0.3):
|
||||
self.root = root
|
||||
self.maze_size = maze_size
|
||||
self.obstacle_prob = obstacle_prob
|
||||
self.maze = Maze(maze_size, obstacle_prob)
|
||||
|
||||
self.canvas = tk.Canvas(root, width=self.maze_size * 40, height=self.maze_size * 40)
|
||||
self.canvas.pack()
|
||||
self.button_frame = tk.Frame(root)
|
||||
self.button_frame.pack()
|
||||
|
||||
self.solve_button = tk.Button(self.button_frame, text="寻找路径", command=self.solve_maze)
|
||||
self.solve_button.grid(row=0, column=0)
|
||||
|
||||
self.new_maze_button = tk.Button(self.button_frame, text="生成新迷宫", command=self.generate_new_maze)
|
||||
self.new_maze_button.grid(row=0, column=1)
|
||||
|
||||
self.custom_settings_button = tk.Button(self.button_frame, text="设置迷宫参数", command=self.custom_settings)
|
||||
self.custom_settings_button.grid(row=0, column=2)
|
||||
|
||||
self.save_button = tk.Button(self.button_frame, text="保存迷宫", command=self.save_maze)
|
||||
self.save_button.grid(row=0, column=3)
|
||||
|
||||
self.reset_path_button = tk.Button(self.button_frame, text="重新设置路径", command=self.reset_path)
|
||||
self.reset_path_button.grid(row=0, column=4)
|
||||
|
||||
self.info_label = tk.Label(root, text="")
|
||||
self.info_label.pack()
|
||||
|
||||
self.draw_maze()
|
||||
|
||||
def draw_maze(self, path=None):
|
||||
self.canvas.delete("all")
|
||||
self.canvas.config(width=self.maze_size * 40, height=self.maze_size * 40)
|
||||
self.root.geometry(f"{self.maze_size * 40 + 40}x{self.maze_size * 40 + 80}") # Update window size
|
||||
|
||||
for i in range(self.maze_size):
|
||||
for j in range(self.maze_size):
|
||||
color = "white"
|
||||
if self.maze.maze[i][j] == 1:
|
||||
color = "grey"
|
||||
elif self.maze.maze[i][j] == 2:
|
||||
color = "light grey"
|
||||
self.canvas.create_rectangle(j * 40, i * 40, (j + 1) * 40, (i + 1) * 40, fill=color)
|
||||
|
||||
if path:
|
||||
for (x, y) in path:
|
||||
self.canvas.create_rectangle(y * 40 + 10, x * 40 + 10, (y + 1) * 40 - 10, (x + 1) * 40 - 10,
|
||||
fill="blue")
|
||||
|
||||
def solve_maze(self):
|
||||
start_time = datetime.now()
|
||||
solver = DepthFirstSearchSolver(self.maze)
|
||||
path = self.maze.solve_maze(DepthFirstSearchSolver)
|
||||
end_time = datetime.now()
|
||||
time_taken = (end_time - start_time).total_seconds()
|
||||
|
||||
if path:
|
||||
print("Path found:", path)
|
||||
self.draw_maze(path)
|
||||
self.info_label.config(text=f"Path found with length {len(path)} in {time_taken:.4f} seconds.")
|
||||
else:
|
||||
print("No path found")
|
||||
self.info_label.config(text="No path found.")
|
||||
|
||||
def generate_new_maze(self):
|
||||
self.maze = Maze(self.maze_size, self.obstacle_prob)
|
||||
self.info_label.config(text="")
|
||||
self.draw_maze()
|
||||
|
||||
def custom_settings(self):
|
||||
new_size = simpledialog.askinteger("Maze Size", "Enter maze size:", minvalue=5, maxvalue=50)
|
||||
new_prob = simpledialog.askfloat("Obstacle Probability", "Enter obstacle probability (0-1):", minvalue=0.0,
|
||||
maxvalue=1.0)
|
||||
if new_size and new_prob:
|
||||
self.maze_size = new_size
|
||||
self.obstacle_prob = new_prob
|
||||
self.generate_new_maze()
|
||||
|
||||
def save_maze(self):
|
||||
x = self.root.winfo_rootx() + self.canvas.winfo_x()
|
||||
y = self.root.winfo_rooty() + self.canvas.winfo_y()
|
||||
x1 = x + self.canvas.winfo_width()
|
||||
y1 = y + self.canvas.winfo_height()
|
||||
filename = filedialog.asksaveasfilename(defaultextension=".png",
|
||||
filetypes=[("PNG files", "*.png"), ("All files", "*.*")])
|
||||
if filename:
|
||||
ImageGrab.grab().crop((x, y, x1, y1)).save(filename)
|
||||
|
||||
def reset_path(self):
|
||||
self.info_label.config(text="")
|
||||
self.draw_maze()
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
root = tk.Tk()
|
||||
app = MazeApp(root)
|
||||
root.mainloop()
|
Loading…
Reference in new issue