├── .gitignore ├── .vscode └── settings.json ├── README.md ├── bitboard.cpp ├── bitboard.hpp ├── board.cpp ├── board.hpp ├── chess.exe ├── defs.cpp ├── defs.hpp ├── evaluation.cpp ├── evaluation.hpp ├── main.cpp ├── makefile ├── move.cpp ├── move.hpp ├── movegen.cpp ├── movegen.hpp ├── output.bin ├── performance.bin ├── perft.cpp ├── perft.hpp ├── polyglot.cpp ├── polyglot.hpp ├── search.cpp ├── search.hpp ├── transpositionTable.cpp ├── transpositionTable.hpp ├── uci.cpp ├── uci.hpp ├── utils.cpp ├── utils.hpp └── zobristKeys.hpp /.gitignore: -------------------------------------------------------------------------------- 1 | # Compiled Object files 2 | *.o 3 | -------------------------------------------------------------------------------- /.vscode/settings.json: -------------------------------------------------------------------------------- 1 | { 2 | "files.associations": { 3 | "functional": "cpp", 4 | "memory": "cpp", 5 | "sstream": "cpp", 6 | "array": "cpp", 7 | "atomic": "cpp", 8 | "*.tcc": "cpp", 9 | "cctype": "cpp", 10 | "clocale": "cpp", 11 | "cmath": "cpp", 12 | "cstdarg": "cpp", 13 | "cstddef": "cpp", 14 | "cstdint": "cpp", 15 | "cstdio": "cpp", 16 | "cstdlib": "cpp", 17 | "ctime": "cpp", 18 | "cwchar": "cpp", 19 | "cwctype": "cpp", 20 | "deque": "cpp", 21 | "unordered_map": "cpp", 22 | "vector": "cpp", 23 | "exception": "cpp", 24 | "algorithm": "cpp", 25 | "iterator": "cpp", 26 | "memory_resource": "cpp", 27 | "numeric": "cpp", 28 | "random": "cpp", 29 | "string": "cpp", 30 | "system_error": "cpp", 31 | "tuple": "cpp", 32 | "type_traits": "cpp", 33 | "utility": "cpp", 34 | "fstream": "cpp", 35 | "initializer_list": "cpp", 36 | "iomanip": "cpp", 37 | "iosfwd": "cpp", 38 | "iostream": "cpp", 39 | "istream": "cpp", 40 | "limits": "cpp", 41 | "new": "cpp", 42 | "ostream": "cpp", 43 | "stdexcept": "cpp", 44 | "streambuf": "cpp", 45 | "typeinfo": "cpp", 46 | "chrono": "cpp", 47 | "ratio": "cpp", 48 | "bit": "cpp", 49 | "charconv": "cpp", 50 | "compare": "cpp", 51 | "concepts": "cpp", 52 | "optional": "cpp", 53 | "string_view": "cpp", 54 | "format": "cpp", 55 | "numbers": "cpp", 56 | "span": "cpp", 57 | "variant": "cpp", 58 | "semaphore": "cpp", 59 | "stop_token": "cpp", 60 | "thread": "cpp", 61 | "cstring": "cpp" 62 | } 63 | } -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # chess-engine-cpp 2 | chess engine 3 | -------------------------------------------------------------------------------- /bitboard.cpp: -------------------------------------------------------------------------------- 1 | #include "defs.hpp" 2 | #include "bitboard.hpp" 3 | #include 4 | #include 5 | #include 6 | 7 | U64 randomU64() 8 | { 9 | static std::random_device rd; // Seed 10 | static std::mt19937_64 gen(rd()); // Mersenne Twister engine 11 | static std::uniform_int_distribution dis(0, UINT64_MAX); // Uniform distribution 12 | 13 | return dis(gen); 14 | } 15 | U64 random_64_fewbits() 16 | { 17 | return randomU64() & randomU64() & randomU64(); 18 | } 19 | 20 | // ========================================================== 21 | // ======================= constructor ====================== 22 | // ========================================================== 23 | 24 | U64 Bitboard::rookLookupTable[64][4096] = {}; 25 | U64 Bitboard::bishopLookupTable[64][4096] = {}; 26 | U64 Bitboard::fileMasks[8] = {0ULL}; 27 | U64 Bitboard::rankMasks[8] = {0ULL}; 28 | U64 Bitboard::isolatedPawnMask[64] = {0ULL}; 29 | U64 Bitboard::passedPawnMask[2][64] = {0ULL}; 30 | std::vector Bitboard::rookBlockers[64]; 31 | std::vector Bitboard::bishopBlockers[64]; 32 | 33 | // ========================================================== 34 | // ======================= constructor ====================== 35 | // ========================================================== 36 | 37 | Bitboard *bitboard = new Bitboard; 38 | 39 | Bitboard::Bitboard() 40 | { 41 | for (int i = 0; i < 13; ++i) 42 | { 43 | pieces[i] = 0ULL; 44 | } 45 | // init defs 46 | initialize(); 47 | 48 | initMasks(); 49 | init_attackMasks(); 50 | 51 | generateBlockersFor(rookAttacks, rookBlockers); 52 | generateBlockersFor(bishopAttacks, bishopBlockers); 53 | } 54 | 55 | // ========================================================== 56 | // ===================== helper functions =================== 57 | // ========================================================== 58 | 59 | void Bitboard::clearBit(int piece, int sq) 60 | { 61 | pieces[piece] &= ~(1ULL << sq); 62 | } 63 | void Bitboard::setBit(U64 &bitBoard, int sq) 64 | { 65 | bitBoard |= (1ULL << sq); 66 | } 67 | void Bitboard::setBit(int piece, int sq) 68 | { 69 | pieces[piece] |= (1ULL << sq); 70 | } 71 | int Bitboard::getPieceCount(int piece) 72 | { 73 | return __builtin_popcountll(pieces[piece]); 74 | } 75 | void Bitboard::movePiece(int piece, int fromSq, int toSq) 76 | { 77 | if (!(pieces[piece] & (1ULL << fromSq))) 78 | return; 79 | clearBit(piece, fromSq); 80 | setBit(piece, toSq); 81 | } 82 | 83 | void Bitboard::print(int piece) 84 | { 85 | U64 bitBoard = pieces[piece]; 86 | printf("bitMask for piece \033[32m%s\033[0m\n", pieceName[piece]); 87 | std::cout << "0x" << std::hex << bitboard << std::dec << std::endl; 88 | for (int rank = rank8; rank >= rank1; --rank) 89 | { 90 | std::cout << rank + 1 << " "; 91 | for (int file = fileA; file <= fileH; ++file) 92 | { 93 | int sq = rank * 8 + file; 94 | std::cout << ((bitBoard & (1ULL << sq)) ? "\033[32m1\033[0m" : "\033[90m.\033[0m") << " "; 95 | } 96 | std::cout << std::endl; 97 | } 98 | std::cout<<" "; 99 | for (char file = 'a'; file <= 'h'; ++file) 100 | { 101 | std::cout << file << " "; 102 | } 103 | std::cout << std::endl 104 | << std::endl; 105 | } 106 | void Bitboard::print(U64 bitBoard) 107 | { 108 | std::cout << "0x" << std::hex << bitBoard << std::dec << std::endl; 109 | for (int rank = rank8; rank >= rank1; --rank) 110 | { 111 | std::cout << rank + 1 << " "; 112 | for (int file = fileA; file <= fileH; ++file) 113 | { 114 | int sq = rank * 8 + file; 115 | std::cout << ((bitBoard & (1ULL << sq)) ? "\033[32m1\033[0m" : "\033[90m.\033[0m") << " "; 116 | } 117 | std::cout << std::endl; 118 | } 119 | std::cout<<" "; 120 | for (char file = 'a'; file <= 'h'; ++file) 121 | { 122 | std::cout << file << " "; 123 | } 124 | std::cout << std::endl 125 | << std::endl; 126 | } 127 | 128 | // ex key = (blokerBitboard * rookmagic[sq]) >> rookShifts[sq]; 129 | // call this function for each different 64 squares 130 | /** 131 | * @param sq square for which you want to get magic number. 132 | * @param blockerBitboards all the possible blockerBitboards of 'sq' you are giving. 133 | * @param ortho true for rook : false for bishop 134 | * @return magic number if found 135 | */ 136 | U64 Bitboard::findMagic(int sq, const std::vector &blockerBitboards, bool ortho) 137 | { 138 | std::vector attacksBitboards(blockerBitboards.size()); 139 | U64 used[4096]; 140 | U64 attackMask = ortho ? rookAttacks[sq] : bishopAttacks[sq]; 141 | bool fail = false; 142 | 143 | // Generate attack bitboards for each blocker 144 | for (size_t i = 0; i < blockerBitboards.size(); ++i) 145 | { 146 | attacksBitboards[i] = legalMoveBitboardFromBlockers(sq, blockerBitboards[i], ortho); 147 | } 148 | 149 | // Try finding a suitable magic number 150 | for (int i = 0; i < 100000000; ++i) 151 | { 152 | U64 magic = random_64_fewbits(); 153 | if (__builtin_popcountll((attackMask * magic) & 0xFF00000000000000ULL) < 6) 154 | { 155 | continue; 156 | } 157 | 158 | // Clear used array 159 | for (int i = 0; i < 4096; ++i) 160 | { 161 | used[i] = 0; 162 | } 163 | fail = false; 164 | 165 | for (size_t j = 0; j < blockerBitboards.size(); ++j) 166 | { 167 | int index = (blockerBitboards[j] * magic) >> (64 - 12); // Adjust shift for your table size 168 | if (used[index] == 0) 169 | { 170 | used[index] = attacksBitboards[j]; 171 | } 172 | else if (used[index] != attacksBitboards[j]) 173 | { 174 | fail = true; 175 | break; 176 | } 177 | } 178 | 179 | if (!fail) 180 | { 181 | return magic; 182 | } 183 | } 184 | 185 | // If no suitable magic number found, return 0 186 | return 0; 187 | } 188 | 189 | U64 Bitboard::getPieces(int side) 190 | { 191 | if (side == white) 192 | { 193 | return pieces[wp] | pieces[wr] | pieces[wn] | pieces[wb] | pieces[wq] | pieces[wk]; 194 | } 195 | if (side == black) 196 | { 197 | return pieces[bp] | pieces[br] | pieces[bn] | pieces[bb] | pieces[bq] | pieces[bk]; 198 | } 199 | 200 | return pieces[wp] | pieces[wr] | pieces[wn] | pieces[wb] | pieces[wq] | pieces[wk] | 201 | pieces[bp] | pieces[br] | pieces[bn] | pieces[bb] | pieces[bq] | pieces[bk]; 202 | } 203 | 204 | // ========================================================== 205 | // ============ function to initialize the makes ============ 206 | // ========================================================== 207 | 208 | void Bitboard::initMasks() 209 | { 210 | init_fileMasks(); 211 | init_rankMasks(); 212 | init_isolatedPawnMask(); 213 | init_passedPawnMask(); 214 | } 215 | 216 | void Bitboard::init_fileMasks() 217 | { 218 | for (int file = fileA; file <= fileH; ++file) 219 | { 220 | for (int rank = rank1; rank <= rank8; ++rank) 221 | { 222 | fileMasks[file] |= (1ULL << file) << (8 * rank); 223 | } 224 | } 225 | } 226 | 227 | void Bitboard::init_rankMasks() 228 | { 229 | for (int rank = rank1; rank <= rank8; ++rank) 230 | { 231 | rankMasks[rank] |= 255ULL << (rank * 8); 232 | } 233 | } 234 | void Bitboard::init_isolatedPawnMask() 235 | { 236 | for (int sq = 0; sq < 64; sq++) 237 | { 238 | int file = fileOf(sq64To120[sq]); 239 | if (file > fileA) 240 | { 241 | isolatedPawnMask[sq] |= fileMasks[file - 1]; 242 | } 243 | if (file < fileH) 244 | { 245 | isolatedPawnMask[sq] |= fileMasks[file + 1]; 246 | } 247 | } 248 | } 249 | 250 | void Bitboard::init_passedPawnMask() 251 | { 252 | for (int i = 0; i < 2; ++i) 253 | { 254 | 255 | for (int sq = 0; sq < 64; sq++) 256 | { 257 | int file = fileOf(sq64To120[sq]); 258 | int rank = rankOf(sq64To120[sq]); 259 | 260 | if (file > fileA) 261 | { 262 | passedPawnMask[i][sq] |= fileMasks[file - 1]; 263 | } 264 | if (file < fileH) 265 | { 266 | passedPawnMask[i][sq] |= fileMasks[file + 1]; 267 | } 268 | if (i == white) 269 | { 270 | while (rank >= rank1) 271 | { 272 | passedPawnMask[i][sq] &= ~rankMasks[rank--]; 273 | } 274 | } 275 | else 276 | { 277 | while (rank <= rank8) 278 | { 279 | passedPawnMask[i][sq] &= ~rankMasks[rank++]; 280 | } 281 | } 282 | } 283 | } 284 | } 285 | 286 | // ========================================================== 287 | // ============= function to initialize Blockers ============ 288 | // ========================================================== 289 | 290 | void Bitboard::generateBlockersFor(U64 (&attackMasks)[64], std::vector (&storage)[64]) 291 | { 292 | for (int i = 0; i < 64; ++i) 293 | { 294 | U64 bit = attackMasks[i]; 295 | generateBlockerBoards(bit, storage[i]); 296 | } 297 | } 298 | 299 | void Bitboard::generateBlockerBoards(U64 bitBoard, std::vector &blockerBoards) 300 | { 301 | std::vector setBitIndices; 302 | while (bitBoard) 303 | { 304 | setBitIndices.push_back(__builtin_ctzll(bitBoard)); // store the least significant set bit 305 | bitBoard &= (bitBoard - 1); // Remove the least significant set bit 306 | } 307 | 308 | int setBitCount = setBitIndices.size(); 309 | int totalCombinations = 1 << setBitCount; // 2 ^ n 310 | blockerBoards.resize(totalCombinations, 0ULL); 311 | 312 | for (int i = 0; i < totalCombinations; ++i) 313 | { 314 | // for each bit of i, shift bits correcponding to bitBoard's setBitIndices 315 | for (int j = 0; j < setBitCount; ++j) 316 | { 317 | U64 bit = (i >> j) & 1; 318 | blockerBoards[i] |= bit << setBitIndices[j]; 319 | } 320 | } 321 | } 322 | 323 | // ========================================================== 324 | // ============== functions that needs board ref ============= 325 | // ========================================================== 326 | 327 | void Bitboard::initBoard(Board *board) 328 | { 329 | this->board = board; 330 | init_pieces(); 331 | 332 | init_rookLookupTable(); 333 | init_bishopLookupTable(); 334 | } 335 | 336 | void Bitboard::init_attackMasks() 337 | { 338 | for (int sq = 0; sq < 120; ++sq) 339 | { 340 | Board::pieces[sq] = offBoard; 341 | } 342 | for (auto sq : sq64To120) 343 | { 344 | Board::pieces[sq] = empty; 345 | } 346 | 347 | init_pawnAttacks(); 348 | init_kingAttacks(); 349 | init_knighAttack(); 350 | init_rookAttacks(); 351 | init_bishopAttacks(); 352 | } 353 | 354 | void Bitboard::init_pieces() 355 | { 356 | for (int i = 0; i < 13; ++i) 357 | { 358 | pieces[i] = 0ULL; 359 | } 360 | 361 | for (int rank = rank1; rank <= rank8; ++rank) 362 | { 363 | for (int file = fileA; file <= fileH; ++file) 364 | { 365 | int sq = fileRank2Sq(file, rank); 366 | int piece = board->pieces[sq]; 367 | if (piece) 368 | { 369 | setBit(piece, sq120To64[sq]); 370 | } 371 | } 372 | } 373 | } 374 | 375 | // ============== functions to initialize LOOKUP TABLES ============= 376 | 377 | void Bitboard::init_rookLookupTable() 378 | { 379 | for (int sq = 0; sq < 64; ++sq) 380 | { 381 | U64 magic = rookMagics[sq]; 382 | for (U64 blocker : rookBlockers[sq]) 383 | { 384 | int index = (blocker * magic) >> (64 - 12); 385 | rookLookupTable[sq][index] = legalMoveBitboardFromBlockers(sq, blocker, true); 386 | } 387 | } 388 | } 389 | 390 | void Bitboard::init_bishopLookupTable() 391 | { 392 | for (int sq = 0; sq < 64; ++sq) 393 | { 394 | U64 magic = bishopMagics[sq]; 395 | for (U64 blocker : bishopBlockers[sq]) 396 | { 397 | int index = (blocker * magic) >> (64 - 12); 398 | bishopLookupTable[sq][index] = legalMoveBitboardFromBlockers(sq, blocker, false); 399 | } 400 | } 401 | } 402 | 403 | U64 Bitboard::legalMoveBitboardFromBlockers(int sq, U64 blockerBitboard, bool ortho) 404 | { 405 | U64 bitboard = 0ULL; 406 | const int *directions = ortho ? rookDirections : bishopDirections; 407 | 408 | for (int i = 0; i < 4; ++i) 409 | { 410 | int targetSq = sq64To120[sq] + directions[i]; 411 | while (board->pieces[targetSq] != offBoard) 412 | { 413 | setBit(bitboard, sq120To64[targetSq]); 414 | if (blockerBitboard & (1ULL << sq120To64[targetSq])) 415 | { 416 | break; 417 | } 418 | targetSq += directions[i]; 419 | } 420 | } 421 | return bitboard; 422 | } 423 | 424 | // ============== functions to initialize attacker ============= 425 | 426 | void Bitboard::init_pawnAttacks() 427 | { 428 | for (int rank = rank1; rank <= rank8; ++rank) 429 | { 430 | for (int file = fileA; file <= fileH; ++file) 431 | { 432 | U64 bitBoard = 0ULL; 433 | int sq = fileRank2Sq(file, rank); 434 | if (Board::pieces[sq + 11] != offBoard) 435 | { 436 | setBit(bitBoard, sq120To64[sq + 11]); 437 | } 438 | if (Board::pieces[sq + 9] != offBoard) 439 | { 440 | setBit(bitBoard, sq120To64[sq + 9]); 441 | } 442 | pawnAttacks[white][sq120To64[sq]] = bitBoard; 443 | } 444 | } 445 | for (int rank = rank8; rank >= rank1; --rank) 446 | { 447 | for (int file = fileA; file <= fileH; ++file) 448 | { 449 | U64 bitBoard = 0ULL; 450 | int sq = fileRank2Sq(file, rank); 451 | if (Board::pieces[sq - 11] != offBoard) 452 | { 453 | setBit(bitBoard, sq120To64[sq - 11]); 454 | } 455 | if (Board::pieces[sq - 9] != offBoard) 456 | { 457 | setBit(bitBoard, sq120To64[sq - 9]); 458 | } 459 | pawnAttacks[black][sq120To64[sq]] = bitBoard; 460 | } 461 | } 462 | } 463 | void Bitboard::init_kingAttacks() 464 | { 465 | for (int rank = rank1; rank <= rank8; ++rank) 466 | { 467 | for (int file = fileA; file <= fileH; ++file) 468 | { 469 | int sq = fileRank2Sq(file, rank); 470 | U64 bitBoard = 0ULL; 471 | 472 | for (int i = 0; i < 8; ++i) 473 | { 474 | int direction = kingDirections[i]; 475 | if (Board::pieces[sq + direction] != offBoard) 476 | { 477 | setBit(bitBoard, sq120To64[sq + direction]); 478 | } 479 | } 480 | 481 | kingAttacks[sq120To64[sq]] = bitBoard; 482 | } 483 | } 484 | } 485 | void Bitboard::init_knighAttack() 486 | { 487 | for (int rank = rank1; rank <= rank8; ++rank) 488 | { 489 | for (int file = fileA; file <= fileH; ++file) 490 | { 491 | int sq = fileRank2Sq(file, rank); 492 | U64 bitBoard = 0ULL; 493 | 494 | for (int i = 0; i < 8; ++i) 495 | { 496 | int direction = knightDirections[i]; 497 | if (Board::pieces[sq + direction] != offBoard) 498 | { 499 | setBit(bitBoard, sq120To64[sq + direction]); 500 | } 501 | } 502 | 503 | knightAttacks[sq120To64[sq]] = bitBoard; 504 | } 505 | } 506 | } 507 | void Bitboard::init_rookAttacks() 508 | { 509 | for (int rank = rank1; rank <= rank8; ++rank) 510 | { 511 | for (int file = fileA; file <= fileH; ++file) 512 | { 513 | int sq = fileRank2Sq(file, rank); 514 | U64 bitBoard = 0ULL; 515 | 516 | for (int i = 0; i < 4; ++i) 517 | { 518 | int direction = rookDirections[i]; 519 | int targetSq = sq + direction; 520 | while (Board::pieces[targetSq] != offBoard) 521 | { 522 | setBit(bitBoard, sq120To64[targetSq]); 523 | // erase the edge bits 524 | if (rank != rank8) 525 | bitBoard &= ~rankMasks[rank8]; 526 | if (rank != rank1) 527 | bitBoard &= ~rankMasks[rank1]; 528 | if (file != fileA) 529 | bitBoard &= ~fileMasks[fileA]; 530 | if (file != fileH) 531 | bitBoard &= ~fileMasks[fileH]; 532 | targetSq += direction; 533 | } 534 | } 535 | 536 | rookAttacks[sq120To64[sq]] = bitBoard; 537 | } 538 | } 539 | } 540 | void Bitboard::init_bishopAttacks() 541 | { 542 | for (int rank = rank1; rank <= rank8; ++rank) 543 | { 544 | for (int file = fileA; file <= fileH; ++file) 545 | { 546 | int sq = fileRank2Sq(file, rank); 547 | U64 bitBoard = 0ULL; 548 | 549 | for (int i = 0; i < 4; ++i) 550 | { 551 | int direction = bishopDirections[i]; 552 | int targetSq = sq + direction; 553 | while (Board::pieces[targetSq] != offBoard) 554 | { 555 | setBit(bitBoard, sq120To64[targetSq]); 556 | if (rank != rank8) 557 | bitBoard &= ~rankMasks[rank8]; 558 | if (rank != rank1) 559 | bitBoard &= ~rankMasks[rank1]; 560 | if (file != fileA) 561 | bitBoard &= ~fileMasks[fileA]; 562 | if (file != fileH) 563 | bitBoard &= ~fileMasks[fileH]; 564 | targetSq += direction; 565 | } 566 | } 567 | 568 | bishopAttacks[sq120To64[sq]] = bitBoard; 569 | } 570 | } 571 | } 572 | 573 | // ========================================================== 574 | // =============== pre computed magic numbers =============== 575 | // ========================================================== 576 | 577 | U64 bishopMagics[64] = { 578 | 2253999440997636ULL, 579 | 4903012653716226048ULL, 580 | 864979750796656656ULL, 581 | 9223689804573606017ULL, 582 | 40533607827128336ULL, 583 | 299577372120728576ULL, 584 | 36319073592672642ULL, 585 | 1193489111416705024ULL, 586 | 4972541375373120016ULL, 587 | 22946000217964576ULL, 588 | 9017369804408064ULL, 589 | 3388696984813568ULL, 590 | 633602500984850ULL, 591 | 18014982910509200ULL, 592 | 1747683700970094752ULL, 593 | 150997106696ULL, 594 | 145140010793862272ULL, 595 | 2458965397656174612ULL, 596 | 29863011310239776ULL, 597 | 8797192194216ULL, 598 | 4670759777813568ULL, 599 | 35253162883232ULL, 600 | 234188280696938656ULL, 601 | 4611880121018812945ULL, 602 | 1157425173266301226ULL, 603 | 622350107178172992ULL, 604 | 2676266277592369729ULL, 605 | 9250683922902554882ULL, 606 | 9223512860276032512ULL, 607 | 1161999141891559424ULL, 608 | 9225677714898289537ULL, 609 | 6197257669300996096ULL, 610 | 585503204652123136ULL, 611 | 624038862544443456ULL, 612 | 281613086916618ULL, 613 | 3379903173004288ULL, 614 | 71606768502992ULL, 615 | 13835077846525296706ULL, 616 | 60948414703601026ULL, 617 | 2960160785041410ULL, 618 | 1190711721468114945ULL, 619 | 232203117691904ULL, 620 | 4646048265597371456ULL, 621 | 6920132971833983234ULL, 622 | 1405739018628378688ULL, 623 | 17731810263041ULL, 624 | 5770289833626896641ULL, 625 | 563581347168260ULL, 626 | 9873263690475642898ULL, 627 | 4611686646584181764ULL, 628 | 1137445337841741ULL, 629 | 4899992261091393536ULL, 630 | 9583351950742017ULL, 631 | 2307012889862610973ULL, 632 | 297259565815443456ULL, 633 | 19826995167362ULL, 634 | 5188166566236659712ULL, 635 | 18300824511054208ULL, 636 | 10376294709798123520ULL, 637 | 9029279748760768ULL, 638 | 9512447113385230912ULL, 639 | 140738830565512ULL, 640 | 2307540725094547536ULL, 641 | 2883579206178964483ULL, 642 | }; 643 | U64 rookMagics[64] = { 644 | 108086959066380448ULL, 645 | 9007336962131968ULL, 646 | 13839579385616926736ULL, 647 | 2310346695413203024ULL, 648 | 37154971937934368ULL, 649 | 2310347175777075266ULL, 650 | 9270695171966632192ULL, 651 | 648541994433397504ULL, 652 | 9223389629485498368ULL, 653 | 292804413244833800ULL, 654 | 13228534924356ULL, 655 | 9223416051750930564ULL, 656 | 423708386069121024ULL, 657 | 9223547960964808713ULL, 658 | 580966688661717504ULL, 659 | 77194669145985088ULL, 660 | 36028968855404576ULL, 661 | 37383530719360ULL, 662 | 76561743832162304ULL, 663 | 4611791597347079232ULL, 664 | 4629735679759221012ULL, 665 | 563035855929602ULL, 666 | 1126467379528008ULL, 667 | 324498868114884752ULL, 668 | 2315202052466147872ULL, 669 | 4611725688087777296ULL, 670 | 2814784328433793ULL, 671 | 1441332200800813570ULL, 672 | 9223514973504816128ULL, 673 | 9038294851649544ULL, 674 | 4616263560882963200ULL, 675 | 31669233551149124ULL, 676 | 2594214397734289984ULL, 677 | 4611897133258768968ULL, 678 | 2355382622305130496ULL, 679 | 40533498574012484ULL, 680 | 2251825585586433ULL, 681 | 2317664961459916832ULL, 682 | 73482665268871689ULL, 683 | 2936496526060945440ULL, 684 | 1162069993523775488ULL, 685 | 141838073790472ULL, 686 | 576883171061665844ULL, 687 | 2452212201562310666ULL, 688 | 2199041736724ULL, 689 | 148763923307316353ULL, 690 | 27030397087006724ULL, 691 | 9007487051276304ULL, 692 | 4616190992530358284ULL, 693 | 1805970939508187392ULL, 694 | 579022633732669472ULL, 695 | 10964294838882935297ULL, 696 | 4828003974864974976ULL, 697 | 40816070730195104ULL, 698 | 9026990487119512ULL, 699 | 576481644251185280ULL, 700 | 9314642635405000834ULL, 701 | 5348096498864514ULL, 702 | 4611827039452269586ULL, 703 | 2310384043809572930ULL, 704 | 4755802350109720610ULL, 705 | 360332020515111170ULL, 706 | 5841169267563171908ULL, 707 | 578994029245104193ULL, 708 | }; -------------------------------------------------------------------------------- /bitboard.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "defs.hpp" 4 | #include "board.hpp" 5 | #include 6 | 7 | extern U64 bishopMagics[64]; 8 | extern U64 rookMagics[64]; 9 | 10 | U64 randomU64(); 11 | U64 random_64_fewbits(); 12 | 13 | class Bitboard 14 | { 15 | private: 16 | Board *board; 17 | void initMasks(); 18 | void init_attackMasks(); 19 | void init_pawnAttacks(); 20 | void init_kingAttacks(); 21 | void init_knighAttack(); 22 | void init_rookAttacks(); 23 | void init_bishopAttacks(); 24 | void init_fileMasks(); 25 | void init_rankMasks(); 26 | void init_isolatedPawnMask(); 27 | void init_passedPawnMask(); 28 | void init_pieces(); 29 | void generateBlockerBoards(U64 bitBoard, std::vector &blockerBoards); 30 | void generateBlockersFor(U64 (&attackMasks)[64], std::vector (&storage)[64]); 31 | void init_rookLookupTable(); 32 | void init_bishopLookupTable(); 33 | U64 legalMoveBitboardFromBlockers(int sq, U64 blockerBitboard, bool ortho); 34 | 35 | public: 36 | //static variables 37 | static U64 rookLookupTable[64][4096]; 38 | static U64 bishopLookupTable[64][4096]; 39 | static U64 fileMasks[8]; 40 | static U64 rankMasks[8]; 41 | static U64 isolatedPawnMask[64]; 42 | static U64 passedPawnMask[2][64]; 43 | static std::vector rookBlockers[64]; 44 | static std::vector bishopBlockers[64]; 45 | 46 | //non static variables 47 | U64 pieces[13]; 48 | U64 pawnAttacks[2][64] = {0ULL}; 49 | U64 kingAttacks[64] = {0ULL}; 50 | U64 knightAttacks[64] = {0ULL}; 51 | U64 rookAttacks[64] = {0ULL}; 52 | U64 bishopAttacks[64] = {0ULL}; 53 | 54 | Bitboard(); 55 | void initBoard(Board *board); 56 | void clearBit(int piece, int sq); 57 | void setBit(U64 &bitBoard, int sq); 58 | void setBit(int piece, int sq); 59 | int getPieceCount(int piece); 60 | void movePiece(int piece, int fromSq, int toSq); 61 | void print(int piece); 62 | void print(U64 bitBoard); 63 | U64 findMagic(int sq, const std::vector &blockerBitboards, bool ortho); 64 | U64 getPieces(int side); 65 | }; 66 | 67 | extern Bitboard *bitboard; -------------------------------------------------------------------------------- /board.cpp: -------------------------------------------------------------------------------- 1 | #include "utils.hpp" 2 | #include "board.hpp" 3 | #include "bitboard.hpp" 4 | #include "zobristKeys.hpp" 5 | #include "transpositionTable.hpp" 6 | #include 7 | #include 8 | 9 | Board *board = new Board; 10 | int Board::pieces[120]; 11 | 12 | Board::Board() 13 | { 14 | reset(); 15 | } 16 | 17 | void Board::pushMoveToHistory(int move) 18 | { 19 | history[ply].fiftyMove = this->fiftyMove; 20 | history[ply].fiftyMove = this->fiftyMove; 21 | history[ply].positionKey = this->positionKey; 22 | history[ply].enPassantSq = this->enPassantSq; 23 | history[ply].castlePermission = this->castlePermission; 24 | history[ply].checkSq = this->checkSq; 25 | history[ply].move = move; 26 | ply++; 27 | } 28 | MoveInfo *Board::popMoveFromHistory() 29 | { 30 | if (ply > 0) 31 | { 32 | MoveInfo *moveInfo = &history[--ply]; 33 | return moveInfo; 34 | } 35 | else 36 | { 37 | std::cerr << "No moves to pop!" << std::endl; 38 | return nullptr; 39 | } 40 | } 41 | 42 | U64 Board::generatePositionKey() 43 | { 44 | U64 hashKey = 0; 45 | for (auto sq : sq64To120) 46 | { 47 | int piece = pieces[sq]; 48 | if (piece != empty) 49 | { 50 | hashKey ^= pieceKeys[piece][sq]; 51 | } 52 | } 53 | 54 | hashKey ^= castleKeys[castlePermission]; 55 | 56 | if (side == white) 57 | hashKey ^= sideKey; 58 | if (enPassantSq != noSq) 59 | { 60 | hashKey ^= pieceKeys[empty][enPassantSq]; 61 | } 62 | return hashKey; 63 | } 64 | 65 | void Board::updateMaterial() 66 | { 67 | for (int sq : sq64To120) 68 | { 69 | int piece = pieces[sq]; 70 | if (piece != empty) 71 | { 72 | pieceCount[piece]++; 73 | material[pieceColor[piece]] += pieceValue[piece]; 74 | } 75 | } 76 | } 77 | 78 | void Board::reset() 79 | { 80 | transpositionTable->clear(); 81 | 82 | for (int i = 0; i < 1024; ++i) 83 | { 84 | history[i].fiftyMove = 0; 85 | history[i].positionKey = 0ULL; 86 | history[i].enPassantSq = noSq; 87 | history[i].castlePermission = 0; 88 | history[i].checkSq = noSq; 89 | history[i].move = 0; 90 | } 91 | for (int i = 0; i < 120; ++i) 92 | { 93 | pieces[i] = offBoard; 94 | } 95 | for (auto sq : sq64To120) 96 | { 97 | pieces[sq] = empty; 98 | } 99 | for (int i = 0; i < 13; ++i) 100 | { 101 | pieceCount[i] = 0; 102 | } 103 | material[white] = 0; 104 | material[black] = 0; 105 | side = white; 106 | castlePermission = 0; 107 | fiftyMove = 0; 108 | checkSq = noSq; 109 | positionKey = 0; 110 | ply = 0; 111 | 112 | } 113 | void Board::print() 114 | { 115 | int sq, piece; 116 | std::cout << std::endl; 117 | for (int rank = rank8; rank >= rank1; --rank) 118 | { 119 | std::cout << rank + 1 << " "; 120 | for (int file = fileA; file <= fileH; ++file) 121 | { 122 | sq = fileRank2Sq(file, rank); 123 | piece = pieces[sq]; 124 | if (pieceColor[piece] == black) 125 | { 126 | printf("\033[2m%c \033[0m", pieceChar[piece]); 127 | } 128 | else 129 | { 130 | printf("%c ", pieceChar[piece]); 131 | } 132 | } 133 | std::cout << std::endl; 134 | } 135 | std::cout << "\n "; 136 | for (int file = fileA; file <= fileH; ++file) 137 | { 138 | std::cout << fileChar[file] << " "; 139 | } 140 | std::cout << std::endl 141 | << std::endl; 142 | std::cout << "side : " << side << std::endl; 143 | std::cout << "Key: 0x" << std::hex << positionKey << std::dec << std::endl; 144 | std::cout << "Fen: " << getFen() << std::endl; 145 | std::cout << "Castle: " 146 | << ((castlePermission & castle_K) ? "K" : "_") 147 | << ((castlePermission & castle_Q) ? "Q" : "_") 148 | << ((castlePermission & castle_k) ? "k" : "_") 149 | << ((castlePermission & castle_q) ? "q" : "_") 150 | << std::endl; 151 | 152 | if (board->checkSq != noSq) 153 | { 154 | printf("\033[31mcheck: %s\033[0m\n", squareChar[board->checkSq]); 155 | } 156 | if(board->enPassantSq != noSq){ 157 | printf("\033[33mEP: %s\033[0m\n", squareChar[board->enPassantSq]); 158 | } 159 | } 160 | 161 | void Board::parseFen(std::string &fen) 162 | { 163 | reset(); 164 | 165 | int i = 0; 166 | int file = fileA; 167 | int rank = rank8; 168 | int sq; 169 | while (fen[i] == ' ') i++; // skip white space 170 | 171 | while (fen[i] != ' ') 172 | { 173 | sq = fileRank2Sq(file, rank); 174 | if (fen[i] == '/') 175 | { 176 | --rank; 177 | file = fileA; 178 | } 179 | else if (isalpha(fen[i])) 180 | { 181 | switch (fen[i]) 182 | { 183 | case 'P': pieces[sq] = wp; break; 184 | case 'N': pieces[sq] = wn; break; 185 | case 'B': pieces[sq] = wb; break; 186 | case 'R': pieces[sq] = wr; break; 187 | case 'Q': pieces[sq] = wq; break; 188 | case 'K': pieces[sq] = wk; break; 189 | 190 | case 'p': pieces[sq] = bp; break; 191 | case 'n': pieces[sq] = bn; break; 192 | case 'b': pieces[sq] = bb; break; 193 | case 'r': pieces[sq] = br; break; 194 | case 'q': pieces[sq] = bq; break; 195 | case 'k': pieces[sq] = bk; break; 196 | 197 | default: return; 198 | } 199 | file++; 200 | } 201 | else 202 | { 203 | file += fen[i] - '0'; 204 | } 205 | ++i; 206 | } 207 | while (fen[++i] == ' '); // skip white space 208 | side = (fen[i] == 'w') ? white : black; 209 | while (fen[++i] == ' '); // skip white space 210 | while (fen[i] != ' ') 211 | { 212 | switch (fen[i++]) 213 | { 214 | case 'K': castlePermission |= castle_K; break; 215 | case 'Q': castlePermission |= castle_Q; break; 216 | case 'k': castlePermission |= castle_k; break; 217 | case 'q': castlePermission |= castle_q; break; 218 | default: break; 219 | } 220 | } 221 | 222 | while (fen[++i] == ' '); // skip white space 223 | if (fen[i] != '-') 224 | { 225 | int file = fen[i++] - 'a'; 226 | int rank = fen[i] - '1'; 227 | enPassantSq = fileRank2Sq(file, rank); 228 | } 229 | else{ 230 | enPassantSq = noSq; 231 | } 232 | updateMaterial(); 233 | bitboard->initBoard(this); 234 | 235 | // is in check 236 | int kingOnSq = __builtin_ctzll(bitboard->pieces[Kings[side]]); 237 | board->checkSq = isUnderAttack(kingOnSq, board->side ^ 1)? sq64To120[kingOnSq] : noSq; 238 | 239 | 240 | // generate a uniqe position key 241 | positionKey = generatePositionKey(); 242 | } 243 | 244 | std::string Board::getFen() 245 | { 246 | std::string fen; 247 | int emptySq = 0, sq, piece; 248 | 249 | for (int rank = rank8; rank >= rank1; --rank) 250 | { 251 | emptySq = 0; 252 | for (int file = fileA; file <= fileH; ++file) 253 | { 254 | sq = fileRank2Sq(file, rank); 255 | piece = pieces[sq]; 256 | if (piece == empty) 257 | { 258 | emptySq++; 259 | } 260 | else 261 | { 262 | if (emptySq) 263 | { 264 | fen += std::to_string(emptySq); 265 | emptySq = 0; 266 | } 267 | fen += pieceChar[piece]; 268 | } 269 | } 270 | if (emptySq) 271 | { 272 | fen += std::to_string(emptySq); 273 | } 274 | if (rank != rank1) 275 | { 276 | fen += '/'; 277 | } 278 | } 279 | 280 | fen += ' '; 281 | fen += (side == white) ? 'w' : 'b'; 282 | fen += ' '; 283 | if (castlePermission) 284 | { 285 | if (castlePermission & castle_K) 286 | fen += 'K'; 287 | if (castlePermission & castle_Q) 288 | fen += 'Q'; 289 | if (castlePermission & castle_k) 290 | fen += 'k'; 291 | if (castlePermission & castle_q) 292 | fen += 'q'; 293 | } 294 | else 295 | { 296 | fen += '-'; 297 | } 298 | 299 | if (enPassantSq != noSq) 300 | { 301 | fen += " "; 302 | fen += squareChar[enPassantSq]; 303 | fen += " "; 304 | } 305 | else 306 | { 307 | fen += " - "; 308 | } 309 | fen += std::to_string(fiftyMove) + ' '; 310 | fen += std::to_string(ply + 1); 311 | return fen; 312 | } 313 | -------------------------------------------------------------------------------- /board.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include "defs.hpp" 5 | 6 | class Board 7 | { 8 | U64 generatePositionKey(); 9 | void updateMaterial(); 10 | 11 | public: 12 | static int pieces[120]; 13 | int side = white; 14 | int castlePermission = 0; 15 | int fiftyMove = 0; 16 | int enPassantSq = noSq; 17 | int checkSq = noSq; 18 | int ply = 0; 19 | 20 | int pieceCount[13]; 21 | int material[2]; 22 | U64 positionKey = 0; 23 | MoveInfo history[1024]; 24 | 25 | Board(); 26 | void pushMoveToHistory(int move); 27 | MoveInfo *popMoveFromHistory(); 28 | 29 | void parseFen(std::string &fen); 30 | std::string getFen(); 31 | void print(); 32 | void reset(); 33 | }; 34 | 35 | extern Board* board; 36 | -------------------------------------------------------------------------------- /chess.exe: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/abhijeetSinghRajput/chess-engine-cpp/bb4bfca38f35827ea40fc31d67f8d6546e85b2d3/chess.exe -------------------------------------------------------------------------------- /defs.cpp: -------------------------------------------------------------------------------- 1 | #include "defs.hpp" 2 | #include "move.hpp" 3 | #include 4 | 5 | // Initialize global variables 6 | std::string startFen = "rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR w KQkq - 0 1"; 7 | int sq120To64[120]; 8 | int sq64To120[64]; 9 | 10 | const char pieceChar[] = ".PRNBQKprnbqk"; 11 | const char pieceType[] = ".prnbqkprnbqk"; 12 | const char fileChar[] = "abcdefgh"; 13 | const int pieceColor[] = { 14 | 2, 15 | 0, 0, 0, 0, 0, 0, 16 | 1, 1, 1, 1, 1, 1, 17 | }; 18 | const char *squareChar[] = { 19 | ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", 20 | ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", 21 | ".", "a1", "b1", "c1", "d1", "e1", "f1", "g1", "h1", ".", 22 | ".", "a2", "b2", "c2", "d2", "e2", "f2", "g2", "h2", ".", 23 | ".", "a3", "b3", "c3", "d3", "e3", "f3", "g3", "h3", ".", 24 | ".", "a4", "b4", "c4", "d4", "e4", "f4", "g4", "h4", ".", 25 | ".", "a5", "b5", "c5", "d5", "e5", "f5", "g5", "h5", ".", 26 | ".", "a6", "b6", "c6", "d6", "e6", "f6", "g6", "h6", ".", 27 | ".", "a7", "b7", "c7", "d7", "e7", "f7", "g7", "h7", ".", 28 | ".", "a8", "b8", "c8", "d8", "e8", "f8", "g8", "h8", ".", 29 | ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", 30 | ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", 31 | }; 32 | const char *pieceName[] = { 33 | ".", 34 | "wp", "wr", "wn", "wb", "wq", "wk", 35 | "bp", "br", "bn", "bb", "bq", "bk" 36 | }; 37 | const int pieceValue[] = { 38 | 0, 39 | 100, 500, 320, 330, 900, 50000, 40 | 100, 500, 320, 330, 900, 50000, 41 | }; 42 | 43 | const int Kings[] = {wk, bk}; 44 | 45 | const int maxDepth = 64; 46 | const int Infinite = 30000; 47 | const int Mate = Infinite - maxDepth; 48 | 49 | const int CastlePermission[] = { 50 | 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 51 | 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 52 | 15, 11, 15, 15, 15, 3, 15, 15, 7, 15,//white 1011 0011 0111 53 | 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 54 | 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 55 | 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 56 | 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 57 | 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 58 | 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 59 | 15, 14, 15, 15, 15, 12, 15, 15, 13, 15,//black 1101 1100 1110 60 | 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 61 | 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 62 | }; 63 | 64 | const int Mirror64[] = { 65 | 56 , 57 , 58 , 59 , 60 , 61 , 62 , 63 , 66 | 48 , 49 , 50 , 51 , 52 , 53 , 54 , 55 , 67 | 40 , 41 , 42 , 43 , 44 , 45 , 46 , 47 , 68 | 32 , 33 , 34 , 35 , 36 , 37 , 38 , 39 , 69 | 24 , 25 , 26 , 27 , 28 , 29 , 30 , 31 , 70 | 16 , 17 , 18 , 19 , 20 , 21 , 22 , 23 , 71 | 8 , 9 , 10 , 11 , 12 , 13 , 14 , 15 , 72 | 0 , 1 , 2 , 3 , 4 , 5 , 6 , 7 73 | }; 74 | 75 | 76 | const int rookDirections[] = {-10, 1, 10, -1}; 77 | const int knightDirections[] = {19, 21, 12, 8, -19, -21, -12, -8}; 78 | const int bishopDirections[] = {-9, -11, 9, 11}; 79 | const int kingDirections[] = {-10, 1, 10, -1, -9, -11, 9, 11}; 80 | const int queenDirections[] = {-10, 1, 10, -1, -9, -11, 9, 11}; 81 | 82 | const int slidingPieces[2][3] = { 83 | wr, wb, wq, 84 | br, bb, bq, 85 | }; 86 | const int nonSlidingPieces[2][2] = { 87 | wn, wk, 88 | bn, bk, 89 | }; 90 | 91 | void initSquareMappings() { 92 | for (int rank = rank1; rank <= rank8; ++rank) { 93 | for (int file = fileA; file <= fileH; ++file) { 94 | int sq120 = fileRank2Sq(file, rank); 95 | int sq64 = rank * 8 + file; 96 | sq120To64[sq120] = sq64; 97 | sq64To120[sq64] = sq120; 98 | } 99 | } 100 | } 101 | 102 | void initialize() { 103 | initSquareMappings(); 104 | } 105 | 106 | std::string moveStr(int move) { 107 | if (!move) return ""; 108 | 109 | char moveStr[5]; 110 | int from = moveFrom(move); 111 | int to = moveTo(move); 112 | 113 | moveStr[0] = 'a' + fileOf(from); 114 | moveStr[1] = '1' + rankOf(from); 115 | moveStr[2] = 'a' + fileOf(to); 116 | moveStr[3] = '1' + rankOf(to); 117 | moveStr[4] = '\0'; 118 | 119 | return std::string(moveStr); 120 | } 121 | 122 | long long getCurrTime() { 123 | // Get current time with milliseconds since epoch 124 | auto now = std::chrono::system_clock::now(); 125 | auto duration = now.time_since_epoch(); 126 | auto milliseconds = std::chrono::duration_cast(duration).count(); 127 | 128 | return milliseconds; 129 | } -------------------------------------------------------------------------------- /defs.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | 10 | 11 | extern std::string startFen; 12 | extern int sq120To64[120]; 13 | extern int sq64To120[64]; 14 | 15 | extern const char pieceChar[]; 16 | extern const char pieceType[]; 17 | extern const char fileChar[]; 18 | extern const int pieceColor[]; 19 | extern const char *squareChar[]; 20 | extern const char *pieceName[]; 21 | extern const int pieceValue[]; 22 | extern const int CastlePermission[]; 23 | extern const int Mirror64[]; 24 | 25 | extern const int rookDirections[]; 26 | extern const int knightDirections[]; 27 | extern const int bishopDirections[]; 28 | extern const int kingDirections[]; 29 | extern const int queenDirections[]; 30 | extern const int Kings[]; 31 | 32 | extern const int maxDepth; 33 | extern const int Infinite; 34 | extern const int Mate; 35 | 36 | extern const int slidingPieces[2][3]; 37 | extern const int nonSlidingPieces[2][2]; 38 | 39 | enum 40 | { 41 | empty, 42 | wp,wr,wn,wb,wq,wk, 43 | bp,br,bn,bb,bq,bk 44 | }; 45 | enum 46 | { 47 | white, 48 | black, 49 | both 50 | }; 51 | enum {fileA, fileB, fileC, fileD, fileE, fileF, fileG, fileH}; 52 | enum {rank1, rank2, rank3, rank4, rank5, rank6, rank7, rank8}; 53 | 54 | typedef unsigned long long U64; 55 | 56 | enum 57 | { 58 | castle_K = 8, 59 | castle_Q = 4, 60 | castle_k = 2, 61 | castle_q = 1 62 | }; 63 | 64 | enum 65 | { 66 | a1 = 21, b1, c1, d1, e1, f1, g1, h1, 67 | a2 = 31, b2, c2, d2, e2, f2, g2, h2, 68 | a3 = 41, b3, c3, d3, e3, f3, g3, h3, 69 | a4 = 51, b4, c4, d4, e4, f4, g4, h4, 70 | a5 = 61, b5, c5, d5, e5, f5, g5, h5, 71 | a6 = 71, b6, c6, d6, e6, f6, g6, h6, 72 | a7 = 81, b7, c7, d7, e7, f7, g7, h7, 73 | a8 = 91, b8, c8, d8, e8, f8, g8, h8, 74 | noSq = -1, offBoard = -2 75 | }; 76 | 77 | struct MoveInfo 78 | { 79 | int fiftyMove; 80 | U64 positionKey; 81 | int enPassantSq; 82 | int castlePermission; 83 | int checkSq; 84 | int move; 85 | }; 86 | 87 | struct TableData 88 | { 89 | U64 smp_data; 90 | U64 smp_key; 91 | }; 92 | 93 | struct polyEntry{ 94 | // U64 key; 95 | uint16_t move; 96 | uint16_t weight; 97 | uint32_t learn; 98 | }; 99 | extern std::unordered_map> openingBook; 100 | 101 | // functions 102 | 103 | void initialize(); 104 | 105 | inline int fileRank2Sq(int file, int rank) { return (rank * 10 + file) + 21; } 106 | inline int fileOf(int sq) { return (sq % 10) - 1; } 107 | inline int rankOf(int sq) { return (sq - 21) / 10; } 108 | std::string moveStr(int move); 109 | long long getCurrTime(); -------------------------------------------------------------------------------- /evaluation.cpp: -------------------------------------------------------------------------------- 1 | #include "evaluation.hpp" 2 | #include "defs.hpp" 3 | #include "board.hpp" 4 | #include "bitboard.hpp" 5 | #include "utils.hpp" 6 | #include 7 | 8 | const int PawnTable[] = { 9 | 0, 0, 0, 0, 0, 0, 0, 0, 10 | 10, 10, 0, -10, -10, 0, 10, 10, 11 | 5, 0, 0, 5, 5, 0, 0, 5, 12 | 0, 0, 10, 20, 20, 10, 0, 0, 13 | 5, 5, 5, 10, 10, 5, 5, 5, 14 | 10, 10, 10, 20, 20, 10, 10, 10, 15 | 20, 20, 20, 30, 30, 20, 20, 20, 16 | 0, 0, 0, 0, 0, 0, 0, 0}; 17 | 18 | const int KnightTable[] = { 19 | 0, -10, 0, 0, 0, 0, -10, 0, 20 | 0, 0, 0, 5, 5, 0, 0, 0, 21 | 0, 0, 10, 10, 10, 10, 0, 0, 22 | 0, 0, 10, 20, 20, 10, 5, 0, 23 | 5, 10, 15, 20, 20, 15, 10, 5, 24 | 5, 10, 10, 20, 20, 10, 10, 5, 25 | 0, 0, 5, 10, 10, 5, 0, 0, 26 | 0, 0, 0, 0, 0, 0, 0, 0}; 27 | 28 | const int BishopTable[] = { 29 | 0, 0, -10, 0, 0, -10, 0, 0, 30 | 0, 0, 0, 10, 10, 0, 0, 0, 31 | 0, 0, 10, 15, 15, 10, 0, 0, 32 | 0, 10, 15, 20, 20, 15, 10, 0, 33 | 0, 10, 15, 20, 20, 15, 10, 0, 34 | 0, 0, 10, 15, 15, 10, 0, 0, 35 | 0, 0, 0, 10, 10, 0, 0, 0, 36 | 0, 0, 0, 0, 0, 0, 0, 0}; 37 | 38 | const int RookTable[] = { 39 | 0, 0, 5, 10, 10, 5, 0, 0, 40 | 0, 0, 5, 10, 10, 5, 0, 0, 41 | 0, 0, 5, 10, 10, 5, 0, 0, 42 | 0, 0, 5, 10, 10, 5, 0, 0, 43 | 0, 0, 5, 10, 10, 5, 0, 0, 44 | 0, 0, 5, 10, 10, 5, 0, 0, 45 | 25, 25, 25, 25, 25, 25, 25, 25, 46 | 0, 0, 5, 10, 10, 5, 0, 0}; 47 | 48 | const int KingO[] = { 49 | 0, 5, 5, -10, -10, 0, 10, 5, 50 | -30, -30, -30, -30, -30, -30, -30, -30, 51 | -50, -50, -50, -50, -50, -50, -50, -50, 52 | -70, -70, -70, -70, -70, -70, -70, -70, 53 | -70, -70, -70, -70, -70, -70, -70, -70, 54 | -70, -70, -70, -70, -70, -70, -70, -70, 55 | -70, -70, -70, -70, -70, -70, -70, -70, 56 | -70, -70, -70, -70, -70, -70, -70, -70}; 57 | 58 | const int KingE[] = { 59 | -50, -10, 0, 0, 0, 0, -10, -50, 60 | -10, 0, 10, 10, 10, 10, 0, -10, 61 | 0, 10, 20, 20, 20, 20, 10, 0, 62 | 0, 10, 20, 40, 40, 20, 10, 0, 63 | 0, 10, 20, 40, 40, 20, 10, 0, 64 | 0, 10, 20, 20, 20, 20, 10, 0, 65 | -10, 0, 10, 10, 10, 10, 0, -10, 66 | -50, -10, 0, 0, 0, 0, -10, -50}; 67 | 68 | const int BishopPair = 40; 69 | const int PawnIsolated = -10; 70 | const int PawnPassed[] = {0, 5, 10, 20, 35, 60, 100, 200}; 71 | const int rookSupportSameFile = 10; 72 | const int rookSupportSameRank = 5; 73 | const int RookOpenFile = 20; 74 | const int RookSemiOpenFile = 10; 75 | const int QueenOpenFile = 10; 76 | const int QueenSemiOpenFile = 5; 77 | const int DoublePawnPenality = -5; 78 | const int PawnSupport = 5; 79 | const int brokenPawnShieldPenalty = -20; 80 | const int exposedKingPenalty = -30; 81 | const int kingZoneAttackPenalty = -10; 82 | const int pawnStormPenalty[2][8] = { 83 | {0, 65, 35, 20, 10, 5, 0, 0}, 84 | {0, 0, 5, 10, 20, 35, 65, 0}, 85 | }; 86 | const int EndGame_Material = (1 * pieceValue[wr]) + (2 * pieceValue[wn]) + (2 * pieceValue[wp]) + (pieceValue[wk]); 87 | 88 | // MobilityBonus[phase][piece][mobility]; 89 | const int MobilityBonus[2][6][32] = { 90 | // midgame 91 | { 92 | {}, // Empty 93 | {}, // Pawns 94 | {-20, -14, -8, -2, 4, 10, 14, 19, 23, 26, 27, 28, 29, 30, 31, 32}, // Rooks 95 | {-38, -25, -12, 0, 12, 25, 31, 38, 38}, // Knights 96 | {-25, -11, 3, 17, 31, 45, 57, 65, 71, 74, 76, 78, 79, 80, 81, 81}, // Bishops 97 | {-10, -8, -6, -3, -1, 1, 3, 5, 8, 10, 12, 15, 16, 17, 18, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20} // Queens 98 | }, 99 | // endgame 100 | { 101 | {}, // Empty 102 | {}, // Pawns 103 | {-36, -19, -3, 13, 29, 46, 62, 79, 95, 106, 111, 114, 116, 117, 118, 118}, // Rooks 104 | {-33, -23, -13, -3, 7, 17, 22, 27, 27}, // Knights 105 | {-30, -16, -2, 12, 26, 40, 52, 60, 65, 69, 71, 73, 74, 75, 76, 76}, // Bishops 106 | {-18, -13, -7, -2, 3, 8, 13, 19, 23, 27, 32, 34, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35} // Queens 107 | }}; 108 | 109 | int kingSafety(int kingSq, int color) 110 | { 111 | int score = 0, sq; 112 | U64 pawnBitboard = (color == white) ? bitboard->pieces[wp] : bitboard->pieces[bp]; 113 | U64 enemyPawnBitboard = (color == white) ? bitboard->pieces[bp] : bitboard->pieces[wp]; 114 | 115 | U64 pawnShieldMask = 0ULL, pawnShield, pawnStorm; 116 | int missingPawn; 117 | 118 | switch (kingSq) 119 | { 120 | case b1: pawnShieldMask = (7ULL << 8); pawnStorm = enemyPawnBitboard & 0x70707070700ULL; break; 121 | case c1: pawnShieldMask = (7ULL << 9); pawnStorm = enemyPawnBitboard & 0xe0e0e0e0e00ULL; break; 122 | case g1: pawnShieldMask = (7ULL << 13); pawnStorm = enemyPawnBitboard & 0xe0e0e0e0e000ULL; break; 123 | case b8: pawnShieldMask = (7ULL << 48); pawnStorm = enemyPawnBitboard & 0x7070707070000ULL; break; 124 | case c8: pawnShieldMask = (7ULL << 49); pawnStorm = enemyPawnBitboard & 0xe0e0e0e0e0000ULL; break; 125 | case g8: pawnShieldMask = (7ULL << 53); pawnStorm = enemyPawnBitboard & 0xe0e0e0e0e00000ULL; break; 126 | 127 | default: break; 128 | } 129 | 130 | // non zero pawnShildMask indicating king is on reasonalbe sq 131 | if (pawnShieldMask) 132 | { 133 | pawnShield = pawnBitboard & pawnShieldMask; 134 | missingPawn = ~pawnShield & pawnShieldMask; 135 | 136 | // ============== pawn shield evaluation 137 | score += __builtin_popcountll(missingPawn) * brokenPawnShieldPenalty; 138 | while (missingPawn) 139 | { 140 | sq = __builtin_ctzll(missingPawn); 141 | if ((pawnBitboard & bitboard->fileMasks[sq % 8]) == 0) 142 | { 143 | score += exposedKingPenalty; 144 | } 145 | missingPawn &= missingPawn - 1; 146 | } 147 | 148 | // ============== pawn storm evaluation 149 | while (pawnStorm) 150 | { 151 | sq = __builtin_ctzll(pawnStorm); 152 | score += pawnStormPenalty[color][sq / 8]; 153 | pawnStorm &= pawnStorm - 1; 154 | } 155 | } 156 | 157 | // minor piece attack on a king zone 158 | 159 | U64 knightBitboard = (color == white) ? bitboard->pieces[bn] : bitboard->pieces[wn]; 160 | U64 bishopBitboard = (color == white) ? bitboard->pieces[bb] : bitboard->pieces[wb]; 161 | U64 kingAttack = bitboard->kingAttacks[kingSq]; 162 | 163 | while (knightBitboard) 164 | { 165 | sq = __builtin_ctzll(knightBitboard); 166 | U64 knightAttack = bitboard->knightAttacks[sq]; 167 | score += kingZoneAttackPenalty * __builtin_popcountll(kingAttack & knightAttack); 168 | knightBitboard &= knightBitboard - 1; 169 | } 170 | 171 | while (bishopBitboard) 172 | { 173 | sq = __builtin_ctzll(bishopBitboard); 174 | U64 bishopAttack = bitboard->bishopAttacks[sq]; 175 | if (kingAttack & bishopAttack) 176 | score += kingZoneAttackPenalty; 177 | bishopBitboard &= bishopBitboard - 1; 178 | } 179 | 180 | return score; 181 | } 182 | 183 | int evalPosition() 184 | { 185 | 186 | int score = board->material[white] - board->material[black]; 187 | int doublePawnCount = 0, mobility = 0, sq; 188 | U64 allWhitePieces = bitboard->getPieces(white); 189 | U64 allBlackPieces = bitboard->getPieces(black); 190 | 191 | bool isEndgame = (board->material[black] <= EndGame_Material && board->material[white] <= EndGame_Material) || 192 | (board->material[black] + board->material[white] <= EndGame_Material * 2) || 193 | (board->pieceCount[wp] <= 4 && board->pieceCount[bp] <= 4); 194 | 195 | // ================================================================= 196 | // ============================= PAWN ============================== 197 | // ================================================================= 198 | 199 | U64 pieceBitboard = bitboard->pieces[wp]; 200 | while (pieceBitboard) 201 | { 202 | sq = __builtin_ctzll(pieceBitboard); 203 | pieceBitboard &= pieceBitboard - 1; 204 | score += PawnTable[sq]; 205 | 206 | // double pawn penality 207 | doublePawnCount = __builtin_popcountll(bitboard->pieces[wp] & bitboard->fileMasks[sq % 8]); 208 | if (doublePawnCount > 1) 209 | { 210 | score += DoublePawnPenality; 211 | } 212 | // supporter pawn 213 | if (bitboard->pawnAttacks[white][sq] & bitboard->pieces[wp]) 214 | { 215 | score += PawnSupport; 216 | } 217 | // isolated pawn penality 218 | if ((bitboard->isolatedPawnMask[sq] & bitboard->pieces[wp]) == 0) 219 | { 220 | score += PawnIsolated; 221 | } 222 | // passed pawn 223 | if ((bitboard->passedPawnMask[white][sq] & bitboard->pieces[bp]) == 0) 224 | { 225 | score += PawnPassed[sq / 8]; 226 | } 227 | } 228 | pieceBitboard = bitboard->pieces[bp]; 229 | while (pieceBitboard) 230 | { 231 | sq = __builtin_ctzll(pieceBitboard); 232 | pieceBitboard &= pieceBitboard - 1; 233 | score -= PawnTable[Mirror64[sq]]; 234 | 235 | // double pawn penality 236 | doublePawnCount = __builtin_popcountll(bitboard->pieces[bp] & bitboard->fileMasks[sq % 8]); 237 | if (doublePawnCount > 1) 238 | { 239 | score -= DoublePawnPenality; 240 | } 241 | // supporter pawn 242 | if (bitboard->pawnAttacks[black][sq] & bitboard->pieces[bp]) 243 | { 244 | score -= PawnSupport; 245 | } 246 | // isolated pawn penality 247 | if ((bitboard->isolatedPawnMask[sq] & bitboard->pieces[bp]) == 0) 248 | { 249 | score -= PawnIsolated; 250 | } 251 | // passed pawn 252 | if ((bitboard->passedPawnMask[black][sq] & bitboard->pieces[wp]) == 0) 253 | { 254 | score -= PawnPassed[7 - sq / 8]; 255 | } 256 | } 257 | 258 | // ================================================================= 259 | // ============================ KNIGHT ============================= 260 | // ================================================================= 261 | 262 | pieceBitboard = bitboard->pieces[wn]; 263 | while (pieceBitboard) 264 | { 265 | sq = __builtin_ctzll(pieceBitboard); 266 | pieceBitboard &= pieceBitboard - 1; 267 | score += KnightTable[sq]; 268 | 269 | // mobility bonus 270 | mobility = __builtin_popcountll(bitboard->knightAttacks[wn] & ~allWhitePieces); 271 | score += MobilityBonus[isEndgame][wn][mobility]; 272 | } 273 | 274 | pieceBitboard = bitboard->pieces[bn]; 275 | while (pieceBitboard) 276 | { 277 | sq = __builtin_ctzll(pieceBitboard); 278 | pieceBitboard &= pieceBitboard - 1; 279 | score -= KnightTable[Mirror64[sq]]; 280 | 281 | // mobility bonus 282 | mobility = __builtin_popcountll(bitboard->knightAttacks[wn] & ~allBlackPieces); 283 | score += MobilityBonus[isEndgame][wn][mobility]; 284 | } 285 | 286 | // ================================================================= 287 | // ============================ BISHOP ============================= 288 | // ================================================================= 289 | pieceBitboard = bitboard->pieces[wb]; 290 | while (pieceBitboard) 291 | { 292 | sq = __builtin_ctzll(pieceBitboard); 293 | pieceBitboard &= pieceBitboard - 1; 294 | score += BishopTable[sq]; 295 | 296 | // mobility bonus 297 | mobility = __builtin_popcountll(getBishopAttacks(sq) & ~allWhitePieces); 298 | score += MobilityBonus[isEndgame][wb][mobility]; 299 | } 300 | 301 | pieceBitboard = bitboard->pieces[bb]; 302 | while (pieceBitboard) 303 | { 304 | sq = __builtin_ctzll(pieceBitboard); 305 | pieceBitboard &= pieceBitboard - 1; 306 | score -= BishopTable[Mirror64[sq]]; 307 | 308 | // mobility bonus 309 | mobility = __builtin_popcountll(getBishopAttacks(sq) & ~allBlackPieces); 310 | score -= MobilityBonus[isEndgame][wb][mobility]; 311 | } 312 | 313 | // ================================================================= 314 | // ============================= ROOK ============================== 315 | // ================================================================= 316 | 317 | pieceBitboard = bitboard->pieces[wr]; 318 | U64 rookAttack = 0ULL; 319 | while (pieceBitboard) 320 | { 321 | sq = __builtin_ctzll(pieceBitboard); 322 | pieceBitboard &= pieceBitboard - 1; 323 | rookAttack = getRookAttacks(sq); 324 | score += RookTable[sq]; 325 | 326 | // Brothers 327 | if (rookAttack & bitboard->fileMasks[sq % 8] & pieceBitboard) 328 | { 329 | score += rookSupportSameFile; 330 | } 331 | if (rookAttack & bitboard->fileMasks[sq / 8] & pieceBitboard) 332 | { 333 | score += rookSupportSameFile; 334 | } 335 | 336 | // mobility bonus 337 | mobility = __builtin_popcountll(rookAttack & ~allWhitePieces); 338 | score += MobilityBonus[isEndgame][wr][mobility]; 339 | 340 | if (((bitboard->pieces[wp] | bitboard->pieces[bp]) & bitboard->fileMasks[sq % 8]) == 0) 341 | { 342 | score += RookOpenFile; 343 | } 344 | else if ((bitboard->pieces[wp] & bitboard->fileMasks[sq % 8]) == 0) 345 | { 346 | score += RookSemiOpenFile; 347 | } 348 | } 349 | 350 | pieceBitboard = bitboard->pieces[br]; 351 | while (pieceBitboard) 352 | { 353 | sq = __builtin_ctzll(pieceBitboard); 354 | pieceBitboard &= pieceBitboard - 1; 355 | score -= RookTable[Mirror64[sq]]; 356 | rookAttack = getRookAttacks(sq); 357 | 358 | // Brothers 359 | if (rookAttack & bitboard->fileMasks[sq % 8] & pieceBitboard) 360 | { 361 | score -= rookSupportSameFile; 362 | } 363 | if (rookAttack & bitboard->fileMasks[sq / 8] & pieceBitboard) 364 | { 365 | score -= rookSupportSameRank; 366 | } 367 | 368 | // Mobility bonus 369 | mobility = __builtin_popcountll(rookAttack & ~allBlackPieces); 370 | score -= MobilityBonus[isEndgame][wr][mobility]; 371 | 372 | // Open file bonus 373 | if (((bitboard->pieces[wp] | bitboard->pieces[bp]) & bitboard->fileMasks[sq % 8]) == 0) 374 | { 375 | score -= RookOpenFile; 376 | } 377 | else if ((bitboard->pieces[bp] & bitboard->fileMasks[sq % 8]) == 0) 378 | { 379 | score -= RookSemiOpenFile; 380 | } 381 | } 382 | 383 | // ================================================================= 384 | // ============================= QUEEN ============================= 385 | // ================================================================= 386 | 387 | pieceBitboard = bitboard->pieces[wq]; 388 | while (pieceBitboard) 389 | { 390 | sq = __builtin_ctzll(pieceBitboard); 391 | pieceBitboard &= pieceBitboard - 1; 392 | //an orthogonal support to rook 393 | if (getRookAttacks(sq) & bitboard->pieces[wr]) 394 | { 395 | score += rookSupportSameFile; 396 | } 397 | 398 | // mobility bonus 399 | mobility = __builtin_popcountll((getRookAttacks(sq) | getBishopAttacks(sq)) & ~allWhitePieces); 400 | score += MobilityBonus[isEndgame][wq][mobility]; 401 | 402 | // open file bonus 403 | if (((bitboard->pieces[wp] | bitboard->pieces[bp]) & bitboard->fileMasks[sq % 8]) == 0) 404 | { 405 | score += QueenOpenFile; 406 | } 407 | else if ((bitboard->pieces[wp] & bitboard->fileMasks[sq % 8]) == 0) 408 | { 409 | score += QueenSemiOpenFile; 410 | } 411 | } 412 | 413 | pieceBitboard = bitboard->pieces[bq]; 414 | while (pieceBitboard) 415 | { 416 | sq = __builtin_ctzll(pieceBitboard); 417 | pieceBitboard &= pieceBitboard - 1; 418 | //an orthogonal support from queen 419 | if (getRookAttacks(sq) & bitboard->pieces[br]) 420 | { 421 | score -= rookSupportSameFile; 422 | } 423 | 424 | // mobility bonus 425 | mobility = __builtin_popcountll((getRookAttacks(sq) | getBishopAttacks(sq)) & ~allBlackPieces); 426 | score -= MobilityBonus[isEndgame][wq][mobility]; 427 | 428 | // open file bonus 429 | if (((bitboard->pieces[wp] | bitboard->pieces[bp]) & bitboard->fileMasks[sq % 8]) == 0) 430 | { 431 | score -= QueenOpenFile; 432 | } 433 | else if ((bitboard->pieces[bp] & bitboard->fileMasks[sq % 8]) == 0) 434 | { 435 | score -= QueenSemiOpenFile; 436 | } 437 | } 438 | 439 | // ================================================================= 440 | // ======================= WHITE KING ============================== 441 | // ================================================================= 442 | 443 | int kingSq = (bitboard->pieces[wk]) ? __builtin_ctzll(bitboard->pieces[wk]) : 64; 444 | 445 | if (kingSq < 64 && board->material[black] <= EndGame_Material) 446 | { 447 | score += KingE[kingSq]; 448 | } 449 | else if (kingSq < 64) 450 | { 451 | score += KingO[kingSq]; 452 | } 453 | score += kingSafety(kingSq, white); 454 | 455 | // ================================================================= 456 | // ======================= BLACK KING ============================== 457 | // ================================================================= 458 | 459 | kingSq = (bitboard->pieces[wk]) ? __builtin_ctzll(bitboard->pieces[bk]) : 64; 460 | 461 | if (kingSq < 64 && board->material[white] <= EndGame_Material) 462 | { 463 | score -= KingE[Mirror64[kingSq]]; 464 | } 465 | else if (kingSq < 64) 466 | { 467 | score -= KingO[Mirror64[kingSq]]; 468 | } 469 | score -= kingSafety(kingSq, black); 470 | 471 | // ================================================================= 472 | // ============================ ADD ON ============================= 473 | // ================================================================= 474 | 475 | if (board->pieceCount[wb] >= 2) 476 | { 477 | score += BishopPair; 478 | } 479 | 480 | if (board->pieceCount[bb] >= 2) 481 | { 482 | score -= BishopPair; 483 | } 484 | 485 | return (board->side == white) ? score : -score; 486 | } 487 | -------------------------------------------------------------------------------- /evaluation.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | extern const int PawnTable[]; 3 | extern const int KnightTable[]; 4 | extern const int BishopTable[]; 5 | extern const int RookTable[]; 6 | extern const int KingO[]; 7 | extern const int KingE[]; 8 | 9 | extern const int BishopPair; 10 | extern const int PawnIsolated; 11 | extern const int PawnPassed[]; 12 | extern const int RookOpenFile; 13 | extern const int RookSemiOpenFile; 14 | extern const int QueenOpenFile; 15 | extern const int QueenSemiOpenFile; 16 | extern const int EndGame_Material; 17 | 18 | int evalPosition(); -------------------------------------------------------------------------------- /main.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | #include "uci.hpp" 5 | #include "utils.hpp" 6 | #include "polyglot.hpp" 7 | 8 | using namespace std; 9 | 10 | #include "board.hpp" 11 | 12 | // uint64_t key = 0x463b96181691fc9c; 13 | 14 | // uint16_t moves[3] = {5310, 1234, 5678}; 15 | // uint16_t weights[3] = {8012, 3456, 7890}; 16 | // uint32_t learns[3] = {0, 1, 2}; 17 | 18 | int main() 19 | { 20 | // string fine_70 = "8/k7/3p4/p2P1p2/P2P1P2/8/8/K7 w - -"; 21 | // string WAC_2 = "8/7p/5k2/5p2/p1p2P2/Pr1pPK2/1P1R3P/8 b - -"; 22 | // string LCT_1 = "r3kb1r/3n1pp1/p6p/2pPp2q/Pp2N3/3B2PP/1PQ2P2/R3K2R w KQkq -"; 23 | string path = "./performance.bin"; 24 | newGame(); 25 | loadPolyBook(path); 26 | UCI(); 27 | return 0; 28 | } 29 | 30 | // Fen: rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR w KQkq - 0 1 31 | // Castle: 15 32 | // Depth Time Ordering Nodes Best Move Best Score Line 33 | // 1 4 0.00 21 d2d4 30 d2d4 34 | // 2 5 86.36 92 d2d4 0 d2d4 d7d5 35 | // 3 7 82.35 722 d2d4 25 d2d4 d7d5 c1e3 36 | // 4 10 84.36 3658 d2d4 0 d2d4 d7d5 c1e3 c8f5 37 | // 5 17 83.26 12197 e2e4 25 e2e4 38 | // 6 71 79.87 84773 e2e4 5 e2e4 39 | // 7 188 81.29 243331 e2e4 22 e2e4 40 | // 8 1211 83.31 2230778 e2e4 5 e2e4 41 | // 9 2880 84.24 5804530 e2e4 25 e2e4 42 | // 10 19727 85.17 42211467 e2e4 10 e2e4 43 | 44 | -------------------------------------------------------------------------------- /makefile: -------------------------------------------------------------------------------- 1 | # Compiler 2 | CXX = g++ 3 | 4 | # Compiler flags 5 | CXXFLAGS = -std=c++11 -Wall -Wextra -Ofast 6 | 7 | # Executable name 8 | EXEC = chess 9 | 10 | # Source files 11 | SRCS = defs.cpp main.cpp board.cpp bitboard.cpp utils.cpp evaluation.cpp move.cpp movegen.cpp transpositionTable.cpp search.cpp perft.cpp uci.cpp polyglot.cpp 12 | 13 | # Header files 14 | HEADERS = defs.hpp board.hpp bitboard.hpp utils.hpp evaluation.hpp move.hpp movegen.hpp transpositionTable.hpp search.hpp perft.hpp uci.hpp polyglot.hpp 15 | 16 | # Object files 17 | OBJS = $(SRCS:.cpp=.o) 18 | 19 | # Default target 20 | all: $(EXEC) 21 | 22 | # Link object files to create the executable 23 | $(EXEC): $(OBJS) 24 | $(CXX) $(CXXFLAGS) -o $@ $^ 25 | 26 | # Compile source files into object files 27 | %.o: %.cpp $(HEADERS) 28 | $(CXX) $(CXXFLAGS) -c $< -o $@ 29 | 30 | # Clean up build files 31 | clean: 32 | rm -f $(OBJS) $(EXEC) 33 | 34 | .PHONY: all clean 35 | -------------------------------------------------------------------------------- /move.cpp: -------------------------------------------------------------------------------- 1 | #include "move.hpp" 2 | #include "utils.hpp" 3 | #include "bitboard.hpp" 4 | 5 | int enPassantFlag = 0x400000; 6 | int castleFlag = 0x800000; 7 | int pawnStartFlag = 0x1000000; 8 | 9 | int captureFlag = 0x3c000; 10 | int promotionFlag = 0x3c0000; 11 | 12 | int buildMove(int from, int to, int capturedPiece, int promotedPiece, int flag) 13 | { 14 | return from | (to << 7) | (capturedPiece << 14) | (promotedPiece << 18) | flag; 15 | } 16 | 17 | int moveFrom(int move) 18 | { 19 | return (move & 0x7f); 20 | } 21 | 22 | int moveTo(int move) 23 | { 24 | return (move >> 7) & 0x7f; 25 | } 26 | 27 | int moveCapturePiece(int move) 28 | { 29 | return (move >> 14) & 0xf; 30 | } 31 | int movePromotionPiece(int move) 32 | { 33 | return (move >> 18) & 0xf; 34 | } 35 | 36 | void moveDetail(int move) 37 | { 38 | if (!move) 39 | return; 40 | 41 | printf("from : %s\n", squareChar[moveFrom(move)]); 42 | printf("to : %s\n", squareChar[moveTo(move)]); 43 | printf("capture : %c\n", pieceChar[moveCapturePiece(move)]); 44 | printf("promotion : %c\n", pieceChar[movePromotionPiece(move)]); 45 | 46 | if (move & enPassantFlag) 47 | printf("flag : enPassant\n"); 48 | if (move & pawnStartFlag) 49 | printf("flag : pawn start\n"); 50 | if (move & castleFlag) 51 | printf("flag : castle\n"); 52 | printf("\n"); 53 | } 54 | 55 | void movePiece(int from, int to) 56 | { 57 | int piece = board->pieces[from]; 58 | 59 | hashPiece(from, piece); 60 | board->pieces[from] = empty; 61 | 62 | hashPiece(to, piece); 63 | board->pieces[to] = piece; 64 | 65 | bitboard->movePiece(piece, sq120To64[from], sq120To64[to]); 66 | } 67 | 68 | void addPiece(int sq, int piece) 69 | { 70 | if (board->pieces[sq] != empty) 71 | { 72 | // error 73 | } 74 | hashPiece(sq, piece); 75 | board->pieces[sq] = piece; 76 | board->material[pieceColor[piece]] += pieceValue[piece]; 77 | board->pieceCount[piece]++; 78 | 79 | bitboard->setBit(piece, sq120To64[sq]); 80 | } 81 | 82 | void removePiece(int sq) 83 | { 84 | int piece = board->pieces[sq]; 85 | hashPiece(sq, piece); 86 | board->pieces[sq] = empty; 87 | board->material[pieceColor[piece]] -= pieceValue[piece]; 88 | board->pieceCount[piece]--; 89 | 90 | bitboard->clearBit(piece, sq120To64[sq]); 91 | } 92 | 93 | 94 | int takeMove() { 95 | if (board->ply == 0) { 96 | return 0; 97 | } 98 | 99 | MoveInfo *moveInfo = board->popMoveFromHistory(); 100 | if (board->enPassantSq != noSq) { 101 | hashEnPassant(); 102 | } 103 | hashCastle(); 104 | 105 | board->fiftyMove = moveInfo->fiftyMove; 106 | board->enPassantSq = moveInfo->enPassantSq; 107 | board->castlePermission = moveInfo->castlePermission; 108 | board->checkSq = moveInfo->checkSq; 109 | 110 | if (board->enPassantSq != noSq) { 111 | hashEnPassant(); 112 | } 113 | hashCastle(); 114 | board->side ^= 1; 115 | hashSide(); 116 | 117 | const int move = moveInfo->move; 118 | const int from = moveFrom(move); 119 | const int to = moveTo(move); 120 | 121 | if (move & enPassantFlag) { 122 | if (board->side == white) { 123 | addPiece(to - 10, bp); 124 | } 125 | else { 126 | addPiece(to + 10, wp); 127 | } 128 | } 129 | else if (move & castleFlag) { 130 | switch (to) { 131 | case g1: movePiece(f1, h1); break; 132 | case c1: movePiece(d1, a1); break; 133 | 134 | case g8: movePiece(f8, h8); break; 135 | case c8: movePiece(d8, a8); break; 136 | 137 | default: break; 138 | } 139 | } 140 | 141 | 142 | movePiece(to, from); 143 | if (move & captureFlag) { 144 | addPiece(to, moveCapturePiece(move)); 145 | } 146 | if (move & promotionFlag) { 147 | removePiece(from); 148 | addPiece(from, pieceColor[movePromotionPiece(move)] == white ? wp : bp); 149 | } 150 | 151 | return move; 152 | } 153 | 154 | 155 | 156 | bool makeMove(int move) 157 | { 158 | if (!move) 159 | { 160 | // error 161 | return false; 162 | } 163 | const int from = moveFrom(move); 164 | const int to = moveTo(move); 165 | const int side = board->side; 166 | const int piece = board->pieces[from]; 167 | 168 | board->pushMoveToHistory(move); 169 | 170 | if (move & enPassantFlag) 171 | { 172 | if (side == white) 173 | { 174 | removePiece(to - 10); 175 | } 176 | else 177 | { 178 | removePiece(to + 10); 179 | } 180 | } 181 | else if (move & castleFlag) 182 | { 183 | switch (to) 184 | { 185 | case g1: movePiece(h1, f1); break; 186 | case c1: movePiece(a1, d1); break; 187 | 188 | case g8: movePiece(h8, f8); break; 189 | case c8: movePiece(a8, d8); break; 190 | 191 | default: break; 192 | } 193 | } 194 | // hash out 195 | if (board->enPassantSq != noSq) 196 | { 197 | hashEnPassant(); 198 | } 199 | hashCastle(); 200 | 201 | board->castlePermission &= CastlePermission[from]; 202 | board->castlePermission &= CastlePermission[to]; 203 | board->enPassantSq = noSq; 204 | 205 | // hash in 206 | hashCastle(); 207 | 208 | board->fiftyMove++; 209 | 210 | if (piece == wp || piece == bp) 211 | { 212 | board->fiftyMove = 0; 213 | if (move & pawnStartFlag) 214 | { 215 | if (side == white) 216 | { 217 | board->enPassantSq = from + 10; 218 | } 219 | else 220 | { 221 | board->enPassantSq = from - 10; 222 | } 223 | hashEnPassant(); 224 | } 225 | } 226 | 227 | if (move & captureFlag) 228 | { 229 | board->fiftyMove = 0; 230 | removePiece(to); 231 | } 232 | movePiece(from, to); 233 | 234 | if (move & promotionFlag) 235 | { 236 | removePiece(to); 237 | addPiece(to, movePromotionPiece(move)); 238 | } 239 | 240 | board->side ^= 1; 241 | hashSide(); 242 | 243 | int kingOnSq = __builtin_ctzll(bitboard->pieces[Kings[side]]); 244 | int enemyKingOnSq = __builtin_ctzll(bitboard->pieces[Kings[board->side]]); 245 | 246 | if (isUnderAttack(kingOnSq, board->side)) 247 | { 248 | takeMove(); 249 | return false; 250 | } 251 | 252 | if (isUnderAttack(enemyKingOnSq, side)) 253 | { 254 | board->checkSq = sq64To120[enemyKingOnSq]; 255 | } 256 | else 257 | { 258 | board->checkSq = noSq; 259 | } 260 | return true; 261 | } 262 | 263 | 264 | void makeNullMove() { 265 | if(board->checkSq != noSq) return; 266 | 267 | board->pushMoveToHistory(0); 268 | board->enPassantSq = noSq; 269 | board->side ^= 1; 270 | hashSide(); 271 | } 272 | 273 | int takeNullMove(){ 274 | if (board->ply == 0) { 275 | return 0; 276 | } 277 | 278 | MoveInfo *moveInfo = board->popMoveFromHistory(); 279 | 280 | 281 | if(board->enPassantSq != noSq) { 282 | hashEnPassant(); 283 | } 284 | 285 | board->castlePermission = moveInfo->castlePermission; 286 | board->fiftyMove = moveInfo->fiftyMove; 287 | board->enPassantSq = moveInfo->enPassantSq; 288 | board->checkSq = moveInfo->checkSq; 289 | 290 | if(board->enPassantSq != noSq) { 291 | hashEnPassant(); 292 | } 293 | board->side ^= 1; 294 | hashSide(); 295 | 296 | return 0; 297 | } 298 | 299 | -------------------------------------------------------------------------------- /move.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | // move structure set Mask 4 | // 0000 0000 0000 0000 0000 0111 1111 0x7f from 5 | // 0000 0000 0000 0011 1111 1000 0000 0x7f to 6 | // 0000 0000 0011 1100 0000 0000 0000 0xf capture piece 7 | // 0000 0011 1100 0000 0000 0000 0000 0xf promoted piece 8 | // 0000 0100 0000 0000 0000 0000 0000 0x40000 enpassant 9 | // 0000 1000 0000 0000 0000 0000 0000 0x80000 castle 10 | // 0001 0000 0000 0000 0000 0000 0000 0x1000000 pawnstart 11 | 12 | // flags 🚩 13 | extern int enPassantFlag; 14 | extern int castleFlag; 15 | extern int pawnStartFlag; 16 | 17 | extern int captureFlag; 18 | extern int promotionFlag; 19 | 20 | int buildMove(int from, int to, int capturedPiece, int promotedPiece, int flag); 21 | int moveFrom(int move); 22 | int moveTo(int move); 23 | int moveCapturePiece(int move); 24 | int movePromotionPiece(int move); 25 | void moveDetail(int move); 26 | 27 | void movePiece(int from, int to); 28 | void addPiece(int sq,int piece); 29 | void removePiece(int sq); 30 | 31 | bool makeMove(int move); 32 | int takeMove(); 33 | void makeNullMove(); 34 | int takeNullMove(); -------------------------------------------------------------------------------- /movegen.cpp: -------------------------------------------------------------------------------- 1 | #include "defs.hpp" 2 | #include "board.hpp" 3 | #include "bitboard.hpp" 4 | #include "utils.hpp" 5 | #include "move.hpp" 6 | #include "search.hpp" 7 | #include "movegen.hpp" 8 | #include 9 | 10 | std::vector> moves; 11 | 12 | // MvvLva = [victim][attacker] 13 | int MvvLva[13][13] = { 14 | {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, 15 | {0, 105, 102, 104, 103, 101, 100, 105, 102, 104, 103, 101, 100}, 16 | {0, 405, 402, 404, 403, 401, 400, 405, 402, 404, 403, 401, 400}, 17 | {0, 205, 202, 204, 203, 201, 200, 205, 202, 204, 203, 201, 200}, 18 | {0, 305, 302, 304, 303, 301, 300, 305, 302, 304, 303, 301, 300}, 19 | {0, 505, 502, 504, 503, 501, 500, 505, 502, 504, 503, 501, 500}, 20 | {0, 605, 602, 604, 603, 601, 600, 605, 602, 604, 603, 601, 600}, 21 | {0, 105, 102, 104, 103, 101, 100, 105, 102, 104, 103, 101, 100}, 22 | {0, 405, 402, 404, 403, 401, 400, 405, 402, 404, 403, 401, 400}, 23 | {0, 205, 202, 204, 203, 201, 200, 205, 202, 204, 203, 201, 200}, 24 | {0, 305, 302, 304, 303, 301, 300, 305, 302, 304, 303, 301, 300}, 25 | {0, 505, 502, 504, 503, 501, 500, 505, 502, 504, 503, 501, 500}, 26 | {0, 605, 602, 604, 603, 601, 600, 605, 602, 604, 603, 601, 600}, 27 | }; 28 | 29 | void addCaptureMove(int move) 30 | { 31 | int victim = moveCapturePiece(move); 32 | int attacker = board->pieces[moveFrom(move)]; 33 | int score = MvvLva[victim][attacker] + 1000000; 34 | moves.push_back({move, score}); 35 | } 36 | 37 | void addQuiteMove(int move) 38 | { 39 | int score = 0; 40 | if (searchController->ply < 0 && searchController->ply >= 64) 41 | { 42 | printf("---- %d\n", searchController->ply); 43 | } 44 | if (searchController->killers[searchController->ply][0] == move) 45 | { 46 | score = 900000; 47 | } 48 | else if (searchController->killers[searchController->ply][1] == move) 49 | { 50 | score = 800000; 51 | } 52 | else 53 | { 54 | int piece = board->pieces[moveFrom(move)]; 55 | int toSq = moveTo(move); 56 | score = searchController->history[piece][toSq]; 57 | } 58 | 59 | moves.push_back({move, score}); 60 | } 61 | 62 | void addEnPassantMove(int move) 63 | { 64 | // MvvLva[Pieces.wp][Pieces.bp] == MvvLva[Pieces.bp][Pieces.wp] 65 | int score = MvvLva[wp][bp] + 1000000; 66 | moves.push_back({move, score}); 67 | } 68 | 69 | void addWhitePawnQuietMove(int from, int to) 70 | { 71 | // handling promotion move 72 | if (rankOf(to) == rank8) 73 | { 74 | addQuiteMove(buildMove(from, to, 0, wq, 0)); 75 | addQuiteMove(buildMove(from, to, 0, wr, 0)); 76 | addQuiteMove(buildMove(from, to, 0, wb, 0)); 77 | addQuiteMove(buildMove(from, to, 0, wn, 0)); 78 | } 79 | else 80 | { 81 | addQuiteMove(buildMove(from, to, 0, 0, 0)); 82 | } 83 | } 84 | void addBlackPawnQuietMove(int from, int to) 85 | { 86 | // handling promotion move 87 | if (rankOf(to) == rank1) 88 | { 89 | addQuiteMove(buildMove(from, to, 0, bq, 0)); 90 | addQuiteMove(buildMove(from, to, 0, br, 0)); 91 | addQuiteMove(buildMove(from, to, 0, bb, 0)); 92 | addQuiteMove(buildMove(from, to, 0, bn, 0)); 93 | } 94 | else 95 | { 96 | addQuiteMove(buildMove(from, to, 0, 0, 0)); 97 | } 98 | } 99 | 100 | void addWhiteCaptureMove(int from, int to, int capture) 101 | { 102 | // handling promotion move 103 | if (rankOf(to) == rank8) 104 | { 105 | addCaptureMove(buildMove(from, to, capture, wq, 0)); 106 | addCaptureMove(buildMove(from, to, capture, wr, 0)); 107 | addCaptureMove(buildMove(from, to, capture, wb, 0)); 108 | addCaptureMove(buildMove(from, to, capture, wn, 0)); 109 | } 110 | else 111 | { 112 | addCaptureMove(buildMove(from, to, capture, 0, 0)); 113 | } 114 | } 115 | void addBlackCaptureMove(int from, int to, int capture) 116 | { 117 | // handling promotion move 118 | if (rankOf(to) == rank1) 119 | { 120 | addCaptureMove(buildMove(from, to, capture, bq, 0)); 121 | addCaptureMove(buildMove(from, to, capture, br, 0)); 122 | addCaptureMove(buildMove(from, to, capture, bb, 0)); 123 | addCaptureMove(buildMove(from, to, capture, bn, 0)); 124 | } 125 | else 126 | { 127 | addCaptureMove(buildMove(from, to, capture, 0, 0)); 128 | } 129 | } 130 | 131 | void genNonSlidingMoves(bool capturesOnly) 132 | { 133 | U64 friendlyPiecesBitboard = bitboard->getPieces(board->side); 134 | U64 enemyPiecesBitboard = bitboard->getPieces(board->side ^ 1); 135 | 136 | for (int piece : nonSlidingPieces[board->side]) 137 | { 138 | U64 pieceBitboard = bitboard->pieces[piece]; 139 | 140 | // traverse each square where these pieces are 141 | while (pieceBitboard) 142 | { 143 | int sq = __builtin_ctzll(pieceBitboard); 144 | pieceBitboard &= pieceBitboard - 1; 145 | 146 | U64 attacksPattern = (pieceType[piece] == 'n') ? bitboard->knightAttacks[sq] : bitboard->kingAttacks[sq]; 147 | attacksPattern &= ~friendlyPiecesBitboard; 148 | 149 | while (attacksPattern) 150 | { 151 | int targetSq = sq64To120[__builtin_ctzll(attacksPattern)]; 152 | if (enemyPiecesBitboard & (1ULL << sq120To64[targetSq])) 153 | { 154 | addCaptureMove(buildMove(sq64To120[sq], targetSq, board->pieces[targetSq], 0, 0)); 155 | } 156 | else if (!capturesOnly) 157 | { 158 | addQuiteMove(buildMove(sq64To120[sq], targetSq, 0, 0, 0)); 159 | } 160 | 161 | attacksPattern &= attacksPattern - 1; 162 | } 163 | } 164 | } 165 | } 166 | 167 | void genSlidingMoves(bool capturesOnly) 168 | { 169 | U64 friendlyPiecesBitboard = bitboard->getPieces(board->side); 170 | U64 enemyPiecesBitboard = bitboard->getPieces(board->side ^ 1); 171 | 172 | for (int piece : slidingPieces[board->side]) 173 | { 174 | U64 pieceBitboard = bitboard->pieces[piece]; 175 | // traverse each square 176 | while (pieceBitboard) 177 | { 178 | int sq = __builtin_ctzll(pieceBitboard); 179 | pieceBitboard &= pieceBitboard - 1; 180 | U64 attacksPattern = 0ULL; 181 | 182 | switch (pieceType[piece]) 183 | { 184 | case 'r': 185 | attacksPattern = getRookAttacks(sq); 186 | break; 187 | case 'b': 188 | attacksPattern = getBishopAttacks(sq); 189 | break; 190 | case 'q': 191 | attacksPattern = getBishopAttacks(sq) | getRookAttacks(sq); 192 | break; 193 | default: 194 | break; 195 | } 196 | // remove friendly blockers 197 | attacksPattern &= ~friendlyPiecesBitboard; 198 | 199 | // traverse the squares where these pieces can move 200 | while (attacksPattern) 201 | { 202 | int targetSq = sq64To120[__builtin_ctzll(attacksPattern)]; 203 | if (enemyPiecesBitboard & (1ULL << sq120To64[targetSq])) 204 | { 205 | addCaptureMove(buildMove(sq64To120[sq], targetSq, board->pieces[targetSq], 0, 0)); 206 | } 207 | else if (!capturesOnly) 208 | { 209 | addQuiteMove(buildMove(sq64To120[sq], targetSq, 0, 0, 0)); 210 | } 211 | 212 | attacksPattern &= attacksPattern - 1; 213 | } 214 | } 215 | } 216 | } 217 | 218 | std::vector> &generateMoves() 219 | { 220 | if (moves.capacity() < 218) 221 | { 222 | moves.reserve(218); 223 | } 224 | moves.resize(0); 225 | 226 | if (board->side == white) 227 | { 228 | U64 wpBitboard = bitboard->pieces[wp]; 229 | // loop white pawn 230 | while (wpBitboard) 231 | { 232 | int sq = sq64To120[__builtin_ctzll(wpBitboard)]; 233 | wpBitboard &= wpBitboard - 1; 234 | 235 | if (board->pieces[sq + 10] == empty) 236 | { 237 | addWhitePawnQuietMove(sq, sq + 10); 238 | if (board->pieces[sq + 20] == empty && rankOf(sq) == rank2) 239 | { 240 | addQuiteMove(buildMove(sq, sq + 20, 0, 0, pawnStartFlag)); 241 | } 242 | } 243 | 244 | // add capture move 245 | if (board->pieces[sq + 9] != offBoard && pieceColor[board->pieces[sq + 9]] == black) 246 | { 247 | addWhiteCaptureMove(sq, sq + 9, board->pieces[sq + 9]); 248 | } 249 | if (board->pieces[sq + 11] != offBoard && pieceColor[board->pieces[sq + 11]] == black) 250 | { 251 | addWhiteCaptureMove(sq, sq + 11, board->pieces[sq + 11]); 252 | } 253 | 254 | // add enpassant move 255 | if (sq + 9 == board->enPassantSq) 256 | { 257 | addEnPassantMove(buildMove(sq, sq + 9, 0, 0, enPassantFlag)); 258 | } 259 | if (sq + 11 == board->enPassantSq) 260 | { 261 | addEnPassantMove(buildMove(sq, sq + 11, 0, 0, enPassantFlag)); 262 | } 263 | 264 | } // end loop 265 | 266 | // CASTLING 267 | if (board->castlePermission & castle_K) 268 | { 269 | if (board->pieces[f1] == empty && board->pieces[g1] == empty) 270 | { 271 | if (board->checkSq == noSq && !isUnderAttack(sq120To64[f1], black)) 272 | { 273 | addQuiteMove(buildMove(e1, g1, 0, 0, castleFlag)); 274 | } 275 | } 276 | } 277 | if (board->castlePermission & castle_Q) 278 | { 279 | if (board->pieces[d1] == empty && board->pieces[c1] == empty && board->pieces[b1] == empty) 280 | { 281 | if (board->checkSq == noSq && !isUnderAttack(sq120To64[d1], black)) 282 | { 283 | addQuiteMove(buildMove(e1, c1, 0, 0, castleFlag)); 284 | } 285 | } 286 | } 287 | } 288 | else 289 | { 290 | U64 bpBitboard = bitboard->pieces[bp]; 291 | // loop black pawn 292 | while (bpBitboard) 293 | { 294 | int sq = sq64To120[__builtin_ctzll(bpBitboard)]; 295 | bpBitboard &= bpBitboard - 1; 296 | 297 | if (board->pieces[sq - 10] == empty) 298 | { 299 | addBlackPawnQuietMove(sq, sq - 10); 300 | 301 | if (board->pieces[sq - 20] == empty && rankOf(sq) == rank7) 302 | { 303 | addQuiteMove(buildMove(sq, sq - 20, 0, 0, pawnStartFlag)); 304 | } 305 | } 306 | 307 | // add capture move 308 | if (board->pieces[sq - 9] != offBoard && pieceColor[board->pieces[sq - 9]] == white) 309 | { 310 | addBlackCaptureMove(sq, sq - 9, board->pieces[sq - 9]); 311 | } 312 | if (board->pieces[sq - 11] != offBoard && pieceColor[board->pieces[sq - 11]] == white) 313 | { 314 | addBlackCaptureMove(sq, sq - 11, board->pieces[sq - 11]); 315 | } 316 | 317 | // add enpassant move 318 | if (sq - 9 == board->enPassantSq) 319 | { 320 | addEnPassantMove(buildMove(sq, sq - 9, 0, 0, enPassantFlag)); 321 | } 322 | if (sq - 11 == board->enPassantSq) 323 | { 324 | addEnPassantMove(buildMove(sq, sq - 11, 0, 0, enPassantFlag)); 325 | } 326 | } 327 | 328 | // castling 329 | if (board->castlePermission & castle_k) 330 | { 331 | if (board->pieces[f8] == empty && board->pieces[g8] == empty) 332 | { 333 | if (board->checkSq == noSq && !isUnderAttack(sq120To64[f8], white)) 334 | { 335 | addQuiteMove(buildMove(e8, g8, 0, 0, castleFlag)); 336 | } 337 | } 338 | } 339 | if (board->castlePermission & castle_q) 340 | { 341 | if (board->pieces[d8] == empty && board->pieces[c8] == empty && board->pieces[b8] == empty) 342 | { 343 | if (board->checkSq == noSq && !isUnderAttack(sq120To64[d8], white)) 344 | { 345 | addQuiteMove(buildMove(e8, c8, 0, 0, castleFlag)); 346 | } 347 | } 348 | } 349 | } 350 | genSlidingMoves(); 351 | genNonSlidingMoves(); 352 | return moves; 353 | } 354 | 355 | std::vector> &generateCaptureMoves() 356 | { 357 | if (moves.capacity() < 218) 358 | { 359 | moves.reserve(218); 360 | } 361 | moves.resize(0); 362 | 363 | if (board->side == white) 364 | { 365 | U64 wpBitboard = bitboard->pieces[wp]; 366 | // loop white pawn 367 | while (wpBitboard) 368 | { 369 | int sq = sq64To120[__builtin_ctzll(wpBitboard)]; 370 | wpBitboard &= wpBitboard - 1; 371 | 372 | // add capture move 373 | if (board->pieces[sq + 9] != offBoard && pieceColor[board->pieces[sq + 9]] == black) 374 | { 375 | addWhiteCaptureMove(sq, sq + 9, board->pieces[sq + 9]); 376 | } 377 | if (board->pieces[sq + 11] != offBoard && pieceColor[board->pieces[sq + 11]] == black) 378 | { 379 | addWhiteCaptureMove(sq, sq + 11, board->pieces[sq + 11]); 380 | } 381 | 382 | } // end loop 383 | } 384 | else 385 | { 386 | U64 bpBitboard = bitboard->pieces[bp]; 387 | // loop black pawn 388 | while (bpBitboard) 389 | { 390 | int sq = sq64To120[__builtin_ctzll(bpBitboard)]; 391 | bpBitboard &= bpBitboard - 1; 392 | 393 | // add capture move 394 | if (board->pieces[sq - 9] != offBoard && pieceColor[board->pieces[sq - 9]] == white) 395 | { 396 | addBlackCaptureMove(sq, sq - 9, board->pieces[sq - 9]); 397 | } 398 | if (board->pieces[sq - 11] != offBoard && pieceColor[board->pieces[sq - 11]] == white) 399 | { 400 | addBlackCaptureMove(sq, sq - 11, board->pieces[sq - 11]); 401 | } 402 | } 403 | } 404 | genSlidingMoves(true); 405 | genNonSlidingMoves(true); 406 | return moves; 407 | } 408 | -------------------------------------------------------------------------------- /movegen.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | void addCaptureMove(int move); 4 | void addQuiteMove(int move); 5 | void addEnPassantMove(int move); 6 | void addWhitePawnQuietMove(int from,int to); 7 | void addBlackPawnQuietMove(int from, int to); 8 | void addWhiteCaptureMove(int from,int to,int capture); 9 | void addBlackCaptureMove(int from,int to,int capture); 10 | 11 | void genNonSlidingMoves(bool capturesOnly = false); 12 | void genSlidingMoves(bool capturesOnly = false); 13 | 14 | std::vector> &generateMoves(); 15 | std::vector> &generateCaptureMoves(); 16 | -------------------------------------------------------------------------------- /output.bin: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/abhijeetSinghRajput/chess-engine-cpp/bb4bfca38f35827ea40fc31d67f8d6546e85b2d3/output.bin -------------------------------------------------------------------------------- /performance.bin: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/abhijeetSinghRajput/chess-engine-cpp/bb4bfca38f35827ea40fc31d67f8d6546e85b2d3/performance.bin -------------------------------------------------------------------------------- /perft.cpp: -------------------------------------------------------------------------------- 1 | #include "defs.hpp" 2 | #include "move.hpp" 3 | #include "movegen.hpp" 4 | #include "board.hpp" 5 | #include 6 | #include 7 | #include 8 | 9 | U64 perft(int depth) 10 | { 11 | if (depth <= 0) return 1; 12 | std::vector> moves = generateMoves(); 13 | U64 count = 0; 14 | for (auto& pair : moves) 15 | { 16 | int move = pair.first; 17 | if (makeMove(move) == false) 18 | continue; 19 | count += perft(depth - 1); 20 | takeMove(); 21 | } 22 | return count; 23 | } 24 | 25 | 26 | void perftTest(int depth) 27 | { 28 | int moveCount = 0; 29 | U64 totalNodeSeared = 0; 30 | std::vector> moves = generateMoves(); 31 | printf("go to perft %d\n", depth); 32 | long long startTime = getCurrTime(); 33 | for (auto &pair : moves) 34 | { 35 | int move = pair.first; 36 | if (makeMove(move) == false) 37 | { 38 | continue; 39 | } 40 | 41 | int count = perft(depth - 1); 42 | takeMove(); 43 | 44 | totalNodeSeared += count; 45 | std::cout << std::setw(2) << ++moveCount << " " << moveStr(move) << " " << count <<" " << getCurrTime() - startTime <<" ms" << std::endl; 46 | } 47 | std::cout << "Nodes searched: " << totalNodeSeared << std::endl; 48 | std::cout << "Total time: " << getCurrTime() - startTime; 49 | } 50 | -------------------------------------------------------------------------------- /perft.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "defs.hpp" 3 | 4 | U64 perft(int depth); 5 | void perftTest(int depth); 6 | -------------------------------------------------------------------------------- /polyglot.cpp: -------------------------------------------------------------------------------- 1 | #include "polyglot.hpp" 2 | #include "board.hpp" 3 | #include "utils.hpp" 4 | #include 5 | #include 6 | #include 7 | 8 | 9 | // endian_swap_u32 visual representation 10 | // 11111111 00000000 00000000 00000000 00000000 00000000 00000000 11111111 11 | // 00000000 11111111 00000000 00000000 00000000 00000000 11111111 00000000 12 | // 00000000 00000000 11111111 00000000 00000000 11111111 00000000 00000000 13 | // 00000000 00000000 00000000 11111111 11111111 00000000 00000000 00000000 14 | 15 | // swap the byte order of a 16-bit unsigned integer 16 | uint16_t endian_swap_u16(uint16_t value) 17 | { 18 | return (value >> 8) | (value << 8); 19 | } 20 | 21 | // swap the byte order of a 32-bit unsigned integer 22 | uint32_t endian_swap_u32(uint32_t value) 23 | { 24 | return ((value >> 24) & 0x000000ff) | 25 | ((value >> 8) & 0x0000ff00) | 26 | ((value << 8) & 0x00ff0000) | 27 | ((value << 24) & 0xff000000); 28 | } 29 | 30 | // swap the byte order of a 64-bit unsigned integer 31 | uint64_t endian_swap_u64(uint64_t value) 32 | { 33 | return ((value >> 56) & 0x00000000000000ff) | 34 | ((value >> 40) & 0x000000000000ff00) | 35 | ((value >> 24) & 0x0000000000ff0000) | 36 | ((value >> 8) & 0x00000000ff000000) | 37 | ((value << 8) & 0x000000ff00000000) | 38 | ((value << 24) & 0x0000ff0000000000) | 39 | ((value << 40) & 0x00ff000000000000) | 40 | ((value << 56) & 0xff00000000000000); 41 | } 42 | 43 | bool hasPawnToCapture() 44 | { 45 | int ep = board->enPassantSq; 46 | if (board->side == white) 47 | { 48 | if (board->pieces[ep - 9] == wp || board->pieces[ep - 11] == wp) 49 | { 50 | return true; 51 | } 52 | } 53 | else 54 | { 55 | if (board->pieces[ep + 9] == bp || board->pieces[ep + 11] == bp) 56 | { 57 | return true; 58 | } 59 | } 60 | return false; 61 | } 62 | 63 | U64 getPolyKey() 64 | { 65 | U64 polyKey = 0ULL; 66 | int piece; 67 | 68 | for (int sq = 0; sq < 64; ++sq) 69 | { 70 | piece = board->pieces[sq64To120[sq]]; 71 | if (piece != empty) 72 | { 73 | polyKey ^= piecePolyKeys[polyPieces[piece]][sq]; 74 | } 75 | } 76 | 77 | if (board->castlePermission & castle_K) polyKey ^= castlePolyKeys[0]; 78 | if (board->castlePermission & castle_Q) polyKey ^= castlePolyKeys[1]; 79 | if (board->castlePermission & castle_k) polyKey ^= castlePolyKeys[2]; 80 | if (board->castlePermission & castle_q) polyKey ^= castlePolyKeys[3]; 81 | 82 | if (board->side == white) polyKey ^= sidePolyKey; 83 | if (board->enPassantSq != noSq && hasPawnToCapture()) 84 | { 85 | printf(" 1 "); 86 | polyKey ^= enPassantPolyKeys[fileOf(board->enPassantSq)]; 87 | } 88 | 89 | return polyKey; 90 | } 91 | 92 | #include 93 | std::unordered_map> openingBook; 94 | 95 | void loadPolyBook(const std::string &path) 96 | { 97 | // open the .bin file 98 | std::ifstream file(path, std::ios::binary | std::ios::ate); 99 | 100 | // check if it succefully opened 101 | if (!file) 102 | { 103 | std::cerr << "\033[30mgetting error while reading\033[0m" << std::endl; 104 | return; 105 | } 106 | 107 | std::streampos fileSize = file.tellg(); 108 | file.seekg(0, std::ios::beg); 109 | 110 | if (fileSize < 16) 111 | { 112 | std::cerr << "\033[30mno entries found\033[0m" << std::endl; 113 | return; 114 | } 115 | 116 | size_t entriesSize = fileSize / 16; 117 | std::cout << entriesSize << " entries found in file" << std::endl; 118 | 119 | char buffer[16]; 120 | U64 key; 121 | polyEntry entry; 122 | 123 | while (file.read(buffer, sizeof(buffer))) { 124 | std::memcpy(&key, buffer, sizeof(key)); 125 | std::memcpy(&entry, buffer + sizeof(key), sizeof(polyEntry)); 126 | openingBook[endian_swap_u64(key)].push_back(entry); 127 | } 128 | 129 | std::cout << openingBook.size() << " position loaded in Opening Book" << std::endl; 130 | file.close(); 131 | } 132 | 133 | void readBook() 134 | { 135 | if (openingBook.empty()) 136 | { 137 | std::cout << "book is empty" << std::endl; 138 | return; 139 | } 140 | U64 currPolyKey = getPolyKey(); 141 | if(openingBook.find(currPolyKey) == openingBook.end()){ 142 | std::cout << "no move found for this position" << std::endl; 143 | return; 144 | } 145 | printf("\nbook key: %llx\n", currPolyKey); 146 | for (auto &entry : openingBook[currPolyKey]) 147 | { 148 | printf("move: %-5s weight: %-5d learn: %-10d\n", 149 | extractPolyMove(endian_swap_u16(entry.move)).c_str(), 150 | endian_swap_u16(entry.weight), 151 | endian_swap_u32(entry.learn) 152 | ); 153 | } 154 | std::cout< moves; 158 | U64 currPolyKey = getPolyKey(); 159 | if(!openingBook.empty() || openingBook.find(currPolyKey) != openingBook.end()){ 160 | for(auto &entry : openingBook[currPolyKey]){ 161 | moves.push_back(extractPolyMove(endian_swap_u16(entry.move))); 162 | } 163 | } 164 | if(moves.empty()) return 0; 165 | // Seed the random number generator 166 | std::srand(std::time(0)); 167 | int randIndex = std::rand() % moves.size(); 168 | 169 | int move = parseMove(moves[randIndex]); 170 | return move; 171 | } 172 | 173 | // MOVE 174 | 175 | // bits meaning promotion pieces 176 | // =================================== ================ 177 | // 0,1,2 to file none 0 178 | // 3,4,5 to row knight 1 179 | // 6,7,8 from file bishop 2 180 | // 9,10,11 from row rook 3 181 | // 12,13,14 promotion piece queen 4 182 | 183 | std::string extractPolyMove(uint16_t move) 184 | { 185 | // Extract components from the move using bit manipulation 186 | int toFile = (move & 0x7); // bits 0,1,2 187 | int toRow = ((move >> 3) & 0x7); // bits 3,4,5 188 | int fromFile = ((move >> 6) & 0x7); // bits 6,7,8 189 | int fromRow = ((move >> 9) & 0x7); // bits 9,10,11 190 | int promotionPiece = ((move >> 12) & 0x7); // bits 12,13,14 191 | 192 | // Convert the extracted bits into meaningful chess move components 193 | char fromFileChar = 'a' + fromFile; 194 | char toFileChar = 'a' + toFile; 195 | int fromRank = fromRow + 1; 196 | int toRank = toRow + 1; 197 | 198 | std::string promotion; 199 | switch (promotionPiece) 200 | { 201 | case 1: promotion = "q"; break; 202 | case 2: promotion = "r"; break; 203 | case 3: promotion = "b"; break; 204 | case 4: promotion = "n"; break; 205 | default: promotion = ""; 206 | break; 207 | } 208 | 209 | // Construct and return the human-readable move notation 210 | std::string result = ""; 211 | result += fromFileChar; 212 | result += std::to_string(fromRank); 213 | result += toFileChar; 214 | result += std::to_string(toRank); 215 | result += promotion; 216 | 217 | return result; 218 | } 219 | 220 | // Castling moves 221 | // white short e1h1 222 | // white long e1a1 223 | // black short e8h8 224 | // black long e8a8 -------------------------------------------------------------------------------- /polyglot.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "defs.hpp" 3 | 4 | U64 getPolyKey(); 5 | void loadPolyBook(const std::string &path); 6 | std::string extractPolyMove(uint16_t move); 7 | int getRandBookMove(); 8 | void readBook(); 9 | 10 | const U64 enPassantPolyKeys[8] = { 11 | 0x70CC73D90BC26E24Ull, 0xE21A6B35DF0C3AD7Ull, 0x003A93D8B2806962Ull, 0x1C99DED33CB890A1Ull, 12 | 0xCF3145DE0ADD4289Ull, 0xD0E4427A5514FB72Ull, 0x77C621CC9FB3A483Ull, 0x67A34DAC4356550BUll, 13 | }; 14 | 15 | const U64 castlePolyKeys[4] = { 16 | 0x31D71DCE64B2C310Ull, 0xF165B587DF898190Ull, 0xA57E6339DD2CF3A0Ull, 0x1EF6E6DBB1961EC9Ull, 17 | }; 18 | const U64 piecePolyKeys[12][64] = { 19 | 0x9D39247E33776D41Ull, 0x2AF7398005AAA5C7Ull, 0x44DB015024623547Ull, 0x9C15F73E62A76AE2Ull, 20 | 0x75834465489C0C89Ull, 0x3290AC3A203001BFUll, 0x0FBBAD1F61042279Ull, 0xE83A908FF2FB60CAUll, 21 | 0x0D7E765D58755C10Ull, 0x1A083822CEAFE02DUll, 0x9605D5F0E25EC3B0Ull, 0xD021FF5CD13A2ED5Ull, 22 | 0x40BDF15D4A672E32Ull, 0x011355146FD56395Ull, 0x5DB4832046F3D9E5Ull, 0x239F8B2D7FF719CCUll, 23 | 0x05D1A1AE85B49AA1Ull, 0x679F848F6E8FC971Ull, 0x7449BBFF801FED0BUll, 0x7D11CDB1C3B7ADF0Ull, 24 | 0x82C7709E781EB7CCUll, 0xF3218F1C9510786CUll, 0x331478F3AF51BBE6Ull, 0x4BB38DE5E7219443Ull, 25 | 0xAA649C6EBCFD50FCUll, 0x8DBD98A352AFD40BUll, 0x87D2074B81D79217Ull, 0x19F3C751D3E92AE1Ull, 26 | 0xB4AB30F062B19ABFUll, 0x7B0500AC42047AC4Ull, 0xC9452CA81A09D85DUll, 0x24AA6C514DA27500Ull, 27 | 0x4C9F34427501B447Ull, 0x14A68FD73C910841Ull, 0xA71B9B83461CBD93Ull, 0x03488B95B0F1850FUll, 28 | 0x637B2B34FF93C040Ull, 0x09D1BC9A3DD90A94Ull, 0x3575668334A1DD3BUll, 0x735E2B97A4C45A23Ull, 29 | 0x18727070F1BD400BUll, 0x1FCBACD259BF02E7Ull, 0xD310A7C2CE9B6555Ull, 0xBF983FE0FE5D8244Ull, 30 | 0x9F74D14F7454A824Ull, 0x51EBDC4AB9BA3035Ull, 0x5C82C505DB9AB0FAUll, 0xFCF7FE8A3430B241Ull, 31 | 0x3253A729B9BA3DDEUll, 0x8C74C368081B3075Ull, 0xB9BC6C87167C33E7Ull, 0x7EF48F2B83024E20Ull, 32 | 0x11D505D4C351BD7FUll, 0x6568FCA92C76A243Ull, 0x4DE0B0F40F32A7B8Ull, 0x96D693460CC37E5DUll, 33 | 0x42E240CB63689F2FUll, 0x6D2BDCDAE2919661Ull, 0x42880B0236E4D951Ull, 0x5F0F4A5898171BB6Ull, 34 | 0x39F890F579F92F88Ull, 0x93C5B5F47356388BUll, 0x63DC359D8D231B78Ull, 0xEC16CA8AEA98AD76Ull, 35 | 0x5355F900C2A82DC7Ull, 0x07FB9F855A997142Ull, 0x5093417AA8A7ED5EUll, 0x7BCBC38DA25A7F3CUll, 36 | 0x19FC8A768CF4B6D4Ull, 0x637A7780DECFC0D9Ull, 0x8249A47AEE0E41F7Ull, 0x79AD695501E7D1E8Ull, 37 | 0x14ACBAF4777D5776Ull, 0xF145B6BECCDEA195Ull, 0xDABF2AC8201752FCUll, 0x24C3C94DF9C8D3F6Ull, 38 | 0xBB6E2924F03912EAUll, 0x0CE26C0B95C980D9Ull, 0xA49CD132BFBF7CC4Ull, 0xE99D662AF4243939Ull, 39 | 0x27E6AD7891165C3FUll, 0x8535F040B9744FF1Ull, 0x54B3F4FA5F40D873Ull, 0x72B12C32127FED2BUll, 40 | 0xEE954D3C7B411F47Ull, 0x9A85AC909A24EAA1Ull, 0x70AC4CD9F04F21F5Ull, 0xF9B89D3E99A075C2Ull, 41 | 0x87B3E2B2B5C907B1Ull, 0xA366E5B8C54F48B8Ull, 0xAE4A9346CC3F7CF2Ull, 0x1920C04D47267BBDUll, 42 | 0x87BF02C6B49E2AE9Ull, 0x092237AC237F3859Ull, 0xFF07F64EF8ED14D0Ull, 0x8DE8DCA9F03CC54EUll, 43 | 0x9C1633264DB49C89Ull, 0xB3F22C3D0B0B38EDUll, 0x390E5FB44D01144BUll, 0x5BFEA5B4712768E9Ull, 44 | 0x1E1032911FA78984Ull, 0x9A74ACB964E78CB3Ull, 0x4F80F7A035DAFB04Ull, 0x6304D09A0B3738C4Ull, 45 | 0x2171E64683023A08Ull, 0x5B9B63EB9CEFF80CUll, 0x506AACF489889342Ull, 0x1881AFC9A3A701D6Ull, 46 | 0x6503080440750644Ull, 0xDFD395339CDBF4A7Ull, 0xEF927DBCF00C20F2Ull, 0x7B32F7D1E03680ECUll, 47 | 0xB9FD7620E7316243Ull, 0x05A7E8A57DB91B77Ull, 0xB5889C6E15630A75Ull, 0x4A750A09CE9573F7Ull, 48 | 0xCF464CEC899A2F8AUll, 0xF538639CE705B824Ull, 0x3C79A0FF5580EF7FUll, 0xEDE6C87F8477609DUll, 49 | 0x799E81F05BC93F31Ull, 0x86536B8CF3428A8CUll, 0x97D7374C60087B73Ull, 0xA246637CFF328532Ull, 50 | 0x043FCAE60CC0EBA0Ull, 0x920E449535DD359EUll, 0x70EB093B15B290CCUll, 0x73A1921916591CBDUll, 51 | 0x56436C9FE1A1AA8DUll, 0xEFAC4B70633B8F81Ull, 0xBB215798D45DF7AFUll, 0x45F20042F24F1768Ull, 52 | 0x930F80F4E8EB7462Ull, 0xFF6712FFCFD75EA1Ull, 0xAE623FD67468AA70Ull, 0xDD2C5BC84BC8D8FCUll, 53 | 0x7EED120D54CF2DD9Ull, 0x22FE545401165F1CUll, 0xC91800E98FB99929Ull, 0x808BD68E6AC10365Ull, 54 | 0xDEC468145B7605F6Ull, 0x1BEDE3A3AEF53302Ull, 0x43539603D6C55602Ull, 0xAA969B5C691CCB7AUll, 55 | 0xA87832D392EFEE56Ull, 0x65942C7B3C7E11AEUll, 0xDED2D633CAD004F6Ull, 0x21F08570F420E565Ull, 56 | 0xB415938D7DA94E3CUll, 0x91B859E59ECB6350Ull, 0x10CFF333E0ED804AUll, 0x28AED140BE0BB7DDUll, 57 | 0xC5CC1D89724FA456Ull, 0x5648F680F11A2741Ull, 0x2D255069F0B7DAB3Ull, 0x9BC5A38EF729ABD4Ull, 58 | 0xEF2F054308F6A2BCUll, 0xAF2042F5CC5C2858Ull, 0x480412BAB7F5BE2AUll, 0xAEF3AF4A563DFE43Ull, 59 | 0x19AFE59AE451497FUll, 0x52593803DFF1E840Ull, 0xF4F076E65F2CE6F0Ull, 0x11379625747D5AF3Ull, 60 | 0xBCE5D2248682C115Ull, 0x9DA4243DE836994FUll, 0x066F70B33FE09017Ull, 0x4DC4DE189B671A1CUll, 61 | 0x51039AB7712457C3Ull, 0xC07A3F80C31FB4B4Ull, 0xB46EE9C5E64A6E7CUll, 0xB3819A42ABE61C87Ull, 62 | 0x21A007933A522A20Ull, 0x2DF16F761598AA4FUll, 0x763C4A1371B368FDUll, 0xF793C46702E086A0Ull, 63 | 0xD7288E012AEB8D31Ull, 0xDE336A2A4BC1C44BUll, 0x0BF692B38D079F23Ull, 0x2C604A7A177326B3Ull, 64 | 0x4850E73E03EB6064Ull, 0xCFC447F1E53C8E1BUll, 0xB05CA3F564268D99Ull, 0x9AE182C8BC9474E8Ull, 65 | 0xA4FC4BD4FC5558CAUll, 0xE755178D58FC4E76Ull, 0x69B97DB1A4C03DFEUll, 0xF9B5B7C4ACC67C96Ull, 66 | 0xFC6A82D64B8655FBUll, 0x9C684CB6C4D24417Ull, 0x8EC97D2917456ED0Ull, 0x6703DF9D2924E97EUll, 67 | 0xC547F57E42A7444EUll, 0x78E37644E7CAD29EUll, 0xFE9A44E9362F05FAUll, 0x08BD35CC38336615Ull, 68 | 0x9315E5EB3A129ACEUll, 0x94061B871E04DF75Ull, 0xDF1D9F9D784BA010Ull, 0x3BBA57B68871B59DUll, 69 | 0xD2B7ADEEDED1F73FUll, 0xF7A255D83BC373F8Ull, 0xD7F4F2448C0CEB81Ull, 0xD95BE88CD210FFA7Ull, 70 | 0x336F52F8FF4728E7Ull, 0xA74049DAC312AC71Ull, 0xA2F61BB6E437FDB5Ull, 0x4F2A5CB07F6A35B3Ull, 71 | 0x87D380BDA5BF7859Ull, 0x16B9F7E06C453A21Ull, 0x7BA2484C8A0FD54EUll, 0xF3A678CAD9A2E38CUll, 72 | 0x39B0BF7DDE437BA2Ull, 0xFCAF55C1BF8A4424Ull, 0x18FCF680573FA594Ull, 0x4C0563B89F495AC3Ull, 73 | 0x40E087931A00930DUll, 0x8CFFA9412EB642C1Ull, 0x68CA39053261169FUll, 0x7A1EE967D27579E2Ull, 74 | 0x9D1D60E5076F5B6FUll, 0x3810E399B6F65BA2Ull, 0x32095B6D4AB5F9B1Ull, 0x35CAB62109DD038AUll, 75 | 0xA90B24499FCFAFB1Ull, 0x77A225A07CC2C6BDUll, 0x513E5E634C70E331Ull, 0x4361C0CA3F692F12Ull, 76 | 0xD941ACA44B20A45BUll, 0x528F7C8602C5807BUll, 0x52AB92BEB9613989Ull, 0x9D1DFA2EFC557F73Ull, 77 | 0x722FF175F572C348Ull, 0x1D1260A51107FE97Ull, 0x7A249A57EC0C9BA2Ull, 0x04208FE9E8F7F2D6Ull, 78 | 0x5A110C6058B920A0Ull, 0x0CD9A497658A5698Ull, 0x56FD23C8F9715A4CUll, 0x284C847B9D887AAEUll, 79 | 0x04FEABFBBDB619CBUll, 0x742E1E651C60BA83Ull, 0x9A9632E65904AD3CUll, 0x881B82A13B51B9E2Ull, 80 | 0x506E6744CD974924Ull, 0xB0183DB56FFC6A79Ull, 0x0ED9B915C66ED37EUll, 0x5E11E86D5873D484Ull, 81 | 0xF678647E3519AC6EUll, 0x1B85D488D0F20CC5Ull, 0xDAB9FE6525D89021Ull, 0x0D151D86ADB73615Ull, 82 | 0xA865A54EDCC0F019Ull, 0x93C42566AEF98FFBUll, 0x99E7AFEABE000731Ull, 0x48CBFF086DDF285AUll, 83 | 0x7F9B6AF1EBF78BAFUll, 0x58627E1A149BBA21Ull, 0x2CD16E2ABD791E33Ull, 0xD363EFF5F0977996Ull, 84 | 0x0CE2A38C344A6EEDUll, 0x1A804AADB9CFA741Ull, 0x907F30421D78C5DEUll, 0x501F65EDB3034D07Ull, 85 | 0x37624AE5A48FA6E9Ull, 0x957BAF61700CFF4EUll, 0x3A6C27934E31188AUll, 0xD49503536ABCA345Ull, 86 | 0x088E049589C432E0Ull, 0xF943AEE7FEBF21B8Ull, 0x6C3B8E3E336139D3Ull, 0x364F6FFA464EE52EUll, 87 | 0xD60F6DCEDC314222Ull, 0x56963B0DCA418FC0Ull, 0x16F50EDF91E513AFUll, 0xEF1955914B609F93Ull, 88 | 0x565601C0364E3228Ull, 0xECB53939887E8175Ull, 0xBAC7A9A18531294BUll, 0xB344C470397BBA52Ull, 89 | 0x65D34954DAF3CEBDUll, 0xB4B81B3FA97511E2Ull, 0xB422061193D6F6A7Ull, 0x071582401C38434DUll, 90 | 0x7A13F18BBEDC4FF5Ull, 0xBC4097B116C524D2Ull, 0x59B97885E2F2EA28Ull, 0x99170A5DC3115544Ull, 91 | 0x6F423357E7C6A9F9Ull, 0x325928EE6E6F8794Ull, 0xD0E4366228B03343Ull, 0x565C31F7DE89EA27Ull, 92 | 0x30F5611484119414Ull, 0xD873DB391292ED4FUll, 0x7BD94E1D8E17DEBCUll, 0xC7D9F16864A76E94Ull, 93 | 0x947AE053EE56E63CUll, 0xC8C93882F9475F5FUll, 0x3A9BF55BA91F81CAUll, 0xD9A11FBB3D9808E4Ull, 94 | 0x0FD22063EDC29FCAUll, 0xB3F256D8ACA0B0B9Ull, 0xB03031A8B4516E84Ull, 0x35DD37D5871448AFUll, 95 | 0xE9F6082B05542E4EUll, 0xEBFAFA33D7254B59Ull, 0x9255ABB50D532280Ull, 0xB9AB4CE57F2D34F3Ull, 96 | 0x693501D628297551Ull, 0xC62C58F97DD949BFUll, 0xCD454F8F19C5126AUll, 0xBBE83F4ECC2BDECBUll, 97 | 0xDC842B7E2819E230Ull, 0xBA89142E007503B8Ull, 0xA3BC941D0A5061CBUll, 0xE9F6760E32CD8021Ull, 98 | 0x09C7E552BC76492FUll, 0x852F54934DA55CC9Ull, 0x8107FCCF064FCF56Ull, 0x098954D51FFF6580Ull, 99 | 0x23B70EDB1955C4BFUll, 0xC330DE426430F69DUll, 0x4715ED43E8A45C0AUll, 0xA8D7E4DAB780A08DUll, 100 | 0x0572B974F03CE0BBUll, 0xB57D2E985E1419C7Ull, 0xE8D9ECBE2CF3D73FUll, 0x2FE4B17170E59750Ull, 101 | 0x11317BA87905E790Ull, 0x7FBF21EC8A1F45ECUll, 0x1725CABFCB045B00Ull, 0x964E915CD5E2B207Ull, 102 | 0x3E2B8BCBF016D66DUll, 0xBE7444E39328A0ACUll, 0xF85B2B4FBCDE44B7Ull, 0x49353FEA39BA63B1Ull, 103 | 0x1DD01AAFCD53486AUll, 0x1FCA8A92FD719F85Ull, 0xFC7C95D827357AFAUll, 0x18A6A990C8B35EBDUll, 104 | 0xCCCB7005C6B9C28DUll, 0x3BDBB92C43B17F26Ull, 0xAA70B5B4F89695A2Ull, 0xE94C39A54A98307FUll, 105 | 0xB7A0B174CFF6F36EUll, 0xD4DBA84729AF48ADUll, 0x2E18BC1AD9704A68Ull, 0x2DE0966DAF2F8B1CUll, 106 | 0xB9C11D5B1E43A07EUll, 0x64972D68DEE33360Ull, 0x94628D38D0C20584Ull, 0xDBC0D2B6AB90A559Ull, 107 | 0xD2733C4335C6A72FUll, 0x7E75D99D94A70F4DUll, 0x6CED1983376FA72BUll, 0x97FCAACBF030BC24Ull, 108 | 0x7B77497B32503B12Ull, 0x8547EDDFB81CCB94Ull, 0x79999CDFF70902CBUll, 0xCFFE1939438E9B24Ull, 109 | 0x829626E3892D95D7Ull, 0x92FAE24291F2B3F1Ull, 0x63E22C147B9C3403Ull, 0xC678B6D860284A1CUll, 110 | 0x5873888850659AE7Ull, 0x0981DCD296A8736DUll, 0x9F65789A6509A440Ull, 0x9FF38FED72E9052FUll, 111 | 0xE479EE5B9930578CUll, 0xE7F28ECD2D49EECDUll, 0x56C074A581EA17FEUll, 0x5544F7D774B14AEFUll, 112 | 0x7B3F0195FC6F290FUll, 0x12153635B2C0CF57Ull, 0x7F5126DBBA5E0CA7Ull, 0x7A76956C3EAFB413Ull, 113 | 0x3D5774A11D31AB39Ull, 0x8A1B083821F40CB4Ull, 0x7B4A38E32537DF62Ull, 0x950113646D1D6E03Ull, 114 | 0x4DA8979A0041E8A9Ull, 0x3BC36E078F7515D7Ull, 0x5D0A12F27AD310D1Ull, 0x7F9D1A2E1EBE1327Ull, 115 | 0xDA3A361B1C5157B1Ull, 0xDCDD7D20903D0C25Ull, 0x36833336D068F707Ull, 0xCE68341F79893389Ull, 116 | 0xAB9090168DD05F34Ull, 0x43954B3252DC25E5Ull, 0xB438C2B67F98E5E9Ull, 0x10DCD78E3851A492Ull, 117 | 0xDBC27AB5447822BFUll, 0x9B3CDB65F82CA382Ull, 0xB67B7896167B4C84Ull, 0xBFCED1B0048EAC50Ull, 118 | 0xA9119B60369FFEBDUll, 0x1FFF7AC80904BF45Ull, 0xAC12FB171817EEE7Ull, 0xAF08DA9177DDA93DUll, 119 | 0x1B0CAB936E65C744Ull, 0xB559EB1D04E5E932Ull, 0xC37B45B3F8D6F2BAUll, 0xC3A9DC228CAAC9E9Ull, 120 | 0xF3B8B6675A6507FFUll, 0x9FC477DE4ED681DAUll, 0x67378D8ECCEF96CBUll, 0x6DD856D94D259236Ull, 121 | 0xA319CE15B0B4DB31Ull, 0x073973751F12DD5EUll, 0x8A8E849EB32781A5Ull, 0xE1925C71285279F5Ull, 122 | 0x74C04BF1790C0EFEUll, 0x4DDA48153C94938AUll, 0x9D266D6A1CC0542CUll, 0x7440FB816508C4FEUll, 123 | 0x13328503DF48229FUll, 0xD6BF7BAEE43CAC40Ull, 0x4838D65F6EF6748FUll, 0x1E152328F3318DEAUll, 124 | 0x8F8419A348F296BFUll, 0x72C8834A5957B511Ull, 0xD7A023A73260B45CUll, 0x94EBC8ABCFB56DAEUll, 125 | 0x9FC10D0F989993E0Ull, 0xDE68A2355B93CAE6Ull, 0xA44CFE79AE538BBEUll, 0x9D1D84FCCE371425Ull, 126 | 0x51D2B1AB2DDFB636Ull, 0x2FD7E4B9E72CD38CUll, 0x65CA5B96B7552210Ull, 0xDD69A0D8AB3B546DUll, 127 | 0x604D51B25FBF70E2Ull, 0x73AA8A564FB7AC9EUll, 0x1A8C1E992B941148Ull, 0xAAC40A2703D9BEA0Ull, 128 | 0x764DBEAE7FA4F3A6Ull, 0x1E99B96E70A9BE8BUll, 0x2C5E9DEB57EF4743Ull, 0x3A938FEE32D29981Ull, 129 | 0x26E6DB8FFDF5ADFEUll, 0x469356C504EC9F9DUll, 0xC8763C5B08D1908CUll, 0x3F6C6AF859D80055Ull, 130 | 0x7F7CC39420A3A545Ull, 0x9BFB227EBDF4C5CEUll, 0x89039D79D6FC5C5CUll, 0x8FE88B57305E2AB6Ull, 131 | 0xA09E8C8C35AB96DEUll, 0xFA7E393983325753Ull, 0xD6B6D0ECC617C699Ull, 0xDFEA21EA9E7557E3Ull, 132 | 0xB67C1FA481680AF8Ull, 0xCA1E3785A9E724E5Ull, 0x1CFC8BED0D681639Ull, 0xD18D8549D140CAEAUll, 133 | 0x4ED0FE7E9DC91335Ull, 0xE4DBF0634473F5D2Ull, 0x1761F93A44D5AEFEUll, 0x53898E4C3910DA55Ull, 134 | 0x734DE8181F6EC39AUll, 0x2680B122BAA28D97Ull, 0x298AF231C85BAFABUll, 0x7983EED3740847D5Ull, 135 | 0x66C1A2A1A60CD889Ull, 0x9E17E49642A3E4C1Ull, 0xEDB454E7BADC0805Ull, 0x50B704CAB602C329Ull, 136 | 0x4CC317FB9CDDD023Ull, 0x66B4835D9EAFEA22Ull, 0x219B97E26FFC81BDUll, 0x261E4E4C0A333A9DUll, 137 | 0x1FE2CCA76517DB90Ull, 0xD7504DFA8816EDBBUll, 0xB9571FA04DC089C8Ull, 0x1DDC0325259B27DEUll, 138 | 0xCF3F4688801EB9AAUll, 0xF4F5D05C10CAB243Ull, 0x38B6525C21A42B0EUll, 0x36F60E2BA4FA6800Ull, 139 | 0xEB3593803173E0CEUll, 0x9C4CD6257C5A3603Ull, 0xAF0C317D32ADAA8AUll, 0x258E5A80C7204C4BUll, 140 | 0x8B889D624D44885DUll, 0xF4D14597E660F855Ull, 0xD4347F66EC8941C3Ull, 0xE699ED85B0DFB40DUll, 141 | 0x2472F6207C2D0484Ull, 0xC2A1E7B5B459AEB5Ull, 0xAB4F6451CC1D45ECUll, 0x63767572AE3D6174Ull, 142 | 0xA59E0BD101731A28Ull, 0x116D0016CB948F09Ull, 0x2CF9C8CA052F6E9FUll, 0x0B090A7560A968E3Ull, 143 | 0xABEEDDB2DDE06FF1Ull, 0x58EFC10B06A2068DUll, 0xC6E57A78FBD986E0Ull, 0x2EAB8CA63CE802D7Ull, 144 | 0x14A195640116F336Ull, 0x7C0828DD624EC390Ull, 0xD74BBE77E6116AC7Ull, 0x804456AF10F5FB53Ull, 145 | 0xEBE9EA2ADF4321C7Ull, 0x03219A39EE587A30Ull, 0x49787FEF17AF9924Ull, 0xA1E9300CD8520548Ull, 146 | 0x5B45E522E4B1B4EFUll, 0xB49C3B3995091A36Ull, 0xD4490AD526F14431Ull, 0x12A8F216AF9418C2Ull, 147 | 0x001F837CC7350524Ull, 0x1877B51E57A764D5Ull, 0xA2853B80F17F58EEUll, 0x993E1DE72D36D310Ull, 148 | 0xB3598080CE64A656Ull, 0x252F59CF0D9F04BBUll, 0xD23C8E176D113600Ull, 0x1BDA0492E7E4586EUll, 149 | 0x21E0BD5026C619BFUll, 0x3B097ADAF088F94EUll, 0x8D14DEDB30BE846EUll, 0xF95CFFA23AF5F6F4Ull, 150 | 0x3871700761B3F743Ull, 0xCA672B91E9E4FA16Ull, 0x64C8E531BFF53B55Ull, 0x241260ED4AD1E87DUll, 151 | 0x106C09B972D2E822Ull, 0x7FBA195410E5CA30Ull, 0x7884D9BC6CB569D8Ull, 0x0647DFEDCD894A29Ull, 152 | 0x63573FF03E224774Ull, 0x4FC8E9560F91B123Ull, 0x1DB956E450275779Ull, 0xB8D91274B9E9D4FBUll, 153 | 0xA2EBEE47E2FBFCE1Ull, 0xD9F1F30CCD97FB09Ull, 0xEFED53D75FD64E6BUll, 0x2E6D02C36017F67FUll, 154 | 0xA9AA4D20DB084E9BUll, 0xB64BE8D8B25396C1Ull, 0x70CB6AF7C2D5BCF0Ull, 0x98F076A4F7A2322EUll, 155 | 0xBF84470805E69B5FUll, 0x94C3251F06F90CF3Ull, 0x3E003E616A6591E9Ull, 0xB925A6CD0421AFF3Ull, 156 | 0x61BDD1307C66E300Ull, 0xBF8D5108E27E0D48Ull, 0x240AB57A8B888B20Ull, 0xFC87614BAF287E07Ull, 157 | 0xEF02CDD06FFDB432Ull, 0xA1082C0466DF6C0AUll, 0x8215E577001332C8Ull, 0xD39BB9C3A48DB6CFUll, 158 | 0x2738259634305C14Ull, 0x61CF4F94C97DF93DUll, 0x1B6BACA2AE4E125BUll, 0x758F450C88572E0BUll, 159 | 0x959F587D507A8359Ull, 0xB063E962E045F54DUll, 0x60E8ED72C0DFF5D1Ull, 0x7B64978555326F9FUll, 160 | 0xFD080D236DA814BAUll, 0x8C90FD9B083F4558Ull, 0x106F72FE81E2C590Ull, 0x7976033A39F7D952Ull, 161 | 0xA4EC0132764CA04BUll, 0x733EA705FAE4FA77Ull, 0xB4D8F77BC3E56167Ull, 0x9E21F4F903B33FD9Ull, 162 | 0x9D765E419FB69F6DUll, 0xD30C088BA61EA5EFUll, 0x5D94337FBFAF7F5BUll, 0x1A4E4822EB4D7A59Ull, 163 | 0x6FFE73E81B637FB3Ull, 0xDDF957BC36D8B9CAUll, 0x64D0E29EEA8838B3Ull, 0x08DD9BDFD96B9F63Ull, 164 | 0x087E79E5A57D1D13Ull, 0xE328E230E3E2B3FBUll, 0x1C2559E30F0946BEUll, 0x720BF5F26F4D2EAAUll, 165 | 0xB0774D261CC609DBUll, 0x443F64EC5A371195Ull, 0x4112CF68649A260EUll, 0xD813F2FAB7F5C5CAUll, 166 | 0x660D3257380841EEUll, 0x59AC2C7873F910A3Ull, 0xE846963877671A17Ull, 0x93B633ABFA3469F8Ull, 167 | 0xC0C0F5A60EF4CDCFUll, 0xCAF21ECD4377B28CUll, 0x57277707199B8175Ull, 0x506C11B9D90E8B1DUll, 168 | 0xD83CC2687A19255FUll, 0x4A29C6465A314CD1Ull, 0xED2DF21216235097Ull, 0xB5635C95FF7296E2Ull, 169 | 0x22AF003AB672E811Ull, 0x52E762596BF68235Ull, 0x9AEBA33AC6ECC6B0Ull, 0x944F6DE09134DFB6Ull, 170 | 0x6C47BEC883A7DE39Ull, 0x6AD047C430A12104Ull, 0xA5B1CFDBA0AB4067Ull, 0x7C45D833AFF07862Ull, 171 | 0x5092EF950A16DA0BUll, 0x9338E69C052B8E7BUll, 0x455A4B4CFE30E3F5Ull, 0x6B02E63195AD0CF8Ull, 172 | 0x6B17B224BAD6BF27Ull, 0xD1E0CCD25BB9C169Ull, 0xDE0C89A556B9AE70Ull, 0x50065E535A213CF6Ull, 173 | 0x9C1169FA2777B874Ull, 0x78EDEFD694AF1EEDUll, 0x6DC93D9526A50E68Ull, 0xEE97F453F06791EDUll, 174 | 0x32AB0EDB696703D3Ull, 0x3A6853C7E70757A7Ull, 0x31865CED6120F37DUll, 0x67FEF95D92607890Ull, 175 | 0x1F2B1D1F15F6DC9CUll, 0xB69E38A8965C6B65Ull, 0xAA9119FF184CCCF4Ull, 0xF43C732873F24C13Ull, 176 | 0xFB4A3D794A9A80D2Ull, 0x3550C2321FD6109CUll, 0x371F77E76BB8417EUll, 0x6BFA9AAE5EC05779Ull, 177 | 0xCD04F3FF001A4778Ull, 0xE3273522064480CAUll, 0x9F91508BFFCFC14AUll, 0x049A7F41061A9E60Ull, 178 | 0xFCB6BE43A9F2FE9BUll, 0x08DE8A1C7797DA9BUll, 0x8F9887E6078735A1Ull, 0xB5B4071DBFC73A66Ull, 179 | 0x230E343DFBA08D33Ull, 0x43ED7F5A0FAE657DUll, 0x3A88A0FBBCB05C63Ull, 0x21874B8B4D2DBC4FUll, 180 | 0x1BDEA12E35F6A8C9Ull, 0x53C065C6C8E63528Ull, 0xE34A1D250E7A8D6BUll, 0xD6B04D3B7651DD7EUll, 181 | 0x5E90277E7CB39E2DUll, 0x2C046F22062DC67DUll, 0xB10BB459132D0A26Ull, 0x3FA9DDFB67E2F199Ull, 182 | 0x0E09B88E1914F7AFUll, 0x10E8B35AF3EEAB37Ull, 0x9EEDECA8E272B933Ull, 0xD4C718BC4AE8AE5FUll, 183 | 0x81536D601170FC20Ull, 0x91B534F885818A06Ull, 0xEC8177F83F900978Ull, 0x190E714FADA5156EUll, 184 | 0xB592BF39B0364963Ull, 0x89C350C893AE7DC1Ull, 0xAC042E70F8B383F2Ull, 0xB49B52E587A1EE60Ull, 185 | 0xFB152FE3FF26DA89Ull, 0x3E666E6F69AE2C15Ull, 0x3B544EBE544C19F9Ull, 0xE805A1E290CF2456Ull, 186 | 0x24B33C9D7ED25117Ull, 0xE74733427B72F0C1Ull, 0x0A804D18B7097475Ull, 0x57E3306D881EDB4FUll, 187 | 0x4AE7D6A36EB5DBCBUll, 0x2D8D5432157064C8Ull, 0xD1E649DE1E7F268BUll, 0x8A328A1CEDFE552CUll, 188 | 0x07A3AEC79624C7DAUll, 0x84547DDC3E203C94Ull, 0x990A98FD5071D263Ull, 0x1A4FF12616EEFC89Ull, 189 | 0xF6F7FD1431714200Ull, 0x30C05B1BA332F41CUll, 0x8D2636B81555A786Ull, 0x46C9FEB55D120902Ull, 190 | 0xCCEC0A73B49C9921Ull, 0x4E9D2827355FC492Ull, 0x19EBB029435DCB0FUll, 0x4659D2B743848A2CUll, 191 | 0x963EF2C96B33BE31Ull, 0x74F85198B05A2E7DUll, 0x5A0F544DD2B1FB18Ull, 0x03727073C2E134B1Ull, 192 | 0xC7F6AA2DE59AEA61Ull, 0x352787BAA0D7C22FUll, 0x9853EAB63B5E0B35Ull, 0xABBDCDD7ED5C0860Ull, 193 | 0xCF05DAF5AC8D77B0Ull, 0x49CAD48CEBF4A71EUll, 0x7A4C10EC2158C4A6Ull, 0xD9E92AA246BF719EUll, 194 | 0x13AE978D09FE5557Ull, 0x730499AF921549FFUll, 0x4E4B705B92903BA4Ull, 0xFF577222C14F0A3AUll, 195 | 0x55B6344CF97AAFAEUll, 0xB862225B055B6960Ull, 0xCAC09AFBDDD2CDB4Ull, 0xDAF8E9829FE96B5FUll, 196 | 0xB5FDFC5D3132C498Ull, 0x310CB380DB6F7503Ull, 0xE87FBB46217A360EUll, 0x2102AE466EBB1148Ull, 197 | 0xF8549E1A3AA5E00DUll, 0x07A69AFDCC42261AUll, 0xC4C118BFE78FEAAEUll, 0xF9F4892ED96BD438Ull, 198 | 0x1AF3DBE25D8F45DAUll, 0xF5B4B0B0D2DEEEB4Ull, 0x962ACEEFA82E1C84Ull, 0x046E3ECAAF453CE9Ull, 199 | 0xF05D129681949A4CUll, 0x964781CE734B3C84Ull, 0x9C2ED44081CE5FBDUll, 0x522E23F3925E319EUll, 200 | 0x177E00F9FC32F791Ull, 0x2BC60A63A6F3B3F2Ull, 0x222BBFAE61725606Ull, 0x486289DDCC3D6780Ull, 201 | 0x7DC7785B8EFDFC80Ull, 0x8AF38731C02BA980Ull, 0x1FAB64EA29A2DDF7Ull, 0xE4D9429322CD065AUll, 202 | 0x9DA058C67844F20CUll, 0x24C0E332B70019B0Ull, 0x233003B5A6CFE6ADUll, 0xD586BD01C5C217F6Ull, 203 | 0x5E5637885F29BC2BUll, 0x7EBA726D8C94094BUll, 0x0A56A5F0BFE39272Ull, 0xD79476A84EE20D06Ull, 204 | 0x9E4C1269BAA4BF37Ull, 0x17EFEE45B0DEE640Ull, 0x1D95B0A5FCF90BC6Ull, 0x93CBE0B699C2585DUll, 205 | 0x65FA4F227A2B6D79Ull, 0xD5F9E858292504D5Ull, 0xC2B5A03F71471A6FUll, 0x59300222B4561E00Ull, 206 | 0xCE2F8642CA0712DCUll, 0x7CA9723FBB2E8988Ull, 0x2785338347F2BA08Ull, 0xC61BB3A141E50E8CUll, 207 | 0x150F361DAB9DEC26Ull, 0x9F6A419D382595F4Ull, 0x64A53DC924FE7AC9Ull, 0x142DE49FFF7A7C3DUll, 208 | 0x0C335248857FA9E7Ull, 0x0A9C32D5EAE45305Ull, 0xE6C42178C4BBB92EUll, 0x71F1CE2490D20B07Ull, 209 | 0xF1BCC3D275AFE51AUll, 0xE728E8C83C334074Ull, 0x96FBF83A12884624Ull, 0x81A1549FD6573DA5Ull, 210 | 0x5FA7867CAF35E149Ull, 0x56986E2EF3ED091BUll, 0x917F1DD5F8886C61Ull, 0xD20D8C88C8FFE65FUll, 211 | }; 212 | 213 | const int polyPieces[] = { 214 | -1, 215 | 1,7,3,5,9,11, 216 | 0,6,2,4,8,10 217 | }; 218 | const U64 sidePolyKey = 0xF8D626AAAF278509Ull; 219 | -------------------------------------------------------------------------------- /search.cpp: -------------------------------------------------------------------------------- 1 | #include "search.hpp" 2 | #include "board.hpp" 3 | #include "defs.hpp" 4 | #include "move.hpp" 5 | #include "movegen.hpp" 6 | #include "evaluation.hpp" 7 | #include "transpositionTable.hpp" 8 | #include "utils.hpp" 9 | #include 10 | #include 11 | #include "polyglot.hpp" 12 | 13 | SearchController *searchController = new SearchController; 14 | 15 | SearchController::SearchController() 16 | { 17 | this->clear(); 18 | } 19 | 20 | void SearchController::clear() 21 | { 22 | for (int i = 0; i < maxDepth; ++i) 23 | { 24 | for (int j = 0; j < 2; ++j) 25 | { 26 | killers[i][j] = 0; 27 | } 28 | } 29 | for (int i = 0; i < 13; ++i) 30 | { 31 | for (int j = 0; j < 120; ++j) 32 | { 33 | history[i][j] = 0; 34 | } 35 | } 36 | ply = 0; 37 | nodes = 0; 38 | fh = 0; 39 | fhf = 0; 40 | stopped = false; 41 | useBook = false; 42 | } 43 | 44 | int searchPosition() 45 | { 46 | int bestMove = 0; 47 | int bestScore = -Infinite; 48 | int depth = 1; 49 | float ordering = 0; 50 | 51 | if (searchController->useBook) 52 | { 53 | bestMove = getRandBookMove(); 54 | if (bestMove) 55 | { 56 | std::cout << "bestmove (book)" << moveStr(bestMove) << std::endl; 57 | return bestMove; 58 | } 59 | } 60 | 61 | searchController->clear(); 62 | for (depth = 1; depth <= searchController->depth; ++depth) 63 | { 64 | bestScore = alphaBeta(-Infinite, Infinite, depth, true); 65 | if (searchController->stopped) 66 | break; 67 | 68 | bestMove = transpositionTable->getMove(); 69 | if (depth != 1 && searchController->fh) 70 | { 71 | ordering = (searchController->fhf / searchController->fh) * 100; 72 | } 73 | std::vector line = transpositionTable->getLine(depth); 74 | std::string lineStr; 75 | for (auto move : line) 76 | { 77 | lineStr += moveStr(move) + ' '; 78 | } 79 | 80 | printf("info score cp %d depth %d ordering %.2f nodes %lld time %lld ", 81 | bestScore, depth, ordering, searchController->nodes, getCurrTime() - searchController->startTime); 82 | std::cout << "pv " << lineStr << std::endl; 83 | } 84 | std::cout << "bestmove " << moveStr(bestMove) << std::endl; 85 | return bestMove; 86 | } 87 | 88 | int alphaBeta(int alpha, int beta, int depth, bool doNull) 89 | { 90 | if (depth <= 0) 91 | { 92 | return quiescence(alpha, beta); 93 | } 94 | 95 | if ((searchController->nodes % 2048) == 0) 96 | { 97 | checkTimeUp(); 98 | } 99 | searchController->nodes++; 100 | if ((isRepetition() || board->fiftyMove >= 100) && searchController->ply != 0) 101 | { 102 | return 0; 103 | } 104 | 105 | if (searchController->ply >= maxDepth) 106 | { 107 | return evalPosition(); 108 | } 109 | 110 | bool inCheck = board->checkSq != noSq; 111 | if (inCheck) 112 | { 113 | ++depth; 114 | } 115 | int score = -Infinite; 116 | TableData *ttEntry = transpositionTable->get(board->positionKey); 117 | int pvMove = 0; 118 | if (ttEntry) 119 | { 120 | pvMove = extract_move(ttEntry->smp_data); 121 | if (extract_depth(ttEntry->smp_data) >= depth) 122 | { 123 | score = extract_score(ttEntry->smp_data); 124 | if (score > Mate) 125 | score -= searchController->ply; 126 | else if (score < -Mate) 127 | score += searchController->ply; 128 | if (extract_flag(ttEntry->smp_data) == AlphaFlag && score <= alpha) 129 | return alpha; 130 | if (extract_flag(ttEntry->smp_data) == BetaFlag && score >= beta) 131 | return beta; 132 | if (extract_flag(ttEntry->smp_data) == ExactFlag) 133 | return score; 134 | } 135 | } 136 | 137 | // NULL Move Pruning 138 | if (doNull && !inCheck && searchController->ply && depth >= 4) 139 | { 140 | makeNullMove(); 141 | score = -alphaBeta(-beta, -beta + 1, depth - 4, false); 142 | takeNullMove(); 143 | if (searchController->stopped) 144 | return 0; 145 | if (score >= beta) 146 | { 147 | return beta; 148 | } 149 | } 150 | 151 | std::vector> moves = generateMoves(); 152 | int legalMoves = 0; 153 | int prevAlpha = alpha; 154 | int bestMove = 0; 155 | 156 | if (pvMove) 157 | { 158 | for (auto &pair : moves) 159 | { 160 | if (pair.first == pvMove) 161 | { 162 | pair.second = 2000000; 163 | break; 164 | } 165 | } 166 | } 167 | 168 | for (auto i = 0u; i < moves.size(); ++i) 169 | { 170 | swapWithBest(i, moves); 171 | int move = moves[i].first; 172 | if (makeMove(move) == false) 173 | continue; 174 | legalMoves++; 175 | searchController->ply++; 176 | score = -alphaBeta(-beta, -alpha, depth - 1, true); 177 | 178 | takeMove(); 179 | searchController->ply--; 180 | 181 | if (searchController->stopped) 182 | return 0; 183 | 184 | if (score > alpha) 185 | { 186 | bestMove = move; 187 | 188 | if (score >= beta) 189 | { 190 | if (legalMoves == 1) 191 | searchController->fhf++; 192 | searchController->fh++; 193 | if (!(move & captureFlag)) 194 | { 195 | searchController->killers[searchController->ply][1] = searchController->killers[searchController->ply][0]; 196 | searchController->killers[searchController->ply][0] = move; 197 | } 198 | 199 | transpositionTable->add(board->positionKey, move, beta, BetaFlag, depth); 200 | return beta; 201 | } 202 | alpha = score; 203 | if (!(move & captureFlag)) 204 | { 205 | int piece = board->pieces[moveFrom(move)]; 206 | int toSq = moveTo(move); 207 | searchController->history[piece][toSq] += depth * depth; 208 | } 209 | } 210 | } 211 | 212 | if (legalMoves == 0) 213 | { 214 | if (inCheck) 215 | { 216 | return -Infinite + searchController->ply; 217 | } 218 | else 219 | { 220 | return 0; 221 | } 222 | } 223 | 224 | if (alpha != prevAlpha) 225 | { 226 | transpositionTable->add(board->positionKey, bestMove, score, ExactFlag, depth); 227 | } 228 | else 229 | { 230 | transpositionTable->add(board->positionKey, bestMove, alpha, AlphaFlag, depth); 231 | } 232 | 233 | return alpha; 234 | } 235 | 236 | int quiescence(int alpha, int beta) 237 | { 238 | 239 | if ((searchController->nodes % 2048) == 0) 240 | { 241 | checkTimeUp(); 242 | } 243 | 244 | searchController->nodes++; 245 | 246 | if ((isRepetition() || board->fiftyMove >= 100) && searchController->ply != 0) 247 | { 248 | return 0; 249 | } 250 | 251 | if (searchController->ply >= maxDepth) 252 | { 253 | return evalPosition(); 254 | } 255 | 256 | int score = evalPosition(); 257 | 258 | if (score >= beta) 259 | return beta; 260 | if (score > alpha) 261 | alpha = score; 262 | 263 | int legalMove = 0; 264 | std::vector> moves = generateCaptureMoves(); 265 | 266 | for (auto i = 0u; i < moves.size(); ++i) 267 | { 268 | swapWithBest(i, moves); 269 | const int move = moves[i].first; 270 | 271 | if (makeMove(move) == false) 272 | continue; 273 | legalMove++; 274 | searchController->ply++; 275 | 276 | score = -quiescence(-beta, -alpha); 277 | 278 | takeMove(); 279 | searchController->ply--; 280 | 281 | if (searchController->stopped) 282 | return 0; 283 | 284 | if (score > alpha) 285 | { 286 | if (score >= beta) 287 | { 288 | if (legalMove == 1) 289 | { 290 | searchController->fhf++; 291 | } 292 | searchController->fh++; 293 | return beta; 294 | } 295 | alpha = score; 296 | } 297 | } 298 | 299 | return alpha; 300 | } 301 | 302 | void checkTimeUp() 303 | { 304 | if (searchController->timeSet && getCurrTime() > searchController->stopTime) 305 | { 306 | searchController->stopped = true; 307 | } 308 | } 309 | 310 | void swapWithBest(int i, std::vector> &moves) 311 | { 312 | int bestIndex = i; 313 | for (auto j = unsigned(i + 1); j < moves.size(); ++j) 314 | { 315 | if (moves[j].second > moves[bestIndex].second) 316 | { 317 | bestIndex = j; 318 | } 319 | } 320 | if (bestIndex != i) 321 | { 322 | std::swap(moves[i], moves[bestIndex]); 323 | } 324 | } 325 | 326 | bool isRepetition() 327 | { 328 | for (int i = board->ply - board->fiftyMove; i < board->ply - 1; ++i) 329 | { 330 | if (board->positionKey == board->history[i].positionKey) 331 | { 332 | return true; 333 | } 334 | } 335 | 336 | return false; 337 | } -------------------------------------------------------------------------------- /search.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "defs.hpp" 3 | #include 4 | 5 | class SearchController 6 | { 7 | private: 8 | public: 9 | long long startTime; 10 | long long stopTime; 11 | int depth; 12 | int timeSet; 13 | 14 | long long nodes; 15 | 16 | bool quit; 17 | std::atomic stopped; 18 | 19 | float fh; 20 | float fhf; 21 | bool useBook; 22 | int ply; 23 | int killers[64][2]; // killer[ply][0/1]; 24 | int history[13][120]; // history[piece][toSq] 25 | SearchController(); 26 | void clear(); 27 | }; 28 | 29 | int searchPosition(); 30 | int alphaBeta(int alpha, int beta, int depth, bool doNull); 31 | int quiescence(int alpha, int beta); 32 | void swapWithBest(int i, std::vector> &moves); 33 | void checkTimeUp(); 34 | bool isRepetition(); 35 | 36 | extern SearchController *searchController; 37 | -------------------------------------------------------------------------------- /transpositionTable.cpp: -------------------------------------------------------------------------------- 1 | #include "transpositionTable.hpp" 2 | #include "board.hpp" 3 | #include "search.hpp" 4 | #include "move.hpp" 5 | #include "defs.hpp" 6 | #include "movegen.hpp" 7 | 8 | const int AlphaFlag = 0; 9 | const int BetaFlag = 1; 10 | const int ExactFlag = 2; 11 | 12 | 13 | TranspositionTable *transpositionTable = new TranspositionTable; 14 | 15 | TranspositionTable::TranspositionTable() 16 | { 17 | clear(); 18 | } 19 | TranspositionTable::~TranspositionTable() 20 | { 21 | clear(); 22 | } 23 | 24 | void TranspositionTable::clear() 25 | { 26 | for(int i = 0; imaxEntries; ++i){ 27 | this->entries[i].smp_data = 0ULL; 28 | this->entries[i].smp_key = 0ULL; 29 | } 30 | } 31 | 32 | void TranspositionTable::add(U64 positionKey, int move, int score, int flag, int depth) 33 | { 34 | if (score > Mate) 35 | score += searchController->ply; 36 | if (score < -Mate) 37 | score -= searchController->ply; 38 | long long index = positionKey % this->maxEntries; 39 | 40 | U64 smp_data = pack_tableData(score, depth, flag, move); 41 | U64 smp_key = positionKey ^ smp_data; 42 | 43 | this->entries[index].smp_data = smp_data; 44 | this->entries[index].smp_key = smp_key; 45 | } 46 | 47 | TableData* TranspositionTable::get(U64 positionKey) { 48 | long long index = positionKey % this->maxEntries; 49 | TableData* data = &this->entries[index]; 50 | if ((data->smp_key ^ data->smp_data) != positionKey) return nullptr; 51 | 52 | return data; 53 | } 54 | 55 | int TranspositionTable::getMove() 56 | { 57 | long long index = board->positionKey % this->maxEntries; 58 | TableData *data = &this->entries[index]; 59 | 60 | if ((data->smp_key ^ data->smp_data) == board->positionKey) 61 | return extract_move(data->smp_data); 62 | 63 | return 0; 64 | } 65 | 66 | bool isMoveExists(int arg) 67 | { 68 | std::vector> moves = generateMoves(); 69 | for (auto &pair : moves) 70 | { 71 | if (pair.first == arg) 72 | { 73 | if (makeMove(pair.first) == false) 74 | continue; 75 | takeMove(); 76 | return true; 77 | } 78 | } 79 | return false; 80 | } 81 | 82 | std::vector TranspositionTable::getLine(int depth) 83 | { 84 | std::vector moveList; 85 | int move = this->getMove(); 86 | int count = 0; 87 | 88 | while (move && count < depth) 89 | { 90 | if (isMoveExists(move)) 91 | { 92 | makeMove(move); 93 | moveList.push_back(move); 94 | count++; 95 | } 96 | else 97 | { 98 | break; 99 | } 100 | move = this->getMove(); 101 | } 102 | while (count--) 103 | takeMove(); 104 | return moveList; 105 | } -------------------------------------------------------------------------------- /transpositionTable.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "defs.hpp" 4 | 5 | extern const int AlphaFlag; 6 | extern const int BetaFlag; 7 | extern const int ExactFlag; 8 | 9 | class TranspositionTable 10 | { 11 | private: 12 | static const int maxEntries = 0x100000 * 16; 13 | TableData entries[maxEntries]; 14 | 15 | public: 16 | TranspositionTable(); 17 | ~TranspositionTable(); 18 | void clear(); 19 | void add(U64 positionKey, int move, int score, int flag, int depth); 20 | TableData *get(U64 positionKey); 21 | std::vector getLine(int depth); 22 | int getMove(); 23 | }; 24 | 25 | 26 | inline U64 pack_tableData(int score, int depth, int flag, U64 move) 27 | { 28 | return (score + 32000) | (depth << 16) | (flag << 22) | (move << 24); 29 | } 30 | 31 | inline int extract_score(U64 data) { return (data & 0xffff) - 32000; } 32 | inline int extract_move(U64 data) { return data >> 24; } 33 | inline int extract_flag(U64 data) { return (data >> 22) & 3; } 34 | inline int extract_depth(U64 data) { return (data >> 16) & 0x3f; } 35 | 36 | extern TranspositionTable* transpositionTable; 37 | -------------------------------------------------------------------------------- /uci.cpp: -------------------------------------------------------------------------------- 1 | #include "uci.hpp" 2 | #include "utils.hpp" 3 | #include "board.hpp" 4 | #include "search.hpp" 5 | #include "move.hpp" 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include "polyglot.hpp" 11 | 12 | std::thread searchThread; 13 | 14 | void handlePosition(std::istringstream &iss) 15 | { 16 | std::string positionType, fen, token; 17 | 18 | iss >> positionType; 19 | if (positionType == "startpos") 20 | { 21 | board->parseFen(startFen); 22 | } 23 | else if (positionType == "fen") 24 | { 25 | getline(iss, fen); 26 | std::cout << "fen : " << fen << std::endl; 27 | board->parseFen(fen); 28 | } 29 | 30 | while (iss >> token) 31 | { 32 | if (token == "moves") 33 | { 34 | while (iss >> token) 35 | { 36 | int move = parseMove(token); 37 | if (!move) 38 | break; 39 | makeMove(move); 40 | } 41 | } 42 | } 43 | } 44 | 45 | void handleSearch(std::istringstream &iss) 46 | { 47 | int depth = maxDepth, time = 0, inc = 0, movetime = 0, movestogo = 30; 48 | std::string token; 49 | 50 | while (iss >> token) 51 | { 52 | if (token == "depth") 53 | iss >> depth; 54 | else if (token == "movetime") 55 | iss >> movetime; 56 | else if (token == "movestogo") 57 | iss >> movestogo; 58 | else if (board->side == white && token == "wtime") 59 | iss >> time; 60 | else if (board->side == black && token == "btime") 61 | iss >> time; 62 | else if (board->side == white && token == "winc") 63 | iss >> inc; 64 | else if (board->side == black && token == "binc") 65 | iss >> inc; 66 | } 67 | 68 | searchController->depth = depth; 69 | searchController->startTime = getCurrTime(); 70 | 71 | if (movetime > 0) 72 | { 73 | searchController->timeSet = true; 74 | time = movetime; 75 | } 76 | else 77 | { 78 | time += inc; 79 | searchController->timeSet = static_cast(time); 80 | 81 | if (movestogo <= 0) 82 | { 83 | movestogo = 1; // Avoid division by zero 84 | } 85 | time /= movestogo; 86 | } 87 | 88 | // std::cout<<"time: " <