py-vagabond


Namepy-vagabond JSON
Version 2.0.2 PyPI version JSON
download
home_pagehttps://github.com/Kawai-Senpai/Vagabond
SummaryVagabond is a comprehensive library for pathfinding, navigation, and environmental understanding in robotics and automation. It provides a range of algorithms and tools to help developers create efficient and sophisticated pathfinding solutions for robots and autonomous systems.
upload_time2024-09-10 06:44:30
maintainerNone
docs_urlNone
authorRanit Bhowmick
requires_pythonNone
licenseMIT License with attribution requirement
keywords pathfinding robotics navigation a* algorithm graph theory automation robotic systems
VCS
bugtrack_url
requirements No requirements were recorded.
Travis-CI No Travis.
coveralls test coverage No coveralls.
            # Vagabond

[Vagabond](https://pypi.org/project/py-vagabond/) is a powerful and flexible Python library designed to simplify the implementation of various pathfinding algorithms and related operations developed by [*Ranit Bhowmick*](https://www.linkedin.com/in/ranitbhowmick/) & [*Sayanti Chatterjee*](https://www.linkedin.com/in/sayantichatterjee/). Whether you're working on robotics, AI, or game development, Vagabond offers an easy-to-use interface for complex algorithms like A*, Dijkstra's, and more.

## Table of Contents

1. [Installation](#installation)
2. [Quick Start](#quick-start)
3. [Core Modules](#core-modules)
   - [Node Class](#node-class)
   - [A* Algorithm](#a-algorithm)
   - [Dijkstra's Algorithm](#dijkstra-algorithm)
   - [Breadth-First Search](#breadth-first-search)
   - [Depth-First Search](#depth-first-search)
4. [Graph Visualization](#graph-visualization)
5. [Examples](#examples)
   - [A* Pathfinding](#a-pathfinding-example)
   - [Dijkstra's Pathfinding](#dijkstras-pathfinding-example)
   - [Breadth-First Search](#breadth-first-search-example)
   - [Depth-First Search](#depth-first-search-example)

## Installation

To install the Vagabond library, simply use pip:

```bash
pip install py-vagabond
```

## Quick Start

Here's a quick overview of how to use the library to perform A* pathfinding:

```python
import numpy as np
import matplotlib.pyplot as plt
from vagabond.systems import node
from vagabond.environmental import astar
import numpy as np

#example free space grids (1 is free, 0 is occupied)
free_space_grid = np.array([
    [1, 0.8, 0.5, 0.5, 0.8],
    [0.9, 0, 0, 0.8, 0.6],
    [0, 0.8, 0.9, 0.9, 0.9],
    [0.8, 0.9, 0, 0, 0.9],
    [0.6, 0.5, 0.2, 0.2, 1]
])

# Assuming robot_cell is defined
robot_cell = (0, 0)
end_cell = (4, 4)

start_node = node(value=robot_cell, name="({}, {})".format(robot_cell[0], robot_cell[1]))
end_node = node(value=end_cell, name="({}, {})".format(end_cell[0], end_cell[1]))

# Generate a random end cell
map_height, map_width = free_space_grid.shape

#! A* functions ----------------------------------------------------

# if a cell is given, return the 4-connected neighbors
# probability  high -----> cost low -----> high priority
def get_neighbors(parent_node):

    neighbors = []
    x, y = parent_node.value

    # Check if the neighbor is within the map and is free
    if x > 0 and free_space_grid[x - 1,y] != 0:
        neighbors.append(node(value=(x - 1, y), parent=parent_node, cost=(cost(parent_node, (x - 1, y)))+heuristic((x - 1, y), end_cell), name="({}, {})".format(x - 1, y)))
    if x < map_width - 1 and free_space_grid[x + 1,y] != 0:    
        neighbors.append(node(value=(x + 1, y), parent=parent_node, cost=(cost(parent_node, (x + 1, y)))+heuristic((x + 1, y), end_cell), name="({}, {})".format(x + 1, y)))
    if y > 0 and free_space_grid[x, y - 1] != 0:
        neighbors.append(node(value=(x, y - 1), parent=parent_node, cost=(cost(parent_node, (x, y - 1)))+heuristic((x, y - 1), end_cell), name="({}, {})".format(x, y - 1)))
    if y < map_height - 1 and free_space_grid[x, y + 1] != 0:
        neighbors.append(node(value=(x, y + 1), parent=parent_node, cost=(cost(parent_node, (x, y + 1)))+heuristic((x, y + 1), end_cell), name="({}, {})".format(x, y + 1)))

    return neighbors

def cost(current_cell, neighbor):

    if(current_cell.parent):
        parent = current_cell.parent.value
    else:
        parent = current_cell.value

    current = current_cell.value

    #check if direction has not changed
    direction1 = (parent[0] - current[0], parent[1] - current[1])
    direction2 = (current[0] - neighbor[0], current[1] - neighbor[1])

    if direction1 == direction2:
        penalty = 0.1
    else:
        penalty = 0.5

    return penalty + round(1 - free_space_grid[neighbor],2)

def heuristic(current_cell, end_cell):
    return abs(current_cell[0] - end_cell[0]) + abs(current_cell[1] - end_cell[1])

#! A* algorithm ----------------------------------------------------

# Create an instance of the astar class
astar_obj = astar(get_neighbors)

# Find the path
path = astar_obj.path(start_node, end_node)
astar_obj.display_path(filename="astar_path")
print("Path: ", path)

#! Plot the path ----------------------------------------------------

plt.figure()
plt.imshow(free_space_grid, cmap='gray', origin='upper')

# Plot the path as a line
path = np.array(astar_obj.get_raw())

#plot simplified dots
plt.plot(path[:, 1], path[:, 0], 'r')
plt.scatter(robot_cell[1], robot_cell[0], color='r', marker='x')
plt.scatter(end_cell[1], end_cell[0], color='g', marker='x')
plt.show()
```

This example initializes a simple 5x5 grid with varying cost values and calculates the optimal path from the top-left corner to the bottom-right corner using the A* algorithm.

## Core Modules

### Node Class

The `node` class is the fundamental building block of the Vagabond library. It represents each cell in your grid and contains attributes like `value`, `parent`, `childs`, `cost`, and `name`.

**Initialization:**

```python
from vagabond.systems import node

n = node(value=(x, y), parent=None, cost=0.0, name="Node (x, y)")
```

**Attributes:**

- **value**: Tuple representing the coordinates of the node.
- **parent**: Reference to the parent node (used to track the path).
- **childs**: List of child nodes.
- **cost**: The cost to move to this node.
- **name**: A string representing the name of the node.

### A* Algorithm

The `astar` class implements the A* pathfinding algorithm, which is one of the most popular algorithms used in robotics and game development due to its efficiency and accuracy.

**Initialization:**

```python
from vagabond.environmental import astar

astar_obj = astar(get_neighbors)
```

**Key Functions:**

- `path(start_node, end_node)`: Calculates the optimal path between the start and end nodes.
- `display_path(filename)`: Displays the grid, obstacles, and the computed path using Graphviz.
- `get_raw()`: Returns the raw path as a list of nodes.
- `get()`: Returns the path as a list of nodes.
- `add(node)`: Adds a node to the path.
- `remove(node)`: Removes a node from the path.
- `clear()`: Clears the path.

**Usage:**

```python
path = astar_obj.path(start_node, end_node)
raw_path = astar_obj.get_raw()
```

### Dijkstra's Algorithm

The `dijkstra` class implements Dijkstra's pathfinding algorithm, which is ideal for finding the shortest path in graphs with non-negative weights.

**Initialization:**

```python
from vagabond.environmental import dijkstra

dijkstra_obj = dijkstra(get_neighbors)
```

**Key Functions:**

- `path(start_node, end_node)`: Identifies the shortest path between two nodes using Dijkstra's algorithm.
- `display_path(filename)`: Displays the grid, obstacles, and the computed path using Graphviz.
- `get_raw()`: Returns the raw path as a list of nodes.
- `get()`: Returns the path as a list of nodes.
- `add(node)`: Adds a node to the path.
- `remove(node)`: Removes a node from the path.
- `clear()`: Clears the path.

**Usage:**

```python
path = dijkstra_obj.path(start_node, end_node)
raw_path = dijkstra_obj.get_raw()
```

### Breadth-First Search

The `bfs` class implements the Breadth-First Search algorithm, which is useful for exploring all possible paths in a graph.

**Initialization:**

```python
from vagabond.environmental import bfs

bfs_obj = bfs(get_neighbors)
```

**Key Functions:**

- `path(start_node, end_node)`: Finds the shortest path between two nodes using BFS.
- `display_path(filename)`: Displays the grid, obstacles, and the computed path using Graphviz.
- `get_raw()`: Returns the raw path as a list of nodes.
- `get()`: Returns the path as a list of nodes.
- `add(node)`: Adds a node to the path.
- `remove(node)`: Removes a node from the path.
- `clear()`: Clears the path.

**Usage:**

```python
path = bfs_obj.path(start_node, end_node)
raw_path = bfs_obj.get_raw()
```

### Depth-First Search

The `dfs` class implements the Depth-First Search algorithm, which is useful for exploring all possible paths in a graph.

**Initialization:**

```python
from vagabond.environmental import dfs

dfs_obj = dfs(get_neighbors)
```

**Key Functions:**

- `path(start_node, end_node)`: Finds the shortest path between two nodes using DFS.
- `display_path(filename)`: Displays the grid, obstacles, and the computed path using Graphviz.
- `get_raw()`: Returns the raw path as a list of nodes.
- `get()`: Returns the path as a list of nodes.
- `add(node)`: Adds a node to the path.
- `remove(node)`: Removes a node from the path.
- `clear()`: Clears the path.

**Usage:**

```python

path = dfs_obj.path(start_node, end_node)
raw_path = dfs_obj.get_raw()
```

## Graph Visualization

Vagabond provides a convenient way to visualize your grid, obstacles, and computed paths using the Graphviz library.

**Display Path:**

```python
astar_obj.display_path(filename="astar_path")
```

This function generates a visualization of the grid, obstacles, and the computed path using Graphviz. The resulting image is saved as a PNG file with the specified filename.

![A* Path Output](https://github.com/Kawai-Senpai/Vagabond/blob/2c48df11016c35125353c6ee5235aa1d3ccbb440/Examples/astar_path.png)

It is also possible to display the grid and path using matplotlib:

```python
plt.figure()
plt.imshow(free_space_grid, cmap='gray', origin='upper')

# Plot the path as a line
path = np.array(astar_obj.get_raw())

#plot the path
plt.plot(path[:, 1], path[:, 0], 'r')
plt.scatter(robot_cell[1], robot_cell[0], color='r', marker='x')
plt.scatter(end_cell[1], end_cell[0], color='g', marker='x')
plt.show()
```

## Examples

### A* Pathfinding Example

This example demonstrates how to use the A* algorithm to find the optimal path in a grid with varying cost values.

```python
import numpy as np
import matplotlib.pyplot as plt
from vagabond.systems import node
from vagabond.environmental import astar
import numpy as np

#example free space grids (1 is free, 0 is occupied)
free_space_grid = np.array([
    [1, 0.8, 0.5, 0.5, 0.8],
    [0.9, 0, 0, 0.8, 0.6],
    [0, 0.8, 0.9, 0.9, 0.9],
    [0.8, 0.9, 0, 0, 0.9],
    [0.6, 0.5, 0.2, 0.2, 1]
])

# Assuming robot_cell is defined
robot_cell = (0, 0)
end_cell = (4, 4)

start_node = node(value=robot_cell, name="({}, {})".format(robot_cell[0], robot_cell[1]))
end_node = node(value=end_cell, name="({}, {})".format(end_cell[0], end_cell[1]))

# Generate a random end cell
map_height, map_width = free_space_grid.shape

#! A* functions ----------------------------------------------------

# if a cell is given, return the 4-connected neighbors
# probability  high -----> cost low -----> high priority
def get_neighbors(parent_node):

    neighbors = []
    x, y = parent_node.value

    # Check if the neighbor is within the map and is free
    if x > 0 and free_space_grid[x - 1,y] != 0:
        neighbors.append(node(value=(x - 1, y), parent=parent_node, cost=(cost(parent_node, (x - 1, y)))+heuristic((x - 1, y), end_cell), name="({}, {})".format(x - 1, y)))
    if x < map_width - 1 and free_space_grid[x + 1,y] != 0:    
        neighbors.append(node(value=(x + 1, y), parent=parent_node, cost=(cost(parent_node, (x + 1, y)))+heuristic((x + 1, y), end_cell), name="({}, {})".format(x + 1, y)))
    if y > 0 and free_space_grid[x, y - 1] != 0:
        neighbors.append(node(value=(x, y - 1), parent=parent_node, cost=(cost(parent_node, (x, y - 1)))+heuristic((x, y - 1), end_cell), name="({}, {})".format(x, y - 1)))
    if y < map_height - 1 and free_space_grid[x, y + 1] != 0:
        neighbors.append(node(value=(x, y + 1), parent=parent_node, cost=(cost(parent_node, (x, y + 1)))+heuristic((x, y + 1), end_cell), name="({}, {})".format(x, y + 1)))

    return neighbors

def cost(current_cell, neighbor):

    if(current_cell.parent):
        parent = current_cell.parent.value
    else:
        parent = current_cell.value

    current = current_cell.value

    #check if direction has not changed
    direction1 = (parent[0] - current[0], parent[1] - current[1])
    direction2 = (current[0] - neighbor[0], current[1] - neighbor[1])

    if direction1 == direction2:
        penalty = 0.1
    else:
        penalty = 0.5

    return penalty + round(1 - free_space_grid[neighbor],2)

def heuristic(current_cell, end_cell):
    return abs(current_cell[0] - end_cell[0]) + abs(current_cell[1] - end_cell[1])

#! A* algorithm ----------------------------------------------------

# Create an instance of the astar class
astar_obj = astar(get_neighbors)

# Find the path
path = astar_obj.path(start_node, end_node)
astar_obj.display_path(filename="astar_path")
print("Path: ", path)

#! Plot the path ----------------------------------------------------

plt.figure()
plt.imshow(free_space_grid, cmap='gray', origin='upper')

# Plot the path as a line
path = np.array(astar_obj.get_raw())

plt.plot(path[:, 1], path[:, 0], 'r')
plt.scatter(robot_cell[1], robot_cell[0], color='r', marker='x')
plt.scatter(end_cell[1], end_cell[0], color='g', marker='x')
plt.show()

```

### Dijkstra's Pathfinding Example

This example demonstrates how to use Dijkstra's algorithm to find the shortest path in a grid with varying cost values.

```python
import numpy as np
import matplotlib.pyplot as plt
from vagabond.systems import node
from vagabond.environmental import dijkstra
import numpy as np

#example free space grids (1 is free, 0 is occupied)
free_space_grid = np.array([
    [1, 0.8, 0.5, 0.5, 0.8],
    [0.9, 0, 0, 0.8, 0.6],
    [0, 0.8, 0.9, 0.9, 0.9],
    [0.8, 0.9, 0, 0, 0.9],
    [0.6, 0.5, 0.2, 0.2, 1]
])

# Assuming robot_cell is defined
robot_cell = (0, 0)
end_cell = (4, 4)

start_node = node(value=robot_cell, name="({}, {})".format(robot_cell[0], robot_cell[1]))
end_node = node(value=end_cell, name="({}, {})".format(end_cell[0], end_cell[1]))

# Generate a random end cell
map_height, map_width = free_space_grid.shape

#! A* functions ----------------------------------------------------

# if a cell is given, return the 4-connected neighbors
# probability  high -----> cost low -----> high priority
def get_neighbors(parent_node):

    neighbors = []
    x, y = parent_node.value

    # Check if the neighbor is within the map and is free
    if x > 0 and free_space_grid[x - 1,y] != 0:
        neighbors.append(node(value=(x - 1, y), parent=parent_node, cost=(cost(parent_node, (x - 1, y)))+heuristic((x - 1, y), end_cell), name="({}, {})".format(x - 1, y)))
    if x < map_width - 1 and free_space_grid[x + 1,y] != 0:    
        neighbors.append(node(value=(x + 1, y), parent=parent_node, cost=(cost(parent_node, (x + 1, y)))+heuristic((x + 1, y), end_cell), name="({}, {})".format(x + 1, y)))
    if y > 0 and free_space_grid[x, y - 1] != 0:
        neighbors.append(node(value=(x, y - 1), parent=parent_node, cost=(cost(parent_node, (x, y - 1)))+heuristic((x, y - 1), end_cell), name="({}, {})".format(x, y - 1)))
    if y < map_height - 1 and free_space_grid[x, y + 1] != 0:
        neighbors.append(node(value=(x, y + 1), parent=parent_node, cost=(cost(parent_node, (x, y + 1)))+heuristic((x, y + 1), end_cell), name="({}, {})".format(x, y + 1)))

    return neighbors

def cost(current_cell, neighbor):

    if(current_cell.parent):
        parent = current_cell.parent.value
    else:
        parent = current_cell.value

    current = current_cell.value

    #check if direction has not changed
    direction1 = (parent[0] - current[0], parent[1] - current[1])
    direction2 = (current[0] - neighbor[0], current[1] - neighbor[1])

    if direction1 == direction2:
        penalty = 0.1
    else:
        penalty = 0.5

    return penalty + round(1 - free_space_grid[neighbor],2)

def heuristic(current_cell, end_cell):
    return abs(current_cell[0] - end_cell[0]) + abs(current_cell[1] - end_cell[1])

#! A* algorithm ----------------------------------------------------

# Create an instance of the astar class
dijkstra_obj = dijkstra(get_neighbors)

# Find the path
path = dijkstra_obj.path(start_node, end_node)
dijkstra_obj.display_path(filename="dijkstra_path")
print("Path: ", path)

#! Plot the path ----------------------------------------------------

plt.figure()
plt.imshow(free_space_grid, cmap='gray', origin='upper')

# Plot the path as a line
path = np.array(dijkstra_obj.get_raw())

#plot simplified dots
plt.plot(path[:, 1], path[:, 0], 'r')
plt.scatter(robot_cell[1], robot_cell[0], color='r', marker='x')
plt.scatter(end_cell[1], end_cell[0], color='g', marker='x')
plt.show()

```

### Breadth-First Search Example

This example demonstrates how to use the Breadth-First Search algorithm to explore all possible paths in a grid.

```python
import numpy as np
import matplotlib.pyplot as plt
from vagabond.systems import node
from vagabond.environmental import bfs
import numpy as np

#example free space grids (1 is free, 0 is occupied)
free_space_grid = np.array([
    [1, 0.8, 0.5, 0.5, 0.8],
    [0.9, 0, 0, 0.8, 0.6],
    [0, 0.8, 0.9, 0.9, 0.9],
    [0.8, 0.9, 0, 0, 0.9],
    [0.6, 0.5, 0.2, 0.2, 1]
])

# Assuming robot_cell is defined
robot_cell = (0, 0)
end_cell = (4, 4)

start_node = node(value=robot_cell, name="({}, {})".format(robot_cell[0], robot_cell[1]))
end_node = node(value=end_cell, name="({}, {})".format(end_cell[0], end_cell[1]))

# Generate a random end cell
map_height, map_width = free_space_grid.shape

#! A* functions ----------------------------------------------------

# if a cell is given, return the 4-connected neighbors
# probability  high -----> cost low -----> high priority
def get_neighbors(parent_node):

    neighbors = []
    x, y = parent_node.value

    # Check if the neighbor is within the map and is free
    if x > 0 and free_space_grid[x - 1,y] != 0:
        neighbors.append(node(value=(x - 1, y), parent=parent_node, cost=(cost(parent_node, (x - 1, y)))+heuristic((x - 1, y), end_cell), name="({}, {})".format(x - 1, y)))
    if x < map_width - 1 and free_space_grid[x + 1,y] != 0:    
        neighbors.append(node(value=(x + 1, y), parent=parent_node, cost=(cost(parent_node, (x + 1, y)))+heuristic((x + 1, y), end_cell), name="({}, {})".format(x + 1, y)))
    if y > 0 and free_space_grid[x, y - 1] != 0:
        neighbors.append(node(value=(x, y - 1), parent=parent_node, cost=(cost(parent_node, (x, y - 1)))+heuristic((x, y - 1), end_cell), name="({}, {})".format(x, y - 1)))
    if y < map_height - 1 and free_space_grid[x, y + 1] != 0:
        neighbors.append(node(value=(x, y + 1), parent=parent_node, cost=(cost(parent_node, (x, y + 1)))+heuristic((x, y + 1), end_cell), name="({}, {})".format(x, y + 1)))

    return neighbors

def cost(current_cell, neighbor):

    if(current_cell.parent):
        parent = current_cell.parent.value
    else:
        parent = current_cell.value

    current = current_cell.value

    #check if direction has not changed
    direction1 = (parent[0] - current[0], parent[1] - current[1])
    direction2 = (current[0] - neighbor[0], current[1] - neighbor[1])

    if direction1 == direction2:
        penalty = 0.1
    else:
        penalty = 0.5

    return penalty + round(1 - free_space_grid[neighbor],2)

def heuristic(current_cell, end_cell):
    return abs(current_cell[0] - end_cell[0]) + abs(current_cell[1] - end_cell[1])

#! A* algorithm ----------------------------------------------------

# Create an instance of the astar class
bfs_obj = bfs(get_neighbors)

# Find the path
path = bfs_obj.path(start_node, end_node)
bfs_obj.display_path(filename="bfs_path")
print("Path: ", path)

#! Plot the path ----------------------------------------------------

plt.figure()
plt.imshow(free_space_grid, cmap='gray', origin='upper')

# Plot the path as a line
path = np.array(bfs_obj.get_raw())

#plot simplified dots
plt.plot(path[:, 1], path[:, 0], 'r')
plt.scatter(robot_cell[1], robot_cell[0], color='r', marker='x')
plt.scatter(end_cell[1], end_cell[0], color='g', marker='x')
plt.show()

```

### Depth-First Search Example

This example demonstrates how to use the Depth-First Search algorithm to explore all possible paths in a grid.

```python
import numpy as np
import matplotlib.pyplot as plt
from vagabond.systems import node
from vagabond.environmental import dfs
import numpy as np

#example free space grids (1 is free, 0 is occupied)
free_space_grid = np.array([
    [1, 0.8, 0.5, 0.5, 0.8],
    [0.9, 0, 0, 0.8, 0.6],
    [0, 0.8, 0.9, 0.9, 0.9],
    [0.8, 0.9, 0, 0, 0.9],
    [0.6, 0.5, 0.2, 0.2, 1]
])

# Assuming robot_cell is defined
robot_cell = (0, 0)
end_cell = (4, 4)

start_node = node(value=robot_cell, name="({}, {})".format(robot_cell[0], robot_cell[1]))
end_node = node(value=end_cell, name="({}, {})".format(end_cell[0], end_cell[1]))

# Generate a random end cell
map_height, map_width = free_space_grid.shape

#! A* functions ----------------------------------------------------

# if a cell is given, return the 4-connected neighbors
# probability  high -----> cost low -----> high priority
def get_neighbors(parent_node):

    neighbors = []
    x, y = parent_node.value

    # Check if the neighbor is within the map and is free
    if x > 0 and free_space_grid[x - 1,y] != 0:
        neighbors.append(node(value=(x - 1, y), parent=parent_node, cost=(cost(parent_node, (x - 1, y)))+heuristic((x - 1, y), end_cell), name="({}, {})".format(x - 1, y)))
    if x < map_width - 1 and free_space_grid[x + 1,y] != 0:    
        neighbors.append(node(value=(x + 1, y), parent=parent_node, cost=(cost(parent_node, (x + 1, y)))+heuristic((x + 1, y), end_cell), name="({}, {})".format(x + 1, y)))
    if y > 0 and free_space_grid[x, y - 1] != 0:
        neighbors.append(node(value=(x, y - 1), parent=parent_node, cost=(cost(parent_node, (x, y - 1)))+heuristic((x, y - 1), end_cell), name="({}, {})".format(x, y - 1)))
    if y < map_height - 1 and free_space_grid[x, y + 1] != 0:
        neighbors.append(node(value=(x, y + 1), parent=parent_node, cost=(cost(parent_node, (x, y + 1)))+heuristic((x, y + 1), end_cell), name="({}, {})".format(x, y + 1)))

    return neighbors

def cost(current_cell, neighbor):

    if(current_cell.parent):
        parent = current_cell.parent.value
    else:
        parent = current_cell.value

    current = current_cell.value

    #check if direction has not changed
    direction1 = (parent[0] - current[0], parent[1] - current[1])
    direction2 = (current[0] - neighbor[0], current[1] - neighbor[1])

    if direction1 == direction2:
        penalty = 0.1
    else:
        penalty = 0.5

    return penalty + round(1 - free_space_grid[neighbor],2)

def heuristic(current_cell, end_cell):
    return abs(current_cell[0] - end_cell[0]) + abs(current_cell[1] - end_cell[1])

#! A* algorithm ----------------------------------------------------

# Create an instance of the astar class
dfs_obj = dfs(get_neighbors)


# Find the path
path = dfs_obj.path(start_node, end_node)
dfs_obj.display_path(filename="dfs_path")
print("Path: ", path)

#! Plot the path ----------------------------------------------------

plt.figure()
plt.imshow(free_space_grid, cmap='gray', origin='upper')

# Plot the path as a line
path = np.array(dfs_obj.get_raw())

#plot simplified dots
plt.plot(path[:, 1], path[:, 0], 'r')
plt.scatter(robot_cell[1], robot_cell[0], color='r', marker='x')
plt.scatter(end_cell[1], end_cell[0], color='g', marker='x')
plt.show()

```

            

Raw data

            {
    "_id": null,
    "home_page": "https://github.com/Kawai-Senpai/Vagabond",
    "name": "py-vagabond",
    "maintainer": null,
    "docs_url": null,
    "requires_python": null,
    "maintainer_email": null,
    "keywords": "Pathfinding, Robotics, Navigation, A* Algorithm, Graph Theory, Automation, Robotic Systems",
    "author": "Ranit Bhowmick",
    "author_email": "bhowmickranitking@duck.com",
    "download_url": "https://files.pythonhosted.org/packages/04/7e/aec336259151394fa862a1846f983843b2c79990c50c1721fa210a33a22a/py-vagabond-2.0.2.tar.gz",
    "platform": null,
    "description": "# Vagabond\r\n\r\n[Vagabond](https://pypi.org/project/py-vagabond/) is a powerful and flexible Python library designed to simplify the implementation of various pathfinding algorithms and related operations developed by [*Ranit Bhowmick*](https://www.linkedin.com/in/ranitbhowmick/) & [*Sayanti Chatterjee*](https://www.linkedin.com/in/sayantichatterjee/). Whether you're working on robotics, AI, or game development, Vagabond offers an easy-to-use interface for complex algorithms like A*, Dijkstra's, and more.\r\n\r\n## Table of Contents\r\n\r\n1. [Installation](#installation)\r\n2. [Quick Start](#quick-start)\r\n3. [Core Modules](#core-modules)\r\n   - [Node Class](#node-class)\r\n   - [A* Algorithm](#a-algorithm)\r\n   - [Dijkstra's Algorithm](#dijkstra-algorithm)\r\n   - [Breadth-First Search](#breadth-first-search)\r\n   - [Depth-First Search](#depth-first-search)\r\n4. [Graph Visualization](#graph-visualization)\r\n5. [Examples](#examples)\r\n   - [A* Pathfinding](#a-pathfinding-example)\r\n   - [Dijkstra's Pathfinding](#dijkstras-pathfinding-example)\r\n   - [Breadth-First Search](#breadth-first-search-example)\r\n   - [Depth-First Search](#depth-first-search-example)\r\n\r\n## Installation\r\n\r\nTo install the Vagabond library, simply use pip:\r\n\r\n```bash\r\npip install py-vagabond\r\n```\r\n\r\n## Quick Start\r\n\r\nHere's a quick overview of how to use the library to perform A* pathfinding:\r\n\r\n```python\r\nimport numpy as np\r\nimport matplotlib.pyplot as plt\r\nfrom vagabond.systems import node\r\nfrom vagabond.environmental import astar\r\nimport numpy as np\r\n\r\n#example free space grids (1 is free, 0 is occupied)\r\nfree_space_grid = np.array([\r\n    [1, 0.8, 0.5, 0.5, 0.8],\r\n    [0.9, 0, 0, 0.8, 0.6],\r\n    [0, 0.8, 0.9, 0.9, 0.9],\r\n    [0.8, 0.9, 0, 0, 0.9],\r\n    [0.6, 0.5, 0.2, 0.2, 1]\r\n])\r\n\r\n# Assuming robot_cell is defined\r\nrobot_cell = (0, 0)\r\nend_cell = (4, 4)\r\n\r\nstart_node = node(value=robot_cell, name=\"({}, {})\".format(robot_cell[0], robot_cell[1]))\r\nend_node = node(value=end_cell, name=\"({}, {})\".format(end_cell[0], end_cell[1]))\r\n\r\n# Generate a random end cell\r\nmap_height, map_width = free_space_grid.shape\r\n\r\n#! A* functions ----------------------------------------------------\r\n\r\n# if a cell is given, return the 4-connected neighbors\r\n# probability  high -----> cost low -----> high priority\r\ndef get_neighbors(parent_node):\r\n\r\n    neighbors = []\r\n    x, y = parent_node.value\r\n\r\n    # Check if the neighbor is within the map and is free\r\n    if x > 0 and free_space_grid[x - 1,y] != 0:\r\n        neighbors.append(node(value=(x - 1, y), parent=parent_node, cost=(cost(parent_node, (x - 1, y)))+heuristic((x - 1, y), end_cell), name=\"({}, {})\".format(x - 1, y)))\r\n    if x < map_width - 1 and free_space_grid[x + 1,y] != 0:    \r\n        neighbors.append(node(value=(x + 1, y), parent=parent_node, cost=(cost(parent_node, (x + 1, y)))+heuristic((x + 1, y), end_cell), name=\"({}, {})\".format(x + 1, y)))\r\n    if y > 0 and free_space_grid[x, y - 1] != 0:\r\n        neighbors.append(node(value=(x, y - 1), parent=parent_node, cost=(cost(parent_node, (x, y - 1)))+heuristic((x, y - 1), end_cell), name=\"({}, {})\".format(x, y - 1)))\r\n    if y < map_height - 1 and free_space_grid[x, y + 1] != 0:\r\n        neighbors.append(node(value=(x, y + 1), parent=parent_node, cost=(cost(parent_node, (x, y + 1)))+heuristic((x, y + 1), end_cell), name=\"({}, {})\".format(x, y + 1)))\r\n\r\n    return neighbors\r\n\r\ndef cost(current_cell, neighbor):\r\n\r\n    if(current_cell.parent):\r\n        parent = current_cell.parent.value\r\n    else:\r\n        parent = current_cell.value\r\n\r\n    current = current_cell.value\r\n\r\n    #check if direction has not changed\r\n    direction1 = (parent[0] - current[0], parent[1] - current[1])\r\n    direction2 = (current[0] - neighbor[0], current[1] - neighbor[1])\r\n\r\n    if direction1 == direction2:\r\n        penalty = 0.1\r\n    else:\r\n        penalty = 0.5\r\n\r\n    return penalty + round(1 - free_space_grid[neighbor],2)\r\n\r\ndef heuristic(current_cell, end_cell):\r\n    return abs(current_cell[0] - end_cell[0]) + abs(current_cell[1] - end_cell[1])\r\n\r\n#! A* algorithm ----------------------------------------------------\r\n\r\n# Create an instance of the astar class\r\nastar_obj = astar(get_neighbors)\r\n\r\n# Find the path\r\npath = astar_obj.path(start_node, end_node)\r\nastar_obj.display_path(filename=\"astar_path\")\r\nprint(\"Path: \", path)\r\n\r\n#! Plot the path ----------------------------------------------------\r\n\r\nplt.figure()\r\nplt.imshow(free_space_grid, cmap='gray', origin='upper')\r\n\r\n# Plot the path as a line\r\npath = np.array(astar_obj.get_raw())\r\n\r\n#plot simplified dots\r\nplt.plot(path[:, 1], path[:, 0], 'r')\r\nplt.scatter(robot_cell[1], robot_cell[0], color='r', marker='x')\r\nplt.scatter(end_cell[1], end_cell[0], color='g', marker='x')\r\nplt.show()\r\n```\r\n\r\nThis example initializes a simple 5x5 grid with varying cost values and calculates the optimal path from the top-left corner to the bottom-right corner using the A* algorithm.\r\n\r\n## Core Modules\r\n\r\n### Node Class\r\n\r\nThe `node` class is the fundamental building block of the Vagabond library. It represents each cell in your grid and contains attributes like `value`, `parent`, `childs`, `cost`, and `name`.\r\n\r\n**Initialization:**\r\n\r\n```python\r\nfrom vagabond.systems import node\r\n\r\nn = node(value=(x, y), parent=None, cost=0.0, name=\"Node (x, y)\")\r\n```\r\n\r\n**Attributes:**\r\n\r\n- **value**: Tuple representing the coordinates of the node.\r\n- **parent**: Reference to the parent node (used to track the path).\r\n- **childs**: List of child nodes.\r\n- **cost**: The cost to move to this node.\r\n- **name**: A string representing the name of the node.\r\n\r\n### A* Algorithm\r\n\r\nThe `astar` class implements the A* pathfinding algorithm, which is one of the most popular algorithms used in robotics and game development due to its efficiency and accuracy.\r\n\r\n**Initialization:**\r\n\r\n```python\r\nfrom vagabond.environmental import astar\r\n\r\nastar_obj = astar(get_neighbors)\r\n```\r\n\r\n**Key Functions:**\r\n\r\n- `path(start_node, end_node)`: Calculates the optimal path between the start and end nodes.\r\n- `display_path(filename)`: Displays the grid, obstacles, and the computed path using Graphviz.\r\n- `get_raw()`: Returns the raw path as a list of nodes.\r\n- `get()`: Returns the path as a list of nodes.\r\n- `add(node)`: Adds a node to the path.\r\n- `remove(node)`: Removes a node from the path.\r\n- `clear()`: Clears the path.\r\n\r\n**Usage:**\r\n\r\n```python\r\npath = astar_obj.path(start_node, end_node)\r\nraw_path = astar_obj.get_raw()\r\n```\r\n\r\n### Dijkstra's Algorithm\r\n\r\nThe `dijkstra` class implements Dijkstra's pathfinding algorithm, which is ideal for finding the shortest path in graphs with non-negative weights.\r\n\r\n**Initialization:**\r\n\r\n```python\r\nfrom vagabond.environmental import dijkstra\r\n\r\ndijkstra_obj = dijkstra(get_neighbors)\r\n```\r\n\r\n**Key Functions:**\r\n\r\n- `path(start_node, end_node)`: Identifies the shortest path between two nodes using Dijkstra's algorithm.\r\n- `display_path(filename)`: Displays the grid, obstacles, and the computed path using Graphviz.\r\n- `get_raw()`: Returns the raw path as a list of nodes.\r\n- `get()`: Returns the path as a list of nodes.\r\n- `add(node)`: Adds a node to the path.\r\n- `remove(node)`: Removes a node from the path.\r\n- `clear()`: Clears the path.\r\n\r\n**Usage:**\r\n\r\n```python\r\npath = dijkstra_obj.path(start_node, end_node)\r\nraw_path = dijkstra_obj.get_raw()\r\n```\r\n\r\n### Breadth-First Search\r\n\r\nThe `bfs` class implements the Breadth-First Search algorithm, which is useful for exploring all possible paths in a graph.\r\n\r\n**Initialization:**\r\n\r\n```python\r\nfrom vagabond.environmental import bfs\r\n\r\nbfs_obj = bfs(get_neighbors)\r\n```\r\n\r\n**Key Functions:**\r\n\r\n- `path(start_node, end_node)`: Finds the shortest path between two nodes using BFS.\r\n- `display_path(filename)`: Displays the grid, obstacles, and the computed path using Graphviz.\r\n- `get_raw()`: Returns the raw path as a list of nodes.\r\n- `get()`: Returns the path as a list of nodes.\r\n- `add(node)`: Adds a node to the path.\r\n- `remove(node)`: Removes a node from the path.\r\n- `clear()`: Clears the path.\r\n\r\n**Usage:**\r\n\r\n```python\r\npath = bfs_obj.path(start_node, end_node)\r\nraw_path = bfs_obj.get_raw()\r\n```\r\n\r\n### Depth-First Search\r\n\r\nThe `dfs` class implements the Depth-First Search algorithm, which is useful for exploring all possible paths in a graph.\r\n\r\n**Initialization:**\r\n\r\n```python\r\nfrom vagabond.environmental import dfs\r\n\r\ndfs_obj = dfs(get_neighbors)\r\n```\r\n\r\n**Key Functions:**\r\n\r\n- `path(start_node, end_node)`: Finds the shortest path between two nodes using DFS.\r\n- `display_path(filename)`: Displays the grid, obstacles, and the computed path using Graphviz.\r\n- `get_raw()`: Returns the raw path as a list of nodes.\r\n- `get()`: Returns the path as a list of nodes.\r\n- `add(node)`: Adds a node to the path.\r\n- `remove(node)`: Removes a node from the path.\r\n- `clear()`: Clears the path.\r\n\r\n**Usage:**\r\n\r\n```python\r\n\r\npath = dfs_obj.path(start_node, end_node)\r\nraw_path = dfs_obj.get_raw()\r\n```\r\n\r\n## Graph Visualization\r\n\r\nVagabond provides a convenient way to visualize your grid, obstacles, and computed paths using the Graphviz library.\r\n\r\n**Display Path:**\r\n\r\n```python\r\nastar_obj.display_path(filename=\"astar_path\")\r\n```\r\n\r\nThis function generates a visualization of the grid, obstacles, and the computed path using Graphviz. The resulting image is saved as a PNG file with the specified filename.\r\n\r\n![A* Path Output](https://github.com/Kawai-Senpai/Vagabond/blob/2c48df11016c35125353c6ee5235aa1d3ccbb440/Examples/astar_path.png)\r\n\r\nIt is also possible to display the grid and path using matplotlib:\r\n\r\n```python\r\nplt.figure()\r\nplt.imshow(free_space_grid, cmap='gray', origin='upper')\r\n\r\n# Plot the path as a line\r\npath = np.array(astar_obj.get_raw())\r\n\r\n#plot the path\r\nplt.plot(path[:, 1], path[:, 0], 'r')\r\nplt.scatter(robot_cell[1], robot_cell[0], color='r', marker='x')\r\nplt.scatter(end_cell[1], end_cell[0], color='g', marker='x')\r\nplt.show()\r\n```\r\n\r\n## Examples\r\n\r\n### A* Pathfinding Example\r\n\r\nThis example demonstrates how to use the A* algorithm to find the optimal path in a grid with varying cost values.\r\n\r\n```python\r\nimport numpy as np\r\nimport matplotlib.pyplot as plt\r\nfrom vagabond.systems import node\r\nfrom vagabond.environmental import astar\r\nimport numpy as np\r\n\r\n#example free space grids (1 is free, 0 is occupied)\r\nfree_space_grid = np.array([\r\n    [1, 0.8, 0.5, 0.5, 0.8],\r\n    [0.9, 0, 0, 0.8, 0.6],\r\n    [0, 0.8, 0.9, 0.9, 0.9],\r\n    [0.8, 0.9, 0, 0, 0.9],\r\n    [0.6, 0.5, 0.2, 0.2, 1]\r\n])\r\n\r\n# Assuming robot_cell is defined\r\nrobot_cell = (0, 0)\r\nend_cell = (4, 4)\r\n\r\nstart_node = node(value=robot_cell, name=\"({}, {})\".format(robot_cell[0], robot_cell[1]))\r\nend_node = node(value=end_cell, name=\"({}, {})\".format(end_cell[0], end_cell[1]))\r\n\r\n# Generate a random end cell\r\nmap_height, map_width = free_space_grid.shape\r\n\r\n#! A* functions ----------------------------------------------------\r\n\r\n# if a cell is given, return the 4-connected neighbors\r\n# probability  high -----> cost low -----> high priority\r\ndef get_neighbors(parent_node):\r\n\r\n    neighbors = []\r\n    x, y = parent_node.value\r\n\r\n    # Check if the neighbor is within the map and is free\r\n    if x > 0 and free_space_grid[x - 1,y] != 0:\r\n        neighbors.append(node(value=(x - 1, y), parent=parent_node, cost=(cost(parent_node, (x - 1, y)))+heuristic((x - 1, y), end_cell), name=\"({}, {})\".format(x - 1, y)))\r\n    if x < map_width - 1 and free_space_grid[x + 1,y] != 0:    \r\n        neighbors.append(node(value=(x + 1, y), parent=parent_node, cost=(cost(parent_node, (x + 1, y)))+heuristic((x + 1, y), end_cell), name=\"({}, {})\".format(x + 1, y)))\r\n    if y > 0 and free_space_grid[x, y - 1] != 0:\r\n        neighbors.append(node(value=(x, y - 1), parent=parent_node, cost=(cost(parent_node, (x, y - 1)))+heuristic((x, y - 1), end_cell), name=\"({}, {})\".format(x, y - 1)))\r\n    if y < map_height - 1 and free_space_grid[x, y + 1] != 0:\r\n        neighbors.append(node(value=(x, y + 1), parent=parent_node, cost=(cost(parent_node, (x, y + 1)))+heuristic((x, y + 1), end_cell), name=\"({}, {})\".format(x, y + 1)))\r\n\r\n    return neighbors\r\n\r\ndef cost(current_cell, neighbor):\r\n\r\n    if(current_cell.parent):\r\n        parent = current_cell.parent.value\r\n    else:\r\n        parent = current_cell.value\r\n\r\n    current = current_cell.value\r\n\r\n    #check if direction has not changed\r\n    direction1 = (parent[0] - current[0], parent[1] - current[1])\r\n    direction2 = (current[0] - neighbor[0], current[1] - neighbor[1])\r\n\r\n    if direction1 == direction2:\r\n        penalty = 0.1\r\n    else:\r\n        penalty = 0.5\r\n\r\n    return penalty + round(1 - free_space_grid[neighbor],2)\r\n\r\ndef heuristic(current_cell, end_cell):\r\n    return abs(current_cell[0] - end_cell[0]) + abs(current_cell[1] - end_cell[1])\r\n\r\n#! A* algorithm ----------------------------------------------------\r\n\r\n# Create an instance of the astar class\r\nastar_obj = astar(get_neighbors)\r\n\r\n# Find the path\r\npath = astar_obj.path(start_node, end_node)\r\nastar_obj.display_path(filename=\"astar_path\")\r\nprint(\"Path: \", path)\r\n\r\n#! Plot the path ----------------------------------------------------\r\n\r\nplt.figure()\r\nplt.imshow(free_space_grid, cmap='gray', origin='upper')\r\n\r\n# Plot the path as a line\r\npath = np.array(astar_obj.get_raw())\r\n\r\nplt.plot(path[:, 1], path[:, 0], 'r')\r\nplt.scatter(robot_cell[1], robot_cell[0], color='r', marker='x')\r\nplt.scatter(end_cell[1], end_cell[0], color='g', marker='x')\r\nplt.show()\r\n\r\n```\r\n\r\n### Dijkstra's Pathfinding Example\r\n\r\nThis example demonstrates how to use Dijkstra's algorithm to find the shortest path in a grid with varying cost values.\r\n\r\n```python\r\nimport numpy as np\r\nimport matplotlib.pyplot as plt\r\nfrom vagabond.systems import node\r\nfrom vagabond.environmental import dijkstra\r\nimport numpy as np\r\n\r\n#example free space grids (1 is free, 0 is occupied)\r\nfree_space_grid = np.array([\r\n    [1, 0.8, 0.5, 0.5, 0.8],\r\n    [0.9, 0, 0, 0.8, 0.6],\r\n    [0, 0.8, 0.9, 0.9, 0.9],\r\n    [0.8, 0.9, 0, 0, 0.9],\r\n    [0.6, 0.5, 0.2, 0.2, 1]\r\n])\r\n\r\n# Assuming robot_cell is defined\r\nrobot_cell = (0, 0)\r\nend_cell = (4, 4)\r\n\r\nstart_node = node(value=robot_cell, name=\"({}, {})\".format(robot_cell[0], robot_cell[1]))\r\nend_node = node(value=end_cell, name=\"({}, {})\".format(end_cell[0], end_cell[1]))\r\n\r\n# Generate a random end cell\r\nmap_height, map_width = free_space_grid.shape\r\n\r\n#! A* functions ----------------------------------------------------\r\n\r\n# if a cell is given, return the 4-connected neighbors\r\n# probability  high -----> cost low -----> high priority\r\ndef get_neighbors(parent_node):\r\n\r\n    neighbors = []\r\n    x, y = parent_node.value\r\n\r\n    # Check if the neighbor is within the map and is free\r\n    if x > 0 and free_space_grid[x - 1,y] != 0:\r\n        neighbors.append(node(value=(x - 1, y), parent=parent_node, cost=(cost(parent_node, (x - 1, y)))+heuristic((x - 1, y), end_cell), name=\"({}, {})\".format(x - 1, y)))\r\n    if x < map_width - 1 and free_space_grid[x + 1,y] != 0:    \r\n        neighbors.append(node(value=(x + 1, y), parent=parent_node, cost=(cost(parent_node, (x + 1, y)))+heuristic((x + 1, y), end_cell), name=\"({}, {})\".format(x + 1, y)))\r\n    if y > 0 and free_space_grid[x, y - 1] != 0:\r\n        neighbors.append(node(value=(x, y - 1), parent=parent_node, cost=(cost(parent_node, (x, y - 1)))+heuristic((x, y - 1), end_cell), name=\"({}, {})\".format(x, y - 1)))\r\n    if y < map_height - 1 and free_space_grid[x, y + 1] != 0:\r\n        neighbors.append(node(value=(x, y + 1), parent=parent_node, cost=(cost(parent_node, (x, y + 1)))+heuristic((x, y + 1), end_cell), name=\"({}, {})\".format(x, y + 1)))\r\n\r\n    return neighbors\r\n\r\ndef cost(current_cell, neighbor):\r\n\r\n    if(current_cell.parent):\r\n        parent = current_cell.parent.value\r\n    else:\r\n        parent = current_cell.value\r\n\r\n    current = current_cell.value\r\n\r\n    #check if direction has not changed\r\n    direction1 = (parent[0] - current[0], parent[1] - current[1])\r\n    direction2 = (current[0] - neighbor[0], current[1] - neighbor[1])\r\n\r\n    if direction1 == direction2:\r\n        penalty = 0.1\r\n    else:\r\n        penalty = 0.5\r\n\r\n    return penalty + round(1 - free_space_grid[neighbor],2)\r\n\r\ndef heuristic(current_cell, end_cell):\r\n    return abs(current_cell[0] - end_cell[0]) + abs(current_cell[1] - end_cell[1])\r\n\r\n#! A* algorithm ----------------------------------------------------\r\n\r\n# Create an instance of the astar class\r\ndijkstra_obj = dijkstra(get_neighbors)\r\n\r\n# Find the path\r\npath = dijkstra_obj.path(start_node, end_node)\r\ndijkstra_obj.display_path(filename=\"dijkstra_path\")\r\nprint(\"Path: \", path)\r\n\r\n#! Plot the path ----------------------------------------------------\r\n\r\nplt.figure()\r\nplt.imshow(free_space_grid, cmap='gray', origin='upper')\r\n\r\n# Plot the path as a line\r\npath = np.array(dijkstra_obj.get_raw())\r\n\r\n#plot simplified dots\r\nplt.plot(path[:, 1], path[:, 0], 'r')\r\nplt.scatter(robot_cell[1], robot_cell[0], color='r', marker='x')\r\nplt.scatter(end_cell[1], end_cell[0], color='g', marker='x')\r\nplt.show()\r\n\r\n```\r\n\r\n### Breadth-First Search Example\r\n\r\nThis example demonstrates how to use the Breadth-First Search algorithm to explore all possible paths in a grid.\r\n\r\n```python\r\nimport numpy as np\r\nimport matplotlib.pyplot as plt\r\nfrom vagabond.systems import node\r\nfrom vagabond.environmental import bfs\r\nimport numpy as np\r\n\r\n#example free space grids (1 is free, 0 is occupied)\r\nfree_space_grid = np.array([\r\n    [1, 0.8, 0.5, 0.5, 0.8],\r\n    [0.9, 0, 0, 0.8, 0.6],\r\n    [0, 0.8, 0.9, 0.9, 0.9],\r\n    [0.8, 0.9, 0, 0, 0.9],\r\n    [0.6, 0.5, 0.2, 0.2, 1]\r\n])\r\n\r\n# Assuming robot_cell is defined\r\nrobot_cell = (0, 0)\r\nend_cell = (4, 4)\r\n\r\nstart_node = node(value=robot_cell, name=\"({}, {})\".format(robot_cell[0], robot_cell[1]))\r\nend_node = node(value=end_cell, name=\"({}, {})\".format(end_cell[0], end_cell[1]))\r\n\r\n# Generate a random end cell\r\nmap_height, map_width = free_space_grid.shape\r\n\r\n#! A* functions ----------------------------------------------------\r\n\r\n# if a cell is given, return the 4-connected neighbors\r\n# probability  high -----> cost low -----> high priority\r\ndef get_neighbors(parent_node):\r\n\r\n    neighbors = []\r\n    x, y = parent_node.value\r\n\r\n    # Check if the neighbor is within the map and is free\r\n    if x > 0 and free_space_grid[x - 1,y] != 0:\r\n        neighbors.append(node(value=(x - 1, y), parent=parent_node, cost=(cost(parent_node, (x - 1, y)))+heuristic((x - 1, y), end_cell), name=\"({}, {})\".format(x - 1, y)))\r\n    if x < map_width - 1 and free_space_grid[x + 1,y] != 0:    \r\n        neighbors.append(node(value=(x + 1, y), parent=parent_node, cost=(cost(parent_node, (x + 1, y)))+heuristic((x + 1, y), end_cell), name=\"({}, {})\".format(x + 1, y)))\r\n    if y > 0 and free_space_grid[x, y - 1] != 0:\r\n        neighbors.append(node(value=(x, y - 1), parent=parent_node, cost=(cost(parent_node, (x, y - 1)))+heuristic((x, y - 1), end_cell), name=\"({}, {})\".format(x, y - 1)))\r\n    if y < map_height - 1 and free_space_grid[x, y + 1] != 0:\r\n        neighbors.append(node(value=(x, y + 1), parent=parent_node, cost=(cost(parent_node, (x, y + 1)))+heuristic((x, y + 1), end_cell), name=\"({}, {})\".format(x, y + 1)))\r\n\r\n    return neighbors\r\n\r\ndef cost(current_cell, neighbor):\r\n\r\n    if(current_cell.parent):\r\n        parent = current_cell.parent.value\r\n    else:\r\n        parent = current_cell.value\r\n\r\n    current = current_cell.value\r\n\r\n    #check if direction has not changed\r\n    direction1 = (parent[0] - current[0], parent[1] - current[1])\r\n    direction2 = (current[0] - neighbor[0], current[1] - neighbor[1])\r\n\r\n    if direction1 == direction2:\r\n        penalty = 0.1\r\n    else:\r\n        penalty = 0.5\r\n\r\n    return penalty + round(1 - free_space_grid[neighbor],2)\r\n\r\ndef heuristic(current_cell, end_cell):\r\n    return abs(current_cell[0] - end_cell[0]) + abs(current_cell[1] - end_cell[1])\r\n\r\n#! A* algorithm ----------------------------------------------------\r\n\r\n# Create an instance of the astar class\r\nbfs_obj = bfs(get_neighbors)\r\n\r\n# Find the path\r\npath = bfs_obj.path(start_node, end_node)\r\nbfs_obj.display_path(filename=\"bfs_path\")\r\nprint(\"Path: \", path)\r\n\r\n#! Plot the path ----------------------------------------------------\r\n\r\nplt.figure()\r\nplt.imshow(free_space_grid, cmap='gray', origin='upper')\r\n\r\n# Plot the path as a line\r\npath = np.array(bfs_obj.get_raw())\r\n\r\n#plot simplified dots\r\nplt.plot(path[:, 1], path[:, 0], 'r')\r\nplt.scatter(robot_cell[1], robot_cell[0], color='r', marker='x')\r\nplt.scatter(end_cell[1], end_cell[0], color='g', marker='x')\r\nplt.show()\r\n\r\n```\r\n\r\n### Depth-First Search Example\r\n\r\nThis example demonstrates how to use the Depth-First Search algorithm to explore all possible paths in a grid.\r\n\r\n```python\r\nimport numpy as np\r\nimport matplotlib.pyplot as plt\r\nfrom vagabond.systems import node\r\nfrom vagabond.environmental import dfs\r\nimport numpy as np\r\n\r\n#example free space grids (1 is free, 0 is occupied)\r\nfree_space_grid = np.array([\r\n    [1, 0.8, 0.5, 0.5, 0.8],\r\n    [0.9, 0, 0, 0.8, 0.6],\r\n    [0, 0.8, 0.9, 0.9, 0.9],\r\n    [0.8, 0.9, 0, 0, 0.9],\r\n    [0.6, 0.5, 0.2, 0.2, 1]\r\n])\r\n\r\n# Assuming robot_cell is defined\r\nrobot_cell = (0, 0)\r\nend_cell = (4, 4)\r\n\r\nstart_node = node(value=robot_cell, name=\"({}, {})\".format(robot_cell[0], robot_cell[1]))\r\nend_node = node(value=end_cell, name=\"({}, {})\".format(end_cell[0], end_cell[1]))\r\n\r\n# Generate a random end cell\r\nmap_height, map_width = free_space_grid.shape\r\n\r\n#! A* functions ----------------------------------------------------\r\n\r\n# if a cell is given, return the 4-connected neighbors\r\n# probability  high -----> cost low -----> high priority\r\ndef get_neighbors(parent_node):\r\n\r\n    neighbors = []\r\n    x, y = parent_node.value\r\n\r\n    # Check if the neighbor is within the map and is free\r\n    if x > 0 and free_space_grid[x - 1,y] != 0:\r\n        neighbors.append(node(value=(x - 1, y), parent=parent_node, cost=(cost(parent_node, (x - 1, y)))+heuristic((x - 1, y), end_cell), name=\"({}, {})\".format(x - 1, y)))\r\n    if x < map_width - 1 and free_space_grid[x + 1,y] != 0:    \r\n        neighbors.append(node(value=(x + 1, y), parent=parent_node, cost=(cost(parent_node, (x + 1, y)))+heuristic((x + 1, y), end_cell), name=\"({}, {})\".format(x + 1, y)))\r\n    if y > 0 and free_space_grid[x, y - 1] != 0:\r\n        neighbors.append(node(value=(x, y - 1), parent=parent_node, cost=(cost(parent_node, (x, y - 1)))+heuristic((x, y - 1), end_cell), name=\"({}, {})\".format(x, y - 1)))\r\n    if y < map_height - 1 and free_space_grid[x, y + 1] != 0:\r\n        neighbors.append(node(value=(x, y + 1), parent=parent_node, cost=(cost(parent_node, (x, y + 1)))+heuristic((x, y + 1), end_cell), name=\"({}, {})\".format(x, y + 1)))\r\n\r\n    return neighbors\r\n\r\ndef cost(current_cell, neighbor):\r\n\r\n    if(current_cell.parent):\r\n        parent = current_cell.parent.value\r\n    else:\r\n        parent = current_cell.value\r\n\r\n    current = current_cell.value\r\n\r\n    #check if direction has not changed\r\n    direction1 = (parent[0] - current[0], parent[1] - current[1])\r\n    direction2 = (current[0] - neighbor[0], current[1] - neighbor[1])\r\n\r\n    if direction1 == direction2:\r\n        penalty = 0.1\r\n    else:\r\n        penalty = 0.5\r\n\r\n    return penalty + round(1 - free_space_grid[neighbor],2)\r\n\r\ndef heuristic(current_cell, end_cell):\r\n    return abs(current_cell[0] - end_cell[0]) + abs(current_cell[1] - end_cell[1])\r\n\r\n#! A* algorithm ----------------------------------------------------\r\n\r\n# Create an instance of the astar class\r\ndfs_obj = dfs(get_neighbors)\r\n\r\n\r\n# Find the path\r\npath = dfs_obj.path(start_node, end_node)\r\ndfs_obj.display_path(filename=\"dfs_path\")\r\nprint(\"Path: \", path)\r\n\r\n#! Plot the path ----------------------------------------------------\r\n\r\nplt.figure()\r\nplt.imshow(free_space_grid, cmap='gray', origin='upper')\r\n\r\n# Plot the path as a line\r\npath = np.array(dfs_obj.get_raw())\r\n\r\n#plot simplified dots\r\nplt.plot(path[:, 1], path[:, 0], 'r')\r\nplt.scatter(robot_cell[1], robot_cell[0], color='r', marker='x')\r\nplt.scatter(end_cell[1], end_cell[0], color='g', marker='x')\r\nplt.show()\r\n\r\n```\r\n",
    "bugtrack_url": null,
    "license": "MIT License with attribution requirement",
    "summary": "Vagabond is a comprehensive library for pathfinding, navigation, and environmental understanding in robotics and automation. It provides a range of algorithms and tools to help developers create efficient and sophisticated pathfinding solutions for robots and autonomous systems.",
    "version": "2.0.2",
    "project_urls": {
        "Download": "https://github.com/Kawai-Senpai/Vagabond",
        "Homepage": "https://github.com/Kawai-Senpai/Vagabond"
    },
    "split_keywords": [
        "pathfinding",
        " robotics",
        " navigation",
        " a* algorithm",
        " graph theory",
        " automation",
        " robotic systems"
    ],
    "urls": [
        {
            "comment_text": "",
            "digests": {
                "blake2b_256": "7ab6de280d7da52f4f8f443f7c6b2b12c7371d4a475bfe4656658c5ae9332a18",
                "md5": "ff9f79876fb1e0cb617550406c1a4bf4",
                "sha256": "89d06943cf0295eaa2d69dbd54687257a7def96a60902615b023f720818ededd"
            },
            "downloads": -1,
            "filename": "py_vagabond-2.0.2-py3-none-any.whl",
            "has_sig": false,
            "md5_digest": "ff9f79876fb1e0cb617550406c1a4bf4",
            "packagetype": "bdist_wheel",
            "python_version": "py3",
            "requires_python": null,
            "size": 10441,
            "upload_time": "2024-09-10T06:44:28",
            "upload_time_iso_8601": "2024-09-10T06:44:28.867389Z",
            "url": "https://files.pythonhosted.org/packages/7a/b6/de280d7da52f4f8f443f7c6b2b12c7371d4a475bfe4656658c5ae9332a18/py_vagabond-2.0.2-py3-none-any.whl",
            "yanked": false,
            "yanked_reason": null
        },
        {
            "comment_text": "",
            "digests": {
                "blake2b_256": "047eaec336259151394fa862a1846f983843b2c79990c50c1721fa210a33a22a",
                "md5": "7191b815253bf1c13d96bf6ea945cb6e",
                "sha256": "cbf5c270fbe3dd14ad214bc8312fcba747aa777e845664f5b8de2183e2ede0db"
            },
            "downloads": -1,
            "filename": "py-vagabond-2.0.2.tar.gz",
            "has_sig": false,
            "md5_digest": "7191b815253bf1c13d96bf6ea945cb6e",
            "packagetype": "sdist",
            "python_version": "source",
            "requires_python": null,
            "size": 13248,
            "upload_time": "2024-09-10T06:44:30",
            "upload_time_iso_8601": "2024-09-10T06:44:30.730454Z",
            "url": "https://files.pythonhosted.org/packages/04/7e/aec336259151394fa862a1846f983843b2c79990c50c1721fa210a33a22a/py-vagabond-2.0.2.tar.gz",
            "yanked": false,
            "yanked_reason": null
        }
    ],
    "upload_time": "2024-09-10 06:44:30",
    "github": true,
    "gitlab": false,
    "bitbucket": false,
    "codeberg": false,
    "github_user": "Kawai-Senpai",
    "github_project": "Vagabond",
    "travis_ci": false,
    "coveralls": false,
    "github_actions": false,
    "lcname": "py-vagabond"
}
        
Elapsed time: 0.38350s