From d38e2f454368e07cc72f19adb0e32d8cfcfc1e6a Mon Sep 17 00:00:00 2001 From: Bruno Raoult Date: Mon, 8 Nov 2021 08:38:38 +0100 Subject: [PATCH] Occupancy & square control bitboards + continue printf->logX --- .gitignore | 2 + Makefile | 9 ++++ make.deps | 2 +- src/board.h | 9 ++++ src/chessdefs.h | 7 ++- src/debug.h | 6 +-- src/fen.c | 2 + src/move.c | 140 ++++++++++++++++++++++++++---------------------- src/move.h | 6 ++- src/piece.c | 14 ++--- src/piece.h | 1 - src/position.c | 60 +++++++++++++++++++-- src/position.h | 15 ++++-- 13 files changed, 184 insertions(+), 89 deletions(-) diff --git a/.gitignore b/.gitignore index 5f5d2ff..45a4c57 100644 --- a/.gitignore +++ b/.gitignore @@ -6,6 +6,8 @@ fen pool piece move +bits debug +*.s /test/ /obj/ diff --git a/Makefile b/Makefile index bcaae7f..3ea66c6 100644 --- a/Makefile +++ b/Makefile @@ -25,9 +25,12 @@ OBJ=$(addprefix $(OBJDIR)/,$(SRC_S:.c=.o)) BIN=fen pool piece move debug CFLAGS += -std=gnu99 + +FLAGS += -O2 CFLAGS += -g CFLAGS += -Wall CFLAGS += -Wextra +CFLAGS += -march=native #CFLAGS += -pedantic #CFLAGS += -Wno-pointer-arith #CFLAGS += -Werror @@ -37,6 +40,7 @@ CFLAGS += -Wmissing-declarations CFLAGS += -DDEBUG # global CFLAGS += -DDEBUG_POOL # memory pools management CFLAGS += -DDEBUG_FEN # FEN decoding +CFLAGS += -DDEBUG_MOVE # move generation #CFLAGS += -DDEBUG_MAINSLEEP # sleep 1 sec within main loop (SIGINTR test) #CFLAGS += -DDEBUG_EVAL2 # eval 2 @@ -85,3 +89,8 @@ $(BIN): $$(subst $(OBJDIR)/$$@.o,,$(OBJ)) $(SRCDIR)/$$@.c # debug: CFLAGS+=-DDEBUGBIN # debug: $$(subst $(OBJDIR)/$$@.o,,$(OBJ)) $(SRCDIR)/$$@.c # $(CC) $(CFLAGS) $^ -o $@ + +.PHONY: bits +bits: test/bits.c + $(CC) $(CFLAGS) -S $^ -o $@.s + $(CC) -DFOO $(CFLAGS) $^ -o $@ diff --git a/make.deps b/make.deps index 1df5635..895f6a9 100644 --- a/make.deps +++ b/make.deps @@ -2,7 +2,7 @@ ./obj/fen.o:: src/fen.c src/debug.h src/chessdefs.h src/position.h src/board.h \ src/piece.h src/list.h src/pool.h src/fen.h ./obj/move.o:: src/move.c src/chessdefs.h src/piece.h src/board.h src/position.h \ - src/list.h src/pool.h src/move.h + src/list.h src/pool.h src/move.h src/debug.h ./obj/piece.o:: src/piece.c src/chessdefs.h src/piece.h src/board.h \ src/position.h src/list.h src/pool.h src/debug.h ./obj/pool.o:: src/pool.c src/list.h src/pool.h src/debug.h diff --git a/src/board.h b/src/board.h index 98a08e8..3de4dc2 100644 --- a/src/board.h +++ b/src/board.h @@ -34,6 +34,15 @@ typedef struct board_s { #define SQ88_NOK(s) ((s) & 0x88) /* invalid square */ #define SQ88_OK(s) (!SQ88_NOK(s)) +/* definitions for bitboard representation + */ +#define BB(f, r) (8 * (r) + (f)) /* from rank,file to bitboard */ +#define FILEBB(b) ((b) % 8) /* from sq88 to file */ +#define RANKBB(b) ((b) / 8) /* from sq88 to rank */ + +#define SQ88_NOK(s) ((s) & 0x88) /* invalid square */ +#define SQ88_OK(s) (!SQ88_NOK(s)) + /* piece human notation */ #define CHAR_EMPTY ' ' diff --git a/src/chessdefs.h b/src/chessdefs.h index c833983..5543af2 100644 --- a/src/chessdefs.h +++ b/src/chessdefs.h @@ -69,9 +69,14 @@ typedef unsigned char castle_t; #define CASTLE_W 0x03 /* 00000011 W castle mask */ #define CASTLE_B 0x0C /* 00001100 B castle mask */ +/* bitboard + */ +typedef uint64_t bitboard_t; + + /* eval type */ -typedef int64_t eval_t; +typedef int64_t eval_t; /* forward typedefs */ diff --git a/src/debug.h b/src/debug.h index 0b8cbeb..6bcdde5 100644 --- a/src/debug.h +++ b/src/debug.h @@ -30,7 +30,7 @@ void debug(uint32_t level, bool timestamp, uint32_t indent, #define log(level, fmt, args...) \ debug((level), false, 0, NULL, 0, fmt, ##args) -/* format: func name, no line number, indent, no timestamp +/* format: func name, no line number, no indent, no timestamp * foo:15 val=2 */ #define log_f(level, fmt, args...) \ @@ -40,13 +40,13 @@ void debug(uint32_t level, bool timestamp, uint32_t indent, * foo:15 val=2 */ #define log_i(level, fmt, args...) \ - debug((level), false, (level), __func__, __LINE__, fmt, args) + debug((level), false, (level), __func__, __LINE__, fmt, ##args) /* format : func name, indent, timestamp * []foo:15 val=2 */ #define log_it(level, fmt, args...) \ - debug((level), true, (level), __func__, __LINE__, fmt, args) + debug((level), true, (level), __func__, __LINE__, fmt, ##args) /* format: file name, no indent, no timestamp * foo:15 val=2 diff --git a/src/fen.c b/src/fen.c index 2b8014f..bba9f14 100644 --- a/src/fen.c +++ b/src/fen.c @@ -76,12 +76,14 @@ pos_t *fen2pos(pos_t *pos, char *fen) goto set_square; case CHAR_KING: piece = KING; + pos->king[color]=SQ88(file, rank); //goto set_square; set_square: # ifdef DEBUG_FEN log_i(5, "f=%d r=%d *p=%c piece=%c color=%d\n", file, rank, *p, cp, color); # endif + pos->occupied[color] |= (1LL << BB(file, rank)); piece |= color; board[SQ88(file, rank)].piece = piece; board[SQ88(file, rank)].s_piece = piece_add(pos, piece, SQUARE(file, rank)); diff --git a/src/move.c b/src/move.c index 9456f2a..f584ee5 100644 --- a/src/move.c +++ b/src/move.c @@ -17,19 +17,20 @@ #include "piece.h" #include "move.h" #include "list.h" +#include "debug.h" static pool_t *moves_pool; static struct vector { unsigned char ndirs; - char slide; - char dir[8]; + char slide; + char dir[8]; } vectors[] = { - [KNIGHT] = { 8, 0, { -33, -31, -18, -14, 14, 18, 31, 33}}, - [BISHOP] = { 4, 1, { -15, -17, 15, 17}}, - [ROOK] = { 4, 1, { -1, -16, 1, 16}}, - [QUEEN] = { 8, 1, { -1, -16, 1, 16, -15, -17, 15, 17}}, - [KING] = { 8, 0, { -1, -16, 1, 16, -15, -17, 15, 17}}, + [KNIGHT] = { 8, 0, { -33, -31, -18, -14, 14, 18, 31, 33 }}, + [BISHOP] = { 4, 1, { -15, -17, 15, 17 }}, + [ROOK] = { 4, 1, { -1, -16, 1, 16 }}, + [QUEEN] = { 8, 1, { -1, -16, 1, 16, -15, -17, 15, 17 }}, + [KING] = { 8, 0, { -1, -16, 1, 16, -15, -17, 15, 17 }} }; pool_t *moves_pool_init() @@ -42,11 +43,15 @@ pool_t *moves_pool_init() void move_print(move_t *move, move_flags_t flags) { if (flags & M_PR_CAPT && !(move->flags & M_CAPTURE)) { - // printf("capture & %#04x\n", move->flags); +# ifdef DEBUG_MOVE + log_i(4, "capture & %#04x\n", move->flags); +# endif return; } if (flags & M_PR_NCAPT && move->flags & M_CAPTURE) { - // printf("!capture & %#04x\n", move->flags); +# ifdef DEBUG_MOVE + log_i(4, "!capture & %#04x\n", move->flags); +# endif return; } if (move->flags & M_CASTLE_K) { @@ -73,11 +78,6 @@ void move_print(move_t *move, move_flags_t flags) printf("e.p."); if (move->promotion) printf("=%s", P_SYM(move->promotion)); - /*if (move->flags & M_CASTLE_K) - printf("(O-O)"); - if (move->flags & M_CASTLE_Q) - printf("(O-O-O)"); - */ end: printf(" "); } @@ -124,6 +124,8 @@ inline static move_t *move_add(pos_t *pos, piece_t piece, square_t from, board_t *board = pos->board; move_t *move; + if (COLOR(piece) != pos->turn) + return NULL; if (!(move = pool_get(moves_pool))) return NULL; move->piece = piece; @@ -141,11 +143,12 @@ inline static move_t *move_add(pos_t *pos, piece_t piece, square_t from, inline static move_t *move_pawn_add(pos_t *pos, piece_t piece, square_t from, square_t to, unsigned char rank7) { - //board_t *board = pos->board; move_t *move; piece_t promote; unsigned char color = COLOR(piece); + if (color != pos->turn) + return NULL; if (RANK88(from) == rank7) { /* promotion */ for (promote = QUEEN; promote > PAWN; promote >>= 1) { if ((move = move_add(pos, piece, from, to))) { @@ -165,8 +168,8 @@ inline static move_t *move_pawn_add(pos_t *pos, piece_t piece, square_t from, int pseudo_moves_pawn(pos_t *pos, piece_list_t *ppiece) { piece_t piece = PIECE(ppiece->piece); - square_t square = ppiece->square, new; unsigned char color = COLOR(ppiece->piece); + square_t square = ppiece->square, new; board_t *board = pos->board; unsigned char rank2, rank7, rank5; move_t *move = NULL; @@ -189,19 +192,20 @@ int pseudo_moves_pawn(pos_t *pos, piece_list_t *ppiece) /* normal push. We do not test for valid destination square here, * assuming position is valid. Is that correct ? */ - //moves_print(pos); new = square + dir * 16; if (!board[new].piece) { - //printf("pushing pawn %#04x\n", square); +# ifdef DEBUG_MOVE + log_i(4, "pushing pawn %#04x\n", square); +# endif if ((move = move_pawn_add(pos, piece | color, square, new, rank7))) count++; - //moves_print(pos); - /* push 2 squares */ if (move && RANK88(square) == rank2) { new += dir * 16; if (SQ88_OK(new) && !board[new].piece) { - //printf("pushing pawn %#04x 2 squares\n", square); +# ifdef DEBUG_MOVE + log_i(4, "pushing pawn %#04x 2 squares\n", square); +# endif if ((move = move_pawn_add(pos, piece | color, square, new, rank7))) count++; } @@ -213,9 +217,10 @@ int pseudo_moves_pawn(pos_t *pos, piece_list_t *ppiece) unsigned char ep_file = FILE88(pos->en_passant); unsigned char sq_file = FILE88(square); - //printf("possible en passant on rank %#x (current = %#0x)\n", ep_file, - // sq_file); - +# ifdef DEBUG_MOVE + log_i(4, "possible en passant on rank %#x (current = %#0x)\n", ep_file, + sq_file); +# endif if (sq_file == ep_file - 1 || sq_file == ep_file + 1) { square_t taken = board[SQUARE(ep_file, rank5)].piece; move = move_pawn_add(pos, piece | color , square, pos->en_passant, rank7); @@ -230,10 +235,12 @@ int pseudo_moves_pawn(pos_t *pos, piece_list_t *ppiece) /* capture */ int two=0; for (new = square + dir * 15; two < 2; new = square + dir * 17, two++) { - //for (new = square + dir * 15; new <= square + dir * 17; new += 2) { - //printf("pawn capture %#04x\n", square); +# ifdef DEBUG_MOVE + log_i(3, "pawn capture %#04x %#04x\n", square, new); +# endif if (SQ88_NOK(new)) continue; + pos->controlled[color] |= (1ULL << BB(FILE88(new), RANK88(new))); if (board[new].piece && COLOR(board[new].piece) != color) { if ((move = move_pawn_add(pos, piece | color, square, new, rank7))) count++; @@ -291,47 +298,64 @@ int pseudo_moves_castle(pos_t *pos) int pseudo_moves_gen(pos_t *pos, piece_list_t *ppiece) { piece_t piece = PIECE(ppiece->piece); + unsigned char color = COLOR(ppiece->piece); struct vector *vector = vectors+piece; square_t square = ppiece->square; unsigned char ndirs = vector->ndirs; char slide = vector->slide; board_t *board = pos->board; - unsigned char color = COLOR(ppiece->piece); move_t *move; int count = 0; - /*printf("square=%#04x piece=%#04x color = %s\n", square, piece, color==WHITE? "white": "black"); - printf("%s: pos:%p piece:%d [%s] at %#04x[%c%c]\n", __func__, pos, piece, - P_NAME(piece), - square, - FILE2C(GET_F(square)), - RANK2C(GET_R(square))); - printf("\tvector=%ld ndirs=%d slide=%d\n", vector-vectors, ndirs, slide); - */ +# ifdef DEBUG_MOVE + log_i(4, "square=%#04x piece=%#04x color = %s\n", square, piece, + color==WHITE? "white": "black"); + log_f(3, "pos:%p piece:%d [%s] at %#04x[%c%c]\n", pos, piece, + P_NAME(piece), square, + FILE2C(GET_F(square)), RANK2C(GET_R(square))); + log_i(4, "vector=%ld ndirs=%d slide=%d\n", vector-vectors, ndirs, slide); +# endif for (int curdir = 0; curdir < ndirs; ++curdir) { char dir = vector->dir[curdir]; for (square_t new = square + dir; ; new = new + dir) { /* outside board */ if (SQ88_NOK(new)) { - //printf("\t\tskipping %04x (invalid square)\n", new); +# ifdef DEBUG_MOVE + log_i(4,"skipping %04x (invalid square)\n", new); +# endif break; } - // printf("\ttrying %c%c", FILE2C(GET_F(new)), RANK2C(GET_R(new))); +# ifdef DEBUG_MOVE + log_i(3, "trying %c%c\n", FILE2C(GET_F(new)), RANK2C(GET_R(new))); +# endif /* own color on dest square */ - /*if (board[new].piece) { - printf("color=%d color2=%d\n", color, COLOR(board[new].piece)); - }*/ - if (board[new].piece && COLOR(board[new].piece) == color) { - //printf("\t\tskipping %04x (same color piece)\n", new); - break; + if (board[new].piece) { +# ifdef DEBUG_MOVE + log_i(4, "color=%d color2=%d\n", color, COLOR(board[new].piece)); +# endif + } + pos->controlled[color] |= (1ULL << BB(FILE88(new), RANK88(new))); + if (board[new].piece) { + if (COLOR(board[new].piece) == color) { +# ifdef DEBUG_MOVE + log_i(3, "skipping %04x (same color piece)\n", new); +# endif + break; + } } /* we are sure the move is valid : we create move */ - if ((move = move_add(pos, piece, square, new))) - count++; - if (move->taken) + if (color == pos->turn) { + if ((move = move_add(pos, piece, square, new))) { + count++; + //if (move->taken) + // break; + } + } + if (board[new].piece) { break; + } if (!slide) break; } @@ -339,13 +363,13 @@ int pseudo_moves_gen(pos_t *pos, piece_list_t *ppiece) return count; } -int moves_get(pos_t *pos) +int moves_gen(pos_t *pos, bool color) { struct list_head *p_cur, *tmp, *piece_list; piece_list_t *piece; int count = 0; - piece_list = pos->turn == WHITE? &pos->pieces_white: &pos->pieces_black; + piece_list = &pos->pieces[color]; pseudo_moves_castle(pos); list_for_each_safe(p_cur, tmp, piece_list) { @@ -360,17 +384,6 @@ int moves_get(pos_t *pos) return count; } -/* unused - move_t *(*moves_fct[])(pos_t *) = { - [PAWN] = pseudo_moves_pawn, - [KNIGHT] = pseudo_moves_knight, - [BISHOP] = pseudo_moves_bishop, - [ROOK] = pseudo_moves_rook, - [QUEEN] = pseudo_moves_queen, - [KING] = pseudo_moves_king - }; -*/ - #ifdef BIN_move #include "fen.h" #include "debug.h" @@ -378,19 +391,20 @@ int main(int ac, char**av) { pos_t *pos; - debug_init(1); - pos = pos_create(); + debug_init(2); piece_pool_init(); moves_pool_init(); + pos = pos_create(); if (ac == 1) { pos_startpos(pos); } else { fen2pos(pos, av[1]); } + moves_gen(pos, WHITE); + moves_gen(pos, BLACK); pos_print(pos); - pieces_print_pos_pieces(pos); - moves_get(pos); + pos_pieces_print(pos); moves_print(pos, M_PR_SEPARATE); } #endif diff --git a/src/move.h b/src/move.h index e2399da..666a6d5 100644 --- a/src/move.h +++ b/src/move.h @@ -19,6 +19,10 @@ #include "pool.h" #include "piece.h" +/* move_add() return value when generating + */ + + /* move flags */ typedef unsigned char move_flags_t; @@ -52,6 +56,6 @@ void moves_print(pos_t *move, move_flags_t flags); int pseudo_moves_castle(pos_t *pos); int pseudo_moves_gen(pos_t *pos, piece_list_t *piece); int pseudo_moves_pawn(pos_t *pos, piece_list_t *piece); -int moves_get(pos_t *pos); +int moves_gen(pos_t *pos, bool color); #endif /* MODE_H */ diff --git a/src/piece.c b/src/piece.c index 28593bb..9d6f5bf 100644 --- a/src/piece.c +++ b/src/piece.c @@ -46,14 +46,6 @@ void piece_list_print(struct list_head *list) printf("Total pieces = %d\n", i); } -void pieces_print_pos_pieces(pos_t *pos) -{ - printf("White pieces : \n\t"); - piece_list_print(&pos->pieces_white); - printf("Black pieces : \n\t"); - piece_list_print(&pos->pieces_black); -} - pool_t *piece_pool_init() { if (!pieces_pool) @@ -81,8 +73,8 @@ piece_list_t *piece_add(pos_t *pos, piece_t piece, square_t square) piece2string(piece), FILE2C(GET_F(square)), RANK2C(GET_R(square))); # endif if ((new = pool_get(pieces_pool))) { - list_add_tail(&new->list, - color? &pos->pieces_black: &pos->pieces_white); + list_add_tail(&new->list, &pos->pieces[color]); + //color? &pos->pieces_black: &pos->pieces_white); new->piece = piece; new->square = square; new->castle = 0; @@ -108,6 +100,6 @@ int main(int ac, char**av) fen2pos(pos, av[1]); } pos_print(pos); - pieces_print_pos_pieces(pos); + pos_pieces_print(pos); } #endif diff --git a/src/piece.h b/src/piece.h index 1536776..5859354 100644 --- a/src/piece.h +++ b/src/piece.h @@ -63,7 +63,6 @@ extern struct piece_details { #define P_USE_UTF 1 void piece_list_print(struct list_head *list); -void pieces_print_pos_pieces(pos_t *pos); pool_t *piece_pool_init(); piece_list_t *piece_add(pos_t *pos, piece_t piece, square_t square); diff --git a/src/position.c b/src/position.c index a583970..1685a3e 100644 --- a/src/position.c +++ b/src/position.c @@ -22,6 +22,43 @@ #include "fen.h" #include "piece.h" +#define BYTE_PRINT "%c%c%c%c%c%c%c%c" +#define BYTE2BIN(b) ((b) & 0x01 ? '1' : '0'), \ + ((b) & 0x02 ? '1' : '0'), \ + ((b) & 0x04 ? '1' : '0'), \ + ((b) & 0x08 ? '1' : '0'), \ + ((b) & 0x10 ? '1' : '0'), \ + ((b) & 0x20 ? '1' : '0'), \ + ((b) & 0x40 ? '1' : '0'), \ + ((b) & 0x80 ? '1' : '0') + +inline void bitboard_print(bitboard_t bb) +{ + int i; + printf("%#018lx\n", bb); + for (i=56; i; i-=8) + printf("\t"BYTE_PRINT"\n", + BYTE2BIN(bb>>i)); +} + +inline void bitboard_print2(bitboard_t bb1, bitboard_t bb2) +{ + int i; + printf("\tW: %#018lx\tB: %#018lx\n", bb1, bb2); + for (i=56; i>=0; i-=8) + printf("\t"BYTE_PRINT"\t\t"BYTE_PRINT"\n", + BYTE2BIN(bb1>>i), + BYTE2BIN(bb2>>i)); +} + +void pos_pieces_print(pos_t *pos) +{ + printf("White pieces : \n\t"); + piece_list_print(&pos->pieces[WHITE]); + printf("Black pieces : \n\t"); + piece_list_print(&pos->pieces[BLACK]); +} + /* void pos_print - Print position on stdout. * @pos: Position address (pos_t * ) * @@ -43,7 +80,12 @@ void pos_print(pos_t *pos) printf("\n +---+---+---+---+---+---+---+---+\n"); } printf(" A B C D E F G H\n\n"); - printf("Next move: %s.\n", IS_WHITE(pos->turn) ? "white" : "black"); + printf("Turn: %s.\n", IS_WHITE(pos->turn) ? "white" : "black"); + printf("Kings: W:%c%c B:%c%c\n", + FILE2C(GET_F(pos->king[WHITE])), + RANK2C(GET_R(pos->king[WHITE])), + FILE2C(GET_F(pos->king[BLACK])), + RANK2C(GET_R(pos->king[BLACK]))); printf("Possible en-passant: [%#x] ", pos->en_passant); if (pos->en_passant == 0) printf("None.\n"); @@ -66,6 +108,10 @@ void pos_print(pos_t *pos) printf("\n50 half-moves-rule = %d\n", pos->clock_50); printf("Current move = %d\n", pos->curmove); + printf("Bitbords occupied :\n"); + bitboard_print2(pos->occupied[WHITE], pos->occupied[BLACK]); + printf("Bitbords controlled :\n"); + bitboard_print2(pos->controlled[WHITE], pos->controlled[BLACK]); } pos_t *pos_init(pos_t *pos) @@ -87,10 +133,16 @@ pos_t *pos_init(pos_t *pos) pos->castle = 0; pos->clock_50 = 0; pos->curmove = 0; + pos->eval = 0; pos->en_passant = 0; - pos->en_passant = 0; - INIT_LIST_HEAD(&pos->pieces_white); - INIT_LIST_HEAD(&pos->pieces_black); + pos->king[WHITE] = 0; + pos->king[BLACK] = 0; + pos->occupied[WHITE] = 0; + pos->occupied[BLACK] = 0; + pos->controlled[WHITE] = 0; + pos->controlled[BLACK] = 0; + INIT_LIST_HEAD(&pos->pieces[WHITE]); + INIT_LIST_HEAD(&pos->pieces[BLACK]); INIT_LIST_HEAD(&pos->moves); return pos; diff --git a/src/position.h b/src/position.h index 2e3ad65..f5792d3 100644 --- a/src/position.h +++ b/src/position.h @@ -22,16 +22,23 @@ typedef struct pos_s { piece_t turn; /* we use only color bit */ castle_t castle; - square_t en_passant; short clock_50; short curmove; eval_t eval; - struct list_head pieces_white; - struct list_head pieces_black; - struct list_head moves; board_t *board; + + square_t en_passant; + square_t king[2]; + bitboard_t occupied[2]; + bitboard_t controlled[2]; + + struct list_head pieces[2]; + struct list_head moves; } pos_t; +void bitboard_print(bitboard_t bb); +void bitboard_print2(bitboard_t bb1, bitboard_t bb2); +void pos_pieces_print(pos_t *pos); void pos_print(pos_t *pos); pos_t *pos_init(pos_t *pos); pos_t *pos_startpos(pos_t *pos);