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 }
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 }