24#include <thirdParty/connect4/Solver.hpp>
26#include <unordered_map>
40using Clock = std::chrono::steady_clock;
42using Clock = std::chrono::high_resolution_clock;
54void writeToCSV(
const std::vector<std::tuple<float, float>>& data,
55 const std::string& filename) {
56 std::ofstream file(filename);
57 if (!file.is_open()) {
58 std::cerr <<
"Error: Unable to open file " << filename << std::endl;
63 file <<
"Bitbully,Pons-C4\n";
66 for (
const auto& [val1, val2] : data) {
67 file << std::fixed << std::setprecision(5)
68 << val1 <<
"," << val2 <<
"\n";
72 std::cout <<
"Data successfully written to " << filename << std::endl;
84std::unordered_map<std::string, std::string>
parseArgs(
85 const int argc,
const char*
const argv[]) {
86 std::unordered_map<std::string, std::string> args;
88 for (
int i = 1; i < argc; i += 2) {
90 args[argv[i]] = argv[i + 1];
92 std::cerr <<
"Error: Missing value for argument " << argv[i] << std::endl;
108int main(
const int argc,
const char*
const argv[]) {
112 std::string filename;
117 if (args.find(
"--nply") != args.end()) nPly = std::stoi(args[
"--nply"]);
118 if (args.find(
"--nrepeats") != args.end())
119 nRepeats = std::stoi(args[
"--nrepeats"]);
120 if (args.find(
"--filename") != args.end())
121 filename = args[
"--filename"];
123 filename =
"../times_" + std::to_string(nPly) +
"_ply_" +
124 std::to_string(nRepeats) +
"_pos.csv";
125 if (args.find(
"--reset_tt") !=
127 reset_tt = std::stoi(args[
"--reset_tt"]);
129 std::vector<std::tuple<float, float>> times = {};
131 using duration = std::chrono::duration<float>;
136 for (
auto i = 0; i < nRepeats; i++) {
139 if (reset_tt > 0 && i % reset_tt == 0) {
140 solverPonsC4.reset();
145 auto tStart = Clock::now();
146 const int scoreBitbully = bb.
mtdf(b, 0);
147 auto tEnd = Clock::now();
148 auto timeBitbully =
static_cast<float>(duration(tEnd - tStart).count());
154 std::accumulate(mvSequence.begin(), mvSequence.end(), std::string(
""),
155 [](
const std::string& a,
const int mv) {
156 return a + std::to_string(mv + 1);
158 if (P.
play(mvSequenceStr) != b.countTokens()) {
159 std::cerr <<
"Error: (P.play(mvSequenceStr) != b.countTokens())";
162 tStart = Clock::now();
163 const int scorePonsC4 = solverPonsC4.solve(P,
false);
165 auto timePonsC4 =
static_cast<float>(duration(tEnd - tStart).count());
166 times.emplace_back(timeBitbully, timePonsC4);
168 if (scorePonsC4 != scoreBitbully) {
169 std::cerr <<
"Error: " << b.toString() <<
"Pons-C4: " << scorePonsC4
170 <<
" BitBully: " << scoreBitbully << std::endl;
174 if (i % (std::max(nRepeats, 100) / 100) == 0) {
175 std::cout <<
"Done with " << i <<
" iterations" << std::endl;
180 std::cout <<
"Node Count Pons-C4: " << solverPonsC4.getNodeCount() <<
", "
183 solverPonsC4.getNodeCount()) /
185 <<
" %" << std::endl;
Connect-4 search engine that operates on BitBully::Board.
Bitboard-based representation of a Connect-4 position.
Perfect-play Connect-4 solver.
int mtdf(const Board &b, const int firstGuess, const int maxDepth=-1) noexcept
Solve a position using the MTD(f) driver.
void resetTranspositionTable()
Discard the contents of the transposition table.
auto getNodeCounter() const
Number of nodes visited since resetNodeCounter().
static std::pair< Board, std::vector< int > > randomBoard(const int nPly, const bool forbidDirectWin=true)
Generate a random reachable position with a fixed number of plies.
A class storing a Connect 4 position.
void play(position_t move)
Plays a possible move given by its bitmap representation.
void writeToCSV(const std::vector< std::tuple< float, float > > &data, const std::string &filename)
Persist per-position timing pairs to a CSV file.
std::unordered_map< std::string, std::string > parseArgs(const int argc, const char *const argv[])
Parse --key value pairs from the program command line.
std::chrono::high_resolution_clock Clock
Wall-clock used for the per-call timing measurements.
int main(const int argc, const char *const argv[])
Entry point of the benchmark binary.