2

As we know from daily experience diagonal moves are cheaper than a horizontal + vertical moves, this becomes a problem of uneven step cost.

So, uniform cost search will be required to solve this problem. To implement uniform cost search, you will need a Priority Queue for frontier.

To add a child to the frontier frontier.insert(item) To extract the item with minimum cost Temp = frontier.extract_min() To decrease the cost of an item frontier.decrease_key(item) To check if in an item is already in the frontier frontier.is_in(item) It returns true if item is in the frontier, returns false if not in the frontier.

Algorithm I used for this code :

import collections
import copy

grid_size = 5
source = (0, 0)
destination = (4, 3)

grid = [[0, 0, 0, 0, 0],
        [0, 1, 0, 1, 0],
        [0, 1, 0, 0, 0],
        [0, 1, 1, 1, 0],
        [0, 0, 0, 0, 0]]


class Location:
    def __init__(self, p, cost=0):
        self.point = p
        self.parent = None
        self.cost = cost
        self.hash_value = self.hash_calc()

    def hash_calc(self):
        x, y = self.point
        return str(x) + "_" + str(y)

    def make_move(self, direction):
        x, y = self.point
        # up
        if direction == 'l':
            if y > 0 and grid[x][y-1] == 0:
                self.point = x, y-1
                self.cost = self.cost + 1
        # down
        elif direction == 'r':
            if y < grid_size-1 and grid[x][y+1] == 0:
                self.point = x, y+1
                self.cost = self.cost + 1
        # left
        elif direction == 'u':
            if x > 0 and grid[x-1][y] == 0:
                self.point = x-1, y
                self.cost = self.cost + 1
        # right
        elif direction == 'd':
            if x < grid_size-1 and grid[x+1][y] == 0:
                self.point = x+1, y
                self.cost = self.cost + 1
        # up-left
        elif direction == 'ul':
            if y>0  and x>0 and grid[x-1][y-1] == 0:
                self.point = x-1, y-1
                self.cost = self.cost + 1.5
        # up-right
        elif direction == 'dl':
            if y>0  and x<grid_size-1 and grid[x+1][y-1] == 0:
                self.point = x+1, y-1
                self.cost = self.cost + 1.5
        # down-left
        elif direction == 'ur':
            if y<grid_size-1  and x>0 and grid[x-1][y+1] == 0:
                self.point = x-1, y+1
                self.cost = self.cost + 1.5
        # down-right
        elif direction == 'dr':
            if y<grid_size-1  and x<grid_size-1 and grid[x+1][y+1] == 0:
                self.point = x+1, y+1
                self.cost = self.cost + 1.5

        self.hash_value = self.hash_calc()
        print(self.point, self.cost)

    def copy_location(self):
        temp = Location(self.point, cost=self.cost)
        temp.parent = self
        return temp

    def print_path(self):
        ancestors = []
        temp = self
        while(temp.parent != None):
            ancestors.append(temp.parent)
            temp = temp.parent
        n = len(ancestors)
        for i in range(n):
            temp = ancestors.pop()
            print(temp.point, end='->')
        print(self.point)
        print('%d steps were required.\nTotal cost is %f' % (n, self.cost))

    def goal_test(self):
        return self.point == destination

    def get_key(self):
        return self.cost


class Priority_Queue:
    def __init__(self):
        self.capacity = 2
        self.q = [None] * self.capacity
        self.items = [None] * self.capacity
        self.dict = {}
        self.size = 0

    def parent(self, i):
        return int((i-1)/2)

    def left(self, i):
        return 2*i + 1

    def right(self, i):
        return 2*i + 2

    def move(self, i, j):
        self.q[i] = self.q[j]
        self.items[i] = self.items[j]
        self.dict[self.items[i].hash_value] = i

    def swap(self, i, j):
        self.q[i], self.q[j] = self.q[j], self.q[i]
        self.items[i], self.items[j] = self.items[j], self.items[i]
        self.dict[self.items[i].hash_value] = i
        self.dict[self.items[j].hash_value] = j

    def min_heapify(self, i):
        left = self.left(i)
        right = self.right(i)
        smallest = i
        if left < self.size and self.q[left] < self.q[i]:
            smallest = left
        if right < self.size and self.q[right] < self.q[smallest]:
            smallest = right
        if smallest != i:
            self.swap(i, smallest)
            self.min_heapify(smallest)

    def insert(self, item):
        self.size = self.size + 1
        if self.size > self.capacity:
            self.q = self.q + [None] * self.capacity
            self.items = self.items + [None] * self.capacity
            self.capacity = self.capacity * 2
        i = self.size - 1
        self.q[i] = item.get_key()
        self.items[i] = item
        self.dict[item.hash_value] = i
        while i != 0 and self.q[self.parent(i)] > self.q[i]:
            self.swap(i, self.parent(i))
            i = self.parent(i)

    def extract_min(self):
        item = self.items[0]
        self.move(0, self.size - 1)
        self.dict.pop(item.hash_value)
        self.size = self.size - 1
        self.min_heapify(0)
        return item

    def decrease_key(self, item):
        i = self.dict[item.hash_value]
        if self.q[i] < item.get_key():
            return
        self.q[i] = item.get_key()
        self.items[i] = item
        while i != 0 and self.q[self.parent(i)] > self.q[i]:
            self.swap(i, self.parent(i))
            i = self.parent(i)

    def get_min(self):
        return self.items[0]

    def is_in(self, item):
        return item.hash_value in self.dict.keys()

# Make an initial State with source
initial_state = Location(source)
# Create an empty frontier
frontier = Priority_Queue()
frontier.insert(initial_state)
# Create an empty explored list
explored = set()
# initialize frontier with initial state




##########################################
####Solution would be here

##############Solution i Tried to solve
x = 0
children=()
Output = False

#While Output is False
while Output == False:
    x = x+1 
    if frontier.size == 0:
        print('No Solution Found !')
        break           
    z = frontier.get_min()
    explored.add(z)    
    #make moves 
    for d in ['u','d','l','r','ul','dl','ur','dr']:

        children = z.copy_location()
        children.make_move(d)

        if children not in explored and children:
            if children.goal_test() == True:
                children.print_path()
                Output = True
                break       

            frontier.insert(children)
    #if output is true 
    if Output == True:
        print('Total %d states Explored !.' %(x))
        break

i want to implement uniform cost search here. i tried to follow the pseudo code but i failed. well this is my first time in stack overflow so if i made any mistake please forgive me ! i will be more careful from next time.

ted
  • 13,596
  • 9
  • 65
  • 107
t311337
  • 21
  • 1
  • 1
    Add a unit test, and show us the expected vs actual output. Consider changing `['u', ..., 'dr']` into delta_x, delta_y tuples: `[(0, -1), ..., (1, 1)]`. Rather than your possibly buggy pqueue, consider using this standard routine: https://docs.python.org/3/library/queue.html#queue.PriorityQueue – J_H Apr 07 '19 at 16:46

0 Answers0