#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 auto same_group(Field const & field, typename Field::Position const & p, typename Field::Position const & q){ return field.get(p) == field.get(q); } template void cluster_expand(Field const & field, typename Field::Position const & p, boost::container::flat_set& 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 auto cluster_at(Field const & field, typename Field::Position const & p){ boost::container::flat_set ret; ret.reserve(10); // speed improvement of 20% ret.insert(p); detail::cluster_expand(field, 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()){ if(!partition.empty(p) || grid.empty(p)) continue; auto cluster = cluster_at(grid, 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; }