pathfinding_demo/python/pathfinding_demo.ipynb
2025-09-18 18:59:47 +02:00

141 lines
17 KiB
Plaintext

{
"metadata": {
"kernelspec": {
"name": "python",
"display_name": "Python (Pyodide)",
"language": "python"
},
"language_info": {
"codemirror_mode": {
"name": "python",
"version": 3
},
"file_extension": ".py",
"mimetype": "text/x-python",
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython3",
"version": "3.8"
}
},
"nbformat_minor": 5,
"nbformat": 4,
"cells": [
{
"id": "16f8fedb-ac10-450c-b5c7-f820a985902d",
"cell_type": "markdown",
"source": "# Pathfinding demo",
"metadata": {
"tags": [],
"slideshow": {
"slide_type": ""
},
"editable": true
}
},
{
"id": "fbdf9d2c-d050-4744-b559-abc71e550725",
"cell_type": "code",
"source": "#\n# Imports\n#\n\nimport matplotlib.pyplot as plt\nimport numpy as np\nfrom typing import Protocol\nfrom dataclasses import dataclass",
"metadata": {
"trusted": true,
"tags": [],
"editable": true,
"slideshow": {
"slide_type": ""
}
},
"outputs": [],
"execution_count": null
},
{
"id": "c704cf15-95fa-49c1-af1b-c99f7b5c8b95",
"cell_type": "code",
"source": "#\n# Type and interfaces definition\n#\n\nPoint2D = tuple[int, int] # tuple(x, y)\nPath = list[Point2D]\n\nclass Map:\n \"\"\"\n 2D map consisting of cells with given cost\n \"\"\"\n array: np.array\n\n def __init__(self, width: int, height: int):\n assert width > 0\n assert height > 0\n self.array = np.zeros((width, height))\n\n def randomize(self, low: float = 0.0, high: float = 1.0):\n self.array = np.random.uniform(low, high, self.array.shape)\n\n \n\nclass PathFinder(Protocol):\n def SetMap(m: Map):\n ...\n def SetStartingPoint(p: Point2D):\n ...\n def SetEndPoint(p: Point2D):\n ...\n def CalculatePath() -> Path:\n \"\"\"\n Calculate path on a given map.\n Note: map must be set first using SetMap\n \"\"\"\n ...",
"metadata": {
"trusted": true,
"tags": [],
"editable": true,
"slideshow": {
"slide_type": ""
}
},
"outputs": [],
"execution_count": 34
},
{
"id": "043a1f1c-a7a7-4f24-b69c-c6c809830111",
"cell_type": "code",
"source": "#\n# Drawing utilities\n#\n\nclass Visualizer:\n _axes: plt.Axes\n\n def draw_map(self, m: Map) -> tuple[plt.Figure, plt.Axes]:\n M, N = m.array.shape\n _, ax = plt.subplots()\n ax.imshow(m.array, cmap='terrain', origin='lower', interpolation='none')\n self._axes = ax\n\n def draw_path(self, path: Path, color='red', label: str = None):\n xs, ys = zip(*path) \n self._axes.plot(xs, ys, 'o-', color='blue', label='Path')\n self._axes.plot(xs[0], ys[0], 'o', color='lime', markersize=8) # start\n self._axes.plot(xs[-1], ys[-1], 'o', color='magenta', markersize=8) # goal\n ",
"metadata": {
"trusted": true,
"tags": [],
"editable": true,
"slideshow": {
"slide_type": ""
}
},
"outputs": [],
"execution_count": 68
},
{
"id": "ece3a6c8-aa1d-49a8-9f4c-06ebff72f991",
"cell_type": "code",
"source": "m = Map(10, 10)\nm.randomize()\npath: Path = [(0,0), (5,5), (6,6), (1,9)]\nv = Visualizer()\nv.draw_map(m)\nprint(path)\nv.draw_path(path)",
"metadata": {
"trusted": true,
"tags": [],
"editable": true,
"slideshow": {
"slide_type": ""
}
},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": "[(0, 0), (5, 5), (6, 6), (1, 9)]\n"
},
{
"output_type": "display_data",
"data": {
"text/plain": "<Figure size 640x480 with 1 Axes>",
"image/png": "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"
},
"metadata": {}
}
],
"execution_count": 69
},
{
"id": "2ec9fb78-089d-4d51-9f16-087a04b4e8a4",
"cell_type": "code",
"source": "",
"metadata": {
"trusted": true,
"tags": [],
"editable": true,
"slideshow": {
"slide_type": ""
}
},
"outputs": [],
"execution_count": null
},
{
"id": "b050caaa-d9b5-4a22-8e6d-aaccfaa4fb1b",
"cell_type": "code",
"source": "",
"metadata": {
"trusted": true,
"tags": [],
"editable": true,
"slideshow": {
"slide_type": ""
}
},
"outputs": [],
"execution_count": null
}
]
}