#pragma once #include #include #include // Using boost flat set was faster than std::set. template auto make_empty(Field field, Cluster const & c){ for(auto&& p : c){ field.get(p) = 0; } field.collapse(); return field; } namespace detail { template void cluster_expand(Field const & field, Rules const & rules, typename Field::Position const & p, boost::container::flat_set& ret){ for(auto&& q : field.neighbors(p)){ if(!rules.same_cluster(field.get(p), field.get(q))) continue; if(ret.insert(q).second){ cluster_expand(field, rules, q, ret); } } } } template auto cluster_at(Field const & field, Rules const & rules, typename Field::Position const & p){ boost::container::flat_set ret; ret.reserve(10); // speed improvement of 20% ret.insert(p); detail::cluster_expand(field, rules, p, ret); return ret; } template auto all_clusters(Grid const & grid, Rules const & rules){ std::vector()))> ret; ret.reserve(10); auto partition = make_empty(grid, grid.all_positions()); auto current_p = 1; for(auto&& p : partition.all_positions()){ // ignore if it already belongs to a cluster or is empty if(!partition.empty(p) || grid.empty(p)) continue; auto cluster = cluster_at(grid, rules, p); for(auto&& q : cluster){ partition.get(q) = current_p; } current_p++; if(cluster.size() >= rules.min_cluster_size()) ret.push_back(std::move(cluster)); } return ret; }