BitBully 0.0.59-a2
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, "BitBullyCore")
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
42 // Expose the Board class
43 // TODO: Check functions.... Many not necessary and some might be missing
44 py::class_<B>(m, "BoardCore")
45 .def(py::init<>()) // Default constructor
46 .def(py::init<const B&>()) // Copy-Konstruktor
47 .def("__str__", &B::toString) // Override __str__ in Python
48 .def("__repr__", &B::toString) // Override __repr__ in Python
49 .def("canWin", py::overload_cast<int>(&B::canWin, py::const_),
50 "Check, if current player can win by moving into column.",
51 py::arg("column"))
52 .def("copy", &B::copy, "Create a deep copy of the board.")
53 .def("canWin", py::overload_cast<>(&B::canWin, py::const_),
54 "Check, if current player can win with the next move.")
55 .def("hash", py::overload_cast<>(&B::hash, py::const_),
56 "Hash the current position and return hash value.")
57 .def("hasWin", &B::hasWin,
58 "Check, if the player who performed the last move has a winning "
59 "position (4 in a row).")
60 .def("play", py::overload_cast<int>(&B::play),
61 "Play a move by column index", py::arg("column"))
62 .def("play", py::overload_cast<const std::vector<int>&>(&B::play),
63 "Play a sequence of moves by column index", py::arg("moveSequence"))
64 .def("play", py::overload_cast<const std::string&>(&B::play),
65 "Play a sequence of moves by column index", py::arg("moveSequence"))
66 .def("playMoveOnCopy", &B::playMoveOnCopy,
67 "Play a move on a copy of the board and return the new board",
68 py::arg("mv"))
69 .def("legalMovesMask", &B::legalMovesMask, "Generate possible moves")
70 .def("generateNonLosingMoves", &B::generateNonLosingMoves,
71 "Generate non-losing moves")
72 .def("legalMoves", &B::legalMoves,
73 "Generate possible moves as a vector of column indices",
74 py::arg("nonLosing"), py::arg("orderMoves"))
75 .def("isLegalMove", &B::isLegalMove, "Check if a move is legal",
76 py::arg("column"))
77 .def("toString", &B::toString,
78 "Return a string representation of the board")
79 .def("movesLeft", &B::movesLeft, "Get the number of moves left")
80 .def("countTokens", &B::countTokens,
81 "Get the number of Tokens on the board")
82 .def("mirror", &B::mirror,
83 "Get the mirrored board (mirror around center column)")
84 .def("sortMoves", &B::sortMoves, "Sort moves based on priority",
85 py::arg("moves"))
86 .def("allPositions", &B::allPositions,
87 "Generate all positions that can be reached from the current board "
88 "with n tokens.",
89 py::arg("upToNPly"), py::arg("exactlyN"))
90 .def("findThreats", &B::findThreats, "Find threats on the board",
91 py::arg("moves"))
92 .def("doubleThreat", &B::doubleThreat, "Find double threats",
93 py::arg("moves"))
94 .def("toArray", &B::toArray,
95 "Convert the board to a 2D array representation")
96 .def("setBoard", py::overload_cast<const std::vector<int>&>(&B::setBoard),
97 "Set the board using a list", py::arg("moveSequence"))
98 .def("setBoard", py::overload_cast<const B::TBoardArray&>(&B::setBoard),
99 "Set the board using a 2D array", py::arg("array"))
100 .def("setBoard", py::overload_cast<const B::TBoardArrayT&>(&B::setBoard),
101 "Set the board using a 2D array", py::arg("array"))
102 .def("setBoard", py::overload_cast<const std::string&>(&B::setBoard),
103 "Play a sequence of moves by column index", py::arg("moveSequence"))
104 .def_static("isValid", &B::isValid, "Check, if a board is a valid one.",
105 py::arg("board"))
106 .def_static("randomBoard", &B::randomBoard,
107 "Create a random board with n tokens.", py::arg("nPly"),
108 py::arg("forbidDirectWin"))
109 .def("toHuffman", &B::toHuffman,
110 "Encode position into a huffman-code compressed sequence.")
111 .def("uid", &B::uid, "Get the unique identifier for the board")
112 .def("__eq__", &B::operator==, "Check if two boards are equal")
113 .def("__ne__", &B::operator!=, "Check if two boards are not equal");
114
115 // Expose OpeningBook:
116 py::class_<BitBully::OpeningBook>(m, "OpeningBookCore")
117 // Constructors
118 .def(py::init<const std::filesystem::path&, bool, bool>(),
119 py::arg("bookPath"), py::arg("is_8ply"), py::arg("with_distances"),
120 "Initialize an OpeningBook with explicit settings.")
121 .def(py::init<const std::filesystem::path&>(), py::arg("bookPath"),
122 "Initialize an OpeningBook by inferring database type from file "
123 "size.")
124
125 // Member functions
126 .def("init", &BitBully::OpeningBook::init, py::arg("bookPath"),
127 py::arg("is_8ply"), py::arg("with_distances"),
128 "Reinitialize the OpeningBook with new settings.")
129 .def("getEntry", &BitBully::OpeningBook::getEntry, py::arg("entryIdx"),
130 "Get an entry from the book by index.")
131 .def("getBook", &BitBully::OpeningBook::getBook,
132 "Return the raw book table.")
133 .def("getBookSize", &BitBully::OpeningBook::getBookSize,
134 "Get the size of the book.")
135 .def("getBoardValue", &BitBully::OpeningBook::getBoardValue,
136 py::arg("board"), "Get the value of a given board.")
137 .def("isInBook", &BitBully::OpeningBook::isInBook, py::arg("board"),
138 "Check, if the given board is in the opening book. Note, that "
139 "usually boards are only present in one mirrored variant.")
140 .def("convertValue", &BitBully::OpeningBook::convertValue,
141 py::arg("value"), py::arg("board"),
142 "Convert a value to the internal scoring system.")
143 .def("getNPly", &BitBully::OpeningBook::getNPly,
144 "Get the ply depth of the book.")
145
146 // Static functions
147 .def_static("readBook", &BitBully::OpeningBook::readBook,
148 py::arg("filename"), py::arg("with_distances") = true,
149 py::arg("is_8ply") = false, "Read a book from a file.");
150}