fix pathfind code dublication.

This commit is contained in:
gfgtdf 2018-10-20 13:08:53 +02:00
parent 856ac1cded
commit e0234608ae
3 changed files with 76 additions and 70 deletions

View file

@ -18,6 +18,7 @@
*/ */
#include "pathutils.hpp" #include "pathutils.hpp"
#include "pathutils_impl.hpp"
#include "map/map.hpp" #include "map/map.hpp"
@ -238,36 +239,14 @@ void get_tiles_radius(const gamemap& map, const std::vector<map_location>& locs,
bool with_border, const xy_pred& pred) bool with_border, const xy_pred& pred)
{ {
typedef std::set<map_location> location_set; typedef std::set<map_location> location_set;
location_set must_visit, filtered_out;
location_set not_visited(locs.begin(), locs.end()); location_set not_visited(locs.begin(), locs.end());
for ( ; radius != 0 && !not_visited.empty(); --radius ) get_tiles_radius(std::move(not_visited), radius, result,
{ [&](const map_location& l) {
location_set::const_iterator it = not_visited.begin(); return with_border ? map.on_board_with_border(l) : map.on_board(l);
location_set::const_iterator it_end = not_visited.end(); },
[&](const map_location& l) {
result.insert(it, it_end); return pred(l);
for(; it != it_end; ++it) {
adjacent_loc_array_t adj;
get_adjacent_tiles(*it, adj.data());
for(std::size_t i = 0; i < adj.size(); ++i) {
const map_location& loc = adj[i];
if ( with_border ? map.on_board_with_border(loc) :
map.on_board(loc) ) {
if ( !result.count(loc) && !filtered_out.count(loc) ) {
if ( pred(loc) )
must_visit.insert(loc);
else
filtered_out.insert(loc);
}
}
}
} }
);
not_visited.swap(must_visit);
must_visit.clear();
}
result.insert(not_visited.begin(), not_visited.end());
} }

67
src/pathutils_impl.hpp Normal file
View file

@ -0,0 +1,67 @@
/*
Copyright (C) 2018 the Battle for Wesnoth Project https://www.wesnoth.org/
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY.
See the COPYING file for more details.
*/
/** @file */
#pragma once
#include "map/location.hpp"
#include <set>
/**
* Function that will add to @a result all elements of @a locs, plus all
* on-board (that is: all locs that match @pred1) locations matching @a pred2
* that are connected to elements of
* locs by a chain of at most @a radius tiles, each of which matches @a pred2.
* @a result must be a std::set of locations.
*
* @a pred1 a fast predicate (used before cachecheck).
* @a pred2 a slow predicate (used after cachecheck).
*/
template<typename FPred1, typename FPred2>
void get_tiles_radius(std::set<map_location>&& locs, size_t radius, std::set<map_location>& result, const FPred1& pred1, const FPred2& pred2)
{
typedef std::set<map_location> location_set;
location_set must_visit, filtered_out;
location_set not_visited = std::move(locs);
for ( ; radius != 0 && !not_visited.empty(); --radius )
{
location_set::const_iterator it = not_visited.begin();
location_set::const_iterator it_end = not_visited.end();
result.insert(it, it_end);
for(; it != it_end; ++it) {
adjacent_loc_array_t adj;
get_adjacent_tiles(*it, adj.data());
for(size_t i = 0; i < adj.size(); ++i) {
const map_location& loc = adj[i];
if( pred1(loc) ) {
if( !result.count(loc) && !filtered_out.count(loc) ) {
if( pred2(loc) ) {
must_visit.insert(loc);
}
else {
filtered_out.insert(loc);
}
}
}
}
}
not_visited.swap(must_visit);
must_visit.clear();
}
result.insert(not_visited.begin(), not_visited.end());
}

View file

@ -18,6 +18,7 @@
#include "log.hpp" #include "log.hpp"
#include "map/location.hpp" #include "map/location.hpp"
#include "map/map.hpp" #include "map/map.hpp"
#include "pathutils_impl.hpp"
#include "scripting/lua_common.hpp" #include "scripting/lua_common.hpp"
#include "scripting/push_check.hpp" #include "scripting/push_check.hpp"
#include "scripting/game_lua_kernel.hpp" #include "scripting/game_lua_kernel.hpp"
@ -194,48 +195,7 @@ namespace {
* on-board locations matching @a pred that are connected to elements of * on-board locations matching @a pred that are connected to elements of
* locs by a chain of at most @a radius tiles, each of which matches @a pred. * locs by a chain of at most @a radius tiles, each of which matches @a pred.
* @a add_result a function that takes a location_range * @a add_result a function that takes a location_range
* @pred1 a fast predicate (used before cachecheck).
* @pred2 a slow predicate (used after cachecheck).
*/ */
using location_range = boost::iterator_range<location_set::const_iterator>;
template<typename FPred1, typename FPred2>
void get_tiles_radius(location_set&& locs, size_t radius, location_set& result, const FPred1& pred1, const FPred2& pred2)
{
location_set must_visit, filtered_out;
location_set not_visited(locs.begin(), locs.end());
for ( ; radius != 0 && !not_visited.empty(); --radius )
{
location_set::const_iterator it = not_visited.begin();
location_set::const_iterator it_end = not_visited.end();
result.insert(it, it_end);
for(; it != it_end; ++it) {
adjacent_loc_array_t adj;
get_adjacent_tiles(*it, adj.data());
for(size_t i = 0; i < adj.size(); ++i) {
const map_location& loc = adj[i];
if( pred1(loc) ) {
if( !result.count(loc) && !filtered_out.count(loc) ) {
if( pred2(loc) ) {
must_visit.insert(loc);
}
else {
filtered_out.insert(loc);
}
}
}
}
}
not_visited.swap(must_visit);
must_visit.clear();
}
result.insert(not_visited.begin(), not_visited.end());
}
} //end namespace } //end namespace