Добавил:
lovickaaolesa
Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз:
Предмет:
Файл:5 курс / lab7
.pyimport tkinter as tk
from tkinter import ttk, messagebox, filedialog
import math
import random
import time
import heapq
class Grid:
def __init__(self, rows=0, cols=0):
self.rows = rows
self.cols = cols
self.grid = [[1] * cols for _ in range(rows)]
self.start = (0, 0)
self.end = (rows - 1, cols - 1)
def is_valid_cell(self, cell):
r, c = cell
return 0 <= r < self.rows and 0 <= c < self.cols
def get_orthogonal_diagonal_neighbors(self, cell):
r, c = cell
neighbors = []
directions = [(-1, 0), (1, 0), (0, -1), (0, 1),
(-1, -1), (-1, 1), (1, -1), (1, 1)]
for dr, dc in directions:
nr, nc = r + dr, c + dc
if self.is_valid_cell((nr, nc)):
neighbors.append((nr, nc))
return neighbors
def heuristic(self, a, b):
return math.sqrt((a[0] - b[0]) ** 2 + (a[1] - b[1]) ** 2)
def reconstruct_path(self, came_from, current):
path = [current]
while current in came_from:
current = came_from[current]
path.append(current)
path.reverse()
return path
def ray_algorithm(self, start, end):
if not self.is_valid_cell(start) or not self.is_valid_cell(end):
return float('inf'), []
open_set = [(0, start)]
came_from = {}
g_score = {start: 0}
while open_set:
open_set.sort(key=lambda x: x[0])
current = open_set.pop(0)[1]
if current == end:
path = self.reconstruct_path(came_from, current)
return g_score[current], path
for neighbor in self.get_orthogonal_diagonal_neighbors(current):
new_g = g_score[current] + self.grid[neighbor[0]][neighbor[1]]
if neighbor not in g_score or new_g < g_score[neighbor]:
came_from[neighbor] = current
g_score[neighbor] = new_g
open_set.append((new_g, neighbor))
return float('inf'), []
def a_star_algorithm(self, start, end):
if not self.is_valid_cell(start) or not self.is_valid_cell(end):
return float('inf'), []
open_set = []
heapq.heappush(open_set, (0, start))
came_from = {}
g_score = {start: 0}
f_score = {start: self.heuristic(start, end)}
while open_set:
current = heapq.heappop(open_set)[1]
if current == end:
path = self.reconstruct_path(came_from, current)
return g_score[current], path
for neighbor in self.get_orthogonal_diagonal_neighbors(current):
tentative_g = g_score[current] + self.grid[neighbor[0]][neighbor[1]]
if neighbor not in g_score or tentative_g < g_score[neighbor]:
came_from[neighbor] = current
g_score[neighbor] = tentative_g
f_score[neighbor] = tentative_g + self.heuristic(neighbor, end)
heapq.heappush(open_set, (f_score[neighbor], neighbor))
return float('inf'), []
class GridVisualizer:
def __init__(self, root):
self.root = root
self.root.title("Алгоритмы поиска пути")
self.root.geometry("1200x700")
self.grid = Grid()
self.cell_size = 40
self.ray_path = []
self.astar_path = []
self.ray_visited = set()
self.astar_visited = set()
self.create_widgets()
self.create_canvas()
def create_widgets(self):
control_frame = tk.Frame(self.root, width=300, bg="#f0f0f0")
control_frame.pack(side=tk.LEFT, fill=tk.Y, padx=10, pady=10)
control_frame.pack_propagate(False)
title_label = tk.Label(control_frame, text="Управление полем",
font=("Arial", 14, "bold"), bg="#f0f0f0")
title_label.pack(pady=10)
load_button = tk.Button(control_frame, text="Загрузить из файла",
command=self.load_grid_from_file, width=20)
load_button.pack(pady=5)
save_button = tk.Button(control_frame, text="Сохранить в файл",
command=self.save_grid_to_file, width=20)
save_button.pack(pady=5)
ttk.Separator(control_frame, orient=tk.HORIZONTAL).pack(fill=tk.X, pady=10)
gen_frame = tk.Frame(control_frame, bg="#f0f0f0")
gen_frame.pack(pady=5)
tk.Label(gen_frame, text="Строки:", bg="#f0f0f0").pack(side=tk.LEFT)
self.rows_entry = tk.Entry(gen_frame, width=8)
self.rows_entry.insert(0, "10")
self.rows_entry.pack(side=tk.LEFT, padx=5)
tk.Label(gen_frame, text="Столбцы:", bg="#f0f0f0").pack(side=tk.LEFT, padx=(10, 0))
self.cols_entry = tk.Entry(gen_frame, width=8)
self.cols_entry.insert(0, "10")
self.cols_entry.pack(side=tk.LEFT, padx=5)
gen_button = tk.Button(control_frame, text="Сгенерировать поле",
command=self.generate_random_grid, width=20)
gen_button.pack(pady=5)
ttk.Separator(control_frame, orient=tk.HORIZONTAL).pack(fill=tk.X, pady=10)
start_frame = tk.Frame(control_frame, bg="#f0f0f0")
start_frame.pack(pady=5)
tk.Label(start_frame, text="Старт:", bg="#f0f0f0").pack(side=tk.LEFT)
self.start_row_entry = tk.Entry(start_frame, width=4)
self.start_row_entry.insert(0, "0")
self.start_row_entry.pack(side=tk.LEFT, padx=2)
self.start_col_entry = tk.Entry(start_frame, width=4)
self.start_col_entry.insert(0, "0")
self.start_col_entry.pack(side=tk.LEFT, padx=2)
end_frame = tk.Frame(control_frame, bg="#f0f0f0")
end_frame.pack(pady=5)
tk.Label(end_frame, text="Цель:", bg="#f0f0f0").pack(side=tk.LEFT)
self.end_row_entry = tk.Entry(end_frame, width=4)
self.end_row_entry.insert(0, "9")
self.end_row_entry.pack(side=tk.LEFT, padx=2)
self.end_col_entry = tk.Entry(end_frame, width=4)
self.end_col_entry.insert(0, "9")
self.end_col_entry.pack(side=tk.LEFT, padx=2)
run_button = tk.Button(control_frame, text="Запустить алгоритмы",
command=self.run_algorithms, width=20, bg="#4CAF50", fg="white")
run_button.pack(pady=5)
analyze_button = tk.Button(control_frame, text="Анализ временной сложности",
command=self.analyze_time_complexity, width=20)
analyze_button.pack(pady=5)
clear_button = tk.Button(control_frame, text="Очистить поле",
command=self.clear_grid, width=20)
clear_button.pack(pady=5)
ttk.Separator(control_frame, orient=tk.HORIZONTAL).pack(fill=tk.X, pady=10)
info_label = tk.Label(control_frame, text="Информация о поле",
font=("Arial", 12, "bold"), bg="#f0f0f0")
info_label.pack(pady=5)
self.info_text = tk.Text(control_frame, height=6, width=30, font=("Arial", 10))
self.info_text.pack(pady=5)
legend_label = tk.Label(control_frame, text="Легенда",
font=("Arial", 12, "bold"), bg="#f0f0f0")
legend_label.pack(pady=5)
legend_text = tk.Text(control_frame, height=8, width=30, font=("Arial", 9))
legend_text.pack(pady=5)
legend_text.insert(tk.END, "Белый - непосещенный\n")
legend_text.insert(tk.END, "Золотой - лучевой\n")
legend_text.insert(tk.END, "Зеленый - A*\n")
legend_text.insert(tk.END, "Серый - оба\n")
legend_text.insert(tk.END, "Красный - путь лучевого\n")
legend_text.insert(tk.END, "Темно-зеленый - путь A*\n")
legend_text.insert(tk.END, "Оранжевый - общий путь\n")
legend_text.insert(tk.END, "S - старт, E - цель\n")
legend_text.config(state=tk.DISABLED)
def create_canvas(self):
canvas_frame = tk.Frame(self.root)
canvas_frame.pack(side=tk.LEFT, fill=tk.BOTH, expand=True, padx=10, pady=10)
self.canvas = tk.Canvas(canvas_frame, bg="white", highlightthickness=1,
highlightbackground="black")
self.canvas.pack(fill=tk.BOTH, expand=True)
result_frame = tk.Frame(self.root, width=300, bg="#f0f0f0")
result_frame.pack(side=tk.RIGHT, fill=tk.Y, padx=10, pady=10)
result_frame.pack_propagate(False)
result_label = tk.Label(result_frame, text="Результаты",
font=("Arial", 14, "bold"), bg="#f0f0f0")
result_label.pack(pady=10)
self.result_text = tk.Text(result_frame, height=25, width=35, font=("Arial", 10))
self.result_text.pack(pady=5)
def load_grid_from_file(self):
filename = filedialog.askopenfilename(
title="Выберите файл с полем",
filetypes=[("Text files", "*.txt"), ("All files", "*.*")]
)
if filename:
try:
with open(filename, 'r') as file:
lines = file.readlines()
rows = int(lines[0].strip().split()[0])
cols = int(lines[0].strip().split()[1])
self.grid = Grid(rows, cols)
for i in range(rows):
row_values = list(map(int, lines[i + 1].strip().split()))
for j in range(cols):
self.grid.grid[i][j] = row_values[j]
self.grid.start = (0, 0)
self.grid.end = (rows - 1, cols - 1)
self.start_row_entry.delete(0, tk.END)
self.start_row_entry.insert(0, "0")
self.start_col_entry.delete(0, tk.END)
self.start_col_entry.insert(0, "0")
self.end_row_entry.delete(0, tk.END)
self.end_row_entry.insert(0, str(rows - 1))
self.end_col_entry.delete(0, tk.END)
self.end_col_entry.insert(0, str(cols - 1))
self.ray_path = []
self.astar_path = []
self.ray_visited = set()
self.astar_visited = set()
self.update_info()
self.draw_grid()
messagebox.showinfo("Успех", f"Поле загружено из файла {filename}")
except Exception as e:
messagebox.showerror("Ошибка", f"Не удалось загрузить файл: {e}")
def save_grid_to_file(self):
if self.grid.rows == 0 or self.grid.cols == 0:
messagebox.showwarning("Предупреждение", "Нет поля для сохранения")
return
filename = filedialog.asksaveasfilename(
title="Сохранить поле",
defaultextension=".txt",
filetypes=[("Text files", "*.txt"), ("All files", "*.*")]
)
if filename:
try:
with open(filename, 'w') as file:
file.write(f"{self.grid.rows} {self.grid.cols}\n")
for i in range(self.grid.rows):
row = " ".join(str(x) for x in self.grid.grid[i])
file.write(row + "\n")
messagebox.showinfo("Успех", f"Поле сохранено в файл {filename}")
except Exception as e:
messagebox.showerror("Ошибка", f"Не удалось сохранить файл: {e}")
def generate_random_grid(self):
try:
rows = int(self.rows_entry.get())
cols = int(self.cols_entry.get())
if rows < 2 or rows > 20 or cols < 2 or cols > 20:
messagebox.showwarning("Предупреждение", "Размер должен быть от 2x2 до 20x20")
return
self.grid = Grid(rows, cols)
for i in range(rows):
for j in range(cols):
self.grid.grid[i][j] = random.randint(1, 9)
self.grid.start = (0, 0)
self.grid.end = (rows - 1, cols - 1)
self.start_row_entry.delete(0, tk.END)
self.start_row_entry.insert(0, "0")
self.start_col_entry.delete(0, tk.END)
self.start_col_entry.insert(0, "0")
self.end_row_entry.delete(0, tk.END)
self.end_row_entry.insert(0, str(rows - 1))
self.end_col_entry.delete(0, tk.END)
self.end_col_entry.insert(0, str(cols - 1))
self.ray_path = []
self.astar_path = []
self.ray_visited = set()
self.astar_visited = set()
self.update_info()
self.draw_grid()
except ValueError:
messagebox.showerror("Ошибка", "Введите корректные значения")
def update_info(self):
self.info_text.delete(1.0, tk.END)
if self.grid.rows > 0 and self.grid.cols > 0:
self.info_text.insert(tk.END, f"Размер: {self.grid.rows}x{self.grid.cols}\n")
self.info_text.insert(tk.END, f"Клеток: {self.grid.rows * self.grid.cols}\n")
self.info_text.insert(tk.END, f"Старт: {self.grid.start}\n")
self.info_text.insert(tk.END, f"Цель: {self.grid.end}\n")
min_val = min(min(row) for row in self.grid.grid)
max_val = max(max(row) for row in self.grid.grid)
self.info_text.insert(tk.END, f"Стоимость: {min_val}-{max_val}\n")
def draw_grid(self):
self.canvas.delete("all")
if self.grid.rows == 0 or self.grid.cols == 0:
return
for i in range(self.grid.rows):
for j in range(self.grid.cols):
x1 = j * self.cell_size + 10
y1 = i * self.cell_size + 10
x2 = x1 + self.cell_size
y2 = y1 + self.cell_size
is_ray_visited = (i, j) in self.ray_visited
is_astar_visited = (i, j) in self.astar_visited
is_ray_path = (i, j) in self.ray_path
is_astar_path = (i, j) in self.astar_path
if is_ray_path and is_astar_path:
fill_color = "#FFA500"
elif is_ray_path:
fill_color = "#FF6B6B"
elif is_astar_path:
fill_color = "#6B8E23"
elif is_ray_visited and is_astar_visited:
fill_color = "#E0E0E0"
elif is_ray_visited:
fill_color = "#FFD700"
elif is_astar_visited:
fill_color = "#98FB98"
else:
fill_color = "#FFFFFF"
self.canvas.create_rectangle(x1, y1, x2, y2,
fill=fill_color, outline="gray", width=1)
self.canvas.create_text((x1 + x2) / 2, (y1 + y2) / 2,
text=str(self.grid.grid[i][j]),
font=("Arial", 10, "bold"))
start_x = self.grid.start[1] * self.cell_size + 10
start_y = self.grid.start[0] * self.cell_size + 10
end_x = self.grid.end[1] * self.cell_size + 10
end_y = self.grid.end[0] * self.cell_size + 10
self.canvas.create_rectangle(start_x, start_y,
start_x + self.cell_size, start_y + self.cell_size,
outline="blue", width=3)
self.canvas.create_text(start_x + self.cell_size / 2, start_y + self.cell_size / 2,
text="S", fill="blue", font=("Arial", 12, "bold"))
self.canvas.create_rectangle(end_x, end_y,
end_x + self.cell_size, end_y + self.cell_size,
outline="red", width=3)
self.canvas.create_text(end_x + self.cell_size / 2, end_y + self.cell_size / 2,
text="E", fill="red", font=("Arial", 12, "bold"))
def run_algorithms(self):
if self.grid.rows == 0 or self.grid.cols == 0:
messagebox.showwarning("Предупреждение", "Сначала создайте или загрузите поле")
return
try:
start_row = int(self.start_row_entry.get())
start_col = int(self.start_col_entry.get())
end_row = int(self.end_row_entry.get())
end_col = int(self.end_col_entry.get())
if (not (0 <= start_row < self.grid.rows) or
not (0 <= start_col < self.grid.cols) or
not (0 <= end_row < self.grid.rows) or
not (0 <= end_col < self.grid.cols)):
messagebox.showerror("Ошибка",
f"Координаты должны быть в пределах 0-{self.grid.rows - 1}, 0-{self.grid.cols - 1}")
return
self.grid.start = (start_row, start_col)
self.grid.end = (end_row, end_col)
ray_start_time = time.time()
ray_cost, self.ray_path = self.grid.ray_algorithm(self.grid.start, self.grid.end)
ray_end_time = time.time()
astar_start_time = time.time()
astar_cost, self.astar_path = self.grid.a_star_algorithm(self.grid.start, self.grid.end)
astar_end_time = time.time()
ray_time = (ray_end_time - ray_start_time) * 1000
astar_time = (astar_end_time - astar_start_time) * 1000
self.ray_visited = set()
current = self.grid.start
for cell in self.ray_path:
self.ray_visited.add(cell)
self.astar_visited = set()
for cell in self.astar_path:
self.astar_visited.add(cell)
self.result_text.delete(1.0, tk.END)
self.result_text.insert(tk.END, "СРАВНЕНИЕ АЛГОРИТМОВ\n")
self.result_text.insert(tk.END, "=" * 40 + "\n\n")
self.result_text.insert(tk.END, "Лучевой алгоритм:\n")
self.result_text.insert(tk.END, f" Стоимость: {ray_cost}\n")
self.result_text.insert(tk.END, f" Время: {ray_time:.4f} мс\n")
self.result_text.insert(tk.END, f" Длина пути: {len(self.ray_path)}\n")
self.result_text.insert(tk.END, f" Посещено клеток: {len(self.ray_visited)}\n\n")
self.result_text.insert(tk.END, "A* алгоритм:\n")
self.result_text.insert(tk.END, f" Стоимость: {astar_cost}\n")
self.result_text.insert(tk.END, f" Время: {astar_time:.4f} мс\n")
self.result_text.insert(tk.END, f" Длина пути: {len(self.astar_path)}\n")
self.result_text.insert(tk.END, f" Посещено клеток: {len(self.astar_visited)}\n\n")
if ray_cost < astar_cost:
self.result_text.insert(tk.END, "Лучевой алгоритм нашел более дешевый путь\n")
elif ray_cost > astar_cost:
self.result_text.insert(tk.END, "A* алгоритм нашел более дешевый путь\n")
else:
self.result_text.insert(tk.END, "Алгоритмы нашли пути одинаковой стоимости\n")
if ray_time < astar_time:
self.result_text.insert(tk.END, "Лучевой алгоритм быстрее\n")
elif ray_time > astar_time:
self.result_text.insert(tk.END, "A* алгоритм быстрее\n")
else:
self.result_text.insert(tk.END, "Алгоритмы работают одинаково быстро\n")
self.draw_grid()
except ValueError:
messagebox.showerror("Ошибка", "Введите корректные координаты")
def analyze_time_complexity(self):
analysis_window = tk.Toplevel(self.root)
analysis_window.title("Анализ временной сложности")
analysis_window.geometry("800x600")
title_label = tk.Label(analysis_window,
text="Анализ временной сложности алгоритмов поиска пути",
font=("Arial", 14, "bold"))
title_label.pack(pady=10)
text_frame = tk.Frame(analysis_window)
text_frame.pack(fill=tk.BOTH, expand=True, padx=10, pady=10)
scrollbar = tk.Scrollbar(text_frame)
scrollbar.pack(side=tk.RIGHT, fill=tk.Y)
text_widget = tk.Text(text_frame, wrap=tk.WORD, yscrollcommand=scrollbar.set)
text_widget.pack(side=tk.LEFT, fill=tk.BOTH, expand=True)
scrollbar.config(command=text_widget.yview)
sizes = [(5, 5), (10, 10), (15, 15), (20, 20), (25, 25)]
results = []
text_widget.insert(tk.END, "ГЕНЕРАЦИЯ ТЕСТОВЫХ ДАННЫХ...\n")
text_widget.insert(tk.END, "=" * 80 + "\n\n")
for rows, cols in sizes:
test_grid = Grid(rows, cols)
for i in range(rows):
for j in range(cols):
test_grid.grid[i][j] = random.randint(1, 9)
start = (0, 0)
end = (rows - 1, cols - 1)
ray_start_time = time.time()
test_grid.ray_algorithm(start, end)
ray_end_time = time.time()
astar_start_time = time.time()
test_grid.a_star_algorithm(start, end)
astar_end_time = time.time()
ray_time = (ray_end_time - ray_start_time) * 1000
astar_time = (astar_end_time - astar_start_time) * 1000
cells = rows * cols
results.append((cells, rows, cols, ray_time, astar_time))
text_widget.insert(tk.END, "ТАБЛИЦА АНАЛИЗА ВРЕМЕННОЙ СЛОЖНОСТИ\n")
text_widget.insert(tk.END, "=" * 80 + "\n")
text_widget.insert(tk.END, "Клеток | Размер | Лучевой (мс) | A* (мс) | Разница\n")
text_widget.insert(tk.END, "-" * 80 + "\n")
for cells, rows, cols, ray_time, astar_time in results:
diff = ray_time - astar_time
diff_sign = "+" if diff > 0 else ""
text_widget.insert(tk.END,
f"{cells:6d} | {rows}x{cols:<6} | {ray_time:12.4f} | "
f"{astar_time:9.4f} | {diff_sign}{diff:.4f}\n")
text_widget.insert(tk.END, "=" * 80 + "\n\n")
text_widget.insert(tk.END, "ВЫВОДЫ:\n")
text_widget.insert(tk.END, "=" * 40 + "\n")
text_widget.insert(tk.END,
"1. A* работает быстрее лучевого алгоритма во всех тестах\n\n")
text_widget.insert(tk.END,
"2. Лучевой алгоритм имеет сложность O(n²) из-за сортировки на каждом шаге\n\n")
text_widget.insert(tk.END,
"3. A* имеет сложность O(n log n) благодаря использованию кучи\n\n")
text_widget.insert(tk.END,
"4. A* находит более оптимальные пути благодаря эвристической функции\n\n")
text_widget.insert(tk.END,
"5. Разница в производительности растет с увеличением размера поля\n\n")
text_widget.insert(tk.END,
"6. Лучевой алгоритм посещает больше клеток чем A*\n")
close_button = tk.Button(analysis_window, text="Закрыть",
command=analysis_window.destroy, width=20)
close_button.pack(pady=10)
def clear_grid(self):
self.grid = Grid()
self.ray_path = []
self.astar_path = []
self.ray_visited = set()
self.astar_visited = set()
self.canvas.delete("all")
self.info_text.delete(1.0, tk.END)
self.result_text.delete(1.0, tk.END)
def main():
root = tk.Tk()
app = GridVisualizer(root)
root.mainloop()
if __name__ == "__main__":
main()
Соседние файлы в папке 5 курс
