Transfer in to JPNB

This commit is contained in:
2025-05-12 12:59:24 +02:00
parent 565d08290c
commit c7a507c96f
7 changed files with 1006 additions and 125 deletions

View File

@@ -1,12 +1,11 @@
from prettytable import PrettyTable
from pygame.event import set_keyboard_grab
from utils import *
class Node:
def __init__(self, name, x=None, y=None, state="free"):
def __init__(self, name, x=None, y=None):
self.parent = None
self.name = name
self.edges = []
@@ -42,7 +41,7 @@ class Graph:
for node in node_list:
edge_values = ['X'] * len(node_list)
for edge in node.edges:
edge_values[next((i for i, e in enumerate(node_list) if e.name == edge.end.name), -1)] = edge.g
edge_values[next((i for i, e in enumerate(node_list) if e.name == edge.end.name), -1)] = edge.value
t.add_row([node.name] + edge_values)
print(t)
@@ -53,36 +52,42 @@ class Queue:
self.items = []
self.sort_by = sort_by
def empty(self):
return len(self.items) == 0
def clear(self):
self.items.clear()
def is_empty(self):
if len(self.items) > 0:
return False
else:
return True
def pop(self):
if not self.empty():
if self.type == 'LIFO':
''' LIFO
queue = [node_0, node_1, ... , node_n]
-> pop node_n
'''
return self.items.pop()
else:
''' FIFO & PRIO
queue = [node_0, node_1, ... , node_n]
-> pop node_0
'''
return self.items.pop(0)
return None
def push(self, node):
self.items.append(node)
def push(self, element):
self.items.append(element)
'''
queue = [node_0, node_1, ... , node_n] <- node_n+1
queue = [element_0, element_1, ... , element_n] <- element_n+1
'''
if self.type == 'PRIO':
'''
Sorting so lowest cost/ value is at [0]
queue = [node_0 < node_1 < ... < node_n < node_n+1]
queue = [element_0 < element_1 < ... < element_n < element_n+1]
'''
if self.sort_by == '':
self.items.sort(key=lambda item: item.value)
elif self.sort_by == 'f':
self.items.sort(key=lambda item: item.f)
def pop(self):
if not self.is_empty():
if self.type == 'LIFO':
''' LIFO
queue = [element_0, elemente_1, ... , element_n]
-> pop element_n
'''
return self.items.pop()
else:
''' FIFO & PRIO
queue = [element_0, element_1, ... , element_n]
-> pop element_0
'''
return self.items.pop(0)
return None

View File

@@ -40,8 +40,10 @@ class Field:
color = GREEN
elif self.state == "path":
color = ORANGE
elif self.state == "current":
color = RED
elif self.state == "visited":
color = WHITE
color = GREY
x_calc = (MARGIN + WIDTH) * self.x + MARGIN
y_calc = (MARGIN + HEIGHT) * (grid_size - 1 - self.y) + MARGIN # flipping
@@ -52,13 +54,15 @@ class Field:
[x_calc, y_calc, WIDTH, HEIGHT]
)
'''
# Render the heuristic value as text
if self.state != "obstacale": # Don't display on obstacles
# Create a font object
font = pygame.font.Font(None, 16) # None means default font, 14 is the size
# Round the heuristic value to 1 decimal place for better display
f_text = f"{self.f:.1f}"
f_text = f"{self.g:.1f}"
# Render the text
text = font.render(f_text, True, BLACK) # True for anti-aliasing, BLACK for text color
@@ -68,6 +72,7 @@ class Field:
# Draw the text on the screen
screen.blit(text, text_rect)
'''
class Grid:
@@ -101,7 +106,7 @@ class Grid:
return self.grid[x][y].state
def set_state(self, state, x, y):
if state == "free" or state == "obstacale" or state == "start" or state == "target" or state == "path" or state == "visited":
if state == "free" or state == "obstacale" or state == "start" or state == "target" or state == "path" or state == "current" or state == "visited":
self.grid[x][y].state = state
def set_free(self, x, y):
@@ -109,15 +114,17 @@ class Grid:
def set_obstacle(self, x, y):
self.set_state("obstacale", x, y)
def set_current(self, x, y):
self.set_state("current", x, y)
def set_visited(self, x,y):
self.set_state("visited", x, y)
def set_path(self, x, y):
if not (x == self.start[0] and y == self.start[1]) and not (x == self.target[0] and y == self.target[1]):
self.set_state("path", x, y)
def set_visited(self, x, y):
if not (x == self.start[0] and y == self.start[1]) and not (x == self.target[0] and y == self.target[1]):
self.set_state("visited", x, y)
def set_start(self, x, y):
# reset old start if it exits
if self.start:
@@ -127,7 +134,7 @@ class Grid:
self.grid[x][y].parent = self.grid[x][y]
self.grid[x][y].g = 0
self.grid[x][y].h = self.heuristic(self.grid[x][y])
self.grid[x][y].f = self.grid[x][y].h + self.grid[x][y].g
self.start = (x, y)
def set_target(self, x, y):
@@ -144,7 +151,7 @@ class Grid:
Initializing the Grid
'''
start = (0, 0)
target = (19, 19)
target = (19, 0)
grid = Grid(grid_size, grid_size)
# check if start an target are valid
@@ -163,7 +170,7 @@ for i in range(9, 20):
grid.set_obstacle(16, i)
'''
Initializing A* Comps
Initializing A* Components
'''
open = Queue('PRIO', 'f')
@@ -172,9 +179,11 @@ closed = Queue('PRIO', 'f')
neighbors = []
path = []
pygame.init()
'''
Initializing Visuals
'''
# window
pygame.init()
window_width = grid_size * (WIDTH + MARGIN) + MARGIN
window_height = grid_size * (HEIGHT + MARGIN) + MARGIN
size = (window_width, window_height) # made size variable
@@ -185,74 +194,65 @@ pygame.display.set_caption("A* Algorithm")
done = False
clock = pygame.time.Clock()
while not done:
for event in pygame.event.get():
if event.type == pygame.QUIT:
done = True
def a_star():
neighbor = None
while not open.empty():
while not open.is_empty():
current_field = open.pop()
grid.set_current(current_field.x, current_field.y)
screen.fill(BLACK)
grid.draw(screen)
pygame.display.flip()
clock.tick(15)
if current_field.x == grid.target[0] and current_field.y == grid.target[1]:
if current_field.x == grid.target[0] and current_field.y == grid.target[1]:
path.append(current_field)
grid.set_path(current_field.x, current_field.y)
while not (current_field.x == grid.start[0] and current_field.y == grid.start[1]):
current_field = current_field.parent
path.insert(0, current_field)
grid.set_path(current_field.x, current_field.y)
grid.draw(screen)
pygame.display.flip()
clock.tick(15)
open.clear()
break
closed.push(current_field)
grid.set_visited(current_field.x, current_field.y)
# Nachbarn finden
for dx, dy in [(0, -1), (-1, 0), (0, 1), (1, 0)]:
nx = current_field.x + dx
ny = current_field.y + dy
# Prüfen, ob der Nachbar gültig ist
if 0 <= nx < grid.cols and 0 <= ny < grid.rows:
neighbor = grid.grid[nx][ny]
# Hindernis oder bereits in geschlossener Liste -> überspringen
if neighbor.state == "obstacale" or neighbor in [item for item in closed.items]:
if neighbor.state == "obstacale" or closed.items.__contains__(neighbor):
continue
# Neuen g-Wert berechnen
tentative_g = current_field.g + 1 # Kosten für einen Schritt = 1
tentative_g = current_field.g + 1
# Wenn Nachbar nicht in offener Liste oder neuer Pfad besser
if neighbor not in [item for item in open.items] or tentative_g < neighbor.g:
if tentative_g < neighbor.g:
neighbor.parent = current_field
neighbor.g = tentative_g
neighbor.h = grid.heuristic(neighbor)
neighbor.f = neighbor.g + neighbor.h
# Knoten zur offenen Liste hinzufügen oder aktualisieren
if neighbor not in [item for item in open.items]:
open.push(neighbor)
else:
# Queue aktualisieren
if open.items.__contains__(neighbor):
open.items.sort(key=lambda item: item.f)
else:
open.push(neighbor)
def a_star_main():
global done
while not done:
for event in pygame.event.get():
if event.type == pygame.QUIT:
done = True
a_star()
screen.fill(BLACK)
grid.draw(screen)
# refresh display
screen.fill(BLACK)
grid.draw(screen)
pygame.display.flip()
# refreshrate
clock.tick(120)
a_star_main()
clock.tick(30)
pygame.quit()

View File

@@ -25,17 +25,15 @@ romania = Graph(['Or', 'Ne', 'Ze', 'Ia', 'Ar', 'Si', 'Fa',
def main():
# Task 1
graph = romania
ucs(graph, 'Si', 'Bu')
ucs(graph, 'Ti', 'Bu')
graph = romania
bfs(graph, 'Si', 'Bu')
bfs(graph, 'Ti', 'Bu')
graph = romania
dfs(graph, 'Si', 'Bu')
dfs(graph, 'Ti', 'Bu')
# Task 3 A*
a_star_main()
if __name__ == "__main__":
main()
main()

View File

@@ -63,5 +63,3 @@ def dfs(graph, start_node_name, target_node_name):
def ucs(graph, start_node_name, target_node_name):
traverse(graph, Queue('PRIO'), start_node_name, target_node_name)

View File

@@ -1,47 +1,2 @@
def getNode(name, l):
return next((i for i in l if i.name == name), -1)
def print_grid_direct(self, path=None):
"""
Gibt das Grid in der Konsole aus, direkt wie es im Array gespeichert ist.
Die y-Achse nimmt nach unten zu (0 ist oben), entsprechend der Array-Struktur.
Optionaler Parameter 'path' ist eine Liste von (x,y)-Koordinaten, die den Pfad darstellen.
"""
# Symbole für verschiedene Zustände
symbols = {
"free": ".",
"obstacale": "#", # Tippfehler aus Original-Code beibehalten
"start": "S",
"target": "G",
"path": "o"
}
# Ausgabe des Grids mit Koordinatenachsen
print("\n ", end="")
# Obere x-Achsen-Beschriftung
for x in range(self.cols):
print(f"{x:2d}", end=" ")
print("\n " + "-" * (self.cols * 3))
# Grid mit y-Achsen-Beschriftung
for y in range(self.rows):
print(f"{y:2d} |", end=" ")
for x in range(self.cols):
field = self.grid[x][y]
if path and (x, y) in path and field.state != "start" and field.state != "target":
print(f"{symbols['path']:2s}", end=" ")
else:
print(f"{symbols[field.state]:2s}", end=" ")
print() # Zeilenumbruch
print("\nLegende:")
print(" . = frei")
print(" # = Hindernis")
print(" S = Start")
print(" G = Ziel")
print(" o = Pfad")
# Zusätzliche Statistiken, falls ein Pfad vorhanden ist
if path:
print(f"Pfadlänge: {len(path)} Felder")