BitBully 0.0.39
Loading...
Searching...
No Matches
bitbully_core.cpp
1#include <pybind11/pybind11.h>
2#include <pybind11/stl.h>
3#include <pybind11/stl/filesystem.h>
4
5#include <array>
6#include <filesystem>
7#include <vector>
8
9#include "BitBully.h"
10#include "Board.h"
11#include "OpeningBook.h"
12
13namespace py = pybind11;
14using B = BitBully::Board;
15
16PYBIND11_MODULE(bitbully_core, m) {
17 m.doc() =
18 "Bitbully is a fast Connect-4 solver."; // optional module docstring
19
20 py::class_<BitBully::BitBully>(m, "BitBully")
21 .def(py::init<>()) // Expose the default constructor
22 .def(py::init<std::filesystem::path>(), py::arg("openingBookPath"))
23 .def("mtdf", &BitBully::BitBully::mtdf, "MTD(f) algorithm",
24 py::arg("board"), py::arg("first_guess"))
25 .def("nullWindow", &BitBully::BitBully::nullWindow, "Null-window search",
26 py::arg("board"))
27 .def("negamax", &BitBully::BitBully::negamax, "negamax search",
28 py::arg("board"), py::arg("alpha"), py::arg("beta"),
29 py::arg("depth"))
30 .def("scoreMoves", &BitBully::BitBully::scoreMoves, "evaluate all moves",
31 py::arg("board"))
32 .def("resetTranspositionTable",
33 &BitBully::BitBully::resetTranspositionTable,
34 "Reset the transposition table")
35 .def("getNodeCounter", &BitBully::BitBully::getNodeCounter,
36 "Get the current node counter")
37 .def("resetNodeCounter", &BitBully::BitBully::resetNodeCounter,
38 "Reset the node counter")
39 .def("isBookLoaded", &BitBully::BitBully::isBookLoaded,
40 "Check, if opening book is loaded")
41 .def("isBookLoaded", &BitBully::BitBully::isBookLoaded,
42 "Check, if opening book is loaded");
43
44 // Expose the Board class
45 // TODO: Check functions.... Many not necessary and some might be missing
46 py::class_<B>(m, "Board")
47 .def(py::init<>()) // Default constructor
48 .def("__str__", &B::toString) // Override __str__ in Python
49 .def("__repr__", &B::toString) // Override __repr__ in Python
50 .def("playMoveFastBB", &B::playMoveFastBB,
51 "Play a move on the board (bitboard representation)", py::arg("mv"))
52 .def("canWin", py::overload_cast<int>(&B::canWin, py::const_),
53 "Check, if current player can win by moving into column.",
54 py::arg("column"))
55 .def("canWin", py::overload_cast<>(&B::canWin, py::const_),
56 "Check, if current player can win with the next move.")
57 .def("hash", py::overload_cast<>(&B::hash, py::const_),
58 "Hash the current position and return hash value.")
59 .def("hasWin", &B::hasWin,
60 "Check, if the player who performed the last move has a winning "
61 "position (4 in a row).")
62 .def("playMove", py::overload_cast<int>(&B::playMove),
63 "Play a move by column index", py::arg("column"))
64 .def("playMoveOnCopy", &B::playMoveOnCopy,
65 "Play a move on a copy of the board and return the new board",
66 py::arg("mv"))
67 .def("generateMoves", &B::generateMoves, "Generate possible moves")
68 .def("isLegalMove", &B::isLegalMove, "Check if a move is legal",
69 py::arg("column"))
70 .def("toString", &B::toString,
71 "Return a string representation of the board")
72 .def("movesLeft", &B::movesLeft, "Get the number of moves left")
73 .def("countTokens", &B::countTokens,
74 "Get the number of Tokens on the board")
75 .def("mirror", &B::mirror, "Get the mirrored board")
76 .def("sortMoves", &B::sortMoves, "Sort moves based on priority",
77 py::arg("moves"))
78 .def("allPositions", &B::allPositions,
79 "Generate all positions that can be reached from the current board "
80 "with n tokens.",
81 py::arg("upToNPly"), py::arg("exactlyN"))
82 .def("findThreats", &B::findThreats, "Find threats on the board",
83 py::arg("moves"))
84 .def("generateNonLosingMoves", &B::generateNonLosingMoves,
85 "Generate non-losing moves")
86 .def("doubleThreat", &B::doubleThreat, "Find double threats",
87 py::arg("moves"))
88 .def("toArray", &B::toArray,
89 "Convert the board to a 2D array representation")
90 .def("setBoard", py::overload_cast<const std::vector<int>&>(&B::setBoard),
91 "Set the board using a 2D array", py::arg("moveSequence"))
92 .def("setBoard", py::overload_cast<const B::TBoardArray&>(&B::setBoard),
93 "Set the board using a 2D array", py::arg("moveSequence"))
94 .def_static("isValid", &B::isValid, "Check, if a board is a valid one.",
95 py::arg("board"))
96 .def_static("randomBoard", &B::randomBoard,
97 "Create a random board with n tokens.", py::arg("nPly"),
98 py::arg("forbidDirectWin"))
99 .def("toHuffman", &B::toHuffman,
100 "Encode position into a huffman-code compressed sequence.")
101 .def("uid", &B::uid, "Get the unique identifier for the board")
102 .def("__eq__", &B::operator==, "Check if two boards are equal")
103 .def("__ne__", &B::operator!=, "Check if two boards are not equal");
104
105 // Expose OpeningBook:
106 py::class_<BitBully::OpeningBook>(m, "OpeningBook")
107 // Constructors
108 .def(py::init<const std::filesystem::path&, bool, bool>(),
109 py::arg("bookPath"), py::arg("is_8ply"), py::arg("with_distances"),
110 "Initialize an OpeningBook with explicit settings.")
111 .def(py::init<const std::filesystem::path&>(), py::arg("bookPath"),
112 "Initialize an OpeningBook by inferring database type from file "
113 "size.")
114
115 // Member functions
116 .def("init", &BitBully::OpeningBook::init, py::arg("bookPath"),
117 py::arg("is_8ply"), py::arg("with_distances"),
118 "Reinitialize the OpeningBook with new settings.")
119 .def("getEntry", &BitBully::OpeningBook::getEntry, py::arg("entryIdx"),
120 "Get an entry from the book by index.")
121 .def("getBook", &BitBully::OpeningBook::getBook,
122 "Return the raw book table.")
123 .def("getBookSize", &BitBully::OpeningBook::getBookSize,
124 "Get the size of the book.")
125 .def("getBoardValue", &BitBully::OpeningBook::getBoardValue,
126 py::arg("board"), "Get the value of a given board.")
127 .def("isInBook", &BitBully::OpeningBook::isInBook, py::arg("board"),
128 "Check, if the given board is in the opening book. Note, that "
129 "usually boards are only present in one mirrored variant.")
130 .def("convertValue", &BitBully::OpeningBook::convertValue,
131 py::arg("value"), py::arg("board"),
132 "Convert a value to the internal scoring system.")
133 .def("getNPly", &BitBully::OpeningBook::getNPly,
134 "Get the ply depth of the book.")
135
136 // Static functions
137 .def_static("readBook", &BitBully::OpeningBook::readBook,
138 py::arg("filename"), py::arg("with_distances") = true,
139 py::arg("is_8ply") = false, "Read a book from a file.");
140}