stellarUCI Chess engine written in C++20 |
git clone git://git.dimitrijedobrota.com/stellar.git |
Log | Files | Refs | README | LICENSE | |
perft.cpp (4343B)
1 #include <iomanip> 2 #include <semaphore> 3 #include <thread> 4 5 #include "board.hpp" 6 #include "move.hpp" 7 #include "movelist.hpp" 8 #include "utils.hpp" 9 10 // FEN debug positions 11 #define tricky_position "r3k2r/p1ppqpb1/bn2pnp1/3PN3/1p2P3/2N2Q1p/PPPBBPPP/R3K2R w KQkq - 0 1 " 12 13 #define THREAD_MAX 64 14 15 class Perft { 16 public: 17 typedef std::counting_semaphore<THREAD_MAX> semaphore_t; 18 Perft(semaphore_t &sem) : sem(sem) {} 19 void operator()(const Board &board_start, Move move, int depth) { 20 Board board = board_start; 21 if (!move.make(board)) return; 22 sem.acquire(); 23 // debug(board_start, move, board); 24 25 if (depth > 1) { 26 test(board, depth - 1); 27 } else { 28 score(board, move); 29 } 30 31 mutex.acquire(); 32 result += local; 33 mutex.release(); 34 sem.release(); 35 } 36 37 struct result_t { 38 U64 node = 0; 39 #ifdef USE_FULL_COUNT 40 U64 check = 0; 41 U64 castle = 0; 42 U64 promote = 0; 43 U64 capture = 0; 44 U64 enpassant = 0; 45 #endif 46 result_t &operator+=(const result_t res) { 47 node += res.node; 48 #ifdef USE_FULL_COUNT 49 check += res.check; 50 castle += res.castle; 51 promote += res.promote; 52 capture += res.capture; 53 enpassant += res.enpassant; 54 #endif 55 return *this; 56 } 57 }; 58 59 static result_t result; 60 61 private: 62 void test(const Board &board, int depth) { 63 const MoveList list(board); 64 for (int i = 0; i < list.size(); i++) { 65 Board copy = board; 66 if (!list[i].make(copy)) continue; 67 // debug(board, list[i], copy); 68 if (depth != 1) 69 test(copy, depth - 1); 70 else 71 score(copy, list[i]); 72 } 73 } 74 75 void debug(const Board &before, Move move, const Board &after) { 76 std::cout << std::setw(16) << std::hex << before.get_hash() << " "; 77 std::cout << move << " "; 78 std::cout << std::setw(16) << std::hex << after.get_hash() << "\n"; 79 } 80 81 void score(const Board &board, Move move) { 82 local.node++; 83 #ifdef USE_FULL_COUNT 84 if (board.is_check()) local.check++; 85 if (move.is_capture()) local.capture++; 86 if (move.is_enpassant()) local.enpassant++; 87 if (move.is_castle()) local.castle++; 88 if (move.is_promote()) local.promote++; 89 #endif 90 } 91 result_t local; 92 semaphore_t &sem; 93 static std::binary_semaphore mutex; 94 }; 95 96 std::binary_semaphore Perft::mutex{1}; 97 Perft::result_t Perft::result; 98 99 void perft_test(const char *fen, int depth, int thread_num) { 100 const Board board = Board(fen); 101 const MoveList list = MoveList(board); 102 std::vector<std::thread> threads(list.size()); 103 104 Perft::semaphore_t sem(thread_num); 105 106 int index = 0; 107 for (int i = 0; i < list.size(); i++) 108 threads[index++] = std::thread(Perft(sem), board, list[i], depth); 109 110 for (auto &thread : threads) 111 thread.join(); 112 113 std::cout << std::dec; 114 std::cout << " Nodes: " << Perft::result.node << "\n"; 115 #ifdef USE_FULL_COUNT 116 std::cout << " Captures: " << Perft::result.capture << "\n"; 117 std::cout << "Enpassants: " << Perft::result.enpassant << "\n"; 118 std::cout << " Castles: " << Perft::result.castle << "\n"; 119 std::cout << "Promotions: " << Perft::result.promote << "\n"; 120 std::cout << " Checks: " << Perft::result.check << "\n"; 121 #endif 122 } 123 124 void usage(const char *program) { 125 std::cout << "Usage: " << program; 126 std::cout << " [-h]"; 127 std::cout << " [-t thread number]"; 128 std::cout << " [-d depth]"; 129 std::cout << " [-f fen]" << std::endl; 130 } 131 132 int main(int argc, char *argv[]) { 133 int c, depth = 1, thread_num = 1; 134 std::string s(start_position); 135 const char *fen = s.data(); 136 while ((c = getopt(argc, argv, "ht:f:d:")) != -1) { 137 switch (c) { 138 case 't': 139 thread_num = atoi(optarg); 140 if (thread_num <= 0 && thread_num > THREAD_MAX) abort(); 141 break; 142 case 'f': fen = optarg; break; 143 case 'd': 144 depth = atoi(optarg); 145 if (depth <= 0) abort(); 146 break; 147 case 'h': usage(argv[0]); return 1; 148 default: usage(argv[0]); abort(); 149 } 150 } 151 152 perft_test(fen, depth, thread_num); 153 return 0; 154 }