commit 1d52c2087a2d9211d186318ca6bd568f88828d60
parent 8f954a0404ce9be9d8d5cb9bb59257b6cb5b83f3
Author: Dimitrije Dobrota <mail@dimitrijedobrota.com>
Date: Sat, 29 Jul 2023 21:48:06 +0200
Extract Piece interface
Diffstat:
14 files changed, 148 insertions(+), 141 deletions(-)
diff --git a/CMakeLists.txt b/CMakeLists.txt
@@ -3,7 +3,7 @@ set(CMAKE_EXPORT_COMPILE_COMMANDS ON)
project(
Stellar
- VERSION 0.0.0
+ VERSION 0.0.1
DESCRIPTION "Chess engine written in C"
HOMEPAGE_URL https://git.dimitrijedobrota.com/stellar.git
LANGUAGES C
diff --git a/src/attack/attack.c b/src/attack/attack.c
@@ -1,7 +1,7 @@
#include "string.h"
#include "attack.h"
-#include "utils.h"
+#include "piece.h"
#define UNUSED(x) (void)(x)
diff --git a/src/board/board.c b/src/board/board.c
@@ -5,66 +5,8 @@
#include <cul/assert.h>
#include <cul/mem.h>
-#include "attack.h"
#include "board.h"
-#include "utils.h"
-
-U64 board_pieceBB_get(Board self, ePiece piece, Square target);
-
-// PIECE
-struct Piece {
- ePiece piece;
- eColor color;
- char code;
- char asci;
- char *unicode;
- attack_f attacks;
-};
-
-// clang-format off
-struct Piece Pieces[2][6] = {
- {
- [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},
- },
- {
- [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 self) { return self->attacks; }
-char Piece_asci(Piece self) { return self->asci; }
-char Piece_code(Piece self) { return self->code; }
-char *Piece_unicode(Piece self) { return self->unicode; }
-eColor Piece_color(Piece self) { return self->color; }
-ePiece Piece_piece(Piece self) { return self->piece; }
-int Piece_index(Piece self) { return self->color * 8 + self->piece; }
-
-Piece Piece_fromCode(char code) {
- int color = (isupper(code)) ? WHITE : BLACK;
- for (int i = 0; i < 6; i++)
- if (Pieces[color][i].code == code) return &Pieces[color][i];
- return NULL;
-}
-
-ePiece Piece_piece_fromCode(int index) {
- return Pieces[WHITE][index % 8].piece;
-}
-
-Piece Piece_fromIndex(int index) { return &Pieces[index / 8][index % 8]; }
-Piece Piece_get(ePiece piece, eColor color) { return &Pieces[color][piece]; }
-// CBOARD
struct Board {
U64 colorBB[2];
U64 pieceBB[6];
@@ -97,8 +39,8 @@ U64 board_pieceBB_get(Board self, ePiece piece, Square target) {
}
U64 board_pieceSet(Board self, Piece piece) {
- return self->pieceBB[Piece_piece(piece)] &
- self->colorBB[Piece_color(piece)];
+ return self->pieceBB[piece_piece(piece)] &
+ self->colorBB[piece_color(piece)];
}
void board_enpassant_set(Board self, Square target) {
@@ -121,14 +63,14 @@ int board_piece_get(Board self, Square square) {
return -1;
}
-void board_piece_pop(Board self, Piece Piece, Square square) {
- bit_pop(self->pieceBB[Piece->piece], square);
- bit_pop(self->colorBB[Piece->color], square);
+void board_piece_pop(Board self, Piece piece, Square square) {
+ bit_pop(self->pieceBB[piece_piece(piece)], square);
+ bit_pop(self->colorBB[piece_color(piece)], square);
}
-void board_piece_set(Board self, Piece Piece, Square square) {
- bit_set(self->pieceBB[Piece->piece], square);
- bit_set(self->colorBB[Piece->color], square);
+void board_piece_set(Board self, Piece piece, Square square) {
+ bit_set(self->pieceBB[piece_piece(piece)], square);
+ bit_set(self->colorBB[piece_color(piece)], square);
}
void board_piece_move(Board self, Piece Piece, Square source, Square target) {
@@ -136,8 +78,8 @@ void board_piece_move(Board self, Piece Piece, Square source, Square target) {
board_piece_set(self, Piece, target);
}
-U64 board_piece_attacks(Board self, Piece Piece, Square src) {
- return Piece_attacks(Piece)(src, board_occupancy(self));
+U64 board_piece_attacks(Board self, Piece piece, Square src) {
+ return piece_attacks(piece)(src, board_occupancy(self));
}
void board_piece_capture(Board self, Piece piece, Piece taken, Square source,
@@ -166,8 +108,8 @@ int board_square_isAttack(Board self, Square square, eColor side) {
U64 occupancy = self->colorBB[WHITE] | self->colorBB[BLACK];
for (int i = 0; i < 6; i++) {
- if (Pieces[!side][i].attacks(square, occupancy) & self->pieceBB[i] &
- self->colorBB[side])
+ if (piece_attacks(piece_get(i, !side))(square, occupancy) &
+ self->pieceBB[i] & self->colorBB[side])
return 1;
}
@@ -176,7 +118,7 @@ int board_square_isAttack(Board self, Square square, eColor side) {
Piece board_square_piece(Board self, Square square, eColor color) {
for (ePiece i = 0; i < 6; i++)
- if (board_pieceBB_get(self, i, square)) return Piece_get(i, color);
+ if (board_pieceBB_get(self, i, square)) return piece_get(i, color);
return NULL;
}
@@ -195,7 +137,7 @@ void board_print(Board self) {
if (color != -1) {
for (int piece_index = 0; piece_index < 6; piece_index++) {
if (bit_get(self->pieceBB[piece_index], square)) {
- piece = &Pieces[color][piece_index];
+ piece = piece_get(piece_index, color);
break;
}
}
@@ -203,7 +145,7 @@ void board_print(Board self) {
if (!file) printf(" %d ", 8 - rank);
- printf("%s", (piece) ? Piece_unicode(piece) : ". ");
+ printf("%s", (piece) ? piece_unicode(piece) : ". ");
}
printf("\n");
}
@@ -216,7 +158,7 @@ void board_print(Board self) {
printf("\n");
}
-Board board_fromFEN(Board board, char *fen) {
+Board board_from_FEN(Board board, char *fen) {
if (!board) NEW(board);
memset(board, 0, sizeof(*board));
@@ -229,9 +171,9 @@ Board board_fromFEN(Board board, char *fen) {
for (Piece piece; *fen != ' '; fen++) {
Square square = rank * 8 + file;
if (isalpha(*fen)) {
- if (!(piece = Piece_fromCode(*fen))) assert(0);
- bit_set(board->colorBB[piece->color], square);
- bit_set(board->pieceBB[piece->piece], square);
+ if (!(piece = piece_from_code(*fen))) assert(0);
+ bit_set(board->colorBB[piece_color(piece)], square);
+ bit_set(board->pieceBB[piece_piece(piece)], square);
file++;
} else if (isdigit(*fen)) {
file += *fen - '0';
diff --git a/src/engine/CMakeLists.txt b/src/engine/CMakeLists.txt
@@ -4,6 +4,7 @@ target_link_libraries(engine
PRIVATE attack
PRIVATE board
PRIVATE moves
+ PRIVATE piece
PRIVATE score
PRIVATE utils
)
diff --git a/src/engine/engine.c b/src/engine/engine.c
@@ -13,7 +13,6 @@
#include <cul/assert.h>
#include <cul/mem.h>
-
#define MAX_PLY 64
typedef struct Stats_T *Stats_T;
@@ -36,15 +35,15 @@ void Stats_free(Stats_T *p) { FREE(*p); }
int move_score(Stats_T stats, Move move) {
if (move_capture(move)) {
- return Score_capture(Piece_piece(move_piece(move)),
- Piece_piece(move_piece_capture(move)));
+ return Score_capture(piece_piece(move_piece(move)),
+ piece_piece(move_piece_capture(move)));
} else {
if (!move_cmp(stats->killer_moves[0][stats->ply], move))
return 9000;
else if (!move_cmp(stats->killer_moves[1][stats->ply], move))
return 8000;
else
- return stats->history_moves[Piece_index(move_piece(move))]
+ return stats->history_moves[piece_index(move_piece(move))]
[move_target(move)];
}
@@ -184,7 +183,7 @@ int negamax(Stats_T stats, Board board, int alpha, int beta, int depth) {
if (score > alpha) {
if (!move_capture(move))
- stats->history_moves[Piece_index(move_piece(move))]
+ stats->history_moves[piece_index(move_piece(move))]
[move_target(move)] += depth;
alpha = score;
@@ -210,7 +209,7 @@ int negamax(Stats_T stats, Board board, int alpha, int beta, int depth) {
void move_print_UCI(Move move) {
printf("%s%s", square_to_coordinates[move_source(move)],
square_to_coordinates[move_target(move)]);
- if (move_promote(move)) printf(" %c", Piece_asci(move_piece_promote(move)));
+ if (move_promote(move)) printf(" %c", piece_asci(move_piece_promote(move)));
}
void search_position(Board board, int depth) {
@@ -312,7 +311,7 @@ Move parse_move(Board board, char *move_string) {
Move move = moves->moves[i];
if (move_source(move) == source && move_target(move) == target) {
if (move_string[4]) {
- if (tolower(Piece_code(move_piece_promote(move))) !=
+ if (tolower(piece_code(move_piece_promote(move))) !=
move_string[4])
continue;
}
@@ -332,7 +331,7 @@ Board Instruction_parse(Instruction_T self, Board board) {
do {
if (strcmp(token, "ucinewgame") == 0) {
- board = board_fromFEN(board, start_position);
+ board = board_from_FEN(board, start_position);
continue;
}
@@ -341,10 +340,10 @@ Board Instruction_parse(Instruction_T self, Board board) {
if (strcmp(token, "position") == 0) {
token = Instruction_token_next(self);
if (token && strcmp(token, "startpos") == 0) {
- board = board_fromFEN(board, start_position);
+ board = board_from_FEN(board, start_position);
} else if (token && strcmp(token, "fen") == 0) {
token = Instruction_token_n(self, 6);
- board = board_fromFEN(board, token);
+ board = board_from_FEN(board, token);
} else {
printf("Unknown argument after position\n");
}
diff --git a/src/include/board.h b/src/include/board.h
@@ -1,7 +1,7 @@
-#ifndef CBOARD_H
-#define CBOARD_H
+#ifndef BOARD_H
+#define BOARD_H
-#include "utils.h"
+#include "piece.h"
enum enumCastle {
WK = 1,
@@ -11,20 +11,6 @@ enum enumCastle {
};
typedef enum enumCastle eCastle;
-typedef struct Piece *Piece;
-
-char Piece_asci(Piece self);
-char Piece_code(Piece self);
-char *Piece_unicode(Piece self);
-eColor Piece_color(Piece self);
-ePiece Piece_piece(Piece self);
-int Piece_index(Piece self);
-
-Piece Piece_get(ePiece piece, eColor color);
-Piece Piece_fromCode(char code);
-Piece Piece_fromIndex(int index);
-ePiece Piece_piece_fromCode(int index);
-
typedef struct Board *Board;
Board board_new(void);
@@ -60,7 +46,7 @@ Piece board_square_piece(Board self, Square square, eColor side);
int board_square_isAttack(Board self, Square square, eColor side);
int board_square_isOccupied(Board self, Square square);
-Board board_fromFEN(Board board, char *fen);
+Board board_from_FEN(Board board, char *fen);
int board_isCheck(Board self);
void board_print(Board self);
void board_side_switch(Board self);
diff --git a/src/include/moves.h b/src/include/moves.h
@@ -47,8 +47,8 @@ int move_make(Move move, Board board, int flag);
#define move_capture(move) (move.capture)
#define move_promote(move) (move.promote)
-#define move_piece(move) (Piece_fromIndex(move.piece))
-#define move_piece_capture(move) (Piece_fromIndex(move.piece_capture))
-#define move_piece_promote(move) (Piece_fromIndex(move.piece_promote))
+#define move_piece(move) (piece_from_index(move.piece))
+#define move_piece_capture(move) (piece_from_index(move.piece_capture))
+#define move_piece_promote(move) (piece_from_index(move.piece_promote))
#endif
diff --git a/src/include/piece.h b/src/include/piece.h
@@ -0,0 +1,36 @@
+#ifndef PIECE_H
+#define PIECE_H
+
+#include "attack.h"
+
+typedef const struct Piece *Piece;
+
+typedef enum enumColor eColor;
+enum enumColor {
+ WHITE = 0,
+ BLACK
+};
+
+typedef enum enumPiece ePiece;
+enum enumPiece {
+ PAWN = 0,
+ KNIGHT,
+ BISHOP,
+ ROOK,
+ QUEEN,
+ KING
+};
+
+char piece_asci(Piece self);
+attack_f piece_attacks(Piece self);
+char piece_code(Piece self);
+char *piece_unicode(Piece self);
+eColor piece_color(Piece self);
+ePiece piece_piece(Piece self);
+int piece_index(Piece self);
+
+Piece piece_get(ePiece piece, eColor color);
+Piece piece_from_code(char code);
+Piece piece_from_index(int index);
+
+#endif
diff --git a/src/include/utils.h b/src/include/utils.h
@@ -62,23 +62,6 @@ U64 noWeOne(U64 b);
U64 rotateLeft(U64 x, int s);
U64 rotateRight(U64 x, int s);
-// enum types for color and piece type
-enum enumColor {
- WHITE = 0,
- BLACK
-};
-enum enumPiece {
- PAWN = 0,
- KNIGHT,
- BISHOP,
- ROOK,
- QUEEN,
- KING
-};
-
-typedef enum enumColor eColor;
-typedef enum enumPiece ePiece;
-
int get_time_ms(void);
typedef U64 (*attack_f)(Square square, U64 occupancy);
diff --git a/src/moves/moves.c b/src/moves/moves.c
@@ -17,9 +17,9 @@ Move move_encode(Square src, Square tgt, Piece piece, Piece capture,
.castle = castle,
.capture = capture != NULL,
.promote = promote != NULL,
- .piece = Piece_index(piece),
- .piece_capture = capture ? Piece_index(capture) : 0,
- .piece_promote = promote ? Piece_index(promote) : 0,
+ .piece = piece_index(piece),
+ .piece_capture = capture ? piece_index(capture) : 0,
+ .piece_promote = promote ? piece_index(promote) : 0,
};
}
@@ -27,9 +27,9 @@ void move_print(Move move) {
printf("%5s %5s %2s %2s %2s %4d %4d %4d %4d %4d\n",
square_to_coordinates[move_source(move)],
square_to_coordinates[move_target(move)],
- Piece_unicode(move_piece(move)),
- move_capture(move) ? Piece_unicode(move_piece_capture(move)) : "X ",
- move_promote(move) ? Piece_unicode(move_piece_promote(move)) : "X ",
+ piece_unicode(move_piece(move)),
+ move_capture(move) ? piece_unicode(move_piece_capture(move)) : "X ",
+ move_promote(move) ? piece_unicode(move_piece_promote(move)) : "X ",
move_double(move) ? 1 : 0, move_enpassant(move) ? 1 : 0,
move_castle(move) ? 1 : 0, move_capture(move) ? 1 : 0,
move_promote(move) ? 1 : 0);
@@ -69,7 +69,7 @@ void move_list_print(MoveList self) {
#define pawn_promote(source, target, Piece, Capture) \
for (int i = 1; i < 5; i++) { \
move = move_encode(source, target, Piece, Capture, \
- Piece_get(i, color), 0, 0, 0); \
+ piece_get(i, color), 0, 0, 0); \
move_list_add(moves, move); \
}
@@ -81,7 +81,7 @@ MoveList move_list_generate(MoveList moves, Board board) {
if (!moves) moves = move_list_new();
{ // pawn moves
- Piece Piece = Piece_get(PAWN, color);
+ Piece Piece = piece_get(PAWN, color);
U64 bitboard = board_pieceSet(board, Piece);
bitboard_for_each_bit(src, bitboard) {
{ // quiet
@@ -135,7 +135,7 @@ MoveList move_list_generate(MoveList moves, Board board) {
// All piece move
for (int piece = 1; piece < 6; piece++) {
- Piece Piece = Piece_get(piece, color);
+ Piece Piece = piece_get(piece, color);
U64 bitboard = board_pieceSet(board, Piece);
bitboard_for_each_bit(src, bitboard) {
U64 attack = board_piece_attacks(board, Piece, src) &
@@ -153,7 +153,7 @@ MoveList move_list_generate(MoveList moves, Board board) {
// Castling
{
if (color == WHITE) {
- Piece Piece = Piece_get(KING, WHITE);
+ Piece Piece = piece_get(KING, WHITE);
if (board_castle(board) & WK) {
if (!board_square_isOccupied(board, f1) &&
!board_square_isOccupied(board, g1) &&
@@ -172,7 +172,7 @@ MoveList move_list_generate(MoveList moves, Board board) {
move_encode(e1, c1, Piece, 0, 0, 0, 0, 1));
}
} else {
- Piece Piece = Piece_get(KING, BLACK);
+ Piece Piece = piece_get(KING, BLACK);
if (board_castle(board) & BK) {
if (!board_square_isOccupied(board, f8) &&
!board_square_isOccupied(board, g8) &&
@@ -231,13 +231,13 @@ int move_make(Move move, Board board, int flag) {
{
int ntarget = target + (color == WHITE ? -8 : +8);
if (move_enpassant(move))
- board_piece_pop(board, Piece_get(PAWN, !color), ntarget);
+ board_piece_pop(board, piece_get(PAWN, !color), ntarget);
board_enpassant_set(board, move_double(move) ? ntarget : no_sq);
}
if (move_castle(move)) {
- Piece Rook = Piece_get(ROOK, board_side(board));
+ Piece Rook = piece_get(ROOK, board_side(board));
switch (target) {
case g1:
board_piece_move(board, Rook, h1, f1);
diff --git a/src/perft/CMakeLists.txt b/src/perft/CMakeLists.txt
@@ -4,6 +4,7 @@ target_link_libraries(perft
PRIVATE attack
PRIVATE board
PRIVATE moves
+ PRIVATE piece
PRIVATE score
PRIVATE utils
)
diff --git a/src/perft/perft.c b/src/perft/perft.c
@@ -140,6 +140,6 @@ void perft_test_threaded(Board board, int depth) {
int main(void) {
init_attacks();
Board board = board_new();
- board_fromFEN(board, tricky_position);
+ board_from_FEN(board, tricky_position);
perft_test_threaded(board, 5);
}
diff --git a/src/piece/CMakeLists.txt b/src/piece/CMakeLists.txt
@@ -0,0 +1,7 @@
+add_library(piece OBJECT
+ piece.c
+)
+
+target_include_directories(piece
+ PUBLIC "${PROJECT_SOURCE_DIR}/src/include"
+)
diff --git a/src/piece/piece.c b/src/piece/piece.c
@@ -0,0 +1,52 @@
+#include <ctype.h>
+#include <stdlib.h>
+
+#include "attack.h"
+#include "board.h"
+
+struct Piece {
+ attack_f attacks;
+ char *unicode;
+ ePiece piece;
+ eColor color;
+ char code;
+ char asci;
+};
+
+// clang-format off
+const struct Piece Pieces[2][6] = {
+[WHITE] = {
+ [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},
+ [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},
+ [PAWN] = {.color = WHITE, .code = 'P', .asci = 'P', .unicode = "♙ ", .piece = PAWN, .attacks = get_wpawn_attacks},
+ [ROOK] = {.color = WHITE, .code = 'R', .asci = 'R', .unicode = "♖ ", .piece = ROOK, .attacks = get_rook_attacks},
+ },
+[BLACK] = {
+ [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},
+ [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},
+ [PAWN] = {.color = BLACK, .code = 'p', .asci = 'p', .unicode = "♟ ", .piece = PAWN, .attacks = get_bpawn_attacks},
+ [ROOK] = {.color = BLACK, .code = 'r', .asci = 'r', .unicode = "♜ ", .piece = ROOK, .attacks = get_rook_attacks},
+ },
+};
+// clang-format on
+
+attack_f piece_attacks(Piece self) { return self->attacks; }
+char piece_asci(Piece self) { return self->asci; }
+char piece_code(Piece self) { return self->code; }
+char *piece_unicode(Piece self) { return self->unicode; }
+eColor piece_color(Piece self) { return self->color; }
+ePiece piece_piece(Piece self) { return self->piece; }
+int piece_index(Piece self) { return self->color * 8 + self->piece; }
+
+Piece piece_get(ePiece piece, eColor color) { return &Pieces[color][piece]; }
+Piece piece_from_index(int index) { return &Pieces[index / 8][index % 8]; }
+Piece piece_from_code(char code) {
+ int color = (isupper(code)) ? WHITE : BLACK;
+ for (int i = 0; i < 6; i++)
+ if (Pieces[color][i].code == code) return &Pieces[color][i];
+ return NULL;
+}