Why my A* algorithm isn't working when I specify a node weight?

44 Views Asked by At

I made a 2d mario kart using python, and now I'm putting together an algorithm to finish the track. The idea is very simple, calculate the shortest route to the next checkpoint and walk towards it. So far the code works, but when I add weight to the grass edges (where the kart has greater friction than the track, making the path through the grass 100x more expensive) the code simply takes a long time to solve the shortest path. When the kart is on a straight line from the checkpoint, it calculates it super quickly, but if there is a grass in the middle of the straight line, the code takes a long time to calculate the path (I don't have the exact value, but I think it's around 10,000x slower).

Here's the code snippet for the A* function:

COST_MAPPING = {
    Road: 3,
    Checkpoint: 3,
    Boost: 1,
    Grass: 300
}

def a_star(self, string, start, goal, h, neighbors):
        """
        A* Search Algorithm

        A* is an informed search algorithm that uses a combination of the cost to
        reach a node (goal), and an estimated cost (h) from the current node to
        the goal, to determine the priority of nodes in the search.

        Wikipedia page: https://en.wikipedia.org/wiki/A*_search_algorithm
        """
        def reconstruct_path(cameFrom, current):
            total_path = [current]
            while current in cameFrom:
                current = cameFrom[current]
                total_path.insert(0, current)
            return total_path

        openSet = [(0, start)]
        cameFrom = {}
        gScore = {tuple(start): 0}
        fScore = {tuple(start): h(string, start, goal)}

        while openSet:
            _, current = heappop(openSet)
            if tuple(current) == tuple(goal):
                return reconstruct_path(cameFrom, tuple(current))

            for neighbor in neighbors(string, current):
                # lines with problem
                neighbor_track_element = self.kart.get_track_element(string, neighbor[0], neighbor[1])[0]
                cost = COST_MAPPING.get(neighbor_track_element)
                tentative_gScore = gScore[tuple(current)] + cost
                # ends here
                if tentative_gScore < gScore.get(tuple(neighbor), float('inf')):
                    cameFrom[tuple(neighbor)] = tuple(current)
                    gScore[tuple(neighbor)] = tentative_gScore
                    fScore[tuple(neighbor)] = tentative_gScore + h(string, neighbor, goal)
                    heappush(openSet, (fScore[tuple(neighbor)], tuple(neighbor)))

        return None

    def h(self, string, current, goal):

        manhattan_distance = abs(int(current[0]) - int(goal[0])) + abs(int(current[1]) - int(goal[1]))
        kart_speed = self.kart.get_speed()
        speed_x, speed_y = self.kart.get_speed()

        kart_speed = math.sqrt(speed_x**2 + speed_y**2)
        track_element, _ = self.kart.get_track_element(string, current[0], current[1])
        terrain_penalty = 1

        if track_element == Grass:
            terrain_penalty = 100

        combined_heuristic = manhattan_distance + terrain_penalty * kart_speed

        return combined_heuristic

    def neighbors(self, string, current):
        x, y = current
        possible_neighbors = [
            (x + 1, y),
            (x - 1, y),
            (x, y + 1),
            (x, y - 1),
            (x - 1, y - 1),
            (x - 1, y + 1),
            (x + 1, y - 1),
            (x + 1, y + 1)
        ]

        valid_neighbors = [
            (nx, ny) for nx, ny in possible_neighbors
            if self.kart.get_track_element(string, nx, ny)[0] in (Road, Boost, Checkpoint, Grass)
        ]
        return valid_neighbors

The heuristic is based on the distance between the start and the goal coordinates combined with the terrain_penalty (100x for the grass) times the current kart speed. combined_heuristic = manhattan_distance + terrain_penalty * kart_speed

The cost when I set it to be always 1 makes the calculations really fast, but the kart goes over grass (obviously). tentative_gScore = gScore[tuple(current)] + cost

My question is, why is cost affecting code performance? what could be the problem?

I tried to apply a simpler heuristic, using only the Manhattan distance, but it didn't work either.

0

There are 0 best solutions below