From 183e9ef2be16d07654d39e621262106881c761d6 Mon Sep 17 00:00:00 2001 From: Bruno Raoult Date: Fri, 7 Jul 2023 02:21:14 +0200 Subject: [PATCH] Improve move gen, delete ling pos, 3 steps moves generation --- src/brchess.c | 19 +++--- src/eval.c | 11 ++-- src/move.c | 173 ++++++++++++++++++++++++++++++++----------------- src/move.h | 15 +++-- src/piece.c | 7 +- src/position.c | 13 ++-- src/position.h | 5 +- 7 files changed, 149 insertions(+), 94 deletions(-) diff --git a/src/brchess.c b/src/brchess.c index 1fec805..0b5e6cd 100644 --- a/src/brchess.c +++ b/src/brchess.c @@ -30,11 +30,11 @@ #include "fen.h" #include "eval.h" -typedef struct { +struct command { char *name; /* User printable name */ int (*func)(pos_t *, char *); /* function doing the job */ char *doc; /* function doc */ -} COMMAND; +}; /* readline example inspired by : * - https://thoughtbot.com/blog/tab-completion-in-gnu-readline @@ -45,7 +45,7 @@ char *commands_generator(const char *, int); char *escape(const char *); int quote_detector(char *, int); int execute_line (pos_t *, char *line); -COMMAND *find_command (char *); +struct command *find_command (char *); char *stripwhite (char *string); /* The names of functions that actually do the manipulation. */ @@ -63,7 +63,7 @@ int do_move(pos_t *, char*); int do_quit(pos_t *, char*); int do_debug(pos_t *, char*); -COMMAND commands[] = { +struct command commands[] = { { "help", do_help, "Display this text" }, { "?", do_help, "Synonym for 'help'" }, { "fen", do_fen, "Set position to FEN" }, @@ -190,7 +190,7 @@ int quote_detector(char *line, int index) int execute_line(pos_t *pos, char *line) { register int i; - COMMAND *command; + struct command *command; char *word; /* Isolate the command word. */ @@ -224,7 +224,7 @@ int execute_line(pos_t *pos, char *line) /* Look up NAME as the name of a command, and return a pointer to that command. Return a NULL pointer if NAME isn't a command name. */ -COMMAND *find_command(char *name) +struct command *find_command(char *name) { register int i; @@ -232,7 +232,7 @@ COMMAND *find_command(char *name) if (strcmp(name, commands[i].name) == 0) return &commands[i]; - return (COMMAND *)NULL; + return (struct command *)NULL; } /* Strip whitespace from the start and end of STRING. Return a pointer @@ -292,15 +292,14 @@ int do_pos(pos_t *pos, __unused char *arg) int do_genmoves(pos_t *pos, __unused char *arg) { log_f(1, "%s\n", arg); - moves_gen(pos, OPPONENT(pos->turn), false); - moves_gen(pos, pos->turn, true); + moves_gen_all(pos); return 1; } int do_prmoves(pos_t *pos, __unused char *arg) { log_f(1, "%s\n", arg); - moves_print(pos, M_PR_SEPARATE); + moves_print(pos, M_PR_SEPARATE | M_PR_NUM); return 1; } diff --git a/src/eval.c b/src/eval.c index 1391c74..8836b66 100644 --- a/src/eval.c +++ b/src/eval.c @@ -40,12 +40,12 @@ inline eval_t eval_material(pos_t *pos, bool color) inline eval_t eval_mobility(pos_t *pos, bool color) { - return popcount64(pos->controlled[color]); + return pos->mobility[color]; } inline eval_t eval_square_control(pos_t *pos, bool color) { - return pos->mobility[color]; + return popcount64(pos->controlled[color]); } eval_t eval(pos_t *pos) @@ -114,11 +114,8 @@ int main(int ac, char**av) pos_print(pos); pos_pieces_print(pos); - moves_gen(pos, OPPONENT(pos->turn), false); - //moves_print(pos, M_PR_SEPARATE); - //pos_print(pos); - //pos_pieces_print(pos); - moves_gen(pos, pos->turn, true); + moves_gen_all(pos); + pos_print(pos); moves_print(pos, M_PR_SEPARATE); res = eval(pos); diff --git a/src/move.c b/src/move.c index 975506d..3d6323d 100644 --- a/src/move.c +++ b/src/move.c @@ -62,7 +62,7 @@ void moves_pool_stats() pool_stats(moves_pool); } -int move_print(move_t *move, move_flags_t flags) +int move_print(int movenum, move_t *move, move_flags_t flags) { if (flags & M_PR_CAPT && !(move->flags & M_CAPTURE)) { # ifdef DEBUG_MOVE @@ -76,6 +76,8 @@ int move_print(move_t *move, move_flags_t flags) # endif return 0; } + if (flags & M_PR_NUM) + printf("%d:", movenum); if (move->flags & M_CASTLE_K) { printf("O-O"); goto end; @@ -110,26 +112,30 @@ void moves_print(pos_t *pos, move_flags_t flags) { struct list_head *p_cur, *tmp; move_t *move; - move_flags_t details = flags & M_PR_LONG; + //move_flags_t details = flags & M_PR_LONG; + int movenum; for (int color=WHITE; color <= BLACK; ++color) { int verif = 0; printf("%s pseudo-moves:\n\t", color == WHITE? "White": "Black"); if (! (flags & M_PR_SEPARATE)) { + movenum = 1; list_for_each_safe(p_cur, tmp, &pos->moves[color]) { move = list_entry(p_cur, move_t, list); - verif += move_print(move, details); + verif += move_print(movenum++, move, flags); } } else { printf("captures: "); + movenum = 1; list_for_each_safe(p_cur, tmp, &pos->moves[color]) { move = list_entry(p_cur, move_t, list); - verif += move_print(move, details | M_PR_CAPT); + verif += move_print(movenum++, move, flags | M_PR_CAPT); } + movenum = 1; printf("\n\tothers : "); list_for_each_safe(p_cur, tmp, &pos->moves[color]) { move = list_entry(p_cur, move_t, list); - verif += move_print(move, details | M_PR_NCAPT); + verif += move_print(movenum++, move, flags | M_PR_NCAPT); } } printf("\n\tTotal moves = %d mobility=%u\n", verif, pos->mobility[color]); @@ -250,28 +256,16 @@ static move_t *move_pawn_add(pos_t *pos, piece_t piece, square_t from, move_t *move; piece_t promote; unsigned char color = COLOR(piece); - //pos_t *newpos; - //if (color != pos->turn) - // return NULL; if (R88(from) == rank7) { /* promotion */ for (promote = QUEEN; promote > PAWN; promote >>= 1) { if ((move = move_add(pos, piece, from, to))) { move->flags |= M_PROMOTION; move->promotion = promote | color; - /* fix piece on board and piece list */ - //newpos = move->newpos; - //newpos->board[to].piece = promote|color; - //newpos->board[to].s_piece->piece = piece|color; - //newpos->board[to].s_piece->value = piece_details[PIECE(piece)].value; - - //piece_del(&newpos->board[from].s_piece); } } } else { move = move_add(pos, piece, from, to); - //newpos = move->newpos; - } return move; } @@ -360,12 +354,6 @@ int pseudo_moves_pawn(pos_t *pos, piece_list_t *ppiece, bool doit) move = move_pawn_add(pos, piece | color , square, pos->en_passant, rank7); move->flags |= M_EN_PASSANT | M_CAPTURE; move->taken = taken; - - /* remove taken pawn from board */ - //piece_del(&move->newpos->board[t_square].s_piece->list); - //move->newpos->board[t_square].piece = 0; - //move->newpos->board[t_square].s_piece = NULL; - pos->mobility[color]++; count++; } @@ -403,9 +391,8 @@ int pseudo_moves_pawn(pos_t *pos, piece_list_t *ppiece, bool doit) return count; } -int pseudo_moves_castle(pos_t *pos, bool color, bool doit) +int pseudo_moves_castle(pos_t *pos, bool color, bool doit, bool doking) { - //unsigned char color = pos->turn; board_t *board = pos->board; unsigned char rank1, castle_K, castle_Q; move_t *move = NULL; @@ -448,22 +435,15 @@ int pseudo_moves_castle(pos_t *pos, bool color, bool doit) # endif goto next; } - pos->mobility[color]++; - count++; + if (doking) { + pos->mobility[color]++; + count++; + } if (doit) { move = move_add(pos, board[SQ88(4, rank1)].piece, SQ88(4, rank1), SQ88(6, rank1)); - if (move) { - //newpos = move->newpos; + if (move) move->flags |= M_CASTLE_K; - - /* move King rook to column F */ - //newpos->board[SQ88(5, rank1)] = newpos->board[SQ88(7, rank1)]; - //SETF88(newpos->board[SQ88(5, rank1)].s_piece->square, 5); - //newpos->board[SQ88(7, rank1)].piece = 0; - //newpos->board[SQ88(7, rank1)].s_piece = NULL; - - } } } @@ -481,29 +461,33 @@ next: # endif goto end; } - pos->mobility[color]++; - count++; + if (doking) { + pos->mobility[color]++; + count++; + } if (doit) { move = move_add(pos, board[SQ88(4, rank1)].piece, SQ88(4, rank1), SQ88(2, rank1)); - if (move) { - //newpos = move->newpos; + if (move) move->flags |= M_CASTLE_Q; - /* move King rook to column F */ - //newpos->board[SQ88(3, rank1)] = newpos->board[SQ88(0, rank1)]; - //SETF88(newpos->board[SQ88(3, rank1)].s_piece->square, 3); - //newpos->board[SQ88(0, rank1)].piece = 0; - //newpos->board[SQ88(0, rank1)].s_piece = NULL; - } } } end: return count; } -/* general rule moves for non pawn pieces +/** + * pseudo_moves_gen() - general move generation for non pawn pieces + * @pos: &position + * @ppiece: &piece_list structure pointer + * @doit: add move to moves list + * @doking: count king moves + * + * Calculate all possible moves for @ppiece. + * If @doit is true, add moves to @pos' moves list. + * If @doking is true, account king moves (incl. castle) to mobility. */ -int pseudo_moves_gen(pos_t *pos, piece_list_t *ppiece, bool doit) +int pseudo_moves_gen(pos_t *pos, piece_list_t *ppiece, bool doit, bool doking) { piece_t piece = PIECE(ppiece->piece); unsigned char color = COLOR(ppiece->piece); @@ -569,9 +553,10 @@ int pseudo_moves_gen(pos_t *pos, piece_list_t *ppiece, bool doit) } /* we are sure the move is valid : we create move */ - //log_f(2, "piece mobility\n"); - pos->mobility[color]++; - count++; + if (piece != KING || doking) { + pos->mobility[color]++; + count++; + } if (doit) { //move = move_add(pos, ppiece->piece, square, new); move_add(pos, ppiece->piece, square, new); @@ -596,7 +581,18 @@ int pseudo_moves_gen(pos_t *pos, piece_list_t *ppiece, bool doit) return count; } -int moves_gen(pos_t *pos, bool color, bool doit) +/** + * moves_gen() - move generation for one color + * @pos: &position + * @color: side + * @doit: add move to moves list + * @doking: count king moves + * + * Calculate all possible moves for @color. + * If @doit is true, add moves to @pos' moves list. + * If @doking is true, account king moves (incl. castle) to mobility. + */ +int moves_gen(pos_t *pos, bool color, bool doit, bool doking) { struct list_head *p_cur, *tmp, *piece_list; piece_list_t *piece; @@ -609,11 +605,11 @@ int moves_gen(pos_t *pos, bool color, bool doit) pos->mobility[color] = 0; pos->controlled[color] = 0; - count += pseudo_moves_castle(pos, color, doit); + count += pseudo_moves_castle(pos, color, doit, doking); list_for_each_safe(p_cur, tmp, piece_list) { piece = list_entry(p_cur, piece_list_t, list); if (PIECE(piece->piece) != PAWN) - count += pseudo_moves_gen(pos, piece, doit); + count += pseudo_moves_gen(pos, piece, doit, doking); else count += pseudo_moves_pawn(pos, piece, doit); @@ -622,6 +618,40 @@ int moves_gen(pos_t *pos, bool color, bool doit) return count; } +/** + * moves_gen_king_moves() - adjust king mobility + * @pos: &position + * @color: king color + * @doit: add move to moves list + * + * Compute the number of king moves (incl. castle), after opponent controlled + * are known. + * If @doit is true, add moves to @pos' moves list. + * + * @return: The number of possible king moves. + */ +int moves_gen_king_moves(pos_t *pos, bool color, bool doit) +{ + int count = 0; + piece_list_t *king = list_first_entry(&pos->pieces[color], piece_list_t, list); + count = pseudo_moves_castle(pos, king, doit, true); + count += pseudo_moves_gen(pos, king, doit, true); + return count; +} + +/** + * moves_gen_all() - calculate all moves + * @pos: &position + * + * Compute pseudo moves for both sides. + */ +void moves_gen_all(pos_t *pos) +{ + moves_gen(pos, OPPONENT(pos->turn), false, false); + moves_gen(pos, pos->turn, false, true); + moves_gen_king_moves(pos, OPPONENT(pos->turn), true); +} + /** * move_do() - execute move in a duplicated position. * @pos: &pos_t struct on which move will be applied @@ -632,7 +662,7 @@ pos_t *move_do(pos_t *pos, move_t *move) { # ifdef DEBUG_MOVE log_f(3, "++++++++++"); - move_print(move, 0); + move_print(0, move, 0); log(3, "\n"); # endif @@ -650,14 +680,14 @@ pos_t *move_do(pos_t *pos, move_t *move) else new->clock_50++; - if (move->taken) { /* capture */ + if (move->flags & M_CAPTURE) { /* capture */ if (!(move->flags & M_EN_PASSANT)) { piece_del(&new->board[to].s_piece->list); new->board[to].piece = 0; new->occupied[OPPONENT(color)] ^= SQ88_2_BB(to); new->bb[OPPONENT(color)][PIECETOBB(piece)] ^= SQ88_2_BB(to); } else { - unsigned char ep_file = F88(pos->en_passant); + uchar ep_file = F88(pos->en_passant); square_t ep_grab = color == WHITE ? SQ88(ep_file, 4): SQ88(ep_file, 3); log_f(1, "en-passant=%d,%d\n", ep_file, color == WHITE ? 4 : 3); piece_del(&new->board[ep_grab].s_piece->list); @@ -666,6 +696,30 @@ pos_t *move_do(pos_t *pos, move_t *move) new->bb[OPPONENT(color)][PIECETOBB(piece)] ^= SQ88_2_BB(ep_grab); } + } else if (move->flags & M_CASTLE_Q) { + uchar row = R88(from); + square_t rook_from = SQ88(0, row); + square_t rook_to = SQ88(3, row); + new->board[rook_to] = new->board[rook_from]; + new->board[rook_to].s_piece->square = rook_to; + new->occupied[color] ^= SQ88_2_BB(rook_from); + new->occupied[color] |= SQ88_2_BB(rook_to); + new->bb[color][PIECETOBB(BB_ROOK)] ^= SQ88_2_BB(rook_from); + new->bb[color][PIECETOBB(BB_ROOK)] |= SQ88_2_BB(rook_to); + new->board[rook_from].piece = 0; + new->board[rook_from].s_piece = NULL; + } else if (move->flags & M_CASTLE_K) { + uchar row = R88(from); + square_t rook_from = SQ88(7, row); + square_t rook_to = SQ88(5, row); + new->board[rook_to] = new->board[rook_from]; + new->board[rook_to].s_piece->square = rook_to; + new->occupied[color] ^= SQ88_2_BB(rook_from); + new->occupied[color] |= SQ88_2_BB(rook_to); + new->bb[color][PIECETOBB(BB_ROOK)] ^= SQ88_2_BB(rook_from); + new->bb[color][PIECETOBB(BB_ROOK)] |= SQ88_2_BB(rook_to); + new->board[rook_from].piece = 0; + new->board[rook_from].s_piece = NULL; } new->board[to] = new->board[from]; @@ -708,8 +762,7 @@ int main(int ac, char**av) fen2pos(pos, av[1]); } //printf("turn = %d opponent = %d\n", pos->turn, OPPONENT(pos->turn)); - moves_gen(pos, WHITE, false); - moves_gen(pos, BLACK, false); + moves_gen_all(pos); pos_print(pos); pos_pieces_print(pos); moves_print(pos, M_PR_SEPARATE); diff --git a/src/move.h b/src/move.h index cbd973b..30ca402 100644 --- a/src/move.h +++ b/src/move.h @@ -32,10 +32,11 @@ typedef unsigned char move_flags_t; /* moves_print flags */ -#define M_PR_SEPARATE 0x40 /* separate capture/non capture */ -#define M_PR_LONG 0x80 #define M_PR_CAPT 0x01 #define M_PR_NCAPT 0x02 +#define M_PR_NUM 0x04 +#define M_PR_SEPARATE 0x40 /* separate captures */ +#define M_PR_LONG 0x80 typedef struct move_s { piece_t piece; @@ -49,16 +50,18 @@ typedef struct move_s { pool_t *moves_pool_init(); void moves_pool_stats(); -int move_print(move_t *move, move_flags_t flags); +int move_print(int movenum, move_t *move, move_flags_t flags); void moves_print(pos_t *move, move_flags_t flags); void move_del(struct list_head *ptr); int moves_del(pos_t *pos); -int pseudo_moves_castle(pos_t *pos, bool color, bool doit); -int pseudo_moves_gen(pos_t *pos, piece_list_t *piece, bool doit); +int pseudo_moves_castle(pos_t *pos, bool color, bool doit, bool doking); +int pseudo_moves_gen(pos_t *pos, piece_list_t *piece, bool doit, bool doking); int pseudo_moves_pawn(pos_t *pos, piece_list_t *piece, bool doit); -int moves_gen(pos_t *pos, bool color, bool doit); +int moves_gen(pos_t *pos, bool color, bool doit, bool doking); +int moves_gen_king_moves(pos_t *pos, bool color, bool doit); +void moves_gen_all(pos_t *pos); pos_t *move_do(pos_t *pos, move_t *move); void move_undo(pos_t *pos, move_t *move); diff --git a/src/piece.c b/src/piece.c index 5b3dc19..139e458 100644 --- a/src/piece.c +++ b/src/piece.c @@ -74,8 +74,11 @@ piece_list_t *piece_add(pos_t *pos, piece_t piece, square_t square) P_NAME(piece), FILE2C(F88(square)), RANK2C(R88(square))); # endif if ((new = pool_get(pieces_pool))) { - list_add_tail(&new->list, &pos->pieces[color]); - //color? &pos->pieces_black: &pos->pieces_white); + /* first piece is always king */ + if (PIECE(piece) == KING) + list_add(&new->list, &pos->pieces[color]); + else + list_add_tail(&new->list, &pos->pieces[color]); new->piece = piece; new->square = square; new->castle = 0; diff --git a/src/position.c b/src/position.c index 60c7b68..8446408 100644 --- a/src/position.c +++ b/src/position.c @@ -72,6 +72,9 @@ void pos_print(pos_t *pos) int rank, file; piece_t piece; board_t *board = pos->board; + piece_list_t *wk = list_first_entry(&pos->pieces[WHITE], piece_list_t, list), + *bk = list_first_entry(&pos->pieces[BLACK], piece_list_t, list); + printf(" +---+---+---+---+---+---+---+---+\n"); for (rank = 7; rank >= 0; --rank) { @@ -85,10 +88,10 @@ void pos_print(pos_t *pos) printf(" A B C D E F G H\n\n"); printf("Turn: %s.\n", IS_WHITE(pos->turn) ? "white" : "black"); printf("Kings: W:%c%c B:%c%c\n", - FILE2C(F88(pos->king[WHITE])), - RANK2C(R88(pos->king[WHITE])), - FILE2C(F88(pos->king[BLACK])), - RANK2C(R88(pos->king[BLACK]))); + FILE2C(F88(wk->square)), + RANK2C(R88(wk->square)), + FILE2C(F88(bk->square)), + RANK2C(R88(bk->square))); printf("Possible en-passant: [%#x] ", pos->en_passant); if (pos->en_passant == 0) printf("None.\n"); @@ -143,8 +146,6 @@ pos_t *pos_clear(pos_t *pos) pos->curmove = 0; pos->eval = 0; pos->en_passant = 0; - pos->king[WHITE] = 0; - pos->king[BLACK] = 0; pos->occupied[WHITE] = 0; pos->occupied[BLACK] = 0; for (int color=0; color<2; ++color) diff --git a/src/position.h b/src/position.h index 7b5714b..5e66fcd 100644 --- a/src/position.h +++ b/src/position.h @@ -15,11 +15,11 @@ #define POSITION_H #include -#include "board.h" #include #include #include +#include "board.h" #include "chessdefs.h" typedef struct pos_s { @@ -31,13 +31,12 @@ typedef struct pos_s { board_t board[BOARDSIZE]; square_t en_passant; - square_t king[2]; /* obsolete by bb array */ bitboard_t bb[2][BB_END]; /* use: pieces[BLACK][BB_PAWN] */ bitboard_t occupied[2]; /* OR of bb[COLOR][x] */ bitboard_t controlled[2]; u16 mobility[2]; - struct list_head pieces[2]; + struct list_head pieces[2]; /* pieces list, King is first */ struct list_head moves[2]; } pos_t;