Skip to content

Commit

Permalink
refactor terrain_filter::get_locations
Browse files Browse the repository at this point in the history
previously the code needed 2^number_of_base_attributes (where base
attributes are those attributes that specify the starting location set
for the search) if-cases which made it quet hard to add new base
attributes.
  • Loading branch information
gfgtdf committed Jun 18, 2016
1 parent 514821f commit 9d975c8
Show file tree
Hide file tree
Showing 2 changed files with 65 additions and 145 deletions.
209 changes: 64 additions & 145 deletions src/terrain/filter.cpp
Expand Up @@ -33,6 +33,8 @@
#include "formula/callable_objects.hpp"
#include "formula/formula.hpp"

#include <boost\range\adaptor\transformed.hpp>

static lg::log_domain log_engine("engine");
#define ERR_NG LOG_STREAM(err, log_engine)
#define WRN_NG LOG_STREAM(warn, log_engine)
Expand Down Expand Up @@ -420,171 +422,88 @@ bool terrain_filter::match(const map_location& loc) const
}
return false;
}

void terrain_filter::get_locations(std::set<map_location>& locs, bool with_border) const
//using a class to be able to firen it in terrain_filter
class terrain_filterimpl
{
std::set<map_location> match_set;

// See if the caller provided an override to with_border
with_border = cfg_["include_borders"].to_bool(with_border);

// None of the generators provided
if ( !cfg_.has_attribute("x") && !cfg_.has_attribute("y")
&& !cfg_.has_attribute("find_in")
&& !cfg_.has_attribute("area") ) {
public:
using location_set = std::set<map_location>;
struct tno_start_set_yet {};
struct tno_filter
{
bool operator()(const map_location&) const { return true; }
};

//consider all locations on the map
int bs = fc_->get_disp_context().map().border_size();
int w = with_border ? fc_->get_disp_context().map().w() + bs : fc_->get_disp_context().map().w();
int h = with_border ? fc_->get_disp_context().map().h() + bs : fc_->get_disp_context().map().h();
for (int x = with_border ? 0 - bs : 0; x < w; ++x) {
for (int y = with_border ? 0 - bs : 0; y < h; ++y) {
match_set.insert(map_location(x,y));
template<typename T, typename F1, typename F2>
static void filter_final(T&& src, location_set& dest, const terrain_filter&, const F1& f1, const F2& f2)
{
for (const map_location &loc : src) {
if (f1(loc) && f2(loc)) {
dest.insert(loc);
}
}
} else

// Only the x,y attributes found
if ( (cfg_.has_attribute("x") || cfg_.has_attribute("y"))
&& !cfg_.has_attribute("find_in")
&& !cfg_.has_attribute("area") ) {

std::vector<map_location> xy_vector;
xy_vector = fc_->get_disp_context().map().parse_location_range(cfg_["x"], cfg_["y"], with_border);
match_set.insert(xy_vector.begin(), xy_vector.end());
} else

// Only find_in provided
if ( !cfg_.has_attribute("x") && !cfg_.has_attribute("y")
&& cfg_.has_attribute("find_in")
&& !cfg_.has_attribute("area") ) {
}

//use content of find_in as starting set
if (const game_data * gd = fc_->get_game_data()) {
try
{
variable_access_const vi = gd->get_variable_access_read(cfg_["find_in"]);
for (const config& cfg : vi.as_array())
{
map_location test_loc(cfg, nullptr);
match_set.insert(test_loc);
}
}
catch(const invalid_variablename_exception&)
{
//Do nothing
}
template<typename T, typename F1>
static void filter_area(T&& src, location_set& dest, const terrain_filter& filter, const F1& f1)
{
if (filter.cfg_.has_attribute("area")) {
const std::set<map_location>& area = filter.fc_->get_tod_man().get_area_by_id(filter.cfg_["area"]);
filter_final(src, dest, filter, f1, [&area](const map_location& loc) { return area.find(loc) != area.end(); });
}
} else

// Only area provided
if ( !cfg_.has_attribute("x") && !cfg_.has_attribute("y")
&& !cfg_.has_attribute("find_in")
&& cfg_.has_attribute("area") ) {

const std::set<map_location>& area = fc_->get_tod_man().get_area_by_id(cfg_["area"]);
match_set.insert(area.begin(), area.end());
} else

// find_in + xy
if ( (cfg_.has_attribute("x") || cfg_.has_attribute("y"))
&& cfg_.has_attribute("find_in")
&& !cfg_.has_attribute("area") ) {

std::vector<map_location> xy_vector;
xy_vector = fc_->get_disp_context().map().parse_location_range(cfg_["x"], cfg_["y"], with_border);
match_set.insert(xy_vector.begin(), xy_vector.end());

// remove any locations not found in the specified variable
if (const game_data * gd = fc_->get_game_data()) {
try
{
std::set<map_location> findin_locs;
variable_access_const vi = gd->get_variable_access_read(cfg_["find_in"]);
for (const config& cfg : vi.as_array())
{
map_location test_loc(cfg, nullptr);
if (match_set.count(test_loc)) {
findin_locs.insert(test_loc);
}
}
match_set.swap(findin_locs);
}
catch(const invalid_variablename_exception&)
{
match_set.clear();
}
else {
filter_final(src, dest, filter, f1, tno_filter());
}
} else

// xy + area
if ( (cfg_.has_attribute("x") || cfg_.has_attribute("y"))
&& !cfg_.has_attribute("find_in")
&& cfg_.has_attribute("area") ) {

std::vector<map_location> xy_vector;
xy_vector = fc_->get_disp_context().map().parse_location_range(cfg_["x"], cfg_["y"], with_border);
const std::set<map_location>& area = fc_->get_tod_man().get_area_by_id(cfg_["area"]);
}

for (const map_location& loc : xy_vector) {
if (area.count(loc) != 0)
match_set.insert(loc);
template<typename T>
static void filter_xy(T&& src, location_set& dest, const terrain_filter& filter, bool with_border)
{
if (filter.cfg_.has_attribute("x") || filter.cfg_.has_attribute("y")) {
std::vector<map_location> xy_vector = filter.fc_->get_disp_context().map().parse_location_range(filter.cfg_["x"], filter.cfg_["y"], with_border);
filter_area(src, dest, filter, [&xy_vector](const map_location& loc) { return std::find(xy_vector.begin(), xy_vector.end(), loc) != xy_vector.end(); });
}
} else

// area + find_in
if ( !(cfg_.has_attribute("x") && cfg_.has_attribute("y"))
&& cfg_.has_attribute("find_in")
&& cfg_.has_attribute("area") ) {
else {
filter_area(src, dest, filter, tno_filter());
}
}
};
void terrain_filter::get_locations(std::set<map_location>& locs, bool with_border) const
{
std::set<map_location> match_set;

const std::set<map_location>& area = fc_->get_tod_man().get_area_by_id(cfg_["area"]);
// See if the caller provided an override to with_border
with_border = cfg_["include_borders"].to_bool(with_border);

//use content of find_in as starting set
if (cfg_.has_attribute("find_in")) {

if (const game_data * gd = fc_->get_game_data()) {
try
{
variable_access_const vi = gd->get_variable_access_read(cfg_["find_in"]);
for (const config& cfg : vi.as_array())
{
map_location test_loc(cfg, nullptr);
if (area.count(test_loc) != 0)
match_set.insert(test_loc);
}
auto ar = gd->get_variable_access_read(cfg_["find_in"]).as_array();
terrain_filterimpl::filter_xy(ar | boost::adaptors::transformed([](const config& cfg) { return map_location(cfg, nullptr);}), match_set, *this, with_border);
}
catch(const invalid_variablename_exception&)
catch (const invalid_variablename_exception&)
{
match_set.clear();
//Do nothing
}
}
} else

// area + find_in + xy
if ( (cfg_.has_attribute("x") && cfg_.has_attribute("y"))
&& cfg_.has_attribute("find_in")
&& cfg_.has_attribute("area") ) {

const std::vector<map_location>& xy_vector =
fc_->get_disp_context().map().parse_location_range(cfg_["x"], cfg_["y"], with_border);
std::set<map_location> xy_set(xy_vector.begin(), xy_vector.end());

}
else if (cfg_.has_attribute("x") || cfg_.has_attribute("y")) {
std::vector<map_location> xy_vector = fc_->get_disp_context().map().parse_location_range(cfg_["x"], cfg_["y"], with_border);
terrain_filterimpl::filter_area(xy_vector, match_set, *this, terrain_filterimpl::tno_filter());
}
else if (cfg_.has_attribute("area")) {
const std::set<map_location>& area = fc_->get_tod_man().get_area_by_id(cfg_["area"]);

//use content of find_in as starting set
if (const game_data * gd = fc_->get_game_data()) {
try
{
variable_access_const vi = gd->get_variable_access_read(cfg_["find_in"]);

for (const config &cfg : vi.as_array()) {
map_location test_loc(cfg, nullptr);
if (area.count(test_loc) != 0 && xy_set.count(test_loc) != 0)
match_set.insert(test_loc);
}
}
catch(const invalid_variablename_exception&)
{
//Do nothing
terrain_filterimpl::filter_final(area, match_set, *this, terrain_filterimpl::tno_filter(), terrain_filterimpl::tno_filter());
}
else {
//consider all locations on the map
int bs = fc_->get_disp_context().map().border_size();
int w = with_border ? fc_->get_disp_context().map().w() + bs : fc_->get_disp_context().map().w();
int h = with_border ? fc_->get_disp_context().map().h() + bs : fc_->get_disp_context().map().h();
for (int x = with_border ? 0 - bs : 0; x < w; ++x) {
for (int y = with_border ? 0 - bs : 0; y < h; ++y) {
match_set.insert(map_location(x, y));
}
}
}
Expand Down
1 change: 1 addition & 0 deletions src/terrain/filter.hpp
Expand Up @@ -66,6 +66,7 @@ class terrain_filter : public xy_pred {
void flatten(const bool flat_tod=true) { flat_ = flat_tod; }

config to_config() const;
friend class terrain_filterimpl;
private:
bool match_internal(const map_location& loc, const bool ignore_xy) const;

Expand Down

0 comments on commit 9d975c8

Please sign in to comment.