prepbook
  • Introduction
  • Some common stuff
    • python __repr__
    • HackerRank input tips
  • Data Structures and Algorithms
    • Breadth first search
    • Depth First Search
    • Dijkstra
    • A* Search Algorithm
    • Binary Search
    • python counter
    • Sorting
      • Merge Sort
      • Quick Sort
    • Priority Queue
  • Multiprocessing vs Threading
  • Common Coding
    • Find loop in lin list
    • Maximum sum subarray
  • Coding
    • Valid palindrome
    • Palindrome number
    • Remove duplicates from sorted array
    • Island perimeter
    • Serialize and Deserialize Binary Tree
    • Valid Soduku
    • Word Pattern
    • Word Pattern II
    • Group Anagrams
    • Implement Trie
    • Deep copy list with random node
    • Palindrome Permutation
    • Combination Sum
    • Clone Graph
    • Generate parenthesis
    • Fibonacci Number
    • LRU Cache
    • Merge two sorted arrays in place
    • Hamming Distance
    • Merge K sorted arrays
    • Kth smalles element in BST
    • Kth largest element in an array
    • Remove duplicates from sorted list
    • Power of 2
    • Nested list weight sum
    • SIngle number in a list
    • Factor combinations
    • Delete node from BST
  • hacker Rank
    • Coding
      • print staircase
      • Drawing book
      • Challenge 0
      • Min-Max sum
  • WorkRelatedCoding
    • Rectangle Overlap
  • Python tips
Powered by GitBook
On this page

Was this helpful?

  1. Data Structures and Algorithms

A* Search Algorithm

PreviousDijkstraNextBinary Search

Last updated 5 years ago

Was this helpful?

There are many articles on this in the internet. One, which is well written and well explained is found here:

Ref:

    [https://github.com/laurentluce/python-algorithms/blob/master/algorithms/a\_star\_path\_finding.py](https://github.com/laurentluce/python-algorithms/blob/master/algorithms/a_star_path_finding.py)
import heapq

class Cell(object):
    def __init__(self, x, y, reachable):
        """Initialize new cell.
        @param reachable is cell reachable? not a wall?
        @param x cell x coordinate
        @param y cell y coordinate
        @param g cost to move from the starting cell to this cell.
        @param h estimation of the cost to move from this cell
                 to the ending cell.
        @param f f = g + h
        """
        self.reachable = reachable
        self.x = x
        self.y = y
        self.parent = None
        self.g = 0
        self.h = 0
        self.f = 0


class AStar(object):
    def __init__(self):
        # open list
        self.opened = []
        heapq.heapify(self.opened)
        # visited cells list
        self.closed = set()
        # grid cells
        self.cells = []
        self.grid_height = None
        self.grid_width = None

    def init_grid(self, width, height, walls, start, end):
        """Prepare grid cells, walls.
        @param width grid's width.
        @param height grid's height.
        @param walls list of wall x,y tuples.
        @param start grid starting point x,y tuple.
        @param end grid ending point x,y tuple.
        """
        self.grid_height = height
        self.grid_width = width
        for x in range(self.grid_width):
            for y in range(self.grid_height):
                if (x, y) in walls:
                    reachable = False
                else:
                    reachable = True
                self.cells.append(Cell(x, y, reachable))
        self.start = self.get_cell(*start)
        self.end = self.get_cell(*end)

    def get_heuristic(self, cell):
        """Compute the heuristic value H for a cell.
        Distance between this cell and the ending cell multiply by 10.
        @returns heuristic value H
        My Notes: This example uses manhattan distance to calculate the estimated distance.
                  Euclidean distance and other techniques can be used as well to compute the 
                  estimated distance
        """
        return 10 * (abs(cell.x - self.end.x) + abs(cell.y - self.end.y))

    def get_cell(self, x, y):
        """Returns a cell from the cells list.
        @param x cell x coordinate
        @param y cell y coordinate
        @returns cell
        """
        return self.cells[x * self.grid_height + y]

    def get_adjacent_cells(self, cell):
        """Returns adjacent cells to a cell.
        Clockwise starting from the one on the right.
        @param cell get adjacent cells for this cell
        @returns adjacent cells list.
        """
        cells = []
        if cell.x < self.grid_width-1:
            cells.append(self.get_cell(cell.x+1, cell.y))
        if cell.y > 0:
            cells.append(self.get_cell(cell.x, cell.y-1))
        if cell.x > 0:
            cells.append(self.get_cell(cell.x-1, cell.y))
        if cell.y < self.grid_height-1:
            cells.append(self.get_cell(cell.x, cell.y+1))
        return cells

    def get_path(self):
        cell = self.end
        path = [(cell.x, cell.y)]
        while cell.parent is not self.start:
            cell = cell.parent
            path.append((cell.x, cell.y))

        path.append((self.start.x, self.start.y))
        path.reverse()
        return path

    def update_cell(self, adj, cell):
        """Update adjacent cell.
        @param adj adjacent cell to current cell
        @param cell current cell being processed
        """
        adj.g = cell.g + 10
        adj.h = self.get_heuristic(adj)
        adj.parent = cell
        adj.f = adj.h + adj.g

    def solve(self):
        """Solve maze, find path to ending cell.
        @returns path or None if not found.
        """
        # add starting cell to open heap queue
        heapq.heappush(self.opened, (self.start.f, self.start))
        while len(self.opened):
            # pop cell from heap queue
            f, cell = heapq.heappop(self.opened)
            # add cell to closed list so we don't process it twice
            self.closed.add(cell)
            # if ending cell, return found path
            if cell is self.end:
                return self.get_path()
            # get adjacent cells for cell
            adj_cells = self.get_adjacent_cells(cell)
            for adj_cell in adj_cells:
                if adj_cell.reachable and adj_cell not in self.closed:
                    if (adj_cell.f, adj_cell) in self.opened:
                        # if adj cell in open list, check if current path is
                        # better than the one previously found
                        # for this adj cell.
                        if adj_cell.g > cell.g + 10:
                            self.update_cell(adj_cell, cell)
                    else:
                        self.update_cell(adj_cell, cell)
                        # add adj cell to open list
                        heapq.heappush(self.opened, (adj_cell.f, adj_cell))
http://www.laurentluce.com/posts/solving-mazes-using-python-simple-recursivity-and-a-search/