commit a6e157ec1fd48ba4c9bc6103836a136039c15def
parent 564362bd70ae4b35fc956fd5c97e8dd672c4341a
Author: Dimitrije Dobrota <mail@dimitrijedobrota.com>
Date: Fri, 30 Sep 2022 00:43:02 +0200
Basic Evaluation Scheme and improved UCI instructions
Diffstat:
3 files changed, 270 insertions(+), 80 deletions(-)
diff --git a/include/CBoard.h b/include/CBoard.h
@@ -8,11 +8,11 @@ typedef enum enumCastle eCastle;
typedef struct Piece_T *Piece_T;
-char Piece_asci(Piece_T pt);
-char Piece_code(Piece_T pt);
-char *Piece_unicode(Piece_T pt);
-eColor Piece_color(Piece_T pt);
-ePiece Piece_piece(Piece_T pt);
+char Piece_asci(Piece_T self);
+char Piece_code(Piece_T self);
+char *Piece_unicode(Piece_T self);
+eColor Piece_color(Piece_T self);
+ePiece Piece_piece(Piece_T self);
int Piece_index(Piece_T self);
Piece_T Piece_fromCode(char code);
diff --git a/src/CBoard.c b/src/CBoard.c
@@ -24,30 +24,30 @@ struct Piece_T {
// clang-format off
struct Piece_T Pieces[2][6] = {
{
- {.color = WHITE, .code = 'P', .asci = 'P', .unicode = "♙ ", .piece = PAWN, .attacks = get_wpawn_attacks},
- {.color = WHITE, .code = 'N', .asci = 'N', .unicode = "♘ ", .piece = KNIGHT, .attacks = get_knight_attacks},
- {.color = WHITE, .code = 'B', .asci = 'B', .unicode = "♗ ", .piece = BISHOP, .attacks = get_bishop_attacks},
- {.color = WHITE, .code = 'R', .asci = 'R', .unicode = "♖ ", .piece = ROOK, .attacks = get_rook_attacks},
- {.color = WHITE, .code = 'Q', .asci = 'Q', .unicode = "♕ ", .piece = QUEEN, .attacks = get_queen_attacks},
- {.color = WHITE, .code = 'K', .asci = 'K', .unicode = "♔ ", .piece = KING, .attacks = get_king_attacks},
+ [PAWN] = {.color = WHITE, .code = 'P', .asci = 'P', .unicode = "♙ ", .piece = PAWN, .attacks = get_wpawn_attacks},
+[KNIGHT] = {.color = WHITE, .code = 'N', .asci = 'N', .unicode = "♘ ", .piece = KNIGHT, .attacks = get_knight_attacks},
+[BISHOP] = {.color = WHITE, .code = 'B', .asci = 'B', .unicode = "♗ ", .piece = BISHOP, .attacks = get_bishop_attacks},
+ [ROOK] = {.color = WHITE, .code = 'R', .asci = 'R', .unicode = "♖ ", .piece = ROOK, .attacks = get_rook_attacks},
+ [QUEEN] = {.color = WHITE, .code = 'Q', .asci = 'Q', .unicode = "♕ ", .piece = QUEEN, .attacks = get_queen_attacks},
+ [KING] = {.color = WHITE, .code = 'K', .asci = 'K', .unicode = "♔ ", .piece = KING, .attacks = get_king_attacks},
},
{
- {.color = BLACK, .code = 'p', .asci = 'p', .unicode = "♟ ", .piece = PAWN, .attacks = get_bpawn_attacks},
- {.color = BLACK, .code = 'n', .asci = 'n', .unicode = "♞ ", .piece = KNIGHT, .attacks = get_knight_attacks},
- {.color = BLACK, .code = 'b', .asci = 'b', .unicode = "♝ ", .piece = BISHOP, .attacks = get_bishop_attacks},
- {.color = BLACK, .code = 'r', .asci = 'r', .unicode = "♜ ", .piece = ROOK, .attacks = get_rook_attacks},
- {.color = BLACK, .code = 'q', .asci = 'q', .unicode = "♛ ", .piece = QUEEN, .attacks = get_queen_attacks},
- {.color = BLACK, .code = 'k', .asci = 'k', .unicode = "♚ ", .piece = KING, .attacks = get_king_attacks},
+ [PAWN] = {.color = BLACK, .code = 'p', .asci = 'p', .unicode = "♟ ", .piece = PAWN, .attacks = get_bpawn_attacks},
+[KNIGHT] = {.color = BLACK, .code = 'n', .asci = 'n', .unicode = "♞ ", .piece = KNIGHT, .attacks = get_knight_attacks},
+[BISHOP] = {.color = BLACK, .code = 'b', .asci = 'b', .unicode = "♝ ", .piece = BISHOP, .attacks = get_bishop_attacks},
+ [ROOK] = {.color = BLACK, .code = 'r', .asci = 'r', .unicode = "♜ ", .piece = ROOK, .attacks = get_rook_attacks},
+ [QUEEN] = {.color = BLACK, .code = 'q', .asci = 'q', .unicode = "♛ ", .piece = QUEEN, .attacks = get_queen_attacks},
+ [KING] = {.color = BLACK, .code = 'k', .asci = 'k', .unicode = "♚ ", .piece = KING, .attacks = get_king_attacks},
},
};
// clang-format on
-attack_f Piece_attacks(Piece_T pt) { return pt->attacks; }
-char Piece_asci(Piece_T pt) { return pt->asci; }
-char Piece_code(Piece_T pt) { return pt->code; }
-char *Piece_unicode(Piece_T pt) { return pt->unicode; }
-eColor Piece_color(Piece_T pt) { return pt->color; }
-ePiece Piece_piece(Piece_T pt) { return pt->piece; }
+attack_f Piece_attacks(Piece_T self) { return self->attacks; }
+char Piece_asci(Piece_T self) { return self->asci; }
+char Piece_code(Piece_T self) { return self->code; }
+char *Piece_unicode(Piece_T self) { return self->unicode; }
+eColor Piece_color(Piece_T self) { return self->color; }
+ePiece Piece_piece(Piece_T self) { return self->piece; }
int Piece_index(Piece_T self) { return self->color * 8 + self->piece; }
Piece_T Piece_fromCode(char code) {
@@ -215,7 +215,7 @@ CBoard_T CBoard_fromFEN(CBoard_T board, char *fen) {
if (!board)
NEW(board);
- memset(board, C64(0), sizeof(*board));
+ memset(board, 0, sizeof(*board));
board->side = -1;
board->enpassant = no_sq;
diff --git a/src/engine.c b/src/engine.c
@@ -162,35 +162,35 @@ MoveList_T generate_moves(CBoard_T cboard, MoveList_T moves) {
int index = Piece_index(Piece_get(KING, WHITE));
if (CBoard_castle(cboard) & WK) {
if (!CBoard_square_isOccupied(cboard, f1) &&
- !CBoard_square_isOccupied(cboard, g1))
- if (!CBoard_square_isAttack(cboard, e1, BLACK) &&
- !CBoard_square_isAttack(cboard, f1, BLACK))
- MoveList_add(moves, Move_encode(e1, g1, index, 0, 0, 0, 0, 1));
+ !CBoard_square_isOccupied(cboard, g1) &&
+ !CBoard_square_isAttack(cboard, e1, BLACK) &&
+ !CBoard_square_isAttack(cboard, f1, BLACK))
+ MoveList_add(moves, Move_encode(e1, g1, index, 0, 0, 0, 0, 1));
}
if (CBoard_castle(cboard) & WQ) {
if (!CBoard_square_isOccupied(cboard, d1) &&
!CBoard_square_isOccupied(cboard, c1) &&
- !CBoard_square_isOccupied(cboard, b1))
- if (!CBoard_square_isAttack(cboard, e1, BLACK) &&
- !CBoard_square_isAttack(cboard, d1, BLACK))
- MoveList_add(moves, Move_encode(e1, c1, index, 0, 0, 0, 0, 1));
+ !CBoard_square_isOccupied(cboard, b1) &&
+ !CBoard_square_isAttack(cboard, e1, BLACK) &&
+ !CBoard_square_isAttack(cboard, d1, BLACK))
+ MoveList_add(moves, Move_encode(e1, c1, index, 0, 0, 0, 0, 1));
}
} else {
int index = Piece_index(Piece_get(KING, BLACK));
if (CBoard_castle(cboard) & BK) {
if (!CBoard_square_isOccupied(cboard, f8) &&
- !CBoard_square_isOccupied(cboard, g8))
- if (!CBoard_square_isAttack(cboard, e8, WHITE) &&
- !CBoard_square_isAttack(cboard, f8, WHITE))
- MoveList_add(moves, Move_encode(e8, g8, index, 0, 0, 0, 0, 1));
+ !CBoard_square_isOccupied(cboard, g8) &&
+ !CBoard_square_isAttack(cboard, e8, WHITE) &&
+ !CBoard_square_isAttack(cboard, f8, WHITE))
+ MoveList_add(moves, Move_encode(e8, g8, index, 0, 0, 0, 0, 1));
}
if (CBoard_castle(cboard) & BQ) {
if (!CBoard_square_isOccupied(cboard, d8) &&
!CBoard_square_isOccupied(cboard, c8) &&
- !CBoard_square_isOccupied(cboard, b8))
- if (!CBoard_square_isAttack(cboard, e8, WHITE) &&
- !CBoard_square_isAttack(cboard, d8, WHITE))
- MoveList_add(moves, Move_encode(e8, c8, index, 0, 0, 0, 0, 1));
+ !CBoard_square_isOccupied(cboard, b8) &&
+ !CBoard_square_isAttack(cboard, e8, WHITE) &&
+ !CBoard_square_isAttack(cboard, d8, WHITE))
+ MoveList_add(moves, Move_encode(e8, c8, index, 0, 0, 0, 0, 1));
}
}
}
@@ -318,34 +318,170 @@ void init_all() {
/* UCI */
-typedef struct Position_T *Position_T;
-struct Position_T {
+struct Score_T {
+ int value;
+ int score[64];
+};
+
+// clang-format off
+struct Score_T Scores[] = {
+[PAWN] = {
+.value = 100,
+.score = {
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, -10, -10, 0, 0, 0,
+ 0, 0, 0, 5, 5, 0, 0, 0,
+ 5, 5, 10, 20, 20, 5, 5, 5,
+ 10, 10, 10, 20, 20, 10, 10, 10,
+ 20, 20, 20, 30, 30, 30, 20, 20,
+ 30, 30, 30, 40, 40, 30, 30, 30,
+ 90, 90, 90, 90, 90, 90, 90, 90,
+ }},
+[KNIGHT] = {
+.value = 300,
+.score = {
+ -5, -10 , 0, 0, 0, 0, -10, -5,
+ -5, 0, 0, 0, 0, 0, 0, -5,
+ -5, 5, 20, 10, 10, 20, 5, -5,
+ -5, 10, 20, 30, 30, 20, 10, -5,
+ -5, 10, 20, 30, 30, 20, 10, -5,
+ -5, 5, 20, 20, 20, 20, 5, -5,
+ -5, 0, 0, 10, 10, 0, 0, -5,
+ -5, 0, 0, 0, 0, 0, 0, -5,
+ }},
+[BISHOP] = {
+.value = 350,
+.score = {
+ 0, 0, -10, 0, 0, -10, 0, 0,
+ 0, 30, 0, 0, 0, 0, 30, 0,
+ 0, 10, 0, 0, 0, 0, 10, 0,
+ 0, 0, 10, 20, 20, 10, 0, 0,
+ 0, 0, 10, 20, 20, 10, 0, 0,
+ 0, 0, 0, 10, 10, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ }},
+[ROOK] = {
+.value = 500,
+.score = {
+ 0, 0, 0, 20, 20, 0, 0, 0,
+ 0, 0, 10, 20, 20, 10, 0, 0,
+ 0, 0, 10, 20, 20, 10, 0, 0,
+ 0, 0, 10, 20, 20, 10, 0, 0,
+ 0, 0, 10, 20, 20, 10, 0, 0,
+ 0, 0, 10, 20, 20, 10, 0, 0,
+ 50, 50, 50, 50, 50, 50, 50, 50,
+ 50, 50, 50, 50, 50, 50, 50, 50,
+ }},
+[QUEEN] = {
+.value = 1000,
+.score = {
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ }},
+[KING] = {
+.value = 10000,
+.score = {
+ 0, 0, 5, 0, -15, 0, 10, 0,
+ 0, 5, 5, -5, -5, 0, 5, 0,
+ 0, 0, 5, 10, 10, 5, 0, 0,
+ 0, 5, 10, 20, 20, 10, 5, 0,
+ 0, 5, 10, 20, 20, 10, 5, 0,
+ 0, 5, 5, 10, 10, 5, 5, 0,
+ 0, 0, 5, 5, 5, 5, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ }},
+};
+
+const int mirror_score[128] =
+{
+ a8, b8, c8, d8, e8, f8, g8, h8,
+ a7, b7, c7, d7, e7, f7, g7, h7,
+ a6, b6, c6, d6, e6, f6, g6, h6,
+ a5, b5, c5, d5, e5, f5, g5, h5,
+ a4, b4, c4, d4, e4, f4, g4, h4,
+ a3, b3, c3, d3, e3, f3, g3, h3,
+ a2, b2, c2, d2, e2, f2, g2, h2,
+ a1, b1, c1, d1, e1, f1, g1, h1, no_sq,
+};
+// clang-format on
+
+int Score_value(ePiece piece) { return Scores[piece].value; }
+
+int Score_score(ePiece piece, eColor color, Square square) {
+ if (color == BLACK)
+ square = mirror_score[square];
+ return Scores[piece].score[square];
+}
+
+int evaluate(CBoard_T board) {
+ Square square;
+ eColor side = CBoard_side(board);
+ U64 occupancy = CBoard_colorBB(board, side);
+
+ int score = 0;
+ for (int i = 0; i < 6; i++) {
+ U64 bitboard = CBoard_pieceBB(board, i);
+ bitboard_for_each_bit(square, bitboard) {
+ if (bit_get(occupancy, square)) {
+ score += Score_value(i);
+ score += Score_score(i, side, square);
+ } else {
+ score -= Score_value(i);
+ score -= Score_score(i, !side, square);
+ }
+ }
+ }
+
+ return side == WHITE ? score : -score;
+}
+
+void search_position(CBoard_T cboard, int depth) {
+ (void)cboard;
+ (void)depth;
+ printf("bestmove d7d5\n");
+}
+
+void print_info(void) {
+ printf("id name chessTrainer\n");
+ printf("id author Dimitrije Dobrota\n");
+ printf("uciok\n");
+}
+
+typedef struct Instruction_T *Instruction_T;
+struct Instruction_T {
char *command;
char *token;
char *crnt;
};
-char *Position_token_next(Position_T self);
+char *Instruction_token_next(Instruction_T self);
-Position_T Position_new(char *command) {
- Position_T p;
+Instruction_T Instruction_new(char *command) {
+ Instruction_T p;
NEW0(p);
p->command = ALLOC(strlen(command) + 1);
p->token = ALLOC(strlen(command) + 1);
strcpy(p->command, command);
p->crnt = command;
- Position_token_next(p);
+ Instruction_token_next(p);
return p;
}
-void Position_free(Position_T *p) {
+void Instruction_free(Instruction_T *p) {
FREE((*p)->command);
FREE((*p)->token);
FREE(*p);
}
-char *Position_token(Position_T self) { return self->token; }
-char *Position_token_n(Position_T self, int n) {
+char *Instruction_token(Instruction_T self) { return self->token; }
+char *Instruction_token_n(Instruction_T self, int n) {
while (isspace(*self->crnt) && *self->crnt != '\0')
self->crnt++;
@@ -356,7 +492,7 @@ char *Position_token_n(Position_T self, int n) {
char *p = self->token;
while (n--) {
- while (!isspace(*self->crnt) && *self->crnt != '\0')
+ while (!isspace(*self->crnt) && *self->crnt != '\0' && *self->crnt != ';')
*p++ = *self->crnt++;
if (*self->crnt == '\0') {
p++;
@@ -370,7 +506,9 @@ char *Position_token_n(Position_T self, int n) {
return self->token;
}
-char *Position_token_next(Position_T self) { return Position_token_n(self, 1); }
+char *Instruction_token_next(Instruction_T self) {
+ return Instruction_token_n(self, 1);
+}
Move parse_move(CBoard_T self, char *move_string) {
Move result = 0;
@@ -398,62 +536,114 @@ Move parse_move(CBoard_T self, char *move_string) {
return result;
}
-CBoard_T Position_parse(Position_T self, CBoard_T board) {
- printf("Commands: %s\n", self->command);
- int count = 0;
- char *token = Position_token(self);
+CBoard_T Instruction_parse(Instruction_T self, CBoard_T board) {
+ char *token = Instruction_token(self);
+
+ if (!board)
+ board = CBoard_new();
+
do {
- printf("Token %d: %s\n", ++count, token);
+ if (strcmp(token, "ucinewgame") == 0) {
+ board = CBoard_fromFEN(board, start_position);
+ continue;
+ }
+
+ if (strcmp(token, "quit") == 0)
+ return NULL;
if (strcmp(token, "position") == 0) {
- printf("FOUND position\n");
- token = Position_token_next(self);
- if (strcmp(token, "startpos") == 0) {
- printf("FOUND startpos\n");
+ token = Instruction_token_next(self);
+ if (token && strcmp(token, "startpos") == 0) {
board = CBoard_fromFEN(board, start_position);
- } else if (strcmp(token, "fen") == 0) {
- token = Position_token_n(self, 6);
- printf("fen: %s\n", token);
+ } else if (token && strcmp(token, "fen") == 0) {
+ token = Instruction_token_n(self, 6);
board = CBoard_fromFEN(board, token);
- continue;
} else {
printf("Unknown argument after position\n");
- assert(0);
}
+ CBoard_print(board);
+ continue;
}
if (strcmp(token, "moves") == 0) {
- printf("FOUND moves\n");
- CBoard_print(board);
- while ((token = Position_token_next(self))) {
+ while ((token = Instruction_token_next(self))) {
Move move = parse_move(board, token);
if (move) {
make_move(board, move, 0);
- CBoard_print(board);
-
} else {
printf("Invalid move %s!\n", token);
- assert(0);
}
}
+ CBoard_print(board);
+ return board;
+ }
+
+ if (strcmp(token, "go") == 0) {
+ token = Instruction_token_next(self);
+ if (token && strcmp(token, "depth") == 0) {
+ token = Instruction_token_next(self);
+ search_position(board, atoi(token));
+ } else {
+ search_position(board, 6);
+ printf("Unknown argument after go\n");
+ }
+ continue;
}
- } while ((token = Position_token_next(self)));
+ if (strcmp(token, "isready") == 0) {
+ printf("readyok\n");
+ continue;
+ }
+
+ if (strcmp(token, "uci") == 0) {
+ print_info();
+ continue;
+ }
+
+ } while ((token = Instruction_token_next(self)));
return board;
}
-int main(void) {
- init_all();
+void uci_loop(void) {
+ CBoard_T board = NULL;
+ Instruction_T instruction;
+ char input[2000];
+
+ setbuf(stdin, NULL);
+ setbuf(stdout, NULL);
- CBoard_T board = NULL;
- Position_T position;
+ print_info();
+ while (1) {
+ memset(input, 0, sizeof(input));
+ fflush(stdout);
+ if (!fgets(input, sizeof(input), stdin))
+ continue;
- position =
- Position_new(" position \t fen " start_position " moves e2e4 e7e5");
- board = Position_parse(position, board);
- Position_free(&position);
+ instruction = Instruction_new(input);
+ if (!(board = Instruction_parse(instruction, board)))
+ break;
+ Instruction_free(&instruction);
+ }
+
+ Instruction_free(&instruction);
CBoard_free(&board);
+}
+int main(void) {
+ init_all();
+ int debug = 1;
+ if (debug) {
+ printf("debugging!\n");
+ CBoard_T board = NULL;
+ board = CBoard_fromFEN(board, start_position);
+ make_move(board, parse_move(board, "e2e4"), 0);
+ make_move(board, parse_move(board, "b7b6"), 0);
+ make_move(board, parse_move(board, "d2d4"), 0);
+ make_move(board, parse_move(board, "c8b7"), 0);
+ CBoard_print(board);
+ printf("Evaluation: %d\n", evaluate(board));
+ } else
+ uci_loop();
return 0;
}