-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
770dbd1
commit dc41ccf
Showing
3 changed files
with
184 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,114 @@ | ||
class Node(): | ||
"""A node class for A* Pathfinding""" | ||
|
||
def __init__(self, parent=None, position=None): | ||
self.parent = parent | ||
self.position = position | ||
|
||
self.g = 0 | ||
self.h = 0 | ||
self.f = 0 | ||
|
||
def __eq__(self, other): | ||
return self.position == other.position | ||
|
||
|
||
def astar(maze, start, end): | ||
"""Returns a list of tuples as a path from the given start to the given end in the given maze""" | ||
|
||
# Create start and end node | ||
start_node = Node(None, start) | ||
start_node.g = start_node.h = start_node.f = 0 | ||
end_node = Node(None, end) | ||
end_node.g = end_node.h = end_node.f = 0 | ||
|
||
# Initialize both open and closed list | ||
open_list = [] | ||
closed_list = [] | ||
|
||
# Add the start node | ||
open_list.append(start_node) | ||
|
||
# Loop until you find the end | ||
while len(open_list) > 0: | ||
|
||
# Get the current node | ||
current_node = open_list[0] | ||
current_index = 0 | ||
for index, item in enumerate(open_list): | ||
if item.f < current_node.f: | ||
current_node = item | ||
current_index = index | ||
|
||
# Pop current off open list, add to closed list | ||
open_list.pop(current_index) | ||
closed_list.append(current_node) | ||
|
||
# Found the goal | ||
if current_node == end_node: | ||
path = [] | ||
current = current_node | ||
while current is not None: | ||
path.append(current.position) | ||
current = current.parent | ||
return path[::-1] # Return reversed path | ||
|
||
# Generate children | ||
children = [] | ||
for new_position in [(0, -1), (0, 1), (-1, 0), (1, 0), (-1, -1), (-1, 1), (1, -1), (1, 1)]: # Adjacent squares | ||
|
||
# Get node position | ||
node_position = (current_node.position[0] + new_position[0], current_node.position[1] + new_position[1]) | ||
|
||
# Make sure within range | ||
if node_position[0] > (len(maze) - 1) or node_position[0] < 0 or node_position[1] > (len(maze[len(maze)-1]) -1) or node_position[1] < 0: | ||
continue | ||
|
||
# Make sure walkable terrain | ||
if maze[node_position[0]][node_position[1]] != 0: | ||
continue | ||
|
||
# Create new node | ||
new_node = Node(current_node, node_position) | ||
|
||
# Append | ||
children.append(new_node) | ||
|
||
# Loop through children | ||
for child in children: | ||
|
||
# Child is on the closed list | ||
for closed_child in closed_list: | ||
if child == closed_child: | ||
continue | ||
|
||
# Create the f, g, and h values | ||
child.g = current_node.g + 1 | ||
child.h = ((child.position[0] - end_node.position[0]) ** 2) + ((child.position[1] - end_node.position[1]) ** 2) | ||
child.f = child.g + child.h | ||
|
||
# Child is already in the open list | ||
for open_node in open_list: | ||
if child == open_node and child.g > open_node.g: | ||
continue | ||
|
||
# Add the child to the open list | ||
open_list.append(child) | ||
|
||
|
||
maze = [[0, 0, 0, 0, 1, 0, 0, 0, 0, 0], | ||
[0, 0, 0, 0, 1, 0, 0, 0, 0, 0], | ||
[0, 0, 0, 0, 1, 0, 0, 0, 0, 0], | ||
[0, 0, 0, 0, 1, 0, 0, 0, 0, 0], | ||
[0, 0, 0, 0, 1, 0, 0, 0, 0, 0], | ||
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0], | ||
[0, 0, 0, 0, 1, 0, 0, 0, 0, 0], | ||
[0, 0, 0, 0, 1, 0, 0, 0, 0, 0], | ||
[0, 0, 0, 0, 1, 0, 0, 0, 0, 0], | ||
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0]] | ||
|
||
start = (0, 0) | ||
end = (7, 6) | ||
|
||
path = astar(maze, start, end) | ||
print(path) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,67 @@ | ||
""" | ||
Implementing the B* (B-star) search algorithm can be a bit more complex than A* | ||
because it requires maintaining both primary and secondary heuristics, as well as balancing the two heuristics during the search. | ||
Below is a Python program for a simplified version of B* search. | ||
Keep in mind that the B* algorithm can be more complex in practice and often requires careful consideration of heuristics. | ||
This example focuses on the concept, but real-world applications may involve additional details and optimizations. | ||
""" | ||
import heapq | ||
|
||
def b_star_search(graph, start, goal, primary_heuristic, secondary_heuristic): | ||
open_set = [(0, start)] # Priority queue to store (f-cost, state) pairs | ||
g_costs = {node: float('inf') for node in graph} # Initialize g-costs to infinity | ||
g_costs[start] = 0 | ||
visited = set() | ||
|
||
while open_set: | ||
f_cost, current_state = heapq.heappop(open_set) | ||
|
||
if current_state == goal: | ||
print("Goal found!") | ||
return | ||
|
||
if current_state in visited: | ||
continue | ||
|
||
visited.add(current_state) | ||
|
||
for neighbor, cost in graph[current_state]: | ||
tentative_g_cost = g_costs[current_state] + cost | ||
if tentative_g_cost < g_costs[neighbor]: | ||
g_costs[neighbor] = tentative_g_cost | ||
h_cost = primary_heuristic[neighbor] | ||
h2_cost = secondary_heuristic[neighbor] | ||
f_cost = tentative_g_cost + max(h_cost, h2_cost) # B* balance | ||
heapq.heappush(open_set, (f_cost, neighbor)) | ||
|
||
print("Goal not found!") | ||
|
||
# Example usage | ||
graph = { | ||
'A': [('B', 2), ('C', 4)], | ||
'B': [('D', 5)], | ||
'C': [('D', 7)], | ||
'D': [('E', 3)], | ||
'E': [], | ||
} | ||
|
||
primary_heuristic = { | ||
'A': 8, # Primary heuristic values for each state, estimated distance to the goal | ||
'B': 6, | ||
'C': 5, | ||
'D': 3, | ||
'E': 0, | ||
} | ||
|
||
secondary_heuristic = { | ||
'A': 6, # Secondary heuristic values for each state | ||
'B': 4, | ||
'C': 3, | ||
'D': 1, | ||
'E': 0, | ||
} | ||
|
||
start_state = 'A' | ||
goal_state = 'E' | ||
|
||
b_star_search(graph, start_state, goal_state, primary_heuristic, secondary_heuristic) |