#include "coord/comparator.hpp" #include "coord/iostream.hpp" #include "geom/sample/edge.hpp" #include "rand/generic.hpp" #include "tap.hpp" #include int main () { static constexpr int ITERATIONS = 1'000'000; static const cruft::extent2i AREA { 3, 7 }; std::map> counts; auto sampler = cruft::geom::sample::edge (AREA); cruft::rand::general_generator gen (42); cruft::TAP::logger tap; for (int i = 0; i < ITERATIONS; ++i) { auto const pos = sampler.eval (gen); bool const x_perim = pos.x == 0 || pos.x == AREA.w; bool const y_perim = pos.y == 0 || pos.y == AREA.h; if (!x_perim && !y_perim) { tap.fail ("position {} falls outside perimeter: {}", i, pos); return tap.status (); } auto const [val, success] = counts.try_emplace (pos, 0); val->second++; } auto const expected_count = 2 * (AREA[0] + 1) + 2 * (AREA[1] - 1); tap.expect_eq ( counts.size (), std::size_t (expected_count), "all perimeter options are covered" ); auto const [lo,hi] = std::minmax_element ( std::begin (counts), std::end (counts), [] (auto const &a, auto const &b) { return a.second < b.second; }); auto const abs_diff = hi->second - lo->second; auto const rel_diff = float (abs_diff) / lo->second; tap.expect_lt ( std::abs (rel_diff), 0.05f, "occurence counts are evenly spaced: {}:{} vs {}:{}", hi->first, hi->second, lo->first, lo->second ); return tap.status (); }