/* * Copyright 2026, Matthew-Gretton-Dann * SPDX-License-Identifier: Apache-2.0 */ #define PARTRIDGE_TESTING #include "../main.cc" #include #include #include #include #include #include namespace { using Clock = std::chrono::steady_clock; auto seconds(Clock::time_point begin, Clock::time_point end) -> double { return std::chrono::duration(end - begin).count(); } auto valid(std::uint64_t order, Results const &result) -> bool { auto const expected = triangle_num(order); if (result.length() != expected) { return false; } std::vector multiplicities(order + 1); std::vector occupied(expected * expected); for (auto const &square: result.squares()) { auto const side = square.length(); auto const x0 = square.pos() % expected; auto const y0 = square.pos() / expected; if (side == 0 || side > order || x0 + side > expected || y0 + side > expected) { return false; } ++multiplicities[side]; for (auto y = y0; y < y0 + side; ++y) { for (auto x = x0; x < x0 + side; ++x) { auto &&cell = occupied[x + y * expected]; if (cell) { return false; } cell = true; } } } for (std::uint64_t side = 1; side <= order; ++side) { if (multiplicities[side] != side) { return result.squares().empty() && order < 8; } } return std::ranges::find(occupied, false) == occupied.end(); } auto boolean(bool value) -> char const * { return value ? "true" : "false"; } } int main(int argc, char **argv) { if (argc != 3) { std::cerr << "usage: partridge_benchmark ORDER counters|plain\n"; return 2; } auto const order = static_cast(std::strtoull(argv[1], nullptr, 10)); auto const instrument = std::string_view(argv[2]) == "counters"; if (!instrument && std::string_view(argv[2]) != "plain") { std::cerr << "counter mode must be counters or plain\n"; return 2; } SearchCounters counters; auto const solve_begin = Clock::now(); auto result = instrument ? find_solution_instrumented(order, counters) : find_solution(order); auto const solve_end = Clock::now(); auto const validation_begin = Clock::now(); auto const validation_ok = valid(order, result); auto const validation_end = Clock::now(); auto const render_begin = Clock::now(); std::ostringstream rendered; auto *const old_buffer = std::cout.rdbuf(rendered.rdbuf()); result.output(); std::cout.rdbuf(old_buffer); auto const render_end = Clock::now(); std::cout.precision(17); std::cout << "{\"schema_version\":1" << ",\"order\":" << order << ",\"instrumented\":" << boolean(instrument) << ",\"solved\":" << boolean(!result.squares().empty()) << ",\"valid\":" << boolean(validation_ok) << ",\"timing_seconds\":{\"solve\":" << seconds(solve_begin, solve_end) << ",\"construction\":0" << ",\"validation\":" << seconds(validation_begin, validation_end) << ",\"render\":" << seconds(render_begin, render_end) << "}" << ",\"counters\":{\"search_nodes\":" << counters.search_nodes << ",\"loop_iterations\":" << counters.loop_iterations << ",\"attempted_placements\":" << counters.attempted_placements << ",\"backtracks\":" << counters.backtracks << ",\"prune_checks\":" << counters.prune_checks << ",\"prune_hits\":" << counters.prune_hits << ",\"generated_tasks\":" << counters.generated_tasks << ",\"completed_tasks\":" << counters.completed_tasks << "}}\n"; return validation_ok ? 0 : 1; }