Spaces:
Sleeping
Sleeping
Rebuild project without binary files
Browse files- A_Star.py +0 -39
- Bellman_Ford.py +0 -44
- Dijkstra.py +0 -49
- HUGGINGFACE_YUKLE.txt +28 -0
- README.md +23 -6
- app.py +70 -123
- docker-compose.yml +0 -11
- main.py +0 -87
- requirements.txt +1 -1
- run_local.sh +0 -30
- templates/index.html +253 -0
A_Star.py
DELETED
|
@@ -1,39 +0,0 @@
|
|
| 1 |
-
from heapq import *
|
| 2 |
-
|
| 3 |
-
# A* algoritmasında kullanılacak olan heuristik fonksiyon
|
| 4 |
-
def heuristic(a, b):
|
| 5 |
-
return abs(a[0] - b[0]) + abs(a[1] - b[1]) # A ile B arasındaki Manhattan mesafesi
|
| 6 |
-
|
| 7 |
-
# Yolu geri döndürmek için kullanılan fonksiyon
|
| 8 |
-
def reconstruct_path(came_from, current):
|
| 9 |
-
total_path = [current]
|
| 10 |
-
while current in came_from and came_from[current] is not None:
|
| 11 |
-
current = came_from[current]
|
| 12 |
-
total_path.append(current) # Yolun parçalarını sırayla ekle
|
| 13 |
-
return total_path[::-1] # Yolu ters çevir, böylece başlangıç -> hedef sırası olur
|
| 14 |
-
|
| 15 |
-
def a_star(graph, start, goal):
|
| 16 |
-
queue = []
|
| 17 |
-
heappush(queue, (0, start)) # Başlangıç düğümünü maliyet 0 ile kuyruğa ekle
|
| 18 |
-
g_score = {start: 0} # Başlangıç düğümünün maliyeti 0
|
| 19 |
-
came_from = {start: None} # Her düğümün nereden geldiğini takip etmek için
|
| 20 |
-
|
| 21 |
-
while queue:
|
| 22 |
-
_, current = heappop(queue) # En düşük maliyetli düğümü al
|
| 23 |
-
|
| 24 |
-
if current == goal:
|
| 25 |
-
return reconstruct_path(came_from, goal) # Hedefe ulaşıldıysa yolu geri döndür
|
| 26 |
-
|
| 27 |
-
# Mevcut düğümün komşularını dolaş
|
| 28 |
-
for neighbor_cost, neighbor in graph[current]:
|
| 29 |
-
tentative_g_score = g_score[current] + neighbor_cost # Komşuya ulaşmanın maliyetini hesapla
|
| 30 |
-
|
| 31 |
-
# Daha düşük maliyet bulunursa güncelle
|
| 32 |
-
if neighbor not in g_score or tentative_g_score < g_score[neighbor]:
|
| 33 |
-
g_score[neighbor] = tentative_g_score # En iyi g_score güncelle
|
| 34 |
-
f_score = tentative_g_score + heuristic(neighbor, goal) # Toplam maliyeti hesapla (g + h)
|
| 35 |
-
heappush(queue, (f_score, neighbor)) # Komşuyu öncelik sırasına ekle
|
| 36 |
-
came_from[neighbor] = current # Bu komşuya, mevcut düğümden gelindi
|
| 37 |
-
|
| 38 |
-
return None # Eğer hedefe ulaşılamazsa None döndür
|
| 39 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Bellman_Ford.py
DELETED
|
@@ -1,44 +0,0 @@
|
|
| 1 |
-
# kaynak: https://www.youtube.com/watch?v=24HziTZ8_xo
|
| 2 |
-
|
| 3 |
-
def bellman_ford(graph,başlangıç,hedef):
|
| 4 |
-
# Mesafeleri sonsuz olarak başlat
|
| 5 |
-
mesafeler = {node: float('infinity') for node in graph}
|
| 6 |
-
önceki = {node: None for node in graph} # Her düğümün öncesini kaydet
|
| 7 |
-
|
| 8 |
-
# Başlangıç düğümünün mesafesini sıfır olarak ayarla
|
| 9 |
-
mesafeler[başlangıç] = 0
|
| 10 |
-
|
| 11 |
-
# Döngü graftaki düğümlerin sayısının 1 eksiği kadar devam etmeli.
|
| 12 |
-
for _ in range(len(graph) - 1): # Düğüm sayısı - 1 kadar tekrar et
|
| 13 |
-
for i in graph: # Her düğüm üzerinde dolaş
|
| 14 |
-
for j in graph[i]: # Düğümün komşularına bak
|
| 15 |
-
hedef_dugum = j[1] # Hedef düğümü al
|
| 16 |
-
maliyet = j[0] # Kenar maliyetini al
|
| 17 |
-
|
| 18 |
-
# Eğer mevcut düğümün mesafesi sonsuz değilse ve komşuya olan mesafe daha düşükse güncelle
|
| 19 |
-
if mesafeler[i] != float('infinity') and (mesafeler[i] + maliyet < mesafeler[hedef_dugum]):
|
| 20 |
-
mesafeler[hedef_dugum] = mesafeler[i] + maliyet
|
| 21 |
-
önceki[hedef_dugum] = i # Önceki düğümü güncelle
|
| 22 |
-
|
| 23 |
-
# Negatif ağırlıklı döngü kontrolü
|
| 24 |
-
for i in graph:
|
| 25 |
-
for j in graph[i]:
|
| 26 |
-
hedef_dugum = j[1]
|
| 27 |
-
maliyet = j[0]
|
| 28 |
-
|
| 29 |
-
# Eğer hala bir iyileştirme yapılabiliyorsa negatif döngü vardır
|
| 30 |
-
if mesafeler[i] != float('infinity') and (mesafeler[i] + maliyet < mesafeler[hedef_dugum]):
|
| 31 |
-
return None # Negatif döngü bulunduktan sonra işlevi sonlandırın.
|
| 32 |
-
|
| 33 |
-
|
| 34 |
-
# En kısa yolu bulmak için hedeften başlangıca doğru git
|
| 35 |
-
yol = []
|
| 36 |
-
geçerli_dugum = hedef
|
| 37 |
-
|
| 38 |
-
while geçerli_dugum is not None:
|
| 39 |
-
yol.append(geçerli_dugum)
|
| 40 |
-
geçerli_dugum = önceki[geçerli_dugum]
|
| 41 |
-
|
| 42 |
-
# Yolu ters çevir ve döndür.
|
| 43 |
-
yol.reverse()
|
| 44 |
-
return yol
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Dijkstra.py
DELETED
|
@@ -1,49 +0,0 @@
|
|
| 1 |
-
def get_shortest_path(previous_nodes, start, target):
|
| 2 |
-
path = []
|
| 3 |
-
current_node = target
|
| 4 |
-
|
| 5 |
-
while current_node is not None:
|
| 6 |
-
path.insert(0, current_node) # Düğümü başa ekle
|
| 7 |
-
current_node = previous_nodes[current_node] # Bir önceki düğüme git
|
| 8 |
-
|
| 9 |
-
if path[0] == start:
|
| 10 |
-
return path
|
| 11 |
-
else:
|
| 12 |
-
return [] # Eğer yol yoksa boş liste döner
|
| 13 |
-
|
| 14 |
-
def dijkstra(graph, start,target):
|
| 15 |
-
# 1. Mesafe tablosu: Başlangıç düğümünden diğer düğümlere olan mesafeleri tutar
|
| 16 |
-
mesafeler = {node: float('infinity') for node in graph}
|
| 17 |
-
mesafeler[start] = 0
|
| 18 |
-
|
| 19 |
-
# 2. Ziyaret edilen düğümleri tutan liste
|
| 20 |
-
ziyaret_edilen = []
|
| 21 |
-
|
| 22 |
-
# 3. Önceki düğümleri tutan tablo: En kısa yolu oluşturmak için
|
| 23 |
-
önceki_düğümler = {node: None for node in graph}
|
| 24 |
-
|
| 25 |
-
while len(ziyaret_edilen) < len(graph):
|
| 26 |
-
# 4. Ziyaret edilmemiş düğümler arasında en kısa mesafeye sahip olanı seç
|
| 27 |
-
en_kısa_yol_düğümü = None
|
| 28 |
-
for node in mesafeler:
|
| 29 |
-
if node not in ziyaret_edilen:
|
| 30 |
-
if en_kısa_yol_düğümü is None:
|
| 31 |
-
en_kısa_yol_düğümü = node
|
| 32 |
-
elif mesafeler[node] < mesafeler[en_kısa_yol_düğümü]:
|
| 33 |
-
en_kısa_yol_düğümü = node
|
| 34 |
-
|
| 35 |
-
if en_kısa_yol_düğümü is None:
|
| 36 |
-
break # Tüm düğümler ziyaret edilmişse ya da ulaşılamayan düğümler kalmışsa döngüyü sonlandır
|
| 37 |
-
|
| 38 |
-
# 5. Seçilen düğümün komşularının mesafelerini güncelle
|
| 39 |
-
for ağırlık,komşu in graph[en_kısa_yol_düğümü]:
|
| 40 |
-
|
| 41 |
-
yeni_mesafe = mesafeler[en_kısa_yol_düğümü] + ağırlık
|
| 42 |
-
if yeni_mesafe < mesafeler[komşu]:
|
| 43 |
-
mesafeler[komşu] = yeni_mesafe
|
| 44 |
-
önceki_düğümler[komşu] = en_kısa_yol_düğümü
|
| 45 |
-
|
| 46 |
-
# 6. Seçilen düğümü ziyaret edilmiş olarak işaretle
|
| 47 |
-
ziyaret_edilen.append(en_kısa_yol_düğümü)
|
| 48 |
-
|
| 49 |
-
return get_shortest_path(önceki_düğümler, start, target)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
HUGGINGFACE_YUKLE.txt
ADDED
|
@@ -0,0 +1,28 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
🚀 HUGGING FACE SPACES'E YÜKLEME
|
| 2 |
+
|
| 3 |
+
Bu klasördeki TÜM dosya ve klasörleri Hugging Face'e yükleyin.
|
| 4 |
+
|
| 5 |
+
📁 YÜKLENECEK DOSYALAR:
|
| 6 |
+
|
| 7 |
+
├── app.py
|
| 8 |
+
├── Dockerfile
|
| 9 |
+
├── README.md
|
| 10 |
+
├── requirements.txt
|
| 11 |
+
├── static/
|
| 12 |
+
│ └── images/
|
| 13 |
+
│ └── map.jpg
|
| 14 |
+
└── templates/
|
| 15 |
+
└── index.html
|
| 16 |
+
|
| 17 |
+
🎯 ADIMLAR:
|
| 18 |
+
|
| 19 |
+
1. https://huggingface.co/new-space
|
| 20 |
+
2. SDK: DOCKER seçin
|
| 21 |
+
3. Tüm dosyaları yükleyin
|
| 22 |
+
4. Build bekleyin (5-10 dakika)
|
| 23 |
+
5. Hazır!
|
| 24 |
+
|
| 25 |
+
✅ KONTROL:
|
| 26 |
+
- Sayfa açılır açılmaz resim üzerinde path göreceksiniz
|
| 27 |
+
- Algoritma seçebileceksiniz
|
| 28 |
+
- Slider ile start/goal ayarlayabileceksiniz
|
README.md
CHANGED
|
@@ -1,12 +1,29 @@
|
|
| 1 |
---
|
| 2 |
-
title:
|
| 3 |
-
emoji:
|
| 4 |
-
colorFrom:
|
| 5 |
-
colorTo:
|
| 6 |
sdk: docker
|
|
|
|
| 7 |
pinned: false
|
| 8 |
license: mit
|
| 9 |
-
short_description: '``` Interactive pathfinding algorithm visualizer with A*, Di'
|
| 10 |
---
|
| 11 |
|
| 12 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
---
|
| 2 |
+
title: Path Finding Algorithms
|
| 3 |
+
emoji: 🗺️
|
| 4 |
+
colorFrom: blue
|
| 5 |
+
colorTo: green
|
| 6 |
sdk: docker
|
| 7 |
+
app_port: 7860
|
| 8 |
pinned: false
|
| 9 |
license: mit
|
|
|
|
| 10 |
---
|
| 11 |
|
| 12 |
+
# 🗺️ Path Finding Algorithms Visualizer
|
| 13 |
+
|
| 14 |
+
Interactive pathfinding visualization with **A\***, **Dijkstra**, and **Bellman-Ford** algorithms on a custom map.
|
| 15 |
+
|
| 16 |
+
## 🚀 How to Use
|
| 17 |
+
|
| 18 |
+
1. **Select Algorithm**: A*, Dijkstra, or Bellman-Ford
|
| 19 |
+
2. **Set Start Position**: X and Y sliders
|
| 20 |
+
3. **Set Goal Position**: X and Y sliders
|
| 21 |
+
4. **Find Path**: Click button to visualize
|
| 22 |
+
|
| 23 |
+
## 📊 Algorithms
|
| 24 |
+
|
| 25 |
+
- **A\***: Fastest with heuristic
|
| 26 |
+
- **Dijkstra**: Classic shortest path
|
| 27 |
+
- **Bellman-Ford**: Handles negative weights
|
| 28 |
+
|
| 29 |
+
Built with Python, Flask, and Matplotlib
|
app.py
CHANGED
|
@@ -1,17 +1,19 @@
|
|
| 1 |
-
import
|
| 2 |
import numpy as np
|
| 3 |
import matplotlib
|
| 4 |
-
matplotlib.use('Agg')
|
| 5 |
import matplotlib.pyplot as plt
|
| 6 |
from matplotlib.patches import Rectangle
|
| 7 |
from heapq import heappush, heappop
|
| 8 |
import io
|
| 9 |
from PIL import Image
|
| 10 |
import os
|
|
|
|
| 11 |
|
| 12 |
-
# Matplotlib config directory
|
| 13 |
os.environ['MPLCONFIGDIR'] = '/tmp/matplotlib'
|
| 14 |
|
|
|
|
|
|
|
| 15 |
# Grid tanımı
|
| 16 |
GRID = [[4, 4, 4, 4, 4, 4, 4, 2, 3, 2, 4, 2],
|
| 17 |
[4, 4, 4, 4, 9, 9, 3, 2, 2, 4, 4, 4],
|
|
@@ -24,7 +26,6 @@ GRID = [[4, 4, 4, 4, 4, 4, 4, 2, 3, 2, 4, 2],
|
|
| 24 |
|
| 25 |
COLS, ROWS = 12, 8
|
| 26 |
|
| 27 |
-
# Graph oluştur
|
| 28 |
def create_graph(grid):
|
| 29 |
graph = {}
|
| 30 |
for y in range(len(grid)):
|
|
@@ -39,7 +40,6 @@ def create_graph(grid):
|
|
| 39 |
|
| 40 |
GRAPH = create_graph(GRID)
|
| 41 |
|
| 42 |
-
# A* Algoritması
|
| 43 |
def heuristic(a, b):
|
| 44 |
return abs(a[0] - b[0]) + abs(a[1] - b[1])
|
| 45 |
|
|
@@ -70,7 +70,6 @@ def a_star(graph, start, goal):
|
|
| 70 |
|
| 71 |
return None
|
| 72 |
|
| 73 |
-
# Dijkstra Algoritması
|
| 74 |
def dijkstra(graph, start, goal):
|
| 75 |
distances = {node: float('infinity') for node in graph}
|
| 76 |
distances[start] = 0
|
|
@@ -103,7 +102,6 @@ def dijkstra(graph, start, goal):
|
|
| 103 |
|
| 104 |
return path if path[0] == start else None
|
| 105 |
|
| 106 |
-
# Bellman-Ford Algoritması
|
| 107 |
def bellman_ford(graph, start, goal):
|
| 108 |
distances = {node: float('infinity') for node in graph}
|
| 109 |
previous = {node: None for node in graph}
|
|
@@ -125,97 +123,78 @@ def bellman_ford(graph, start, goal):
|
|
| 125 |
path.reverse()
|
| 126 |
return path if path and path[0] == start else None
|
| 127 |
|
| 128 |
-
# Görselleştirme
|
| 129 |
def visualize_path(start_x, start_y, goal_x, goal_y, algorithm):
|
| 130 |
-
start = (start_x, start_y)
|
| 131 |
-
goal = (goal_x, goal_y)
|
| 132 |
|
| 133 |
-
# Algoritma seçimi
|
| 134 |
if algorithm == "A*":
|
| 135 |
path = a_star(GRAPH, start, goal)
|
| 136 |
-
color = '#
|
| 137 |
title = "A* Algorithm"
|
| 138 |
elif algorithm == "Dijkstra":
|
| 139 |
path = dijkstra(GRAPH, start, goal)
|
| 140 |
-
color = '#
|
| 141 |
title = "Dijkstra Algorithm"
|
| 142 |
-
else:
|
| 143 |
path = bellman_ford(GRAPH, start, goal)
|
| 144 |
-
color = '#
|
| 145 |
title = "Bellman-Ford Algorithm"
|
| 146 |
|
| 147 |
-
#
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 148 |
fig, ax = plt.subplots(figsize=(14, 8))
|
| 149 |
|
| 150 |
-
#
|
| 151 |
-
|
| 152 |
-
for x in range(COLS):
|
| 153 |
-
cost = GRID[y][x]
|
| 154 |
-
# Maliyet değerine göre renk
|
| 155 |
-
if cost == 1:
|
| 156 |
-
cell_color = '#E8F5E9'
|
| 157 |
-
elif cost <= 3:
|
| 158 |
-
cell_color = '#FFF9C4'
|
| 159 |
-
elif cost <= 6:
|
| 160 |
-
cell_color = '#FFE0B2'
|
| 161 |
-
else:
|
| 162 |
-
cell_color = '#FFCDD2'
|
| 163 |
-
|
| 164 |
-
rect = Rectangle((x, ROWS - y - 1), 1, 1,
|
| 165 |
-
facecolor=cell_color,
|
| 166 |
-
edgecolor='gray',
|
| 167 |
-
linewidth=0.5)
|
| 168 |
-
ax.add_patch(rect)
|
| 169 |
-
|
| 170 |
-
# Maliyet değerini yaz
|
| 171 |
-
ax.text(x + 0.5, ROWS - y - 0.5, str(cost),
|
| 172 |
-
ha='center', va='center',
|
| 173 |
-
fontsize=10, color='#424242', weight='bold')
|
| 174 |
|
| 175 |
-
#
|
| 176 |
if path:
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 177 |
for i, (x, y) in enumerate(path):
|
| 178 |
if (x, y) == start:
|
| 179 |
-
|
| 180 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 181 |
elif (x, y) == goal:
|
| 182 |
-
|
| 183 |
-
|
| 184 |
-
|
| 185 |
-
|
| 186 |
-
|
| 187 |
-
|
| 188 |
-
|
| 189 |
-
color=circle_color, zorder=10)
|
| 190 |
-
ax.add_patch(circle)
|
| 191 |
|
| 192 |
path_length = sum(GRID[y][x] for x, y in path[1:])
|
| 193 |
-
info_text = f"
|
| 194 |
else:
|
| 195 |
-
info_text = "
|
| 196 |
|
| 197 |
ax.set_xlim(0, COLS)
|
| 198 |
ax.set_ylim(0, ROWS)
|
| 199 |
ax.set_aspect('equal')
|
| 200 |
ax.axis('off')
|
| 201 |
-
ax.
|
| 202 |
-
|
| 203 |
-
|
| 204 |
-
|
| 205 |
-
legend_elements = [
|
| 206 |
-
Patch(facecolor='#4CAF50', label='Start'),
|
| 207 |
-
Patch(facecolor='#F44336', label='Goal'),
|
| 208 |
-
Patch(facecolor=color, label='Path'),
|
| 209 |
-
Patch(facecolor='#E8F5E9', label='Low Cost (1)'),
|
| 210 |
-
Patch(facecolor='#FFF9C4', label='Medium Cost (2-3)'),
|
| 211 |
-
Patch(facecolor='#FFE0B2', label='High Cost (4-6)'),
|
| 212 |
-
Patch(facecolor='#FFCDD2', label='Very High Cost (7-9)')
|
| 213 |
-
]
|
| 214 |
-
ax.legend(handles=legend_elements, loc='upper left', bbox_to_anchor=(1, 1))
|
| 215 |
|
| 216 |
plt.tight_layout()
|
| 217 |
|
| 218 |
-
# PIL Image'e çevir
|
| 219 |
buf = io.BytesIO()
|
| 220 |
plt.savefig(buf, format='png', dpi=100, bbox_inches='tight')
|
| 221 |
buf.seek(0)
|
|
@@ -224,60 +203,28 @@ def visualize_path(start_x, start_y, goal_x, goal_y, algorithm):
|
|
| 224 |
|
| 225 |
return img
|
| 226 |
|
| 227 |
-
|
| 228 |
-
|
| 229 |
-
|
| 230 |
-
|
| 231 |
-
|
| 232 |
-
|
| 233 |
-
|
| 234 |
-
|
| 235 |
-
|
| 236 |
-
|
| 237 |
-
|
| 238 |
-
|
| 239 |
-
|
| 240 |
-
|
| 241 |
-
|
| 242 |
-
|
| 243 |
-
|
| 244 |
-
|
| 245 |
-
|
| 246 |
-
|
| 247 |
-
label="Algorithm"
|
| 248 |
-
)
|
| 249 |
-
|
| 250 |
-
with gr.Row():
|
| 251 |
-
start_x = gr.Slider(0, 11, value=0, step=1, label="Start X")
|
| 252 |
-
start_y = gr.Slider(0, 7, value=7, step=1, label="Start Y")
|
| 253 |
-
|
| 254 |
-
with gr.Row():
|
| 255 |
-
goal_x = gr.Slider(0, 11, value=11, step=1, label="Goal X")
|
| 256 |
-
goal_y = gr.Slider(0, 7, value=0, step=1, label="Goal Y")
|
| 257 |
-
|
| 258 |
-
find_btn = gr.Button("🔍 Find Path", variant="primary", size="lg")
|
| 259 |
-
|
| 260 |
-
gr.Markdown("""
|
| 261 |
-
### 📝 Info:
|
| 262 |
-
- **Grid Size**: 12x8
|
| 263 |
-
- **Cost Range**: 1-9
|
| 264 |
-
- **Green**: Start point
|
| 265 |
-
- **Red**: Goal point
|
| 266 |
-
- **Blue/Orange/Red**: Path (depends on algorithm)
|
| 267 |
-
""")
|
| 268 |
-
|
| 269 |
-
with gr.Column(scale=2):
|
| 270 |
-
output_image = gr.Image(label="Visualization", type="pil")
|
| 271 |
|
| 272 |
-
|
| 273 |
-
fn=visualize_path,
|
| 274 |
-
inputs=[start_x, start_y, goal_x, goal_y, algorithm],
|
| 275 |
-
outputs=output_image
|
| 276 |
-
)
|
| 277 |
|
| 278 |
if __name__ == "__main__":
|
| 279 |
-
|
| 280 |
-
server_name="0.0.0.0",
|
| 281 |
-
server_port=7860,
|
| 282 |
-
share=False
|
| 283 |
-
)
|
|
|
|
| 1 |
+
from flask import Flask, render_template, request, jsonify, send_file
|
| 2 |
import numpy as np
|
| 3 |
import matplotlib
|
| 4 |
+
matplotlib.use('Agg')
|
| 5 |
import matplotlib.pyplot as plt
|
| 6 |
from matplotlib.patches import Rectangle
|
| 7 |
from heapq import heappush, heappop
|
| 8 |
import io
|
| 9 |
from PIL import Image
|
| 10 |
import os
|
| 11 |
+
import base64
|
| 12 |
|
|
|
|
| 13 |
os.environ['MPLCONFIGDIR'] = '/tmp/matplotlib'
|
| 14 |
|
| 15 |
+
app = Flask(__name__)
|
| 16 |
+
|
| 17 |
# Grid tanımı
|
| 18 |
GRID = [[4, 4, 4, 4, 4, 4, 4, 2, 3, 2, 4, 2],
|
| 19 |
[4, 4, 4, 4, 9, 9, 3, 2, 2, 4, 4, 4],
|
|
|
|
| 26 |
|
| 27 |
COLS, ROWS = 12, 8
|
| 28 |
|
|
|
|
| 29 |
def create_graph(grid):
|
| 30 |
graph = {}
|
| 31 |
for y in range(len(grid)):
|
|
|
|
| 40 |
|
| 41 |
GRAPH = create_graph(GRID)
|
| 42 |
|
|
|
|
| 43 |
def heuristic(a, b):
|
| 44 |
return abs(a[0] - b[0]) + abs(a[1] - b[1])
|
| 45 |
|
|
|
|
| 70 |
|
| 71 |
return None
|
| 72 |
|
|
|
|
| 73 |
def dijkstra(graph, start, goal):
|
| 74 |
distances = {node: float('infinity') for node in graph}
|
| 75 |
distances[start] = 0
|
|
|
|
| 102 |
|
| 103 |
return path if path[0] == start else None
|
| 104 |
|
|
|
|
| 105 |
def bellman_ford(graph, start, goal):
|
| 106 |
distances = {node: float('infinity') for node in graph}
|
| 107 |
previous = {node: None for node in graph}
|
|
|
|
| 123 |
path.reverse()
|
| 124 |
return path if path and path[0] == start else None
|
| 125 |
|
|
|
|
| 126 |
def visualize_path(start_x, start_y, goal_x, goal_y, algorithm):
|
| 127 |
+
start = (int(start_x), int(start_y))
|
| 128 |
+
goal = (int(goal_x), int(goal_y))
|
| 129 |
|
|
|
|
| 130 |
if algorithm == "A*":
|
| 131 |
path = a_star(GRAPH, start, goal)
|
| 132 |
+
color = '#00FF00'
|
| 133 |
title = "A* Algorithm"
|
| 134 |
elif algorithm == "Dijkstra":
|
| 135 |
path = dijkstra(GRAPH, start, goal)
|
| 136 |
+
color = '#FFA500'
|
| 137 |
title = "Dijkstra Algorithm"
|
| 138 |
+
else:
|
| 139 |
path = bellman_ford(GRAPH, start, goal)
|
| 140 |
+
color = '#FF0000'
|
| 141 |
title = "Bellman-Ford Algorithm"
|
| 142 |
|
| 143 |
+
# Arka plan resmini yükle
|
| 144 |
+
bg_img = Image.open('static/images/map.jpg')
|
| 145 |
+
bg_width, bg_height = bg_img.size
|
| 146 |
+
|
| 147 |
+
# Her hücrenin piksel boyutu
|
| 148 |
+
tile_width = bg_width / COLS
|
| 149 |
+
tile_height = bg_height / ROWS
|
| 150 |
+
|
| 151 |
fig, ax = plt.subplots(figsize=(14, 8))
|
| 152 |
|
| 153 |
+
# Arka plan resmini göster
|
| 154 |
+
ax.imshow(bg_img, extent=[0, COLS, 0, ROWS], aspect='auto')
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 155 |
|
| 156 |
+
# Path'i çiz
|
| 157 |
if path:
|
| 158 |
+
# Path çizgisi
|
| 159 |
+
path_x = [x + 0.5 for x, y in path]
|
| 160 |
+
path_y = [ROWS - y - 0.5 for x, y in path]
|
| 161 |
+
ax.plot(path_x, path_y, color=color, linewidth=4, alpha=0.7, zorder=5)
|
| 162 |
+
|
| 163 |
+
# Start ve goal noktaları
|
| 164 |
for i, (x, y) in enumerate(path):
|
| 165 |
if (x, y) == start:
|
| 166 |
+
circle = plt.Circle((x + 0.5, ROWS - y - 0.5), 0.4,
|
| 167 |
+
color='#00FF00', edgecolor='white',
|
| 168 |
+
linewidth=3, zorder=10)
|
| 169 |
+
ax.add_patch(circle)
|
| 170 |
+
ax.text(x + 0.5, ROWS - y - 0.5, 'S',
|
| 171 |
+
ha='center', va='center',
|
| 172 |
+
fontsize=14, color='white', weight='bold', zorder=11)
|
| 173 |
elif (x, y) == goal:
|
| 174 |
+
circle = plt.Circle((x + 0.5, ROWS - y - 0.5), 0.4,
|
| 175 |
+
color='#FF0000', edgecolor='white',
|
| 176 |
+
linewidth=3, zorder=10)
|
| 177 |
+
ax.add_patch(circle)
|
| 178 |
+
ax.text(x + 0.5, ROWS - y - 0.5, 'G',
|
| 179 |
+
ha='center', va='center',
|
| 180 |
+
fontsize=14, color='white', weight='bold', zorder=11)
|
|
|
|
|
|
|
| 181 |
|
| 182 |
path_length = sum(GRID[y][x] for x, y in path[1:])
|
| 183 |
+
info_text = f"{title}\nPath: {len(path)} nodes | Cost: {path_length}"
|
| 184 |
else:
|
| 185 |
+
info_text = f"{title}\nNo path found!"
|
| 186 |
|
| 187 |
ax.set_xlim(0, COLS)
|
| 188 |
ax.set_ylim(0, ROWS)
|
| 189 |
ax.set_aspect('equal')
|
| 190 |
ax.axis('off')
|
| 191 |
+
ax.text(COLS/2, ROWS + 0.5, info_text,
|
| 192 |
+
ha='center', va='bottom',
|
| 193 |
+
fontsize=14, weight='bold',
|
| 194 |
+
bbox=dict(boxstyle='round', facecolor='white', alpha=0.8))
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 195 |
|
| 196 |
plt.tight_layout()
|
| 197 |
|
|
|
|
| 198 |
buf = io.BytesIO()
|
| 199 |
plt.savefig(buf, format='png', dpi=100, bbox_inches='tight')
|
| 200 |
buf.seek(0)
|
|
|
|
| 203 |
|
| 204 |
return img
|
| 205 |
|
| 206 |
+
@app.route('/')
|
| 207 |
+
def index():
|
| 208 |
+
return render_template('index.html')
|
| 209 |
+
|
| 210 |
+
@app.route('/find_path', methods=['POST'])
|
| 211 |
+
def find_path():
|
| 212 |
+
data = request.json
|
| 213 |
+
start_x = int(data['start_x'])
|
| 214 |
+
start_y = int(data['start_y'])
|
| 215 |
+
goal_x = int(data['goal_x'])
|
| 216 |
+
goal_y = int(data['goal_y'])
|
| 217 |
+
algorithm = data['algorithm']
|
| 218 |
+
|
| 219 |
+
img = visualize_path(start_x, start_y, goal_x, goal_y, algorithm)
|
| 220 |
+
|
| 221 |
+
# PIL Image'i base64'e çevir
|
| 222 |
+
buf = io.BytesIO()
|
| 223 |
+
img.save(buf, format='PNG')
|
| 224 |
+
buf.seek(0)
|
| 225 |
+
img_base64 = base64.b64encode(buf.getvalue()).decode('utf-8')
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 226 |
|
| 227 |
+
return jsonify({'image': f'data:image/png;base64,{img_base64}'})
|
|
|
|
|
|
|
|
|
|
|
|
|
| 228 |
|
| 229 |
if __name__ == "__main__":
|
| 230 |
+
app.run(host="0.0.0.0", port=7860, debug=False)
|
|
|
|
|
|
|
|
|
|
|
|
docker-compose.yml
DELETED
|
@@ -1,11 +0,0 @@
|
|
| 1 |
-
version: '3.8'
|
| 2 |
-
|
| 3 |
-
services:
|
| 4 |
-
pathfinding:
|
| 5 |
-
build: .
|
| 6 |
-
ports:
|
| 7 |
-
- "7860:7860"
|
| 8 |
-
environment:
|
| 9 |
-
- GRADIO_SERVER_NAME=0.0.0.0
|
| 10 |
-
- GRADIO_SERVER_PORT=7860
|
| 11 |
-
restart: unless-stopped
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
main.py
DELETED
|
@@ -1,87 +0,0 @@
|
|
| 1 |
-
import pygame as pg
|
| 2 |
-
from heapq import *
|
| 3 |
-
from A_Star import a_star
|
| 4 |
-
from Dijkstra import dijkstra
|
| 5 |
-
from Bellman_Ford import bellman_ford
|
| 6 |
-
|
| 7 |
-
# Konumun merkezine yerleştirilen çemberin pozisyonunu döndürüyor
|
| 8 |
-
def get_circle(x, y):
|
| 9 |
-
return (x * TILE + TILE // 2, y * TILE + TILE // 2), TILE // 7 # Çemberin merkezini ve yarıçapını döndür
|
| 10 |
-
|
| 11 |
-
# Komşu hücreleri kontrol ediyor
|
| 12 |
-
def neighbor_control(x, y):
|
| 13 |
-
# Komşuların hangi yönlerde olduğunu belirleyen liste (sol, yukarı, sağ, aşağı)
|
| 14 |
-
ways = [-1, 0], [0, -1], [1, 0], [0, 1]
|
| 15 |
-
neighbor = []
|
| 16 |
-
|
| 17 |
-
for dx, dy in ways:
|
| 18 |
-
new_dx, new_dy = x + dx, y + dy
|
| 19 |
-
# Komşu hücrelerin oyun alanı sınırları içinde olup olmadığını kontrol et
|
| 20 |
-
if cols > new_dx >= 0 and rows > new_dy >= 0:
|
| 21 |
-
neighbor.append((grid[new_dy][new_dx], (new_dx, new_dy))) # Geçerli komşuyu listeye ekle
|
| 22 |
-
return neighbor
|
| 23 |
-
|
| 24 |
-
# Fare ile tıklanan hücreyi seçiyor.
|
| 25 |
-
def get_click_mouse_pos():
|
| 26 |
-
x, y = pg.mouse.get_pos() # Fare imlecinin konumunu al
|
| 27 |
-
grid_x, grid_y = x // TILE, y // TILE # Imlecin bulunduğu grid hücresini bul
|
| 28 |
-
pg.draw.circle(sc, pg.Color('black'), * ((grid_x * TILE + TILE // 2, grid_y * TILE + TILE // 2), TILE // 7)) # Hücrede kırmızı çember çiz
|
| 29 |
-
click = pg.mouse.get_pressed() # Fare tıklaması kontrolü
|
| 30 |
-
return (grid_x, grid_y) if click[0] else False # Sol tıklama yapılmışsa pozisyonu döndür, aksi halde False döndür
|
| 31 |
-
|
| 32 |
-
# Oyun alanının boyutları (kolonlar, satırlar ve hücre boyutu)
|
| 33 |
-
cols, rows = 12, 8
|
| 34 |
-
TILE = 70 # Her bir hücrenin piksel boyutu
|
| 35 |
-
|
| 36 |
-
# Pygame başlatma ve ekran ayarlama
|
| 37 |
-
pg.init()
|
| 38 |
-
sc = pg.display.set_mode([cols * TILE, rows * TILE])
|
| 39 |
-
clock = pg.time.Clock()
|
| 40 |
-
|
| 41 |
-
# Oyun alanı için grid oluşturma (her hücrede maliyetler)
|
| 42 |
-
grid = [[4, 4, 4, 4, 4, 4, 4, 2, 3, 2, 4, 2],
|
| 43 |
-
[4, 4, 4, 4, 9, 9, 3, 2, 2, 4, 4, 4],
|
| 44 |
-
[4, 4, 2, 4, 2, 2, 2, 1, 1, 9, 9, 4],
|
| 45 |
-
[4, 2, 2, 4, 2, 2, 1, 1, 1, 4, 4, 2],
|
| 46 |
-
[1, 1, 2, 1, 1, 1, 1, 9, 1, 1, 1, 1],
|
| 47 |
-
[4, 1, 2, 1, 9, 2, 1, 1, 1, 9, 2, 2],
|
| 48 |
-
[4, 1, 4, 1, 2, 4, 4, 1, 1, 4, 4, 2],
|
| 49 |
-
[1, 1, 1, 1, 2, 4, 2, 2, 1, 2, 3, 2]]
|
| 50 |
-
|
| 51 |
-
# Oyun alanı için graph oluşturma (komşuluk ilişkileri ile)
|
| 52 |
-
graph = {}
|
| 53 |
-
for y, row in enumerate(grid):
|
| 54 |
-
for x, col in enumerate(row):
|
| 55 |
-
graph[(x, y)] = graph.get((x, y), []) + neighbor_control(x, y)
|
| 56 |
-
|
| 57 |
-
# Başlangıç ve hedef konum
|
| 58 |
-
start = (0, 7)
|
| 59 |
-
goal = start
|
| 60 |
-
visited = []
|
| 61 |
-
|
| 62 |
-
# Arka plan resmi yükleme ve ölçeklendirme
|
| 63 |
-
bg = pg.image.load('./resim/map.jpg').convert()
|
| 64 |
-
bg = pg.transform.scale(bg, (cols * TILE, rows * TILE))
|
| 65 |
-
|
| 66 |
-
# Oyun döngüsü
|
| 67 |
-
while True:
|
| 68 |
-
|
| 69 |
-
sc.blit(bg, (0, 0))
|
| 70 |
-
mouse_pos = get_click_mouse_pos()
|
| 71 |
-
if mouse_pos:
|
| 72 |
-
#visited = a_star(graph, start, mouse_pos) # A* algoritmasını çalıştır ve yolu bul
|
| 73 |
-
#visited = dijkstra(graph, start, mouse_pos) # dijkstra algoritmasını çalıştır ve yolu bul
|
| 74 |
-
visited = bellman_ford(graph, start, mouse_pos) # bellman_ford algoritmasını çalıştır ve yolu bul
|
| 75 |
-
|
| 76 |
-
|
| 77 |
-
goal = mouse_pos # Hedefi fare ile tıklanan pozisyona ayarla
|
| 78 |
-
|
| 79 |
-
if visited:
|
| 80 |
-
for path_segment in visited:
|
| 81 |
-
pg.draw.circle(sc, pg.Color('blue'), *get_circle(*path_segment)) # Bulunan yol üzerindeki hücreleri maviyle işaretle
|
| 82 |
-
pg.draw.circle(sc, pg.Color('green'), *get_circle(*start)) # Başlangıç hücresini yeşille işaretle
|
| 83 |
-
pg.draw.circle(sc, pg.Color('red'), *get_circle(*goal)) # Hedef hücresini kırmızı işaretle
|
| 84 |
-
|
| 85 |
-
[exit() for event in pg.event.get() if event.type == pg.QUIT]
|
| 86 |
-
pg.display.flip()
|
| 87 |
-
clock.tick(30)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
requirements.txt
CHANGED
|
@@ -1,4 +1,4 @@
|
|
| 1 |
-
|
| 2 |
numpy==1.24.3
|
| 3 |
matplotlib==3.7.1
|
| 4 |
Pillow==10.2.0
|
|
|
|
| 1 |
+
Flask==3.0.0
|
| 2 |
numpy==1.24.3
|
| 3 |
matplotlib==3.7.1
|
| 4 |
Pillow==10.2.0
|
run_local.sh
DELETED
|
@@ -1,30 +0,0 @@
|
|
| 1 |
-
#!/bin/bash
|
| 2 |
-
|
| 3 |
-
echo "🚀 Starting Path Finding Algorithms Visualizer..."
|
| 4 |
-
echo ""
|
| 5 |
-
|
| 6 |
-
# Check if Docker is installed
|
| 7 |
-
if ! command -v docker &> /dev/null; then
|
| 8 |
-
echo "❌ Docker is not installed. Please install Docker first."
|
| 9 |
-
echo "Visit: https://docs.docker.com/get-docker/"
|
| 10 |
-
exit 1
|
| 11 |
-
fi
|
| 12 |
-
|
| 13 |
-
# Build Docker image
|
| 14 |
-
echo "📦 Building Docker image..."
|
| 15 |
-
docker build -t pathfinding-app .
|
| 16 |
-
|
| 17 |
-
if [ $? -ne 0 ]; then
|
| 18 |
-
echo "❌ Docker build failed!"
|
| 19 |
-
exit 1
|
| 20 |
-
fi
|
| 21 |
-
|
| 22 |
-
echo "✅ Docker image built successfully!"
|
| 23 |
-
echo ""
|
| 24 |
-
|
| 25 |
-
# Run container
|
| 26 |
-
echo "🏃 Running container..."
|
| 27 |
-
docker run -p 7860:7860 pathfinding-app
|
| 28 |
-
|
| 29 |
-
# Or use docker-compose
|
| 30 |
-
# docker-compose up
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
templates/index.html
ADDED
|
@@ -0,0 +1,253 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
<!DOCTYPE html>
|
| 2 |
+
<html lang="en">
|
| 3 |
+
<head>
|
| 4 |
+
<meta charset="UTF-8">
|
| 5 |
+
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
| 6 |
+
<title>Path Finding Algorithms Visualizer</title>
|
| 7 |
+
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/css/bootstrap.min.css" rel="stylesheet">
|
| 8 |
+
<style>
|
| 9 |
+
body {
|
| 10 |
+
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
|
| 11 |
+
min-height: 100vh;
|
| 12 |
+
padding: 20px;
|
| 13 |
+
}
|
| 14 |
+
.container {
|
| 15 |
+
background: white;
|
| 16 |
+
border-radius: 15px;
|
| 17 |
+
padding: 30px;
|
| 18 |
+
box-shadow: 0 10px 40px rgba(0,0,0,0.2);
|
| 19 |
+
}
|
| 20 |
+
.header {
|
| 21 |
+
text-align: center;
|
| 22 |
+
margin-bottom: 30px;
|
| 23 |
+
}
|
| 24 |
+
.header h1 {
|
| 25 |
+
color: #667eea;
|
| 26 |
+
font-weight: bold;
|
| 27 |
+
}
|
| 28 |
+
.controls-panel {
|
| 29 |
+
background: #f8f9fa;
|
| 30 |
+
padding: 20px;
|
| 31 |
+
border-radius: 10px;
|
| 32 |
+
margin-bottom: 20px;
|
| 33 |
+
}
|
| 34 |
+
.slider-container {
|
| 35 |
+
margin: 15px 0;
|
| 36 |
+
}
|
| 37 |
+
.slider-label {
|
| 38 |
+
font-weight: 600;
|
| 39 |
+
color: #495057;
|
| 40 |
+
margin-bottom: 5px;
|
| 41 |
+
}
|
| 42 |
+
.slider-value {
|
| 43 |
+
display: inline-block;
|
| 44 |
+
min-width: 30px;
|
| 45 |
+
text-align: center;
|
| 46 |
+
font-weight: bold;
|
| 47 |
+
color: #667eea;
|
| 48 |
+
}
|
| 49 |
+
.btn-find {
|
| 50 |
+
width: 100%;
|
| 51 |
+
padding: 12px;
|
| 52 |
+
font-size: 18px;
|
| 53 |
+
font-weight: bold;
|
| 54 |
+
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
|
| 55 |
+
border: none;
|
| 56 |
+
margin-top: 20px;
|
| 57 |
+
}
|
| 58 |
+
.btn-find:hover {
|
| 59 |
+
transform: translateY(-2px);
|
| 60 |
+
box-shadow: 0 5px 15px rgba(102, 126, 234, 0.4);
|
| 61 |
+
}
|
| 62 |
+
#resultImage {
|
| 63 |
+
max-width: 100%;
|
| 64 |
+
border-radius: 10px;
|
| 65 |
+
box-shadow: 0 5px 20px rgba(0,0,0,0.1);
|
| 66 |
+
}
|
| 67 |
+
.info-box {
|
| 68 |
+
background: #e7f3ff;
|
| 69 |
+
padding: 15px;
|
| 70 |
+
border-radius: 8px;
|
| 71 |
+
border-left: 4px solid #667eea;
|
| 72 |
+
margin-top: 20px;
|
| 73 |
+
}
|
| 74 |
+
.info-box h6 {
|
| 75 |
+
color: #667eea;
|
| 76 |
+
font-weight: bold;
|
| 77 |
+
}
|
| 78 |
+
.algorithm-btn {
|
| 79 |
+
margin: 5px;
|
| 80 |
+
}
|
| 81 |
+
.loading {
|
| 82 |
+
display: none;
|
| 83 |
+
text-align: center;
|
| 84 |
+
padding: 40px;
|
| 85 |
+
}
|
| 86 |
+
.spinner-border {
|
| 87 |
+
color: #667eea;
|
| 88 |
+
}
|
| 89 |
+
</style>
|
| 90 |
+
</head>
|
| 91 |
+
<body>
|
| 92 |
+
<div class="container">
|
| 93 |
+
<div class="header">
|
| 94 |
+
<h1>🗺️ Path Finding Algorithms Visualizer</h1>
|
| 95 |
+
<p class="text-muted">Select start and goal positions, choose an algorithm, and visualize the shortest path!</p>
|
| 96 |
+
</div>
|
| 97 |
+
|
| 98 |
+
<div class="row">
|
| 99 |
+
<div class="col-lg-4">
|
| 100 |
+
<div class="controls-panel">
|
| 101 |
+
<h5 class="mb-3">⚙️ Settings</h5>
|
| 102 |
+
|
| 103 |
+
<!-- Algorithm Selection -->
|
| 104 |
+
<div class="mb-4">
|
| 105 |
+
<label class="slider-label">🎯 Algorithm</label>
|
| 106 |
+
<div class="btn-group-vertical w-100" role="group">
|
| 107 |
+
<input type="radio" class="btn-check" name="algorithm" id="astar" value="A*" checked>
|
| 108 |
+
<label class="btn btn-outline-primary algorithm-btn" for="astar">
|
| 109 |
+
A* (Fastest)
|
| 110 |
+
</label>
|
| 111 |
+
|
| 112 |
+
<input type="radio" class="btn-check" name="algorithm" id="dijkstra" value="Dijkstra">
|
| 113 |
+
<label class="btn btn-outline-warning algorithm-btn" for="dijkstra">
|
| 114 |
+
Dijkstra (Classic)
|
| 115 |
+
</label>
|
| 116 |
+
|
| 117 |
+
<input type="radio" class="btn-check" name="algorithm" id="bellman" value="Bellman-Ford">
|
| 118 |
+
<label class="btn btn-outline-danger algorithm-btn" for="bellman">
|
| 119 |
+
Bellman-Ford (Robust)
|
| 120 |
+
</label>
|
| 121 |
+
</div>
|
| 122 |
+
</div>
|
| 123 |
+
|
| 124 |
+
<!-- Start Position -->
|
| 125 |
+
<h6 class="mt-4">📍 Start Position</h6>
|
| 126 |
+
<div class="slider-container">
|
| 127 |
+
<label class="slider-label">
|
| 128 |
+
X: <span class="slider-value" id="startXValue">0</span>
|
| 129 |
+
</label>
|
| 130 |
+
<input type="range" class="form-range" id="startX" min="0" max="11" value="0">
|
| 131 |
+
</div>
|
| 132 |
+
<div class="slider-container">
|
| 133 |
+
<label class="slider-label">
|
| 134 |
+
Y: <span class="slider-value" id="startYValue">7</span>
|
| 135 |
+
</label>
|
| 136 |
+
<input type="range" class="form-range" id="startY" min="0" max="7" value="7">
|
| 137 |
+
</div>
|
| 138 |
+
|
| 139 |
+
<!-- Goal Position -->
|
| 140 |
+
<h6 class="mt-4">🎯 Goal Position</h6>
|
| 141 |
+
<div class="slider-container">
|
| 142 |
+
<label class="slider-label">
|
| 143 |
+
X: <span class="slider-value" id="goalXValue">11</span>
|
| 144 |
+
</label>
|
| 145 |
+
<input type="range" class="form-range" id="goalX" min="0" max="11" value="11">
|
| 146 |
+
</div>
|
| 147 |
+
<div class="slider-container">
|
| 148 |
+
<label class="slider-label">
|
| 149 |
+
Y: <span class="slider-value" id="goalYValue">0</span>
|
| 150 |
+
</label>
|
| 151 |
+
<input type="range" class="form-range" id="goalY" min="0" max="7" value="0">
|
| 152 |
+
</div>
|
| 153 |
+
|
| 154 |
+
<!-- Find Path Button -->
|
| 155 |
+
<button class="btn btn-primary btn-find" onclick="findPath()">
|
| 156 |
+
🔍 Find Path
|
| 157 |
+
</button>
|
| 158 |
+
|
| 159 |
+
<!-- Info Box -->
|
| 160 |
+
<div class="info-box">
|
| 161 |
+
<h6>📝 Grid Info</h6>
|
| 162 |
+
<ul class="small mb-0">
|
| 163 |
+
<li><strong>Size:</strong> 12x8 cells</li>
|
| 164 |
+
<li><strong>Cost Range:</strong> 1-9</li>
|
| 165 |
+
<li><strong>Green:</strong> Start</li>
|
| 166 |
+
<li><strong>Red:</strong> Goal</li>
|
| 167 |
+
<li><strong>Blue/Orange/Red:</strong> Path</li>
|
| 168 |
+
</ul>
|
| 169 |
+
</div>
|
| 170 |
+
</div>
|
| 171 |
+
</div>
|
| 172 |
+
|
| 173 |
+
<div class="col-lg-8">
|
| 174 |
+
<div class="visualization-panel">
|
| 175 |
+
<h5 class="mb-3">🗺️ Visualization</h5>
|
| 176 |
+
<div id="loading" class="loading">
|
| 177 |
+
<div class="spinner-border" role="status">
|
| 178 |
+
<span class="visually-hidden">Loading...</span>
|
| 179 |
+
</div>
|
| 180 |
+
<p class="mt-3">Calculating path...</p>
|
| 181 |
+
</div>
|
| 182 |
+
<div id="imageContainer">
|
| 183 |
+
<img id="resultImage" src="" alt="Path visualization will appear here">
|
| 184 |
+
</div>
|
| 185 |
+
</div>
|
| 186 |
+
</div>
|
| 187 |
+
</div>
|
| 188 |
+
</div>
|
| 189 |
+
|
| 190 |
+
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/js/bootstrap.bundle.min.js"></script>
|
| 191 |
+
<script>
|
| 192 |
+
// Update slider values
|
| 193 |
+
document.getElementById('startX').addEventListener('input', function() {
|
| 194 |
+
document.getElementById('startXValue').textContent = this.value;
|
| 195 |
+
});
|
| 196 |
+
document.getElementById('startY').addEventListener('input', function() {
|
| 197 |
+
document.getElementById('startYValue').textContent = this.value;
|
| 198 |
+
});
|
| 199 |
+
document.getElementById('goalX').addEventListener('input', function() {
|
| 200 |
+
document.getElementById('goalXValue').textContent = this.value;
|
| 201 |
+
});
|
| 202 |
+
document.getElementById('goalY').addEventListener('input', function() {
|
| 203 |
+
document.getElementById('goalYValue').textContent = this.value;
|
| 204 |
+
});
|
| 205 |
+
|
| 206 |
+
// Load initial visualization
|
| 207 |
+
window.onload = function() {
|
| 208 |
+
findPath();
|
| 209 |
+
};
|
| 210 |
+
|
| 211 |
+
// Find Path function
|
| 212 |
+
async function findPath() {
|
| 213 |
+
const startX = document.getElementById('startX').value;
|
| 214 |
+
const startY = document.getElementById('startY').value;
|
| 215 |
+
const goalX = document.getElementById('goalX').value;
|
| 216 |
+
const goalY = document.getElementById('goalY').value;
|
| 217 |
+
const algorithm = document.querySelector('input[name="algorithm"]:checked').value;
|
| 218 |
+
|
| 219 |
+
// Show loading
|
| 220 |
+
document.getElementById('loading').style.display = 'block';
|
| 221 |
+
document.getElementById('imageContainer').style.display = 'none';
|
| 222 |
+
|
| 223 |
+
try {
|
| 224 |
+
const response = await fetch('/find_path', {
|
| 225 |
+
method: 'POST',
|
| 226 |
+
headers: {
|
| 227 |
+
'Content-Type': 'application/json',
|
| 228 |
+
},
|
| 229 |
+
body: JSON.stringify({
|
| 230 |
+
start_x: startX,
|
| 231 |
+
start_y: startY,
|
| 232 |
+
goal_x: goalX,
|
| 233 |
+
goal_y: goalY,
|
| 234 |
+
algorithm: algorithm
|
| 235 |
+
})
|
| 236 |
+
});
|
| 237 |
+
|
| 238 |
+
const data = await response.json();
|
| 239 |
+
|
| 240 |
+
// Hide loading, show image
|
| 241 |
+
document.getElementById('loading').style.display = 'none';
|
| 242 |
+
document.getElementById('imageContainer').style.display = 'block';
|
| 243 |
+
document.getElementById('resultImage').src = data.image;
|
| 244 |
+
} catch (error) {
|
| 245 |
+
console.error('Error:', error);
|
| 246 |
+
alert('An error occurred while finding the path. Please try again.');
|
| 247 |
+
document.getElementById('loading').style.display = 'none';
|
| 248 |
+
document.getElementById('imageContainer').style.display = 'block';
|
| 249 |
+
}
|
| 250 |
+
}
|
| 251 |
+
</script>
|
| 252 |
+
</body>
|
| 253 |
+
</html>
|