I tried to create a chess engine in C using the Negamax with alpha-beta pruning, but I couldn't get it working. It works as expected in the first few moves of the game, and starts to sacrifice pieces without an aim. But as it nears the endgame, it seems to behave as expected, again. I have tried debugging for about a week now, but without any success. Any help is greatly appreciated. Here is the related code:
#define INFINITY INT_MAX
char isCheckMateOrStaleMate(uint64_t const *board, uint64_t const *prevBoard, char brkrwrkr00, char isWhiteYourColor) {
...
}
struct node {
unsigned long len;
uint64_t *pos;
uint64_t *basepos;
char brkrwrkr00;
struct node *branches;
char *move;
char color;
};
int max(int a, int b) {
return a > b ? a : b;
}
int evaluateNode(struct node n) {
char cmate = isCheckMateOrStaleMate(n.pos, n.basepos, n.brkrwrkr00, !n.color);
if (cmate)
return (isCheckOnKing(n.pos, 1) ? -64000 : isCheckOnKing(n.pos, 0) ? 64000 : 0) * (!n.color - n.color);
int posAdv = 0;
char p;
for (char i = 0; i < 64; i++) {
p = accessBoardAt(n.pos, i);
posAdv += p == PAWN_B ? -10 : p == PAWN_W ? 10 : p == KNIGHT_B ? -29 : p == KNIGHT_W ? 29 : p == BISHOP_B ? -30 : p == BISHOP_W ? 30 : p == ROOK_B ? -50 : p == ROOK_W ? 50 : p == QUEEN_B ? -90 : p == QUEEN_W ? 90 : 0;
}
return (!n.color - n.color) * posAdv;
}
unsigned long generateNodes(uint64_t const *board, uint64_t const *prevBoard, char brkrwrkr00, char isWhiteYourColor, struct node **ret, int depth) {
if (!depth)
return 0;
char *valids = 0;
unsigned long _len_ = validMoves(board, prevBoard, brkrwrkr00, isWhiteYourColor, &valids);
if (!_len_)
return 0;
*ret = malloc(_len_ / 3 * sizeof **ret);
for (unsigned long i = 0, j = 0; i < _len_; i += 3, j++) {
(*ret)[j].color = isWhiteYourColor;
(*ret)[j].pos = {board[0], board[1], board[2], board[3]};
(*ret)[j].basepos = {board[0], board[1], board[2], board[3]};
(*ret)[j].brkrwrkr00 = brkrwrkr00;
(*ret)[j].move = {valids[i], valids[i + 1], valids[i + 2]};
makeForcedMove((*ret)[j].pos, &((*ret)[j].brkrwrkr00), (*ret)[j].move);
(*ret)[j].len = generateNodes((*ret)[j].pos, board, (*ret)[j].brkrwrkr00, !isWhiteYourColor, &((*ret)[j].branches), depth - 1);
}
free(valids);
return _len_ / 3;
};
int negamaxscore(struct node n, int depth, char maximizer, int alpha, int beta) {
if (!depth || !n.len)
return evaluateNode(n);
int eval = -INFINITY;
for (unsigned long i = 0; i < n.len; i++) {
eval = max(-negamaxscore(n.branches[i], depth - 1, !maximizer, -beta, -alpha), eval);
alpha = max(eval, alpha);
if (beta <= alpha)
break;
}
return eval;
}
char *theBestMove(uint64_t const *board, uint64_t const *prevBoard, char brkrwrkr00, char isWhiteYourColor, int depth) {
if (!depth)
return NULL;
struct node *branches;
unsigned long len = generateNodes(board, prevBoard, brkrwrkr00, isWhiteYourColor, &branches, depth);
if (!len)
return NULL;
char *bestmove = NULL;
int curr;
int eval = -INFINITY;
int alpha = -INFINITY;
int beta = INFINITY;
for (unsigned long i = 0; i < len; i++) {
curr = -negamaxscore(branches[i], depth - 1, !isWhiteYourColor, -beta, -alpha);
if (curr >= eval) {
eval = curr;
bestmove = branches[i].move;
}
alpha = max(eval, alpha);
if (beta <= alpha)
break;
}
bestmove = memcpy(malloc(3), bestmove, 3);
return bestmove;
}
char *theBestMove(uint64_t const *board, uint64_t const *prevBoard, char brkrwrkr00, char isWhiteYourColor, int depth) {
if (!depth)
return NULL;
struct node *branches;
unsigned long len = generateNodes(board, prevBoard, brkrwrkr00, isWhiteYourColor, &branches, depth);
if (!len)
return NULL;
char *bestmove = NULL;
int curr;
int eval = -INFINITY;
int alpha = -INFINITY;
int beta = INFINITY;
char seq[depth * 5];
for (unsigned long i = 0; i < len; i++) {
curr = -negamaxscore(branches[i], depth - 1, !isWhiteYourColor, -beta, -alpha);
if (curr >= eval) {
eval = curr;
bestmove = branches[i].move;
}
alpha = max(eval, alpha);
if (beta <= alpha)
break;
}
bestmove = memcpy(malloc(3), bestmove, 3);
return bestmove;
}