I'm currently writing my first chess engine and the code below is what i use to find the best move.
it is able to solve lichess puzzles up to 1800 elo but i have many questions regarding its functionality
1) i used other people's code to write so i don't even know if i implemented it correctly
2) even though i get perft 6 in 4.5 seconds (no bulk-counting) it becomes incredibly slow after depth 3 (i assume this is because i don't order the moves)
3) i did some hacky things to get it working, they are described in the comments
4) it only gives the best move only if the depth is odd, otherwise it gives the best move to favor the other side
Code: Select all
#define WORST_EVAL -1e4
#define BEST_EVAL 1e4
// code adapted from TSCP
// eval_board is this code https://www.chessprogramming.org/PeSTO%27s_Evaluation_Function
static int quiesce(Board *board, int alpha, int beta)
{
int eval = eval_board(board);
if (eval >= beta)
return beta;
if (eval > alpha)
alpha = eval;
int movelist[MAX_MOVES];
// pseudo-legal
int n = generate_captures(board, movelist);
bool legals = false;
for (int i = 0; i < n; ++i) {
move = movelist[i];
int play_move(board, move);
if (!move_was_legal(board)) {
undo_move(board, move);
continue;
}
legals = true;
eval = -quiesce(board, -beta, -alpha);
undo_move(board, move);
if (eval >= beta)
return beta;
if (eval > alpha)
alpha = eval;
}
// no legal moves found, either checkmate or stalemate
if (!legals)
return king_in_check(board) ? WORST_EVAL : 0;
return alpha;
}
static int alphabeta(Board *board, int alpha, int beta, int depth)
{
if (depth == 0)
return quiesce(board, alpha, beta);
int movelist[MAX_MOVES];
int n = generate_all(board, movelist);
bool legals = false;
int move, eval;
for (int i = 0; i < n; ++i) {
move = movelist[i];
play_move(board, move);
if (!move_was_legal(board)) {
undo_move(board, move);
continue;
}
legals = true;
eval = -alphabeta(board, -beta, -alpha, depth - 1);
undo_move(board, move);
if (eval >= beta)
return beta;
if (eval > alpha)
alpha = eval;
}
if (!legals)
return king_in_check(board) ? WORST_EVAL : 0;
return alpha;
}
int search(Board *board, int depth)
{
// moves are encoded as integers
int movelist[MAX_MOVES];
// number of pseudo-legal moves
int n = generate_all(board, movelist);
int move, result, score;
score = WORST_EVAL;
// i do this because after i get the best score
// how am i supposed to know which move it is attached to?
for (int i = 0; i < n; ++i) {
int move = movelist[i];
play_move(board, move);
if (!move_was_legal(board)) {
undo_move(board, move);
continue;
}
// putting a '-' for some reason fixed it
if ((result = -alphabeta(board, WORST_EVAL, BEST_EVAL, depth)) > score) {
score = result;
// here i know move has the best score
}
// if a checkmate is found stop trying other moves
if (score >= BEST_EVAL) {
undo_move(board, move);
return score;
}
undo_move(board, move);
}
return score;
}