From afa3c146b05c9c795209210a4eb797bc0f781a67 Mon Sep 17 00:00:00 2001 From: 4eker <423785z@gmail.com> Date: Sat, 23 May 2026 13:37:43 +0300 Subject: [PATCH] micro bag fix --- pomelovsd/ExitMaze/Builder/Builder.py | 30 ++ .../ExitMaze/Builder/BuilderInterface.py | 6 + pomelovsd/ExitMaze/Builder/__init__.py | 0 pomelovsd/ExitMaze/Core/Benchmark.py | 3 +- pomelovsd/ExitMaze/Core/Cell.py | 2 +- pomelovsd/ExitMaze/Core/__init__.py | 0 pomelovsd/ExitMaze/MazeSolver/SearchStats.py | 5 + pomelovsd/ExitMaze/MazeSolver/Solver.py | 2 +- pomelovsd/ExitMaze/MazeSolver/__init__.py | 0 .../ExitMaze/Observer_Command/Command.py | 6 + .../ExitMaze/Observer_Command/ConsoleView.py | 31 ++ .../ExitMaze/Observer_Command/MoveCommand.py | 2 +- .../ExitMaze/Observer_Command/__init__.py | 0 pomelovsd/ExitMaze/Strategies/AStar.py | 2 +- pomelovsd/ExitMaze/Strategies/BFS.py | 23 ++ pomelovsd/ExitMaze/Strategies/DFS.py | 4 +- pomelovsd/ExitMaze/Strategies/__init__.py | 0 pomelovsd/ExitMaze/main.ipynb | 335 +++++++++++++++++- 18 files changed, 437 insertions(+), 14 deletions(-) create mode 100644 pomelovsd/ExitMaze/Builder/BuilderInterface.py create mode 100644 pomelovsd/ExitMaze/Builder/__init__.py create mode 100644 pomelovsd/ExitMaze/Core/__init__.py create mode 100644 pomelovsd/ExitMaze/MazeSolver/__init__.py create mode 100644 pomelovsd/ExitMaze/Observer_Command/__init__.py create mode 100644 pomelovsd/ExitMaze/Strategies/__init__.py diff --git a/pomelovsd/ExitMaze/Builder/Builder.py b/pomelovsd/ExitMaze/Builder/Builder.py index e69de29..69eec1a 100644 --- a/pomelovsd/ExitMaze/Builder/Builder.py +++ b/pomelovsd/ExitMaze/Builder/Builder.py @@ -0,0 +1,30 @@ +from Core.Cell import Cell +from Core.Maze import Maze +from Builder.BuilderInterface import MazeBuilders + +class TextFileMazeBuilder(MazeBuilders): + + def build_from_file(self, filename): + grid = [] + start = None + exit = None + + with open(filename, "r", encoding="utf-8") as f: + lines = [line.rstrip("\n") for line in f] + + for y, line in enumerate(lines): + row = [] + for x, ch in enumerate(line): + + cell = Cell(x, y, is_wall = (ch == "#"), is_start = (ch == "S"), is_exit = (ch == "E")) + + if (ch == "S"): + start = cell + if (ch == "E"): + exit = cell + + row.append(cell) + + grid.append(row) + + return Maze(grid, start, exit) \ No newline at end of file diff --git a/pomelovsd/ExitMaze/Builder/BuilderInterface.py b/pomelovsd/ExitMaze/Builder/BuilderInterface.py new file mode 100644 index 0000000..d9c2dff --- /dev/null +++ b/pomelovsd/ExitMaze/Builder/BuilderInterface.py @@ -0,0 +1,6 @@ +from abc import ABC, abstractmethod + +class MazeBuilders(ABC): + @abstractmethod + def build_from_file(self, filename): + pass \ No newline at end of file diff --git a/pomelovsd/ExitMaze/Builder/__init__.py b/pomelovsd/ExitMaze/Builder/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/pomelovsd/ExitMaze/Core/Benchmark.py b/pomelovsd/ExitMaze/Core/Benchmark.py index ad31d92..0977605 100644 --- a/pomelovsd/ExitMaze/Core/Benchmark.py +++ b/pomelovsd/ExitMaze/Core/Benchmark.py @@ -16,4 +16,5 @@ def RunBenchmark(maze, strategies, repeats = 5): with open("results.csv", "w", newline="") as f: writer = csv.writer(f) writer.writerow(["strategy", "time_ms", "visited", "path_length"]) - writer.writerows(rows) \ No newline at end of file + writer.writerows(rows) + \ No newline at end of file diff --git a/pomelovsd/ExitMaze/Core/Cell.py b/pomelovsd/ExitMaze/Core/Cell.py index 44032ca..dd79f48 100644 --- a/pomelovsd/ExitMaze/Core/Cell.py +++ b/pomelovsd/ExitMaze/Core/Cell.py @@ -1,5 +1,5 @@ class Cell: - def __init__(self, x, y, isWall = False, isStart = False, isExit = False): + def __init__(self, x = 0, y = 0, isWall = False, isStart = False, isExit = False): self.x = x self.y = y self.isWall = isWall diff --git a/pomelovsd/ExitMaze/Core/__init__.py b/pomelovsd/ExitMaze/Core/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/pomelovsd/ExitMaze/MazeSolver/SearchStats.py b/pomelovsd/ExitMaze/MazeSolver/SearchStats.py index e69de29..580ff4e 100644 --- a/pomelovsd/ExitMaze/MazeSolver/SearchStats.py +++ b/pomelovsd/ExitMaze/MazeSolver/SearchStats.py @@ -0,0 +1,5 @@ +class SearchStats: + def __init__(self, time_ms, visited_cells, path_length): + self.time_ms = time_ms + self.visited_cells = visited_cells + self.path_length = path_length \ No newline at end of file diff --git a/pomelovsd/ExitMaze/MazeSolver/Solver.py b/pomelovsd/ExitMaze/MazeSolver/Solver.py index 4d304da..59cf71f 100644 --- a/pomelovsd/ExitMaze/MazeSolver/Solver.py +++ b/pomelovsd/ExitMaze/MazeSolver/Solver.py @@ -1,4 +1,4 @@ -from SearchStats import SearchStats +from .SearchStats import SearchStats import time class MazeSolver: diff --git a/pomelovsd/ExitMaze/MazeSolver/__init__.py b/pomelovsd/ExitMaze/MazeSolver/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/pomelovsd/ExitMaze/Observer_Command/Command.py b/pomelovsd/ExitMaze/Observer_Command/Command.py index e69de29..6c5f048 100644 --- a/pomelovsd/ExitMaze/Observer_Command/Command.py +++ b/pomelovsd/ExitMaze/Observer_Command/Command.py @@ -0,0 +1,6 @@ +class Command: + def execute(self): + pass + def undo(self): + pass + \ No newline at end of file diff --git a/pomelovsd/ExitMaze/Observer_Command/ConsoleView.py b/pomelovsd/ExitMaze/Observer_Command/ConsoleView.py index e69de29..f619378 100644 --- a/pomelovsd/ExitMaze/Observer_Command/ConsoleView.py +++ b/pomelovsd/ExitMaze/Observer_Command/ConsoleView.py @@ -0,0 +1,31 @@ +from .Observer import Observer + +class ConsoleView(Observer): + + def update(self, event): + print("[событие]", event) + + def render(self, maze, path = None): + path = set(path or []) + + for row in maze.grid: + line = "" + + for cell in row: + + if cell in path: + line += "*" + + elif cell.is_wall: + line += "#" + + elif cell.is_start: + line += "S" + + elif cell.is_exit: + line += "E" + + else: + line += " " + + print(line) \ No newline at end of file diff --git a/pomelovsd/ExitMaze/Observer_Command/MoveCommand.py b/pomelovsd/ExitMaze/Observer_Command/MoveCommand.py index d3f054d..e107ed5 100644 --- a/pomelovsd/ExitMaze/Observer_Command/MoveCommand.py +++ b/pomelovsd/ExitMaze/Observer_Command/MoveCommand.py @@ -1,4 +1,4 @@ -from Command import Command +from .Command import Command class MoveCommand(Command): diff --git a/pomelovsd/ExitMaze/Observer_Command/__init__.py b/pomelovsd/ExitMaze/Observer_Command/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/pomelovsd/ExitMaze/Strategies/AStar.py b/pomelovsd/ExitMaze/Strategies/AStar.py index 87c975f..3382d61 100644 --- a/pomelovsd/ExitMaze/Strategies/AStar.py +++ b/pomelovsd/ExitMaze/Strategies/AStar.py @@ -1,4 +1,4 @@ -from strat import PathFindingStrategy +from Strategies.strat import PathFindingStrategy from path import restore import heapq diff --git a/pomelovsd/ExitMaze/Strategies/BFS.py b/pomelovsd/ExitMaze/Strategies/BFS.py index e69de29..4fadd8d 100644 --- a/pomelovsd/ExitMaze/Strategies/BFS.py +++ b/pomelovsd/ExitMaze/Strategies/BFS.py @@ -0,0 +1,23 @@ +from Strategies.strat import PathFindingStrategy +from path import restore +from collections import deque + +class BFS(PathFindingStrategy): + def findPath(self, maze, start, exit): + queue = deque([start]) + visited = {start} + parent = {} + + while queue: + current = queue.popleft() + + if current == exit: + break + + for n in maze.get_neigbors(current): + if n not in visited: + visited.add(n) + parent[n] = current + queue.append(n) + + return self.restore(parent, start, exit), len(visited) \ No newline at end of file diff --git a/pomelovsd/ExitMaze/Strategies/DFS.py b/pomelovsd/ExitMaze/Strategies/DFS.py index 9962e92..f49998e 100644 --- a/pomelovsd/ExitMaze/Strategies/DFS.py +++ b/pomelovsd/ExitMaze/Strategies/DFS.py @@ -1,9 +1,9 @@ -from strat import PathFindingStrategy +from Strategies.strat import PathFindingStrategy from path import restore class DFS(PathFindingStrategy): - def find_path(self, maze, start, exit): + def findPath(self, maze, start, exit): stack = [start] visited = {start} parent = {} diff --git a/pomelovsd/ExitMaze/Strategies/__init__.py b/pomelovsd/ExitMaze/Strategies/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/pomelovsd/ExitMaze/main.ipynb b/pomelovsd/ExitMaze/main.ipynb index 7a00a96..273dc97 100644 --- a/pomelovsd/ExitMaze/main.ipynb +++ b/pomelovsd/ExitMaze/main.ipynb @@ -2,23 +2,344 @@ "cells": [ { "cell_type": "code", - "execution_count": null, - "id": "66bfd079", + "execution_count": 21, + "id": "a1dff6b4", "metadata": {}, "outputs": [], + "source": [ + "import time\n", + "import csv\n", + "import matplotlib.pyplot as plt" + ] + }, + { + "cell_type": "code", + "execution_count": 4, + "id": "66bfd079", + "metadata": {}, + "outputs": [ + { + "ename": "ModuleNotFoundError", + "evalue": "No module named 'path'", + "output_type": "error", + "traceback": [ + "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m", + "\u001b[0;31mModuleNotFoundError\u001b[0m Traceback (most recent call last)", + "Cell \u001b[0;32mIn[4], line 5\u001b[0m\n\u001b[1;32m 3\u001b[0m \u001b[38;5;28;01mfrom\u001b[39;00m \u001b[38;5;21;01mMazeSolver\u001b[39;00m\u001b[38;5;21;01m.\u001b[39;00m\u001b[38;5;21;01mSolver\u001b[39;00m \u001b[38;5;28;01mimport\u001b[39;00m MazeSolver\n\u001b[1;32m 4\u001b[0m \u001b[38;5;28;01mfrom\u001b[39;00m \u001b[38;5;21;01mObserver_Command\u001b[39;00m\u001b[38;5;21;01m.\u001b[39;00m\u001b[38;5;21;01mConsoleView\u001b[39;00m \u001b[38;5;28;01mimport\u001b[39;00m ConsoleView\n\u001b[0;32m----> 5\u001b[0m \u001b[38;5;28;01mfrom\u001b[39;00m \u001b[38;5;21;01mStrategies\u001b[39;00m\u001b[38;5;21;01m.\u001b[39;00m\u001b[38;5;21;01mBFS\u001b[39;00m \u001b[38;5;28;01mimport\u001b[39;00m BFS\n\u001b[1;32m 6\u001b[0m \u001b[38;5;28;01mfrom\u001b[39;00m \u001b[38;5;21;01mStrategies\u001b[39;00m\u001b[38;5;21;01m.\u001b[39;00m\u001b[38;5;21;01mDFS\u001b[39;00m \u001b[38;5;28;01mimport\u001b[39;00m DFS\n\u001b[1;32m 7\u001b[0m \u001b[38;5;28;01mfrom\u001b[39;00m \u001b[38;5;21;01mStrategies\u001b[39;00m\u001b[38;5;21;01m.\u001b[39;00m\u001b[38;5;21;01mAStar\u001b[39;00m \u001b[38;5;28;01mimport\u001b[39;00m AStar\n", + "File \u001b[0;32m~/2026-rff_mp/pomelovsd/ExitMaze/Strategies/BFS.py:2\u001b[0m\n\u001b[1;32m 1\u001b[0m \u001b[38;5;28;01mfrom\u001b[39;00m \u001b[38;5;21;01m.\u001b[39;00m\u001b[38;5;21;01mstrat\u001b[39;00m \u001b[38;5;28;01mimport\u001b[39;00m PathFindingStrategy\n\u001b[0;32m----> 2\u001b[0m \u001b[38;5;28;01mfrom\u001b[39;00m \u001b[38;5;21;01mpath\u001b[39;00m \u001b[38;5;28;01mimport\u001b[39;00m restore\n\u001b[1;32m 3\u001b[0m \u001b[38;5;28;01mfrom\u001b[39;00m \u001b[38;5;21;01mcollections\u001b[39;00m \u001b[38;5;28;01mimport\u001b[39;00m deque\n\u001b[1;32m 5\u001b[0m \u001b[38;5;28;01mclass\u001b[39;00m \u001b[38;5;21;01mBFS\u001b[39;00m(PathFindingStrategy):\n", + "\u001b[0;31mModuleNotFoundError\u001b[0m: No module named 'path'" + ] + } + ], "source": [ "from Builder.Builder import TextFileMazeBuilder\n", "from Core.Benchmark import RunBenchmark\n", - "from Core.Cell import Cell\n", - "from Core.Maze import Maze\n", - "from MazeSolver.SearchStats import SearchStats\n", - "from MazeSolver.SearchStats import SearchStats" + "from MazeSolver.Solver import MazeSolver\n", + "from Observer_Command.ConsoleView import ConsoleView\n", + "from Strategies.BFS import BFS\n", + "from Strategies.DFS import DFS\n", + "from Strategies.AStar import AStar" ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "50c7010d", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "\n" + ] + } + ], + "source": [ + "print(TextFileMazeBuilder)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "6ed7f922", + "metadata": {}, + "outputs": [ + { + "ename": "ImportError", + "evalue": "cannot import name 'BFS' from 'Strategies.BFS' (/home/i4eker/2026-rff_mp/pomelovsd/ExitMaze/Strategies/BFS.py)", + "output_type": "error", + "traceback": [ + "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m", + "\u001b[0;31mImportError\u001b[0m Traceback (most recent call last)", + "Cell \u001b[0;32mIn[13], line 3\u001b[0m\n\u001b[1;32m 1\u001b[0m \u001b[38;5;28;01mfrom\u001b[39;00m \u001b[38;5;21;01mBuilder\u001b[39;00m\u001b[38;5;21;01m.\u001b[39;00m\u001b[38;5;21;01mBuilder\u001b[39;00m \u001b[38;5;28;01mimport\u001b[39;00m TextFileMazeBuilder\n\u001b[0;32m----> 3\u001b[0m \u001b[38;5;28;01mfrom\u001b[39;00m \u001b[38;5;21;01mStrategies\u001b[39;00m\u001b[38;5;21;01m.\u001b[39;00m\u001b[38;5;21;01mBFS\u001b[39;00m \u001b[38;5;28;01mimport\u001b[39;00m BFS\n\u001b[1;32m 4\u001b[0m \u001b[38;5;28;01mfrom\u001b[39;00m \u001b[38;5;21;01mStrategies\u001b[39;00m\u001b[38;5;21;01m.\u001b[39;00m\u001b[38;5;21;01mDFS\u001b[39;00m \u001b[38;5;28;01mimport\u001b[39;00m DFS\n\u001b[1;32m 5\u001b[0m \u001b[38;5;28;01mfrom\u001b[39;00m \u001b[38;5;21;01mStrategies\u001b[39;00m\u001b[38;5;21;01m.\u001b[39;00m\u001b[38;5;21;01mAStar\u001b[39;00m \u001b[38;5;28;01mimport\u001b[39;00m AStar\n", + "\u001b[0;31mImportError\u001b[0m: cannot import name 'BFS' from 'Strategies.BFS' (/home/i4eker/2026-rff_mp/pomelovsd/ExitMaze/Strategies/BFS.py)" + ] + } + ], + "source": [ + "\n", + "from Builder.Builder import TextFileMazeBuilder\n", + "\n", + "from Strategies.BFS import BFS\n", + "from Strategies.DFS import DFS\n", + "from Strategies.AStar import AStar\n", + "\n", + "from MazeSolver.Solver import MazeSolver\n", + "\n", + "\n", + "# ============================================\n", + "# ЗАГРУЗКА ЛАБИРИНТОВ\n", + "# ============================================\n", + "\n", + "builder = TextFileMazeBuilder()\n", + "\n", + "mazes = {\n", + " \"small\": builder.build_from_file(\"Mazes/small.txt\"),\n", + " \"medium\": builder.build_from_file(\"Mazes/medium.txt\"),\n", + " \"large\": builder.build_from_file(\"Mazes/large.txt\"),\n", + " \"empty\": builder.build_from_file(\"Mazes/empty.txt\"),\n", + " \"no_exit\": builder.build_from_file(\"Mazes/no_exit.txt\"),\n", + "}\n", + "\n", + "\n", + "# ============================================\n", + "# СТРАТЕГИИ\n", + "# ============================================\n", + "\n", + "strategies = {\n", + " \"BFS\": BFS(),\n", + " \"DFS\": DFS(),\n", + " \"A*\": AStar()\n", + "}\n", + "\n", + "\n", + "# ============================================\n", + "# РЕЗУЛЬТАТЫ\n", + "# ============================================\n", + "\n", + "results = []\n", + "\n", + "\n", + "# ============================================\n", + "# BENCHMARK\n", + "# ============================================\n", + "\n", + "REPEATS = 5\n", + "\n", + "for maze_name, maze in mazes.items():\n", + "\n", + " print(f\"\\n===== LABYRINTH: {maze_name} =====\")\n", + "\n", + " for strategy_name, strategy in strategies.items():\n", + "\n", + " total_time = 0\n", + " total_visited = 0\n", + " total_path = 0\n", + "\n", + " print(f\"Testing {strategy_name}...\")\n", + "\n", + " for _ in range(REPEATS):\n", + "\n", + " solver = MazeSolver(maze, strategy)\n", + "\n", + " start_time = time.perf_counter()\n", + "\n", + " stats, path = solver.solve()\n", + "\n", + " end_time = time.perf_counter()\n", + "\n", + " elapsed_ms = (end_time - start_time) * 1000\n", + "\n", + " total_time += elapsed_ms\n", + " total_visited += stats.visited_cells\n", + " total_path += stats.path_length\n", + "\n", + " avg_time = total_time / REPEATS\n", + " avg_visited = total_visited / REPEATS\n", + " avg_path = total_path / REPEATS\n", + "\n", + " results.append({\n", + " \"maze\": maze_name,\n", + " \"strategy\": strategy_name,\n", + " \"time_ms\": round(avg_time, 3),\n", + " \"visited_cells\": int(avg_visited),\n", + " \"path_length\": int(avg_path)\n", + " })\n", + "\n", + " print(\n", + " f\"{strategy_name}: \"\n", + " f\"time={avg_time:.3f} ms | \"\n", + " f\"visited={avg_visited:.0f} | \"\n", + " f\"path={avg_path:.0f}\"\n", + " )\n", + "\n", + "\n", + "# ============================================\n", + "# СОХРАНЕНИЕ CSV\n", + "# ============================================\n", + "\n", + "csv_file = \"benchmark_results.csv\"\n", + "\n", + "with open(csv_file, \"w\", newline=\"\", encoding=\"utf-8\") as file:\n", + "\n", + " writer = csv.writer(file)\n", + "\n", + " writer.writerow([\n", + " \"maze\",\n", + " \"strategy\",\n", + " \"time_ms\",\n", + " \"visited_cells\",\n", + " \"path_length\"\n", + " ])\n", + "\n", + " for row in results:\n", + " writer.writerow([\n", + " row[\"maze\"],\n", + " row[\"strategy\"],\n", + " row[\"time_ms\"],\n", + " row[\"visited_cells\"],\n", + " row[\"path_length\"]\n", + " ])\n", + "\n", + "print(f\"\\nCSV saved: {csv_file}\")\n", + "\n", + "\n", + "# ============================================\n", + "# ВЫВОД ТАБЛИЦЫ\n", + "# ============================================\n", + "\n", + "print(\"\\nRESULTS:\\n\")\n", + "\n", + "for row in results:\n", + "\n", + " print(\n", + " f\"{row['maze']:10} | \"\n", + " f\"{row['strategy']:5} | \"\n", + " f\"{row['time_ms']:10} ms | \"\n", + " f\"{row['visited_cells']:10} visited | \"\n", + " f\"{row['path_length']:5} path\"\n", + " )\n", + "\n", + "\n", + "# ============================================\n", + "# ГРАФИК ВРЕМЕНИ\n", + "# ============================================\n", + "\n", + "for maze_name in mazes.keys():\n", + "\n", + " strategy_names = []\n", + " times = []\n", + "\n", + " for row in results:\n", + "\n", + " if row[\"maze\"] == maze_name:\n", + "\n", + " strategy_names.append(row[\"strategy\"])\n", + " times.append(row[\"time_ms\"])\n", + "\n", + " plt.figure(figsize=(8, 5))\n", + "\n", + " plt.bar(strategy_names, times)\n", + "\n", + " plt.title(f\"Execution Time — {maze_name}\")\n", + " plt.xlabel(\"Strategy\")\n", + " plt.ylabel(\"Time (ms)\")\n", + "\n", + " plt.show()\n", + "\n", + "\n", + "# ============================================\n", + "# ГРАФИК ПОСЕЩЁННЫХ КЛЕТОК\n", + "# ============================================\n", + "\n", + "for maze_name in mazes.keys():\n", + "\n", + " strategy_names = []\n", + " visited = []\n", + "\n", + " for row in results:\n", + "\n", + " if row[\"maze\"] == maze_name:\n", + "\n", + " strategy_names.append(row[\"strategy\"])\n", + " visited.append(row[\"visited_cells\"])\n", + "\n", + " plt.figure(figsize=(8, 5))\n", + "\n", + " plt.bar(strategy_names, visited)\n", + "\n", + " plt.title(f\"Visited Cells — {maze_name}\")\n", + " plt.xlabel(\"Strategy\")\n", + " plt.ylabel(\"Visited Cells\")\n", + "\n", + " plt.show()\n", + "\n", + "\n", + "# ============================================\n", + "# ГРАФИК ДЛИНЫ ПУТИ\n", + "# ============================================\n", + "\n", + "for maze_name in mazes.keys():\n", + "\n", + " strategy_names = []\n", + " path_lengths = []\n", + "\n", + " for row in results:\n", + "\n", + " if row[\"maze\"] == maze_name:\n", + "\n", + " strategy_names.append(row[\"strategy\"])\n", + " path_lengths.append(row[\"path_length\"])\n", + "\n", + " plt.figure(figsize=(8, 5))\n", + "\n", + " plt.bar(strategy_names, path_lengths)\n", + "\n", + " plt.title(f\"Path Length — {maze_name}\")\n", + " plt.xlabel(\"Strategy\")\n", + " plt.ylabel(\"Path Length\")\n", + "\n", + " plt.show()\n", + "\n", + "\n", + "print(\"\\nBenchmark completed.\")" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "b001bee8", + "metadata": {}, + "outputs": [], + "source": [] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "083b0af8", + "metadata": {}, + "outputs": [], + "source": [] } ], "metadata": { + "kernelspec": { + "display_name": "Python 3", + "language": "python", + "name": "python3" + }, "language_info": { - "name": "python" + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.12.3" } }, "nbformat": 4,