From ec64e2e44dd0112fe62c72c31251f26e064d81cb Mon Sep 17 00:00:00 2001 From: Bruno Raoult Date: Tue, 28 May 2024 09:40:20 +0200 Subject: [PATCH] replace pawn_shift_xxx with bb_pawns_attacks --- src/attack.c | 9 ++++--- src/bitboard.c | 8 +++--- src/bitboard.h | 64 ++++++++++---------------------------------- src/chessdefs.h | 6 +++-- src/fen.c | 71 +++++++++++++++++++++++++------------------------ src/fen.h | 1 + src/move-gen.c | 70 +++++++++++------------------------------------- src/position.c | 5 +++- src/position.h | 2 +- 9 files changed, 85 insertions(+), 151 deletions(-) diff --git a/src/attack.c b/src/attack.c index 5ab5cc7..6ef4618 100644 --- a/src/attack.c +++ b/src/attack.c @@ -115,13 +115,16 @@ bitboard_t sq_attackers(const pos_t *pos, const bitboard_t occ, const square_t s /* pawn */ to = pos->bb[c][PAWN]; - tmp = pawn_shift_upleft(sqbb, opp) & to; + tmp = bb_pawns_attacks(sqbb, sq_up(opp)) & to; attackers |= tmp; + //to = pos->bb[c][PAWN]; + //tmp = pawn_shift_upleft(sqbb, opp) & to; + //attackers |= tmp; # ifdef DEBUG_ATTACK_ATTACKERS bb_print("att pawn upleft", tmp); # endif - tmp = pawn_shift_upright(sqbb, opp) & to; - attackers |= tmp; + //tmp = pawn_shift_upright(sqbb, opp) & to; + //attackers |= tmp; # ifdef DEBUG_ATTACK_ATTACKERS bb_print("att pawn upright", tmp); # endif diff --git a/src/bitboard.c b/src/bitboard.c index 83d55b8..637b953 100644 --- a/src/bitboard.c +++ b/src/bitboard.c @@ -160,10 +160,10 @@ void bitboard_init(void) /* 3) pawn, knight and king attacks */ for (square_t sq = A1; sq <= H8; ++sq) { - if (sq >= A2) - bb_pawn_attacks[BLACK][sq] = pawn_attacks_bb(BIT(sq), BLACK); - if (sq <= H7) - bb_pawn_attacks[WHITE][sq] = pawn_attacks_bb(BIT(sq), WHITE); + if (sq <= H7) + bb_pawn_attacks[WHITE][sq] = bb_pawns_attacks(BIT(sq), sq_up(WHITE)); + if (sq >= A2) + bb_pawn_attacks[BLACK][sq] = bb_pawns_attacks(BIT(sq), sq_up(BLACK)); for (int vec = 0; vec < 8; ++vec) { int dst = sq + knight_vector[vec]; diff --git a/src/bitboard.h b/src/bitboard.h index 2a60d87..4848f7a 100644 --- a/src/bitboard.h +++ b/src/bitboard.h @@ -234,12 +234,25 @@ static __always_inline bitboard_t bb_shift(bitboard_t bb, int shift) return shift >= 0 ? bb << shift : bb >> -shift; } +/** + * bb_pawns_attacks() - shift up pawns on both diagonals (attacks) + * @bb: pawns bitboard + * @push: shift value for pawn up + * + * Get the possible attacks for all @bb pawns. + * + * @return: squares attacked by @bbpawns + */ +static __always_inline bitboard_t bb_pawns_attacks(const bitboard_t bb, int push) +{ + return bb_shift(bb & ~FILE_Abb, push - 1) | bb_shift(bb & ~FILE_Hbb, push + 1); +} #define bb_rank(r) ((u64) RANK_1bb << ((r) * 8)) #define bb_file(f) ((u64) FILE_Abb << (f)) #define bb_rel_rank(r, c) bb_rank(sq_rel_rank(r, c)) -#define bb_rel_file(f, c) bb_file(sq_rel_rank(f, c)) +#define bb_rel_file(f, c) bb_file(sq_rel_rank(f, c)) /* likely useless */ /** * bb_sq_aligned() - check if two squares are aligned (same file or rank). @@ -276,55 +289,6 @@ static __always_inline bitboard_t bb_sq_between(square_t sq, square_t sq1, squar return bb_between_excl[sq1][sq2] & BIT(sq); } -/* TODO: when OK, replace with macros */ -static __always_inline bitboard_t shift_n(const bitboard_t bb) -{ - return bb << NORTH; -} -static __always_inline bitboard_t shift_ne(const bitboard_t bb) -{ - return (bb & ~FILE_Hbb) << NORTH_EAST; -} -static __always_inline bitboard_t shift_e(const bitboard_t bb) -{ - return (bb & ~FILE_Hbb) << EAST; -} -static __always_inline bitboard_t shift_se(const bitboard_t bb) -{ - return (bb & ~FILE_Hbb) >> -SOUTH_EAST; -} -static __always_inline bitboard_t shift_s(const bitboard_t bb) -{ - return bb >> -SOUTH; -} -static __always_inline bitboard_t shift_sw(const bitboard_t bb) -{ - return (bb & ~FILE_Abb) >> -SOUTH_WEST; -} -static __always_inline bitboard_t shift_w(const bitboard_t bb) -{ - return (bb & ~FILE_Abb) >> -WEST; -} -static __always_inline bitboard_t shift_nw(const bitboard_t bb) -{ - return (bb & ~FILE_Abb) << NORTH_WEST; -} - -/* pawn moves/attacks (for bitboards) */ -#define pawn_shift_up(bb, c) ((c) == WHITE ? shift_n(bb): shift_s(bb)) -#define pawn_shift_upleft(bb, c) ((c) == WHITE ? shift_nw(bb): shift_se(bb)) -#define pawn_shift_upright(bb, c) ((c) == WHITE ? shift_ne(bb): shift_sw(bb)) - -#define pawn_attacks_bb(bb, c) (pawn_shift_upleft(bb, c) | \ - pawn_shift_upright(bb, c)) - -/* pawn move (for single pawn) - NO SQUARE CONTROL HERE ! - * Need to make functions with control instead. - */ -#define pawn_push_up(sq, c) ((sq) + ((c) == WHITE ? NORTH: SOUTH)) -//#define pawn_push_upleft(sq, c) ((sq) + ((c) == WHITE ? NORTH_WEST: SOUTH_EAST)) -//#define pawn_push_upright(sq, c) ((sq) + ((c) == WHITE ? NORTH_EAST: SOUTH_WEST)) - bitboard_t bitboard_between_excl(square_t sq1, square_t sq2); void bitboard_init(void); diff --git a/src/chessdefs.h b/src/chessdefs.h index 75e9665..136f3bc 100644 --- a/src/chessdefs.h +++ b/src/chessdefs.h @@ -139,8 +139,10 @@ typedef enum { /* define diff for relative squares */ #define sq_up(c) ((c) == WHITE ? NORTH: SOUTH) -#define sq_upleft(c) ((c) == WHITE ? NORTH_WEST: SOUTH_EAST) -#define sq_upright(c) ((c) == WHITE ? NORTH_EAST: SOUTH_WEST) +/* Attention here: We mix "up" (color dependent) and W/E, color independant. + */ +#define sq_upwest(up) ((up) - 1) +#define sq_upeast(up) ((up) + 1) #include diff --git a/src/fen.c b/src/fen.c index 6cbb0ae..9005986 100644 --- a/src/fen.c +++ b/src/fen.c @@ -61,18 +61,20 @@ static const char *castle_str = "KQkq"; #define SKIP_BLANK(p) for(;isspace(*(p)); (p)++) /** - * fen_check(pos_t *pos) - test (and try to fix) fen-generated position. - * @pos: position + * fen_ok() - test (and try to fix) fen-generated position. + * @pos: &position + * @fixit: action flag * - * Test and fix the following: + * Test and possibly fix the following: * - inconsistent castle flags (if K & R are not in correct position) - * - inconsistent en-passant square (turn, bad pawn position) + * - inconsistent en-passant square (turn, bad pawns positions) * - * pos_ok() is also called, leading to fatal errors if something is wrong. + * if @fixit is true, any error above will be fixed, and pos_ok() will + is also called, leading to fatal errors if something is wrong. * * @return: 0 if OK, 1 if OK after fix, -1 if fatal issue. */ -static int fen_check(pos_t *pos) +int fen_ok(pos_t *pos, bool fixit) { char *colstr[2] = { "white", "black"}; int warning = 0; @@ -87,18 +89,17 @@ static int fen_check(pos_t *pos) piece_t pawn = MAKE_PIECE(PAWN, them); bitboard_t att = bb_pawn_attacks[them][ep] & pos->bb[us][PAWN]; - if (warn(eprank != rank6 || - pos->board[ep - up] != pawn || - pos->board[ep] != EMPTY || - pos->board[ep + up] != EMPTY || - att == 0ull, - "fen warn: wrong en-passant settings. (fixed)\n")) { -# ifdef DEBUG_FEN - printf("ep5=%o ep6=%o ep7=%o\n", sq_make(epfile, rank5), - sq_make(epfile, rank6), sq_make(epfile, rank7)); -# endif + if (eprank != rank6 || + pos->board[ep - up] != pawn || + pos->board[ep] != EMPTY || + pos->board[ep + up] != EMPTY || + att == 0ull) { + warning++; - pos->en_passant = SQUARE_NONE; + if (fixit) { + warn(true, "pos warn: wrong en-passant settings (fixed).\n"); + pos->en_passant = SQUARE_NONE; + } } } @@ -112,28 +113,28 @@ static int fen_check(pos_t *pos) bitboard_t r_q = bb_sq[sq_make(FILE_A, rank1)]; /* where they are */ - bitboard_t kings = pos->bb[color][KING]; - bitboard_t rooks = pos->bb[color][ROOK]; + bitboard_t kingbb = pos->bb[color][KING]; + bitboard_t rookbb = pos->bb[color][ROOK]; castle_rights_t castle_k = color == WHITE? CASTLE_WK: CASTLE_BK; castle_rights_t castle_q = color == WHITE? CASTLE_WQ: CASTLE_BQ; - if (pos->castle & castle_k) { - if (warn(!(k & kings && r_k & rooks), - "fen warn: wrong %s short castling K or R position (fixed)\n", - colstr[color])) { - warning++; + if (pos->castle & castle_k && !(k & kingbb && r_k & rookbb)) { + warning++; + if (fixit) { + warn(true, "fen warn: wrong %s short castling (fixed)\n", + colstr[color]); pos->castle &= ~castle_k; } } - if (pos->castle & castle_q) { - if (warn(!(k & kings && r_q & rooks), - "fen warn: wrong %s long castling K or R position (fixed)\n", - colstr[color])) { - warning++; + if (pos->castle & castle_q && !(k & kingbb && r_q & rookbb)) { + warning++; + if (fixit) { + warn(true, "fen warn: wrong %s long castling (fixed)\n", + colstr[color]); pos->castle &= ~castle_q; } } } - return pos_ok(pos, 0) ? warning: -1; + return warning; } /** @@ -253,15 +254,15 @@ end: err_line, err_pos, err_char, err_char)) { return NULL; } - if (fen_check(&tmppos) < 0) - return NULL; + + fen_ok(&tmppos, true); /* fix e.p & castling flags */ + if (!pos_ok(&tmppos, false)) + return NULL; /* invalid position: ignored */ + tmppos.key = zobrist_calc(&tmppos); if (!pos) pos = pos_new(); pos_copy(&tmppos, pos); - //puts("prout 1"); - //pos_print_raw(&tmppos, 1); - //puts("prout 2"); # ifdef DEBUG_FEN pos_print_raw(&tmppos, 1); # endif diff --git a/src/fen.h b/src/fen.h index 6a38b0a..3b1fab9 100644 --- a/src/fen.h +++ b/src/fen.h @@ -20,6 +20,7 @@ extern const char *startfen; /* startup position */ +extern int fen_ok(pos_t *pos, bool fixit); extern pos_t *startpos(pos_t *pos); extern pos_t *fen2pos(pos_t *pos, const char *fen); extern char *pos2fen(const pos_t *pos, char *fen); diff --git a/src/move-gen.c b/src/move-gen.c index fed7d94..ffeab3e 100644 --- a/src/move-gen.c +++ b/src/move-gen.c @@ -96,17 +96,14 @@ bool pseudo_is_legal(const pos_t *pos, const move_t move) * would discover a R/Q horizontal check. */ if (is_enpassant(move)) { - bitboard_t rank5 = us == WHITE? RANK_5bb: RANK_4bb; + bitboard_t rank5 = bb_rel_rank(RANK_1, us); if ((pos->bb[us][KING] & rank5)) { bitboard_t exclude = BIT(pos->en_passant - sq_up(us)) | BIT(from); bitboard_t rooks = (pos->bb[them][ROOK] | pos->bb[them][QUEEN]) & rank5; - while (rooks) { - square_t rook = bb_next(&rooks); - if (hyperbola_rank_moves(occ ^ exclude, rook) & kingbb) - return false; - } + if (hyperbola_rank_moves(occ ^ exclude, king) & rooks) + return false; } } return true; @@ -467,62 +464,25 @@ movelist_t *pos_gen_pseudo(pos_t *pos, movelist_t *movelist) } /* pawn: captures */ - /* - * tmp_bb = pawn_attacks_bb(pos->bb[us][PAWN], us) & enemy_pieces; - * //bb_print("FAIL", tmp_bb); - * to_bb = tmp_bb & ~rel_rank8; - * while (to_bb) { - * to = bb_next(&to_bb); - * from_bb = bb_pawn_attacks[them][to] & pos->bb[us][PAWN]; - * while (from_bb) { - * from = bb_next(&from_bb); - * *moves++ = move_make(from, to); - * } - * } - * to_bb = tmp_bb & rel_rank8; - * while (to_bb) { - * to = bb_next(&to_bb); - * from_bb = bb_pawn_attacks[them][to] & pos->bb[us][PAWN]; - * while (from_bb) { - * from = bb_next(&from_bb); - * moves = move_make_promotions(moves, from, to); - * } - * } - */ - - /* pawn: captures left */ - bitboard_t filter = ~bb_rel_file(FILE_A, us); - shift = sq_upleft(us); - tmp_bb = bb_shift(pos->bb[us][PAWN] & filter, shift) & enemy_pieces; - + tmp_bb = bb_pawns_attacks(pos->bb[us][PAWN], shift) & enemy_pieces; + //bb_print("FAIL", tmp_bb); to_bb = tmp_bb & ~rel_rank8; while (to_bb) { to = bb_next(&to_bb); - from = to - shift; - *moves++ = move_make(from, to); + from_bb = bb_pawn_attacks[them][to] & pos->bb[us][PAWN]; + while (from_bb) { + from = bb_next(&from_bb); + *moves++ = move_make(from, to); + } } to_bb = tmp_bb & rel_rank8; while (to_bb) { to = bb_next(&to_bb); - from = to - shift; - moves = move_gen_promotions(moves, from, to); - } - - /* pawn: captures right */ - filter = ~bb_rel_file(FILE_H, us); - shift = sq_upright(us); - tmp_bb = bb_shift(pos->bb[us][PAWN] & filter, shift) & enemy_pieces; - to_bb = tmp_bb & ~rel_rank8; - while (to_bb) { - to = bb_next(&to_bb); - from = to - shift; - *moves++ = move_make(from, to); - } - to_bb = tmp_bb & rel_rank8; - while (to_bb) { - to = bb_next(&to_bb); - from = to - shift; - moves = move_gen_promotions(moves, from, to); + from_bb = bb_pawn_attacks[them][to] & pos->bb[us][PAWN]; + while (from_bb) { + from = bb_next(&from_bb); + moves = move_gen_promotions(moves, from, to); + } } /* pawn: en-passant diff --git a/src/position.c b/src/position.c index bfbec93..faaaa0a 100644 --- a/src/position.c +++ b/src/position.c @@ -346,7 +346,7 @@ bitboard_t pos_king_blockers(const pos_t *pos, const color_t color, const bitboa * * @return: (if @strict is false) return true if check is ok, false otherwise. */ -bool pos_ok(const pos_t *pos, const bool strict) +bool pos_ok(pos_t *pos, const bool strict) { int n, count = 0, bbcount = 0, error = 0; color_t us = pos->turn, them = OPPONENT(us); @@ -397,6 +397,9 @@ bool pos_ok(const pos_t *pos, const bool strict) error += warn_on(popcount64(pos_checkers(pos, us)) > 2); /* kings distance is less than 2 */ error += warn_on(sq_dist(pos->king[WHITE], pos->king[BLACK]) < 2); + /* e.p. and castling rights check */ + error += fen_ok(pos, false); + if (strict) { bug_on(error); /* not reached */ diff --git a/src/position.h b/src/position.h index b99bb30..8a8b8a9 100644 --- a/src/position.h +++ b/src/position.h @@ -180,7 +180,7 @@ bitboard_t pos_checkers(const pos_t *pos, const color_t color); bitboard_t pos_king_pinners(const pos_t *pos, const color_t color); bitboard_t pos_king_blockers(const pos_t *pos, const color_t color, const bitboard_t ); -bool pos_ok(const pos_t *pos, const bool strict); +bool pos_ok(pos_t *pos, const bool strict); void pos_print(const pos_t *pos); void pos_print_mask(const pos_t *pos, const bitboard_t mask);