58 lines
1.5 KiB
C++
58 lines
1.5 KiB
C++
#pragma once
|
|
|
|
#include <boost/container/flat_set.hpp>
|
|
#include <cassert>
|
|
|
|
// Using boost flat set was faster than std::set.
|
|
|
|
template <typename Field, typename Cluster>
|
|
auto make_empty(Field field, Cluster const & c){
|
|
for(auto&& p : c){
|
|
field.get(p) = 0;
|
|
}
|
|
field.collapse();
|
|
return field;
|
|
}
|
|
|
|
namespace detail {
|
|
template <typename Field>
|
|
auto same_group(Field const & field, typename Field::Position const & p, typename Field::Position const & q){
|
|
return field.get(p) == field.get(q);
|
|
}
|
|
|
|
template <typename Field>
|
|
void cluster_expand(Field const & field, typename Field::Position const & p, boost::container::flat_set<typename Field::Position>& ret){
|
|
for(auto&& q : field.neighbors(p)){
|
|
if(!same_group(field, p, q)) continue;
|
|
|
|
if(ret.insert(q).second){
|
|
cluster_expand(field, q, ret);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
template <typename Field>
|
|
auto cluster_at(Field const & field, typename Field::Position const & p){
|
|
boost::container::flat_set<typename Field::Position> ret;
|
|
ret.reserve(10); // speed improvement of 20%
|
|
ret.insert(p);
|
|
detail::cluster_expand(field, p, ret);
|
|
return ret;
|
|
}
|
|
|
|
|
|
template <typename Field, typename Rules>
|
|
auto all_clusters(Field const & field, Rules const & rules){
|
|
boost::container::flat_set<decltype(cluster_at(field, std::declval<typename Field::Position>()))> ret;
|
|
ret.reserve(10);
|
|
for(auto&& p : field.all_positions()){
|
|
if(field.empty(p)) continue;
|
|
ret.insert(cluster_at(field, p));
|
|
}
|
|
for(auto it = ret.begin(); it != ret.end();){
|
|
if (it->size() < rules.min_cluster_size()) it = ret.erase(it);
|
|
else ++it;
|
|
}
|
|
return ret;
|
|
}
|