1
Fork 0
This repository has been archived on 2025-04-09. You can view files and clone it, but cannot push or open issues or pull requests.
puzzle-wuzzle-generator/include/clusters.hpp
2014-03-04 15:32:21 +01:00

60 lines
1.7 KiB
C++

#pragma once
#include <boost/container/flat_set.hpp>
#include <vector>
// 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, typename Rules>
void cluster_expand(Field const & field, Rules const & rules, typename Field::Position const & p, boost::container::flat_set<typename Field::Position>& 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 <typename Field, typename Rules>
auto cluster_at(Field const & field, Rules const & rules, 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, rules, p, ret);
return ret;
}
template <typename Grid, typename Rules>
auto all_clusters(Grid const & grid, Rules const & rules){
std::vector<decltype(cluster_at(grid, rules, std::declval<typename Grid::Position>()))> 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;
}