Skip to content
Merged
5 changes: 2 additions & 3 deletions engine/bitboard.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -70,7 +70,6 @@ struct Board {
uint64_t pawn_hash = 0;
uint64_t nonpawn_hashval[2] = {0, 0}; // [side]
uint64_t major_hash = 0, minor_hash = 0;
TTable ttable;
pzstd::largevector<uint64_t> hash_hist;

// Mailbox representation of the board for faster queries of certain data
Expand All @@ -81,12 +80,12 @@ struct Board {
std::stack<HistoryEntry> move_hist;
std::stack<uint8_t> halfmove_hist;

Board(int ttsize=DEFAULT_TT_SIZE) : ttable(ttsize) {
Board() {
reset_board();
recompute_hash();
}

Board(std::string fen, int ttsize=DEFAULT_TT_SIZE) : ttable(ttsize) {
Board(std::string fen) {
load_fen(fen);
recompute_hash();
};
Expand Down
2 changes: 0 additions & 2 deletions engine/boardstate.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -8,5 +8,3 @@ struct BoardState {
Accumulator w_acc, b_acc;
Piece mailbox[64] = {};
};

extern BoardState bs[NINPUTS * 2][NINPUTS * 2];
281 changes: 29 additions & 252 deletions engine/eval.cpp

Large diffs are not rendered by default.

102 changes: 3 additions & 99 deletions engine/eval.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -5,109 +5,14 @@
#include "includes.hpp"
#include "boardstate.hpp"

extern Network nnue_network;

Value simple_eval(Board &board);

Value eval(Board &board);
Value eval(Board &board, BoardState *bs);

std::array<Value, 8> debug_eval(Board &board);

#ifdef HCE
constexpr int pawn_heatmap[64] = {
// a b c d e f g h
0, 0, 0, 0, 0, 0, 0, 0, // 1
5, 10, 10, -40, -40, 10, 10, 5, // 2
5, -5, -10, 0, 0, -10, -5, 5, // 3
0, 0, 0, 30, 30, 0, 0, 0, // 4
5, 5, 10, 40, 40, 10, 5, 5, // 5
10, 10, 50, 60, 60, 50, 10, 10, // 6
80, 80, 80, 80, 80, 80, 80, 80, // 7
0, 0, 0, 0, 0, 0, 0, 0, // 8
};

constexpr int knight_heatmap[64] = {
// a b c d e f g h
-50, -40, -30, -30, -30, -30, -40, -50, // 1
-40, -20, 0, 5, 5, 0, -20, -40, // 2
-30, 5, 10, 15, 15, 10, 5, -30, // 3
-30, 0, 15, 20, 20, 15, 0, -30, // 4
-30, 5, 15, 20, 20, 15, 5, -30, // 5
-30, 0, 10, 15, 15, 10, 0, -30, // 6
-40, -20, 0, 0, 0, 0, -20, -40, // 7
-50, -40, -30, -30, -30, -30, -40, -50, // 8
};

constexpr int bishop_heatmap[64] = {
// a b c d e f g h
-20, -10, -10, -10, -10, -10, -10, -20, // 1
-10, 5, 0, 0, 0, 0, 5, -10, // 2
-10, 10, 10, 10, 10, 10, 10, -10, // 3
-10, 0, 10, 10, 10, 10, 0, -10, // 4
-10, 5, 5, 10, 10, 5, 5, -10, // 5
-10, 0, 5, 10, 10, 5, 0, -10, // 6
-30, 0, 0, 0, 0, 0, 0, -30, // 7
-20, -10, -10, -10, -10, -10, -10, -20, // 8
};

constexpr int rook_heatmap[64] = {
// a b c d e f g h
-10, 0, 0, 10, 10, 5, 0, -10, // 1
-5, 0, 0, 0, 0, 0, 0, -5, // 2
-5, 0, 0, 0, 0, 0, 0, -5, // 3
-5, 0, 0, 0, 0, 0, 0, -5, // 4
-5, 0, 0, 0, 0, 0, 0, -5, // 5
-5, 0, 0, 0, 0, 0, 0, -5, // 6
-10, 0, 0, 0, 0, 0, 0, -10, // 7
0, 0, 0, 0, 0, 0, 0, 0, // 8
};

constexpr int queen_heatmap[64] = {
// a b c d e f g h
-20, -10, -10, -5, -5, -10, -10, -20, // 1
-10, 0, 5, 0, 0, 0, 0, -10, // 2
-10, 5, 5, 5, 5, 5, 0, -10, // 3
-5, 0, 5, 5, 5, 5, 0, -5, // 4
0, 0, 5, 5, 5, 5, 0, -5, // 5
-10, 0, 5, 5, 5, 5, 0, -10, // 6
-10, 0, 0, 0, 0, 0, 0, -10, // 7
-20, -10, -10, -5, -5, -10, -10, -20, // 8
};

constexpr int king_heatmap[64] = {
// a b c d e f g h
30, 50, 40, 0, 0, 10, 50, 30, // 1
20, 20, -5, -5, -5, -5, 20, 20, // 2
-10, -20, -20, -20, -20, -20, -20, -10, // 3
-20, -30, -30, -40, -40, -30, -30, -20, // 4
-30, -40, -40, -50, -50, -40, -40, -30, // 5
-30, -40, -40, -50, -50, -40, -40, -30, // 6
-30, -40, -40, -50, -50, -40, -40, -30, // 7
-30, -40, -40, -50, -50, -40, -40, -30, // 8
};

constexpr int endgame_heatmap[64] = {
// a b c d e f g h
1, 2, 4, 8, 8, 4, 2, 1, // 1
2, 4, 8, 16, 16, 8, 4, 2, // 2
4, 8, 16, 32, 32, 16, 8, 4, // 3
8, 16, 32, 64, 64, 32, 16, 8, // 4
8, 16, 32, 64, 64, 32, 16, 8, // 5
4, 8, 16, 32, 32, 16, 8, 4, // 6
2, 4, 8, 16, 16, 8, 4, 2, // 7
1, 2, 4, 8, 8, 4, 2, 1, // 8
};

constexpr int pawn_endgame[64] = {
// a b c d e f g h
0, 0, 0, 0, 0, 0, 0, 0, // 1
-10, -10, -10, -10, -10, -10, -10, -10, // 2
5, 5, 5, 5, 5, 5, 5, 5, // 3
10, 10, 10, 10, 10, 10, 10, 10, // 4
20, 20, 20, 20, 20, 20, 20, 20, // 5
60, 60, 60, 60, 60, 60, 60, 60, // 6
100, 100, 100, 100, 100, 100, 100, 100, // 7
0, 0, 0, 0, 0, 0, 0, 0, // 8
};
#else
constexpr int IBUCKET_LAYOUT[] = {
0, 0, 2, 2, 3, 3, 1, 1,
0, 0, 2, 2, 3, 3, 1, 1,
Expand All @@ -118,4 +23,3 @@ constexpr int IBUCKET_LAYOUT[] = {
6, 6, 6, 6, 7, 7, 7, 7,
6, 6, 6, 6, 7, 7, 7, 7,
};
#endif
3 changes: 3 additions & 0 deletions engine/includes.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

#include <algorithm>
#include <array>
#include <atomic>
#include <cmath>
#include <cstdint>
#include <cstring>
Expand All @@ -11,6 +12,7 @@
#include <iostream>
#include <stack>
#include <string>
#include <thread>
#include <utility>

#include "pzstl/vector.hpp"
Expand All @@ -24,6 +26,7 @@ constexpr bool WHITE = false;
constexpr bool BLACK = true;

constexpr int MAX_PLY = 300;
constexpr int MAX_THREADS = 64;

typedef int16_t Value;
constexpr Value VALUE_ZERO = 0;
Expand Down
68 changes: 33 additions & 35 deletions engine/main.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -9,24 +9,25 @@
#include "movegen.hpp"
#include "movetimings.hpp"
#include "search.hpp"
#include "ttable.hpp"

BoardState bs[NINPUTS * 2][NINPUTS * 2];
Copy link

Copilot AI Nov 26, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The global BoardState bs[NINPUTS * 2][NINPUTS * 2] array is still declared here but is never used in main.cpp. This wastes memory (approximately NINPUTS² * 2² * sizeof(BoardState) bytes). Since each ThreadInfo now has its own bs array, this global should be removed.

Suggested change
BoardState bs[NINPUTS * 2][NINPUTS * 2];

Copilot uses AI. Check for mistakes.

// Options
int TT_SIZE = DEFAULT_TT_SIZE;
bool quiet = false, online = false;
int multipv = 1;

ThreadInfo tis[MAX_THREADS];

void run_uci() {
std::string command;
Board board = Board(TT_SIZE);
Board board = Board();
while (getline(std::cin, command)) {
if (command == "uci") {
std::cout << "id name PZChessBot " << VERSION << std::endl;
std::cout << "id author kevlu8 and wdotmathree" << std::endl;
std::cout << "option name Hash type spin default 16 min 1 max 1024" << std::endl;
std::cout << "option name Threads type spin default 1 min 1 max 1" << std::endl; // Not implemented yet
std::cout << "option name MultiPV type spin default 1 min 1 max 256" << std::endl;
std::cout << "option name Threads type spin default 1 min 1 max 64" << std::endl;
std::cout << "option name Quiet type check default false" << std::endl;
std::cout << "uciok" << std::endl;
} else if (command == "icu") {
Expand All @@ -53,12 +54,15 @@ void run_uci() {
TT_SIZE = optionint * 1024 * 1024 / sizeof(TTable::TTBucket);
} else if (optionname == "Quiet") {
quiet = optionvalue == "true";
} else if (optionname == "MultiPV") {
multipv = std::stoi(optionvalue);
} else if (optionname == "Threads") {
num_threads = std::stoi(optionvalue);
}
} else if (command == "ucinewgame") {
board = Board(TT_SIZE);
clear_search_vars();
board = Board();
ttable.resize(TT_SIZE);
for (int i = 0; i < num_threads; i++) {
clear_search_vars(tis[i]);
}
} else if (command.substr(0, 8) == "position") {
// either `position startpos` or `position fen ...`
if (command.find("startpos") != std::string::npos) {
Expand Down Expand Up @@ -133,25 +137,18 @@ void run_uci() {
int timeleft = board.side ? btime : wtime;
int inc = board.side ? binc : winc;
std::pair<Move, Value> res;
if (multipv != 1) {
if (inf) res = search_multipv(board, multipv, 1e9, MAX_PLY, 1e18, quiet)[0];
else if (depth != -1) res = search_multipv(board, multipv, 1e9, depth, 1e18, quiet)[0];
else if (nodes != -1) res = search_multipv(board, multipv, 1e9, MAX_PLY, nodes, quiet)[0];
else if (movetime != -1) res = search_multipv(board, multipv, movetime, MAX_PLY, 1e18, quiet)[0];
else res = search_multipv(board, multipv, 1e9, MAX_PLY, 1e18, quiet)[0];
} else {
if (inf) res = search(board, 1e9, MAX_PLY, 1e18, quiet);
else if (depth != -1) res = search(board, 1e9, depth, 1e18, quiet);
else if (nodes != -1) res = search(board, 1e9, MAX_PLY, nodes, quiet);
else if (movetime != -1) res = search(board, movetime, MAX_PLY, 1e18, quiet);
else res = search(board, timemgmt(timeleft, inc, online), MAX_PLY, 1e18, quiet);
}
if (inf) res = search(board, tis, 1e18, MAX_PLY, 1e18, quiet);
else if (depth != -1) res = search(board, tis, 1e18, depth, 1e18, quiet);
else if (nodes != -1) res = search(board, tis, 1e18, MAX_PLY, nodes, quiet);
else if (movetime != -1) res = search(board, tis, movetime, MAX_PLY, 1e18, quiet);
else res = search(board, tis, timemgmt(timeleft, inc, online), MAX_PLY, 1e18, quiet);
std::cout << "bestmove " << res.first.to_string() << std::endl;
}
}
}

__attribute__((weak)) int main(int argc, char *argv[]) {
for (int i = 0; i < MAX_THREADS; i++) tis[i].set_bs();
Copy link

Copilot AI Nov 26, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Calling tis[i].set_bs() for all MAX_THREADS (64) threads at startup is inefficient, as noted in the PR description. This initializes board states for threads that may never be used. Consider lazy initialization or only initializing up to num_threads.

Copilot uses AI. Check for mistakes.
if (argc == 2 && std::string(argv[1]) == "bench") {
const std::string bench_positions[] = {
"r3k2r/2pb1ppp/2pp1q2/p7/1nP1B3/1P2P3/P2N1PPP/R2QK2R w KQkq - 0 14",
Expand Down Expand Up @@ -205,17 +202,17 @@ __attribute__((weak)) int main(int argc, char *argv[]) {
"3br1k1/p1pn3p/1p3n2/5pNq/2P1p3/1PN3PP/P2Q1PB1/4R1K1 w - - 0 23",
"2r2b2/5p2/5k2/p1r1pP2/P2pB3/1P3P2/K1P3R1/7R w - - 23 93",
};
Board board = Board(TT_SIZE);
Board board = Board();
uint64_t tot_nodes = 0;
uint64_t start = clock();
for (const auto &fen : bench_positions) {
board.reset(fen);
clear_search_vars();
search(board, 1e9, 12, 1e18, 0);
tot_nodes += nodes;
clear_search_vars(tis[0]);
search(board, tis, 1e9, 12, 1e18, 0);
tot_nodes += nodes[0];
}
uint64_t end = clock();
std::cout << tot_nodes << " nodes " << (tot_nodes / ((double)(end - start) / CLOCKS_PER_SEC)) << " nps" << std::endl;
std::cout << tot_nodes << " nodes " << int(tot_nodes / ((double)(end - start) / CLOCKS_PER_SEC)) << " nps" << std::endl;
return 0;
}
if (argc == 3 && std::string(argv[2]) == "quit") {
Expand All @@ -241,7 +238,7 @@ __attribute__((weak)) int main(int argc, char *argv[]) {
ss >> nmoves;
}
}
Board board = Board(TT_SIZE);
Board board = Board();
std::mt19937_64 rng(s);
std::ifstream bookfile(book == "None" ? "" : book);
std::vector<std::string> fens;
Expand Down Expand Up @@ -281,10 +278,11 @@ __attribute__((weak)) int main(int argc, char *argv[]) {
if (!restart) {
if (_mm_popcnt_u64(board.piece_boards[KING]) != 2) restart = true;
else if (filter_weird) {
auto s_eval = eval(board);
int npieces = _mm_popcnt_u64(board.piece_boards[OCC(WHITE)] | board.piece_boards[OCC(BLACK)]);
auto s_eval = debug_eval(board)[(npieces - 2) / 4] * (board.side == WHITE ? 1 : -1);
if (abs(s_eval) >= 600) restart = true; // do a fast static eval to quickly filter out crazy positions
else {
auto res = search(board, 1e9, MAX_PLY, 10000, 1);
auto res = search(board, tis, 1e9, MAX_PLY, 10000, 1);
if (abs(res.second) >= 400) restart = true;
}
}
Expand All @@ -300,15 +298,14 @@ __attribute__((weak)) int main(int argc, char *argv[]) {
online = argc >= 2 && std::string(argv[1]) == "--online=1";
std::cout << "PZChessBot " << VERSION << " developed by kevlu8 and wdotmathree" << std::endl;
std::string command;
Board board = Board(TT_SIZE);
Board board = Board();
std::thread searchthread;
while (getline(std::cin, command)) {
if (command == "uci") {
std::cout << "id name PZChessBot " << VERSION << std::endl;
std::cout << "id author kevlu8 and wdotmathree" << std::endl;
std::cout << "option name Hash type spin default 16 min 1 max 1024" << std::endl;
std::cout << "option name Threads type spin default 1 min 1 max 1" << std::endl; // Not implemented yet
std::cout << "option name MultiPV type spin default 1 min 1 max 256" << std::endl;
std::cout << "option name Threads type spin default 1 min 1 max 64" << std::endl;
std::cout << "option name Quiet type check default false" << std::endl;
std::cout << "uciok" << std::endl;
run_uci();
Expand Down Expand Up @@ -390,18 +387,19 @@ __attribute__((weak)) int main(int argc, char *argv[]) {
}
} else if (command.substr(0, 2) == "go") {
int ms = std::stoi(command.substr(3));
auto res = search(board, ms, MAX_PLY, 1e18, 2); // Use quiet level 2 for pretty output
auto res = search(board, tis, ms, MAX_PLY, 1e18, 2); // Use quiet level 2 for pretty output
std::cout << CYAN "Best move: " RESET BOLD << res.first.to_string() << RESET
<< CYAN " with score: " RESET << (res.second * (board.side == BLACK ? -1 : 1) > 0 ? GREEN : RED)
<< std::showpos << res.second * (board.side == BLACK ? -1 : 1) << " cp" << RESET << std::endl << std::noshowpos;
} else if (command == "undo") {
board.unmake_move();
board.print_board_pretty();
} else if (command == "reset") {
board = Board(TT_SIZE);
board = Board();
ttable.resize(TT_SIZE);
std::cout << "Done" << std::endl;
} else if (command.substr(0, 3) == "fen") {
board = Board(TT_SIZE);
board = Board();
std::string fen = command.substr(4);
board.reset(fen);
std::cout << "Done" << std::endl;
Expand Down
4 changes: 3 additions & 1 deletion engine/nnue/network.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -29,4 +29,6 @@ void accumulator_add(const Network &net, Accumulator &acc, uint16_t index);

void accumulator_sub(const Network &net, Accumulator &acc, uint16_t index);

int32_t nnue_eval(const Network &net, const Accumulator &stm, const Accumulator &ntm, uint8_t nbucket);
int32_t nnue_eval(const Network &net, const Accumulator &stm, const Accumulator &ntm, uint8_t nbucket);

extern Network nnue_network;
Loading
Loading