Unterschiede
Hier werden die Unterschiede zwischen zwei Versionen angezeigt.
| Beide Seiten der vorigen Revision Vorhergehende Überarbeitung Nächste Überarbeitung | Vorhergehende Überarbeitung | ||
| ef:algorithmen:start [2025/10/30 13:57] – lehmannr | ef:algorithmen:start [2025/11/19 16:27] (aktuell) – lehmannr | ||
|---|---|---|---|
| Zeile 1: | Zeile 1: | ||
| - | ======= 1. Pfadfinder-Algorithmen | + | ======= 1. Labyrinthe |
| + | Ein Labyrinth kann man durch einen Graphen darstellen. Ein sogenanntes " | ||
| - | Betrachte die Aufgabe | + | <WRAP nicebox green> |
| + | ** Aufgabe | ||
| + | | ||
| + | - Wozu benötigt man einen Stack, um den DFS zu implementieren. | ||
| + | - Finde zu einem gegebenen Labyrinth den zugehörigen Graphen und umgekehrt (vgl. Arbeitsblatt). | ||
| + | </WRAP> | ||
| + | ======= 2. Pfadfinder-Algorithmen ======= | ||
| + | |||
| + | Betrachte die Aufgabe zum Programmierwettbewerb Hidden-Gems: | ||
| Bei " | Bei " | ||
| + | Es gibt etliche Algorithmen, | ||
| + | |||
| + | ===== 2.1 Labyrinthe lösen ===== | ||
| + | <WRAP nicebox green> | ||
| + | **Aufgabe 2** | ||
| + | - Wie funktioniert der Random-Mouse Algorithmus? | ||
| + | - Wie funktioniert der "Hand on wall" | ||
| + | - Wie funktioniert der DFS-Algorithmus um den Pfad in einem Labyrinth zu finden? Produziert er den kürzesten Weg? | ||
| + | - Wie funktioniert der BFS-Algorithmus um den Pfad in einem Labyrinth zu finden? Produziert er den kürzesten Weg? | ||
| + | </ | ||
| + | |||
| + | ===== 2.2 Andere Pfad-Finder-Algorithmen ===== | ||
| <WRAP nicebox green> | <WRAP nicebox green> | ||
| - | ** Aufgabe ** | + | ** Aufgabe |
| - | - Überlege dir, welchen Algorithmus man bei der Testumgebung verwenden könnte? Wie steuert man den Bot zu den Edelsteinen? | + | - Wie funktioniert der Dijkstra-Algorithmus, um den schnellsten Weg zu finden? Funktioniert er für gerichtete |
| - | - Was ändert sich, wenn man sich in einer Umgebung mit Wänden bewegt? Wie wird die Umgebung, die Position des Bots und der Edelsteine repräsentiert? | + | - Wie funktioniert A*? Erkläre ihn. Recherchiere nach bekannten Pfadfinder-Algorithmen. [[https://youtu.be/-L-WgKMFuhE?si=I7kuQFjTcYBDQRN7|Sebastian Lague A*]] |
| - | - Überlege dir einen möglichen Algorithmus, | + | |
| - | - Recherchiere nach bekannten Pfadfinder-Algorithmen. | + | |
| - Eine gute visuelle Darstellung von verschiedenen Algorithmen findet sich z.B. hier: [[https:// | - Eine gute visuelle Darstellung von verschiedenen Algorithmen findet sich z.B. hier: [[https:// | ||
| + | |||
| </ | </ | ||
| + | |||
| + | |||
| + | main.py | ||
| + | <sxh> | ||
| + | # main.py | ||
| + | import tkinter as tk | ||
| + | from cell import Cell | ||
| + | |||
| + | root = tk.Tk() | ||
| + | root.title(" | ||
| + | |||
| + | cols = 30 | ||
| + | rows = 30 | ||
| + | size = 40 | ||
| + | |||
| + | currentCell = None | ||
| + | canvas = None | ||
| + | cells = [] # Array mit allen Zellen | ||
| + | stack = [] # stack für das Backtracking | ||
| + | |||
| + | |||
| + | def remove_wall(cell1, | ||
| + | x = cell1.x | ||
| + | y = cell1.y | ||
| + | cell1.walls[wall] = False | ||
| + | if (wall==0): | ||
| + | cells[get_index(x, | ||
| + | if (wall==1): | ||
| + | cells[get_index(x+1, | ||
| + | if (wall==2): | ||
| + | cells[get_index(x, | ||
| + | if (wall==3): | ||
| + | cells[get_index(x-1, | ||
| + | |||
| + | |||
| + | # cells are stored in 1 dimensional array, getting indes of cell at position (i,j) | ||
| + | def get_index(i, | ||
| + | return j*rows+i | ||
| + | |||
| + | |||
| + | # Beispiel: mehrere Zellen | ||
| + | def setup(): | ||
| + | global canvas, cells, currentCell | ||
| + | canvas = tk.Canvas(root, | ||
| + | canvas.pack() | ||
| + | for j in range(rows): | ||
| + | for i in range(cols): | ||
| + | cells.append(Cell(i, | ||
| + | | ||
| + | currentCell = cells[0] | ||
| + | |||
| + | |||
| + | def draw_maze(): | ||
| + | global currentCell | ||
| + | | ||
| + | canvas.delete(" | ||
| + | | ||
| + | currentCell.visited = True | ||
| + | | ||
| + | for c in cells: | ||
| + | c.draw(canvas) | ||
| + | | ||
| + | nextCell = currentCell.checkNeighbors(cells, | ||
| + | | ||
| + | if nextCell: | ||
| + | nextCell.visited = True | ||
| + | | ||
| + | | ||
| + | stack.append(nextCell) | ||
| + | | ||
| + | dx = nextCell.x - currentCell.x | ||
| + | dy = nextCell.y - currentCell.y | ||
| + | | ||
| + | if dx == 1: # nach rechts | ||
| + | remove_wall(currentCell, | ||
| + | if dx ==-1: # nach links | ||
| + | remove_wall(currentCell, | ||
| + | if dy == 1: # nach unten | ||
| + | remove_wall(currentCell, | ||
| + | if dy == -1: # nach oben | ||
| + | remove_wall(currentCell, | ||
| + | | ||
| + | currentCell = nextCell | ||
| + | else: | ||
| + | if stack: | ||
| + | currentCell=stack.pop() | ||
| + | for i, c in enumerate(stack): | ||
| + | intensity = int(200/ | ||
| + | col = f"# | ||
| + | c.highlight(canvas, | ||
| + | | ||
| + | currentCell.highlight(canvas, | ||
| + | |||
| + | root.after(100, | ||
| + | | ||
| + | |||
| + | setup() | ||
| + | draw_maze() | ||
| + | |||
| + | |||
| + | root.mainloop() | ||
| + | </ | ||
| + | |||
| + | cell.py | ||
| + | <sxh> | ||
| + | import random | ||
| + | |||
| + | class Cell: | ||
| + | def __init__(self, | ||
| + | self.x = x # X-Koordinate | ||
| + | self.y = y # Y-Koordinate | ||
| + | self.size = size # Breite/ | ||
| + | self.walls = [True, True, True, True] # [oben, rechts, unten, links] | ||
| + | self.col = col # Farbe der Zelle | ||
| + | self.visited = False # Besuchsstatus | ||
| + | |||
| + | def highlight(self, | ||
| + | x1 = self.x * self.size+8 | ||
| + | y1 = self.y * self.size+8 | ||
| + | x2 = x1 + self.size-10 | ||
| + | y2 = y1 + self.size-10 | ||
| + | can.create_rectangle(x1, | ||
| + | | ||
| + | | ||
| + | def draw(self, can): # Zeichnet die Zelle auf dem übergebenen Canvas. | ||
| + | | ||
| + | x1 = self.x * self.size+4 | ||
| + | y1 = self.y * self.size+4 | ||
| + | x2 = x1 + self.size+4 | ||
| + | y2 = y1 + self.size+4 | ||
| + | |||
| + | # Hintergrundfarbe | ||
| + | if self.visited: | ||
| + | can.create_rectangle(x1, | ||
| + | else: | ||
| + | can.create_rectangle(x1, | ||
| + | |||
| + | # Wände zeichnen | ||
| + | if (self.walls[0]): | ||
| + | can.create_line(x1, | ||
| + | if self.walls[1]: | ||
| + | can.create_line(x2, | ||
| + | if self.walls[2]: | ||
| + | can.create_line(x2, | ||
| + | if self.walls[3]: | ||
| + | can.create_line(x1, | ||
| + | | ||
| + | | ||
| + | def checkNeighbors(self, | ||
| + | neighbors = [] | ||
| + | topIndex = Cell.get_index(self.x, | ||
| + | rightIndex = Cell.get_index(self.x+1, | ||
| + | bottomIndex = Cell.get_index(self.x, | ||
| + | leftIndex = Cell.get_index(self.x-1, | ||
| + | | ||
| + | #top = cells[Cell.get_index(self.x, | ||
| + | #right = cells[Cell.get_index(self.x+1, | ||
| + | #bottom = cells[Cell.get_index(self.x, | ||
| + | #left = cells[Cell.get_index(self.x-1, | ||
| + | | ||
| + | if (topIndex and (not cells[topIndex].visited)): | ||
| + | neighbors.append(cells[topIndex]) | ||
| + | if (rightIndex and (not cells[rightIndex].visited)): | ||
| + | neighbors.append(cells[rightIndex]) | ||
| + | if (bottomIndex and (not cells[bottomIndex].visited)): | ||
| + | neighbors.append(cells[bottomIndex]) | ||
| + | if (leftIndex and (not cells[leftIndex].visited)): | ||
| + | neighbors.append(cells[leftIndex]) | ||
| + | | ||
| + | if neighbors: | ||
| + | return random.choice(neighbors) | ||
| + | else: | ||
| + | return None | ||
| + | | ||
| + | | ||
| + | @classmethod | ||
| + | def get_index(cls, | ||
| + | if (i<0 or j<0 or i>=cols or j >= rows): | ||
| + | return None | ||
| + | else: | ||
| + | return j*rows + i | ||
| + | </ | ||