Ejemplo n.º 1
0
void run(const P& p0,
         const P& p1,
         const bool* blocked,
         int* flood_buffer,
         const P& map_dims,
         std::vector<P>& out,
         const bool allow_diagonal,
         const bool randomize_steps)
{
    out.clear();

    if (p0 == p1)
    {
        // Origin and target is same cell
        return;
    }

    floodfill::run(p0,
                   blocked,
                   flood_buffer,
                   map_dims,
                   -1,
                   p1,
                   allow_diagonal);

    if (flood_buffer[idx2(p1, map_dims.y)] == 0)
    {
        // No path exists
        return;
    }

    const std::vector<P>& dirs = allow_diagonal ?
                                 dir_utils::dir_list :
                                 dir_utils::cardinal_list;

    const size_t nr_dirs = dirs.size();

    // Corresponds to the elements in "dirs"
    std::vector<bool> valid_offsets(nr_dirs, false);

    // The path length will be equal to the flood value at the target cell, so
    // we can reserve that many elements beforehand.
    out.reserve(flood_buffer[idx2(p1, map_dims.y)]);

    P p(p1);
    out.push_back(p);

    const R map_r(P(0, 0), map_dims - 1);

    while (true)
    {
        const int val = flood_buffer[idx2(p, map_dims.y)];

        P adj_p;

        // Find valid offsets, and check if origin is reached
        for (size_t i = 0; i < nr_dirs; ++i)
        {
            const P& d(dirs[i]);

            adj_p = p + d;

            if (adj_p == p0)
            {
                // Origin reached
                return;
            }

            // TODO: What is the purpose of this check? If the current value is
            // zero, doesn't that mean this cell is the target? Only the target
            // cell and unreachable cells should have values of zero(?)
            // Try removing the check and verify if the algorithm still works
            if (val != 0)
            {
                const bool is_inside_map = map_r.is_p_inside(adj_p);

                const int adj_val = is_inside_map ?
                                    flood_buffer[idx2(adj_p, map_dims.y)] : 0;

                // Mark this as a valid travel direction if it's fewer steps
                // from the target than the current cell
                valid_offsets[i] = adj_val < val;
            }
        }

        // Set the next position to one of the valid offsets - either pick one
        // randomly, or iterate over the list and pick the first valid choice.
        if (randomize_steps)
        {
            std::vector<P> adj_p_bucket;

            for (size_t i = 0; i < nr_dirs; ++i)
            {
                if (valid_offsets[i])
                {
                    adj_p_bucket.push_back(p + dirs[i]);
                }
            }

            ASSERT(!adj_p_bucket.empty());

            adj_p = rnd::element(adj_p_bucket);
        }
        else // Do not randomize step choices - iterate over offset list
        {
            for (size_t i = 0; i < nr_dirs; ++i)
            {
                if (valid_offsets[i])
                {
                    adj_p = P(p + dirs[i]);
                    break;
                }
            }
        }

        out.push_back(adj_p);

        p = adj_p;

    } //while
}
Ejemplo n.º 2
0
void run(const P& p0,
         const P& p1,
         const bool blocked[map_w][map_h],
         std::vector<P>& out,
         const bool allow_diagonal,
         const bool randomize_steps)
{
    out.clear();

    if (p0 == p1)
    {
        // Origin and target is same cell
        return;
    }

    int flood_buffer[map_w][map_h];

    floodfill::run(p0,
                   blocked,
                   flood_buffer,
                   -1,
                   p1,
                   allow_diagonal);

    if (flood_buffer[p1.x][p1.y] == 0)
    {
        // No path exists
        return;
    }

    const std::vector<P>& dirs = allow_diagonal ?
                                 dir_utils::dir_list :
                                 dir_utils::cardinal_list;

    const size_t nr_dirs = dirs.size();

    // Corresponds to the elements in "dirs"
    std::vector<bool> valid_offsets(nr_dirs, false);

    // The path length will be equal to the flood value at the target cell, so
    // we can reserve that many elements beforehand.
    out.reserve(flood_buffer[p1.x][p1.y]);

    // We start at the target cell
    P p(p1);
    out.push_back(p);

    const R map_r(P(0, 0), P(map_w, map_h) - 1);

    while (true)
    {
        const int current_val = flood_buffer[p.x][p.y];

        P adj_p;

        // Find valid offsets, and check if origin is reached
        for (size_t i = 0; i < nr_dirs; ++i)
        {
            const P& d(dirs[i]);

            adj_p = p + d;

            if (adj_p == p0)
            {
                // Origin reached
                return;
            }

            if (map_r.is_p_inside(adj_p))
            {
                const int adj_val = flood_buffer[adj_p.x][adj_p.y];

                // Mark this as a valid travel direction if it is not blocked,
                // and is fewer steps from the target than the current cell.
                valid_offsets[i] =
                    (adj_val != 0) &&
                    (adj_val < current_val);
            }
        }

        // Set the next position to one of the valid offsets - either pick one
        // randomly, or iterate over the list and pick the first valid choice.
        if (randomize_steps)
        {
            std::vector<P> adj_p_bucket;

            for (size_t i = 0; i < nr_dirs; ++i)
            {
                if (valid_offsets[i])
                {
                    adj_p_bucket.push_back(p + dirs[i]);
                }
            }

            ASSERT(!adj_p_bucket.empty());

            adj_p = rnd::element(adj_p_bucket);
        }
        else // Do not randomize step choices - iterate over offset list
        {
            for (size_t i = 0; i < nr_dirs; ++i)
            {
                if (valid_offsets[i])
                {
                    adj_p = P(p + dirs[i]);
                    break;
                }
            }
        }

        out.push_back(adj_p);

        p = adj_p;

    } // while
}