seally 0.1.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,20 @@
1
+ # Python-generated files
2
+ __pycache__/
3
+ *.py[oc]
4
+ build/
5
+ dist/
6
+ wheels/
7
+ *.egg-info
8
+
9
+ # Virtual environments
10
+ .venv
11
+
12
+ # Python build artifacts
13
+ *.egg-info/
14
+ .egg-fno
15
+ dist/
16
+ build/
17
+ *.egg
18
+
19
+ # vS code
20
+ .vscode/
@@ -0,0 +1 @@
1
+ 3.13
seally-0.1.0/PKG-INFO ADDED
@@ -0,0 +1,37 @@
1
+ Metadata-Version: 2.4
2
+ Name: seally
3
+ Version: 0.1.0
4
+ Summary: A simple planning library for prototyping
5
+ Project-URL: Homepage, https://github.com/nick-Sutton/Seally
6
+ Project-URL: Documentation, https://nick-Sutton.github.io/Seally/
7
+ Project-URL: Repository, https://github.com/nick-Sutton/Seally
8
+ Author-email: Nicholas Sutton <nicksutton46@gmail.com>
9
+ License: MIT
10
+ Keywords: AI,Motion Planning,Robotics
11
+ Classifier: License :: OSI Approved :: MIT License
12
+ Classifier: Operating System :: OS Independent
13
+ Classifier: Programming Language :: Python :: 3
14
+ Requires-Python: >=3.11
15
+ Requires-Dist: networkx[default]>=3.4
16
+ Requires-Dist: numpy>=2.0
17
+ Requires-Dist: pandas>=3.0
18
+ Requires-Dist: pygame>=2.6
19
+ Description-Content-Type: text/markdown
20
+
21
+ ### Seally
22
+ Seally is a planning library that I build to prototype planning algorithms. It currently supports static grid based enviroments.
23
+
24
+ #### Todo
25
+ - [ ] Create better visualization tools
26
+ - [ ] Add enviroment builder
27
+ - [ ] Add performance logging
28
+ - [ ] Add Configuration space enviroments
29
+ - [ ] Find a better map file format
30
+ - [ ] Allow for growing regions
31
+
32
+ ####
33
+ 1. Start with a map
34
+ 2. Grag start and goal positions
35
+ 3. Left-click to place obstacles
36
+ 4. Right-click to delete obstacles
37
+ 5. Robot should simulate SLAM
seally-0.1.0/README.md ADDED
@@ -0,0 +1,17 @@
1
+ ### Seally
2
+ Seally is a planning library that I build to prototype planning algorithms. It currently supports static grid based enviroments.
3
+
4
+ #### Todo
5
+ - [ ] Create better visualization tools
6
+ - [ ] Add enviroment builder
7
+ - [ ] Add performance logging
8
+ - [ ] Add Configuration space enviroments
9
+ - [ ] Find a better map file format
10
+ - [ ] Allow for growing regions
11
+
12
+ ####
13
+ 1. Start with a map
14
+ 2. Grag start and goal positions
15
+ 3. Left-click to place obstacles
16
+ 4. Right-click to delete obstacles
17
+ 5. Robot should simulate SLAM
@@ -0,0 +1 @@
1
+ # API Reference
@@ -0,0 +1 @@
1
+ # Getting Started
@@ -0,0 +1 @@
1
+ # Welcome to My Project
@@ -0,0 +1,27 @@
1
+ from seally.common.path import Path
2
+ from seally.common.heuristics import chebyshev_distance
3
+ from seally.env.grid_map import GridMap, GridCell
4
+ from seally.planners.a_star import AStar
5
+ from seally.viz.vizualizer import Visualizer2D
6
+
7
+ def main():
8
+ # Create an enviroment from a map file
9
+ env: GridMap = GridMap(False, './maps/map2.csv')
10
+
11
+ # Create a planner and pass in the heuristic
12
+ a_star = AStar(env, chebyshev_distance)
13
+
14
+ # Define the source and goal positions
15
+ source = GridCell(0, 4)
16
+ goal = GridCell(11, 2)
17
+
18
+ # Find the shortest path from the start to the goal
19
+ path: Path = a_star.compute_path(source, goal)
20
+
21
+ # Visualize the path
22
+ viz = Visualizer2D(screen_size=(env.x_dim, env.y_dim))
23
+ viz.run_visualization(path, env)
24
+
25
+
26
+ if __name__ == "__main__":
27
+ main()
@@ -0,0 +1,19 @@
1
+ from seally.common.heuristics import chebyshev_distance
2
+ from seally.env.grid_map import GridMap
3
+ from seally.planners.a_star import AStar
4
+ from seally.viz.vizualizer import InteractiveVisualizer2D
5
+
6
+ def main():
7
+ # Create an enviroment from a map file
8
+ env: GridMap = GridMap(False, './maps/map7.csv')
9
+
10
+ # Create a planner and pass in the heuristic
11
+ a_star = AStar(env, chebyshev_distance)
12
+
13
+ # Visualize the path
14
+ viz = InteractiveVisualizer2D(planner=a_star)
15
+ viz.run_visualization(env)
16
+
17
+
18
+ if __name__ == "__main__":
19
+ main()
@@ -0,0 +1,7 @@
1
+ 0,0,1,1,0,1,0,0,0,0,0,0
2
+ 0,0,0,0,0,1,0,1,1,1,1,0
3
+ 0,0,1,1,0,1,0,0,0,1,0,0
4
+ 0,0,1,0,0,0,0,0,0,1,1,0
5
+ 0,0,1,1,1,1,0,0,0,1,0,0
6
+ 0,0,1,0,0,1,0,1,1,1,0,0
7
+ 0,0,1,0,0,0,0,0,0,0,0,0
@@ -0,0 +1,15 @@
1
+ 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1
2
+ 1,0,0,0,0,0,0,0,0,0,0,0,0,0,1
3
+ 1,0,1,1,1,1,1,1,1,1,1,0,1,0,1
4
+ 1,0,1,0,0,0,0,0,0,0,1,0,1,0,1
5
+ 1,0,1,0,1,1,1,1,1,0,1,0,1,0,1
6
+ 1,0,1,0,1,0,0,0,1,0,1,0,1,0,1
7
+ 1,0,1,0,1,0,1,0,1,0,0,0,1,0,1
8
+ 1,0,0,0,1,0,1,0,1,1,1,1,1,0,1
9
+ 1,0,1,0,1,0,1,0,0,0,0,0,0,0,1
10
+ 1,0,1,0,0,0,1,1,1,1,1,0,1,0,1
11
+ 1,0,1,1,1,1,1,0,0,0,1,0,1,0,1
12
+ 1,0,0,0,0,0,0,0,1,0,1,0,0,0,1
13
+ 1,0,1,1,1,1,1,1,1,0,1,1,1,0,1
14
+ 1,0,0,0,0,0,0,0,0,0,0,0,0,0,1
15
+ 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1
@@ -0,0 +1,12 @@
1
+ 1,1,1,1,1,1,1,1,1,1,1,1
2
+ 1,0,0,0,0,0,0,0,0,0,0,1
3
+ 1,0,0,0,0,0,0,0,0,0,0,1
4
+ 1,0,0,1,1,0,0,1,1,0,0,1
5
+ 1,0,0,1,1,0,0,1,1,0,0,1
6
+ 1,0,0,0,0,0,0,0,0,0,0,1
7
+ 1,0,0,0,0,0,0,0,0,0,0,1
8
+ 1,0,0,1,1,0,0,1,1,0,0,1
9
+ 1,0,0,1,1,0,0,1,1,0,0,1
10
+ 1,0,0,0,0,0,0,0,0,0,0,1
11
+ 1,0,0,0,0,0,0,0,0,0,0,1
12
+ 1,1,1,1,1,1,1,1,1,1,1,1
@@ -0,0 +1,10 @@
1
+ 1,1,1,1,1,1,1,1,1,0,0,1,1,1,1,1,1,1,1,1
2
+ 1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1
3
+ 1,0,0,0,0,0,0,0,1,1,1,1,0,0,0,0,0,0,0,1
4
+ 1,0,0,0,0,0,0,0,1,0,0,1,0,0,0,0,0,0,0,1
5
+ 1,0,0,1,1,0,0,0,1,0,0,1,0,0,0,1,1,0,0,1
6
+ 1,0,0,1,1,0,0,0,1,0,0,1,0,0,0,1,1,0,0,1
7
+ 1,0,0,0,0,0,0,0,1,0,0,1,0,0,0,0,0,0,0,1
8
+ 1,0,0,0,0,0,0,0,1,1,1,1,0,0,0,0,0,0,0,1
9
+ 1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1
10
+ 1,1,1,1,1,1,1,1,1,0,0,1,1,1,1,1,1,1,1,1
@@ -0,0 +1,16 @@
1
+ 1,1,1,1,1,1,1,0,0,1,1,1,1,1,1,1
2
+ 1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1
3
+ 1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1
4
+ 1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1
5
+ 1,0,0,0,1,1,1,1,1,1,1,1,0,0,0,1
6
+ 1,0,0,0,1,0,0,0,0,0,0,1,0,0,0,1
7
+ 0,0,0,0,1,0,0,0,0,0,0,1,0,0,0,0
8
+ 0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0
9
+ 0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0
10
+ 0,0,0,0,1,0,0,0,0,0,0,1,0,0,0,0
11
+ 1,0,0,0,1,0,0,0,0,0,0,1,0,0,0,1
12
+ 1,0,0,0,1,1,1,0,0,1,1,1,0,0,0,1
13
+ 1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1
14
+ 1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1
15
+ 1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1
16
+ 1,1,1,1,1,1,1,0,0,1,1,1,1,1,1,1
@@ -0,0 +1,13 @@
1
+ 1,1,1,1,1,1,1,1,1,1,1,1,1
2
+ 1,0,0,0,0,0,0,0,0,0,0,0,1
3
+ 1,0,1,1,1,1,1,1,1,1,1,0,1
4
+ 1,0,1,0,0,0,0,0,0,0,1,0,1
5
+ 1,0,1,0,1,1,1,1,1,0,1,0,1
6
+ 1,0,1,0,1,0,0,0,1,0,1,0,1
7
+ 1,0,1,0,1,0,1,0,1,0,1,0,1
8
+ 1,0,1,0,1,0,0,0,1,0,1,0,1
9
+ 1,0,1,0,1,1,1,1,1,0,1,0,1
10
+ 1,0,1,0,0,0,0,0,0,0,1,0,1
11
+ 1,0,1,1,1,1,1,1,1,1,1,0,1
12
+ 1,0,0,0,0,0,0,0,0,0,0,0,1
13
+ 1,1,1,1,1,1,1,1,1,1,1,1,1
@@ -0,0 +1,30 @@
1
+ 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1
2
+ 1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1
3
+ 1,0,1,1,1,1,1,1,1,1,1,1,1,0,1,1,1,1,1,1,1,0,1,1,1,1,1,1,0,1
4
+ 1,0,1,0,0,0,0,0,0,0,0,0,1,0,1,0,0,0,0,0,1,0,1,0,0,0,0,1,0,1
5
+ 1,0,1,0,1,1,1,1,1,1,1,0,1,0,1,0,1,1,1,0,1,0,1,0,1,1,0,1,0,1
6
+ 1,0,1,0,1,0,0,0,0,0,1,0,1,0,1,0,1,0,1,0,1,0,1,0,1,0,0,1,0,1
7
+ 1,0,1,0,1,0,1,1,1,0,1,0,1,0,0,0,1,0,1,0,1,0,1,0,1,0,1,1,0,1
8
+ 1,0,1,0,1,0,1,0,0,0,1,0,1,1,1,0,1,0,1,0,1,0,1,0,0,0,0,1,0,1
9
+ 1,0,1,0,1,0,1,0,1,0,1,0,0,0,1,0,1,0,0,0,1,0,1,1,1,1,0,1,0,1
10
+ 1,0,0,0,1,0,1,0,1,0,0,0,1,0,1,0,0,0,1,0,0,0,0,0,0,1,0,0,0,1
11
+ 1,0,1,0,0,0,1,0,1,1,1,0,1,0,1,1,1,0,1,1,1,1,1,1,0,1,1,1,0,1
12
+ 1,0,1,1,1,0,1,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,1,0,1
13
+ 1,0,0,0,1,0,0,0,1,0,1,1,1,1,1,0,1,1,1,1,1,0,0,1,1,1,0,1,0,1
14
+ 1,0,1,0,1,1,1,0,1,0,0,0,0,0,1,0,1,0,0,0,1,0,1,0,0,1,0,1,0,1
15
+ 1,0,1,0,0,0,1,0,1,1,1,1,1,0,1,0,1,0,1,0,1,0,1,0,1,1,0,1,0,1
16
+ 1,0,1,1,1,0,1,0,0,0,0,0,1,0,0,0,1,0,1,0,0,0,1,0,0,0,0,1,0,1
17
+ 1,0,0,0,1,0,1,1,1,1,1,0,1,1,1,0,1,0,1,1,1,0,1,1,1,1,0,1,0,1
18
+ 1,0,1,0,1,0,0,0,0,0,1,0,0,0,1,0,0,0,0,0,1,0,0,0,0,0,0,1,0,1
19
+ 1,0,1,0,1,1,1,1,1,0,1,1,1,0,1,1,1,1,1,0,1,1,1,1,1,1,0,1,0,1
20
+ 1,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1
21
+ 1,0,1,1,1,1,1,1,1,0,1,1,1,1,1,0,1,1,1,1,1,0,1,1,1,1,1,1,0,1
22
+ 1,0,0,0,0,0,0,0,1,0,1,0,0,0,1,0,1,0,0,0,1,0,1,0,0,0,0,0,0,1
23
+ 1,0,1,1,1,1,1,0,1,0,1,0,1,0,1,0,0,0,1,0,1,0,1,0,1,1,1,1,0,1
24
+ 1,0,1,0,0,0,1,0,1,0,0,0,1,0,0,0,1,0,1,0,0,0,1,0,1,0,0,1,0,1
25
+ 1,0,1,0,1,0,1,0,1,1,1,0,1,1,1,0,1,0,1,1,1,0,1,0,0,0,1,1,0,1
26
+ 1,0,1,0,1,0,0,0,0,0,1,0,0,0,1,0,1,0,0,0,1,0,1,1,1,0,0,1,0,1
27
+ 1,0,1,0,1,1,1,1,1,0,1,1,1,0,1,0,1,1,1,0,1,0,0,0,1,1,0,1,0,1
28
+ 1,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,1,0,1,0,0,0,0,1,0,1
29
+ 1,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,1,1,1,1,1,1,0,1,0,1
30
+ 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1
@@ -0,0 +1,33 @@
1
+ site_name: Seally
2
+ site_url: https://nick-Sutton.github.io/Seally/
3
+ repo_url: https://github.com/nick-Sutton/Seally
4
+ repo_name: nick-Sutton/Seally
5
+
6
+ theme:
7
+ name: material
8
+ features:
9
+ - navigation.tabs
10
+ - navigation.sections
11
+ - toc.integrate
12
+ - search.suggest
13
+ palette:
14
+ - scheme: default
15
+ toggle:
16
+ icon: material/brightness-7
17
+ name: Switch to dark mode
18
+ - scheme: slate
19
+ toggle:
20
+ icon: material/brightness-4
21
+ name: Switch to light mode
22
+
23
+ nav:
24
+ - Home: index.md
25
+ - Getting Started: getting-started.md
26
+ - API Reference: api.md
27
+
28
+ markdown_extensions:
29
+ - pymdownx.highlight
30
+ - pymdownx.superfences
31
+ - admonition
32
+ - toc:
33
+ permalink: true
@@ -0,0 +1,39 @@
1
+ [project]
2
+ name = "seally"
3
+ version = "0.1.0"
4
+ description = "A simple planning library for prototyping "
5
+ readme = "README.md"
6
+ license = { text = "MIT" }
7
+ requires-python = ">=3.11"
8
+ dependencies = [
9
+ "networkx[default]>=3.4",
10
+ "numpy>=2.0",
11
+ "pandas>=3.0",
12
+ "pygame>=2.6",
13
+ ]
14
+ keywords = ["Motion Planning", "AI", "Robotics"]
15
+ authors = [
16
+ { name = "Nicholas Sutton", email = "nicksutton46@gmail.com" }
17
+ ]
18
+ classifiers = [
19
+ "Programming Language :: Python :: 3",
20
+ "License :: OSI Approved :: MIT License",
21
+ "Operating System :: OS Independent",
22
+ ]
23
+
24
+ [project.urls]
25
+ Homepage = "https://github.com/nick-Sutton/Seally"
26
+ Documentation = "https://nick-Sutton.github.io/Seally/"
27
+ Repository = "https://github.com/nick-Sutton/Seally"
28
+ [build-system]
29
+ requires = ["hatchling"]
30
+ build-backend = "hatchling.build"
31
+
32
+ [tool.hatch.build.targets.wheel]
33
+ packages = ["src/seally"]
34
+
35
+ [dependency-groups]
36
+ dev = [
37
+ "mkdocs>=1.0,<2.0",
38
+ "mkdocs-material>=9.7.6",
39
+ ]
File without changes
File without changes
@@ -0,0 +1,33 @@
1
+ from seally.env.grid_map import GridCell
2
+ import numpy as np
3
+
4
+ def euclidean_distance(source: GridCell, goal: GridCell) -> float:
5
+ source_mat = np.array((source.x, source.y))
6
+ goal_mat = np.array((goal.x, goal.y))
7
+
8
+ dist = np.linalg.norm(source_mat - goal_mat)
9
+
10
+ return dist
11
+
12
+ def manhattan_distance(source: GridCell, goal: GridCell) -> float:
13
+ source_mat = np.array((source.x, source.y))
14
+ goal_mat = np.array((goal.x, goal.y))
15
+
16
+ dist = np.sum(np.abs(source_mat - goal_mat))
17
+
18
+ return dist
19
+
20
+ def chebyshev_distance(source: GridCell, goal: GridCell) -> float:
21
+ source_mat = np.array((source.x, source.y))
22
+ goal_mat = np.array((goal.x, goal.y))
23
+
24
+ dist = np.linalg.norm(source_mat - goal_mat, ord=np.inf)
25
+
26
+ return dist
27
+
28
+
29
+
30
+
31
+
32
+
33
+
@@ -0,0 +1,4 @@
1
+ from typing import List, Tuple, Union
2
+ from seally.env.grid_map import GridCell
3
+
4
+ Path = Union[List[GridCell], List[float]]
File without changes
@@ -0,0 +1,76 @@
1
+ from typing import List
2
+
3
+ import numpy as np
4
+ import pandas as pd
5
+
6
+ class GridCell():
7
+ def __init__(self, x: int, y: int):
8
+ self.x = x
9
+ self.y = y
10
+
11
+ def __hash__(self):
12
+ return hash((self.x, self.y))
13
+
14
+ def __eq__(self, other):
15
+ return self.x == other.x and self.y == other.y
16
+
17
+ class GridMap:
18
+ def __init__(self, gen_random: bool = True, file_path: str = None):
19
+ if gen_random:
20
+ pass
21
+ else:
22
+ self.map = pd.read_csv(file_path).to_numpy()
23
+
24
+ self.x_dim = self.map.shape[1]
25
+ self.y_dim = self.map.shape[0]
26
+
27
+ def is_occupied(self, cell: GridCell) -> bool:
28
+ """
29
+ Determines if the provided coordinates are in collision with an obstacle
30
+
31
+ param: cell to check
32
+ return: True if the position is in collision
33
+ """
34
+ return self.map[cell.y, cell.x] > 0
35
+
36
+ def in_bounds(self, cell: GridCell) -> bool:
37
+ """
38
+ Determines if the provided coordinates within the bounds of the map
39
+
40
+ param: cell to check
41
+ return: True if the position is in bounds
42
+ """
43
+
44
+ if cell.x < 0 or cell.x > self.x_dim - 1:
45
+ return False
46
+
47
+ if cell.y < 0 or cell.y > self.y_dim - 1:
48
+ return False
49
+
50
+ return True
51
+
52
+ def get_neighbors(self, cell: GridCell) -> List[GridCell]:
53
+ """
54
+ Retuns a list of all valid neighbors for a given cell in the Gripmap
55
+ A valid cell is a cell that is within the bounds of the map.
56
+
57
+ params: cell to retrieve neighbors for
58
+ returns: A list of the cells valid neighbors
59
+ """
60
+
61
+ # create a mask of the indicies of the neighboring cells relative to the current cell
62
+ shift_mask = np.array([[-1,-1],[-1,0],[-1,1],
63
+ [0,-1], [0,1],
64
+ [1,-1], [1,0], [1,1]])
65
+
66
+ # broadcast the current cell to each of the shift mask offsets and add them to produce an array of neighbor coordinates
67
+ neighbor_indicies = np.array([cell.x, cell.y]) + shift_mask # shape (8, 2)
68
+
69
+ # create a mask to validate that all cells are in the bounds of the map
70
+ bounds_mask = (
71
+ (neighbor_indicies[:, 0] >= 0) & (neighbor_indicies[:, 0] < self.x_dim) &
72
+ (neighbor_indicies[:, 1] >= 0) & (neighbor_indicies[:, 1] < self.y_dim)
73
+ )
74
+
75
+ # apply the bounds map to each coordinate and return only the cells that are in bounds
76
+ return [GridCell(x, y) for x, y in neighbor_indicies[bounds_mask]]
File without changes
@@ -0,0 +1,65 @@
1
+ from collections.abc import Callable
2
+ import heapq
3
+ import numpy as np
4
+ from seally.env.grid_map import GridMap, GridCell
5
+ from seally.common.path import Path
6
+
7
+ class AStar():
8
+ def __init__(self, env: GridMap, heuristic: Callable[[GridCell, GridCell], float]):
9
+ self.env = env
10
+ self.heuristic = heuristic
11
+
12
+ def cost(self, source: GridCell, goal: GridCell) -> float:
13
+ """
14
+ Computes the cost of going from one cell to another in the map
15
+ """
16
+ dx, dy = abs(source.x - goal.x), abs(source.y - goal.y)
17
+ return np.sqrt(2) if dx + dy == 2 else 1.0
18
+
19
+ def compute_path(self, source: GridCell, goal: GridCell) -> Path:
20
+ if not self.env.in_bounds(source) or self.env.is_occupied(source):
21
+ raise Exception("Source is not a valid position")
22
+
23
+ if not self.env.in_bounds(goal) or self.env.is_occupied(goal):
24
+ raise Exception("Goal is not a valid position")
25
+
26
+ tie_count = 0
27
+ open_set = []
28
+ heapq.heappush(open_set, (0.0, tie_count, source))
29
+
30
+ came_from = {source: None}
31
+ cost_so_far = {source: 0.0}
32
+ closed_set = set() # track fully explored cells
33
+
34
+ while open_set:
35
+ _, _, current = heapq.heappop(open_set)
36
+
37
+ if current in closed_set: # already explored optimally, skip
38
+ continue
39
+
40
+ closed_set.add(current)
41
+
42
+ if current == goal:
43
+ break
44
+
45
+ for next_cell in self.env.get_neighbors(current):
46
+ if self.env.is_occupied(next_cell) or next_cell in closed_set:
47
+ continue
48
+ new_cost = cost_so_far[current] + self.cost(current, next_cell)
49
+ if next_cell not in cost_so_far or new_cost < cost_so_far[next_cell]:
50
+ cost_so_far[next_cell] = new_cost
51
+ priority = new_cost + self.heuristic(next_cell, goal)
52
+ tie_count += 1
53
+ heapq.heappush(open_set, (priority, tie_count, next_cell))
54
+ came_from[next_cell] = current
55
+
56
+ if current != goal:
57
+ raise Exception("Path not found")
58
+
59
+ path = []
60
+ current = goal
61
+ while current is not None:
62
+ path.append(current)
63
+ current = came_from.get(current)
64
+ path.reverse()
65
+ return path
File without changes
@@ -0,0 +1 @@
1
+ #https://theory.stanford.edu/~amitp/GameProgramming/Variations.html#jump-point-search
@@ -0,0 +1 @@
1
+ #https://www.ccs.neu.edu/home/rplatt/cs5335_fall2016/slides/bugs_wavefront.pdf
File without changes