Files
KI/P1/AI_P1_2.ipynb
2025-06-23 22:41:23 +02:00

555 lines
15 KiB
Plaintext

{
"cells": [
{
"cell_type": "markdown",
"id": "e063ba00",
"metadata": {},
"source": [
"# A* Algorithm"
]
},
{
"cell_type": "markdown",
"id": "868592a7",
"metadata": {},
"source": [
"## Install Requirements"
]
},
{
"cell_type": "markdown",
"id": "26dff129",
"metadata": {},
"source": [
"create a virtual environment in current directory by \n",
"\n",
"```\n",
"python3 -m venv .env # macos\n",
"python -m venv .env # linux\n",
"```"
]
},
{
"cell_type": "code",
"execution_count": 12,
"id": "55fa613b",
"metadata": {
"ExecuteTime": {
"end_time": "2025-05-07T21:40:23.660320Z",
"start_time": "2025-05-07T21:40:22.973705Z"
}
},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"Requirement already satisfied: pygame in /home/safak/Dokumente/Uni/KI/.env/lib64/python3.13/site-packages (2.6.1)\n",
"Note: you may need to restart the kernel to use updated packages.\n"
]
}
],
"source": [
"%pip install pygame"
]
},
{
"cell_type": "markdown",
"id": "db35c098",
"metadata": {},
"source": [
"## Imports"
]
},
{
"cell_type": "code",
"execution_count": 13,
"id": "e7034eee",
"metadata": {
"ExecuteTime": {
"end_time": "2025-05-07T21:40:23.825797Z",
"start_time": "2025-05-07T21:40:23.718944Z"
}
},
"outputs": [],
"source": [
"import pygame\n",
"import math"
]
},
{
"cell_type": "markdown",
"id": "77d18f1b",
"metadata": {},
"source": [
"## Global Variables"
]
},
{
"cell_type": "code",
"execution_count": 14,
"id": "60b63344",
"metadata": {
"ExecuteTime": {
"end_time": "2025-05-07T21:40:23.877569Z",
"start_time": "2025-05-07T21:40:23.873797Z"
}
},
"outputs": [],
"source": [
"BLACK = (0, 0, 0)\n",
"WHITE = (255, 255, 255)\n",
"BLUE = (0, 0, 255)\n",
"GREEN = (0, 255, 0)\n",
"RED = (255, 0, 0)\n",
"ORANGE = (255, 165, 0)\n",
"GREY = (128, 128, 128)\n",
"\n",
"WIDTH = 25\n",
"HEIGHT = 25\n",
"MARGIN = 3\n",
"GRID_SIZE= 20"
]
},
{
"cell_type": "markdown",
"id": "87a05a3b",
"metadata": {},
"source": [
"## Classes \n",
"\n",
"The Queue Class is the same from Task 1"
]
},
{
"cell_type": "code",
"execution_count": 15,
"id": "84ad596c",
"metadata": {
"ExecuteTime": {
"end_time": "2025-05-07T21:40:24.013443Z",
"start_time": "2025-05-07T21:40:24.010202Z"
}
},
"outputs": [],
"source": [
"class Queue:\n",
" def __init__(self, type, sort_by = ''):\n",
" self.type = type\n",
" self.items = []\n",
" self.sort_by = sort_by\n",
"\n",
" def clear(self):\n",
" self.items.clear()\n",
" \n",
" def is_empty(self):\n",
" if len(self.items) > 0:\n",
" return False\n",
" else:\n",
" return True\n",
"\n",
" def push(self, element):\n",
" self.items.append(element)\n",
" '''\n",
" queue = [element_0, element_1, ... , element_n] <- element_n+1\n",
" '''\n",
" if self.type == 'PRIO':\n",
" '''\n",
" Sorting so lowest cost/ value is at [0]\n",
" queue = [element_0 < element_1 < ... < element_n < element_n+1]\n",
" '''\n",
" if self.sort_by == '':\n",
" self.items.sort(key=lambda item: item.value)\n",
" elif self.sort_by == 'f':\n",
" self.items.sort(key=lambda item: item.f)\n",
"\n",
" def pop(self):\n",
" if not self.is_empty():\n",
" if self.type == 'LIFO':\n",
" ''' LIFO\n",
" queue = [element_0, elemente_1, ... , element_n]\n",
" -> pop element_n\n",
" '''\n",
" return self.items.pop()\n",
" else:\n",
" ''' FIFO & PRIO\n",
" queue = [element_0, element_1, ... , element_n]\n",
" -> pop element_0\n",
" '''\n",
" return self.items.pop(0)\n",
" return None"
]
},
{
"cell_type": "code",
"execution_count": 16,
"id": "d3b77c0a",
"metadata": {
"ExecuteTime": {
"end_time": "2025-05-07T21:40:24.044268Z",
"start_time": "2025-05-07T21:40:24.041113Z"
}
},
"outputs": [],
"source": [
"class Field:\n",
" def __init__(self, x, y):\n",
" self.x = x\n",
" self.y = y\n",
" self.state = \"free\" # states: free, obstacale, start, target\n",
"\n",
" self.g = float('inf')\n",
" self.h = 0\n",
" self.f = float('inf')\n",
" self.parent = None\n",
"\n",
" def draw(self, screen):\n",
" # state based coloring\n",
" color = WHITE\n",
" if self.state == \"obstacale\":\n",
" color = BLACK\n",
" elif self.state == \"start\":\n",
" color = BLUE\n",
" elif self.state == \"target\":\n",
" color = GREEN\n",
" elif self.state == \"path\":\n",
" color = ORANGE\n",
" elif self.state == \"current\":\n",
" color = RED\n",
" elif self.state == \"visited\":\n",
" color = GREY\n",
"\n",
" x_calc = (MARGIN + WIDTH) * self.x + MARGIN\n",
" y_calc = (MARGIN + HEIGHT) * (GRID_SIZE - 1 - self.y) + MARGIN # flipping\n",
"\n",
" pygame.draw.rect(\n",
" screen,\n",
" color,\n",
" [x_calc, y_calc, WIDTH, HEIGHT]\n",
" )"
]
},
{
"cell_type": "code",
"execution_count": 17,
"id": "b3d9f04f",
"metadata": {
"ExecuteTime": {
"end_time": "2025-05-07T21:40:24.125218Z",
"start_time": "2025-05-07T21:40:24.120389Z"
}
},
"outputs": [],
"source": [
"class Grid:\n",
" def __init__(self, cols, rows):\n",
" self.cols = cols # x\n",
" self.rows = rows # y\n",
" self.grid = []\n",
"\n",
" i = 0\n",
" while i < cols: # col = x\n",
" col = []\n",
" j = 0\n",
" while j < rows: # row = y\n",
" col.append(Field(i, j)) # (x,y)\n",
" j += 1\n",
" self.grid.append(col)\n",
" i += 1\n",
"\n",
" self.start = None\n",
" self.target = None\n",
"\n",
" def draw(self, screen):\n",
" for col in self.grid:\n",
" for field in col:\n",
" field.draw(screen)\n",
"\n",
" def heuristic(self, field):\n",
" return math.sqrt((field.x - self.target[0]) ** 2 + (field.y - self.target[1]) ** 2)\n",
"\n",
" def get_state(self, x, y):\n",
" return self.grid[x][y].state\n",
"\n",
" def set_state(self, state, x, y):\n",
" if state == \"free\" or state == \"obstacale\" or state == \"start\" or state == \"target\" or state == \"path\" or state == \"current\" or state == \"visited\":\n",
" self.grid[x][y].state = state\n",
"\n",
" def set_free(self, x, y):\n",
" self.set_state(\"free\", x, y)\n",
"\n",
" def set_obstacle(self, x, y):\n",
" self.set_state(\"obstacale\", x, y)\n",
" \n",
" def set_current(self, x, y):\n",
" self.set_state(\"current\", x, y)\n",
" \n",
" def set_visited(self, x,y):\n",
" self.set_state(\"visited\", x, y)\n",
"\n",
" def set_path(self, x, y):\n",
" if not (x == self.start[0] and y == self.start[1]) and not (x == self.target[0] and y == self.target[1]):\n",
" self.set_state(\"path\", x, y)\n",
"\n",
" def set_start(self, x, y):\n",
" # reset old start if it exits\n",
" if self.start:\n",
" self.set_free(self.start[0], self.start[1])\n",
"\n",
" self.set_state(\"start\", x, y)\n",
" self.grid[x][y].parent = self.grid[x][y]\n",
" self.grid[x][y].g = 0\n",
" self.grid[x][y].h = self.heuristic(self.grid[x][y])\n",
" self.grid[x][y].f = self.grid[x][y].h + self.grid[x][y].g\n",
" self.start = (x, y)\n",
"\n",
" def set_target(self, x, y):\n",
" # reset old target if it exits\n",
" if self.target:\n",
" self.set_free(self.target[0], self.target[1])\n",
"\n",
" self.set_state(\"target\", x, y)\n",
"\n",
" self.target = (x, y)"
]
},
{
"cell_type": "markdown",
"id": "a01bed4a",
"metadata": {},
"source": [
"## Defining Grid Parameters"
]
},
{
"cell_type": "code",
"execution_count": 18,
"id": "53c20ed6",
"metadata": {
"ExecuteTime": {
"end_time": "2025-05-07T21:40:24.289574Z",
"start_time": "2025-05-07T21:40:24.250017Z"
}
},
"outputs": [],
"source": [
"\n",
"window_width = GRID_SIZE * (WIDTH + MARGIN) + MARGIN\n",
"window_height = GRID_SIZE * (HEIGHT + MARGIN) + MARGIN\n",
"size = (window_width, window_height) # made size variable\n",
"\n",
"start = (0, 0)\n",
"target = (19, 19)\n",
"grid = Grid(GRID_SIZE, GRID_SIZE)\n",
"\n",
"# check if start an target are valid\n",
"if 0 <= start[0] < grid.cols and 0 <= target[0] < grid.cols and 0 <= start[1] < grid.cols and 0 <= target[\n",
" 1] < grid.cols:\n",
" grid.set_target(target[0], target[1])\n",
" grid.set_start(start[0], start[1])\n"
]
},
{
"cell_type": "markdown",
"id": "e67b33e5",
"metadata": {},
"source": [
"### Creating Obsticales"
]
},
{
"cell_type": "code",
"execution_count": 19,
"id": "d01d53b0",
"metadata": {
"ExecuteTime": {
"end_time": "2025-05-07T21:40:24.329858Z",
"start_time": "2025-05-07T21:40:24.327366Z"
}
},
"outputs": [],
"source": [
"for i in range(0, 10):\n",
" grid.set_obstacle(9, i)\n",
"\n",
"for j in range(4, 10):\n",
" grid.set_obstacle(j, 9)\n",
"\n",
"for i in range(9, 20):\n",
" grid.set_obstacle(16, i)"
]
},
{
"cell_type": "markdown",
"id": "334e0e61",
"metadata": {},
"source": [
"## Initialize A* Parameters"
]
},
{
"cell_type": "code",
"execution_count": 20,
"id": "d480bcf1",
"metadata": {
"ExecuteTime": {
"end_time": "2025-05-07T21:40:24.378185Z",
"start_time": "2025-05-07T21:40:24.374640Z"
}
},
"outputs": [],
"source": [
"open = Queue('PRIO', 'f')\n",
"open.push(grid.grid[0][0])\n",
"closed = Queue('PRIO', 'f')\n",
"neighbors = []\n",
"path = []\n",
"done = False"
]
},
{
"cell_type": "markdown",
"id": "6898177d",
"metadata": {},
"source": [
"## Initialize PyGame Window"
]
},
{
"cell_type": "code",
"execution_count": 21,
"id": "a8c78a46",
"metadata": {
"ExecuteTime": {
"end_time": "2025-05-07T21:40:25.086317Z",
"start_time": "2025-05-07T21:40:24.429636Z"
}
},
"outputs": [],
"source": [
"pygame.init()\n",
"screen = pygame.display.set_mode(size)\n",
"pygame.display.set_caption(\"A* Algorithm\")\n",
"clock = pygame.time.Clock()\n",
"\n",
"def update_screen():\n",
" screen.fill(BLACK)\n",
" grid.draw(screen)\n",
" pygame.display.flip()\n",
" clock.tick(60)"
]
},
{
"cell_type": "markdown",
"id": "3939b45f",
"metadata": {},
"source": [
"## A*-Algorithm"
]
},
{
"cell_type": "code",
"execution_count": 22,
"id": "4c138642",
"metadata": {
"ExecuteTime": {
"end_time": "2025-05-07T21:40:49.022562Z",
"start_time": "2025-05-07T21:40:25.146989Z"
}
},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"Gefunden\n"
]
}
],
"source": [
"while not done:\n",
" for event in pygame.event.get():\n",
" if event.type == pygame.QUIT:\n",
" done = True\n",
"\n",
" while not open.is_empty():\n",
" current_field = open.pop()\n",
" grid.set_current(current_field.x, current_field.y)\n",
" \n",
" update_screen()\n",
"\n",
" if current_field.x == grid.target[0] and current_field.y == grid.target[1]: \n",
" path.append(current_field)\n",
" grid.set_path(current_field.x, current_field.y)\n",
" \n",
" while not (current_field.x == grid.start[0] and current_field.y == grid.start[1]):\n",
" current_field = current_field.parent\n",
" path.insert(0, current_field)\n",
" grid.set_path(current_field.x, current_field.y)\n",
"\n",
" update_screen()\n",
"\n",
" open.clear()\n",
" # done = True\n",
"\n",
" closed.push(current_field)\n",
" grid.set_visited(current_field.x, current_field.y)\n",
"\n",
"\n",
" for dx, dy in [(0, -1), (-1, 0), (0, 1), (1, 0)]:\n",
" nx = current_field.x + dx\n",
" ny = current_field.y + dy\n",
"\n",
" if 0 <= nx < grid.cols and 0 <= ny < grid.rows:\n",
" neighbor = grid.grid[nx][ny]\n",
"\n",
" if neighbor.state == \"obstacale\" or closed.items.__contains__(neighbor):\n",
" continue\n",
"\n",
" tentative_g = current_field.g + 1\n",
"\n",
" if tentative_g < neighbor.g:\n",
" neighbor.parent = current_field\n",
" neighbor.g = tentative_g\n",
" neighbor.h = grid.heuristic(neighbor)\n",
" neighbor.f = neighbor.g + neighbor.h\n",
"\n",
" if open.items.__contains__(neighbor):\n",
" open.items.sort(key=lambda item: item.f)\n",
" else:\n",
" open.push(neighbor)\n",
"\n",
" update_screen()\n",
" \n",
"if len(path) == 0:\n",
" print(\"No path between\")\n",
"else:\n",
" print(\"Gefunden\")\n",
"\n",
"pygame.quit()"
]
}
],
"metadata": {
"kernelspec": {
"display_name": ".env",
"language": "python",
"name": "python3"
},
"language_info": {
"codemirror_mode": {
"name": "ipython",
"version": 3
},
"file_extension": ".py",
"mimetype": "text/x-python",
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython3",
"version": "3.13.3"
}
},
"nbformat": 4,
"nbformat_minor": 5
}