Code: Select all
#include <dctl.hpp>
using namespace dctl::core;
using namespace dctl::algo;
int main()
{
static_assert(
traversal::depth_limited_count<true>( // perft with bulk-counting
basic_state<
international,
basic_board<international>
>::initial(), // the starting position in International Draughts
7, // depth = 7
drop_duplicates_gen // no duplicate captures
) == 1'049'442
);
}
Code: Select all
rein@rein-virtual-machine:~/projects/dctl/build$ time example/constexpr
real 0m0,003s
user 0m0,000s
sys 0m0,003s

What makes this possible? Short answer: g++12 and a machine with at leat 38Gb of RAM and 15 minutes of compilation time. Long answer: a conforming C++20 compiler. In C++20, almost everything is constexpr: all the Standard Library algorithms and some of the containers such as std::string and std::vector. There are some caveats (e.g. you must use a compiletime std::vector within the constexpr computation).
In C++20, you can also use almost the full language at compile time. I simply sprinkled "constexpr" in front of every function and increased the default compiler limit of constexpr operations by 1000X from 1<<25 to 1<<35. Without this limit expansion, only perft(4) works out of the box. But that's it: my regular perft() function works at compile-time and the compiler can count over a million positions.
Why not the full perft(11)? I tried it, and g++ ran out of memory

Note to other authors: every draughts program can now achieve this, as long as you mark all your own functions constexpr and use a constexpr container to store your generated moves into (C-array, std::array, std::vector or a homegrown datastructure that is constexpr-ified). You might have troubles using other libraries (I had when I used Boost.StaticVector or Boost.SmallVector to store the generated moves).