1

I want to find a good path from a point A to a point B on a limited hardware (CPU: Vortex86, 256 MB) using the A* algorithm. I have a grid of 300x200 cells with fixed obstacles. The hit box to avoid obstacles is a disk.

I'm looking for an optimized way to check if my hit box is in collision with obstacles as it is done very often in A*.

The most obvious way was to check the whole area of the disk like:

bool check(std::function<bool(const Coordinates &)> collide)
{
    const std::uint32_t RADIUS2 = radius * radius;
    Coordinates cell(-radius, -radius);

    for (; cell.x <= radius; cell.x++)
    {
        for (cell.y = -radius; cell.y <= radius; cell.y++)
        {
            if (cell.x * cell.x + cell.y * cell.y <= RADIUS2 && !collide(center + cell))
            {
                return false;
            }
        }
    }

    return true;
}

Where radius is the radius of the disk and center the coordinates of the center of the disk.

A better solution could be to only check the perimeter of the disk. But both solutions need to use 2 for loops and it doesn't fit the disk area a big part of the time.

Do you have any solution to do it a clever way?

5
  • 4
    Can't you just inflate the obstacles when you generate the map ? Then the collision test will reduce to a single pixel.
    – user1196549
    Commented Aug 5, 2016 at 9:35
  • I don't understand how you do that. Let's imagine an obstacle like a quarter of a disk in a corner. How do you inflate it?
    – didil
    Commented Aug 5, 2016 at 9:42
  • @didile It is easy to inflate any obstacle: just mark as "inflation" all the cells which distance to an obstacle less than R. It is enought to do it only once. After it you'll instantly check is it allowed to be in this cell.
    – Ilya
    Commented Aug 5, 2016 at 12:04
  • @didile: see slide 9 slideshare.net/supermubbasher/dip-morphological
    – user1196549
    Commented Aug 5, 2016 at 12:08
  • @Ilya I got the idea and it works perfectly! It's pretty expensive as I must copy the whole grid but it costs only in the constructor :)
    – didil
    Commented Aug 5, 2016 at 13:33

1 Answer 1

0

Inside a nested loop, you're calling std::function::operator(). That's an indirect call, with a non-trivial abstraction penalty. Now a modern CPU will have branch prediction, which will successfully predict that branch after the first few calls. But your old chip will suffer a lot right there.

So, you indeed need to avoid this. Luckily, the first comment already hits the nail on the head. You can efficiently pre-calculate the hit test, by calculating the no-go zone around obstacles.

Alternatively, assuming that the obstacles don't move, you can cache the results of the hit test on each cell. This is especially effective if you have a large grid where you initially need only a small part.

1
  • I use std::function as a way to change what's effectively an obstacle, a fixed obstacle on the grid or a moving one from another source or both.
    – didil
    Commented Aug 5, 2016 at 13:36

Not the answer you're looking for? Browse other questions tagged or ask your own question.