bb: bb_{first_bb,next,multiple{}, chessdefs: relative sq diffs
This commit is contained in:
@@ -14,8 +14,8 @@
|
|||||||
#ifndef _BITBOARD_H
|
#ifndef _BITBOARD_H
|
||||||
#define _BITBOARD_H
|
#define _BITBOARD_H
|
||||||
|
|
||||||
#include "brlib.h"
|
#include <brlib.h>
|
||||||
#include "bitops.h"
|
#include <bitops.h>
|
||||||
|
|
||||||
#include "chessdefs.h"
|
#include "chessdefs.h"
|
||||||
#include "board.h"
|
#include "board.h"
|
||||||
@@ -183,14 +183,51 @@ static __always_inline bitboard_t bb_file(int file)
|
|||||||
}
|
}
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* bb_first_bb() - return bitboard of first square of a bitboard.
|
||||||
|
* @bb: bitboard
|
||||||
|
*
|
||||||
|
* bb must be non-zero.
|
||||||
|
*
|
||||||
|
* @return: bitboard of first square (lsb) of @bb.
|
||||||
|
*/
|
||||||
|
static __always_inline square_t bb_first_bb(bitboard_t bb)
|
||||||
|
{
|
||||||
|
return bb & -bb;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* bb_next() - clear and return next (lsb) square of a bitboard.
|
||||||
|
* @bb: &bitboard
|
||||||
|
*
|
||||||
|
* The bitboard addressed by @bb must be non-zero.
|
||||||
|
*
|
||||||
|
* @return: first bit (lsb) of @bb.
|
||||||
|
*/
|
||||||
|
static __always_inline square_t bb_next(bitboard_t *bb)
|
||||||
|
{
|
||||||
|
square_t sq = ctz64(*bb);
|
||||||
|
*bb &= *bb - 1;
|
||||||
|
return sq;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* bb_multiple() - test if a bitboard has multiple bits.
|
||||||
|
* @bb: bitboard
|
||||||
|
*
|
||||||
|
* @return: true if @bb has more than 1 bit, false otherwise.
|
||||||
|
*/
|
||||||
|
static __always_inline bool bb_multiple(bitboard_t bb)
|
||||||
|
{
|
||||||
|
return !!(bb & (bb - 1));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
#define bb_rank(r) ((u64) RANK_1bb << ((r) * 8))
|
#define bb_rank(r) ((u64) RANK_1bb << ((r) * 8))
|
||||||
#define BB_FILE(f) ((u64) FILE_Abb << (f))
|
#define bb_file(f) ((u64) FILE_Abb << (f))
|
||||||
|
|
||||||
#define bb_rel_rank(r, c) bb_rank(sq_rel_rank(r, c))
|
#define bb_rel_rank(r, c) bb_rank(sq_rel_rank(r, c))
|
||||||
|
|
||||||
//#define BB_REL_RANK(r, c) (RANK_1bb << (SQ_REL_RANK(r, c) * 8))
|
|
||||||
//#define BB_REL_FILE(f, c) (FILE_Abb << (SQ_REL_RANK((f), (c))))
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* bb_sq_aligned() - check if two squares are aligned (same file or rank).
|
* bb_sq_aligned() - check if two squares are aligned (same file or rank).
|
||||||
* @sq1, @sq2: the two squares.
|
* @sq1, @sq2: the two squares.
|
||||||
@@ -219,7 +256,7 @@ static __always_inline bool bb_sq_aligned3(square_t sq1, square_t sq2, square_t
|
|||||||
* @sq1: square 1
|
* @sq1: square 1
|
||||||
* @sq2: square 2
|
* @sq2: square 2
|
||||||
*
|
*
|
||||||
* @return: bitboard of @betw if between @sq1 and @sq2.
|
* @return: bitboard of @sq if between @sq1 and @sq2.
|
||||||
*/
|
*/
|
||||||
static __always_inline bitboard_t bb_sq_between(square_t sq, square_t sq1, square_t sq2)
|
static __always_inline bitboard_t bb_sq_between(square_t sq, square_t sq1, square_t sq2)
|
||||||
{
|
{
|
||||||
@@ -260,7 +297,6 @@ static __always_inline bitboard_t shift_nw(const bitboard_t bb)
|
|||||||
return (bb & ~FILE_Abb) << NORTH_WEST;
|
return (bb & ~FILE_Abb) << NORTH_WEST;
|
||||||
}
|
}
|
||||||
|
|
||||||
#define pawn_up_value(c) ((c) == WHITE ? 8: -8)
|
|
||||||
/* pawn moves/attacks (for bitboards) */
|
/* pawn moves/attacks (for bitboards) */
|
||||||
#define pawn_shift_up(bb, c) ((c) == WHITE ? shift_n(bb): shift_s(bb))
|
#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_upleft(bb, c) ((c) == WHITE ? shift_nw(bb): shift_se(bb))
|
||||||
|
@@ -134,6 +134,11 @@ typedef enum {
|
|||||||
NORTH_WEST = (NORTH + WEST),
|
NORTH_WEST = (NORTH + WEST),
|
||||||
} dir_t;
|
} dir_t;
|
||||||
|
|
||||||
|
/* 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)
|
||||||
|
|
||||||
#include <time.h>
|
#include <time.h>
|
||||||
|
|
||||||
typedef struct mclock {
|
typedef struct mclock {
|
||||||
|
@@ -36,18 +36,18 @@
|
|||||||
*/
|
*/
|
||||||
bool pseudo_is_legal(const pos_t *pos, const move_t move)
|
bool pseudo_is_legal(const pos_t *pos, const move_t move)
|
||||||
{
|
{
|
||||||
color_t us = pos->turn, them = OPPONENT(us);
|
color_t us = pos->turn, them = OPPONENT(us);
|
||||||
square_t from = move_from(move), to = move_to(move), king = pos->king[us], sq;
|
square_t from = move_from(move), to = move_to(move);
|
||||||
piece_type_t piece = PIECE(pos->board[from]);
|
square_t king = pos->king[us];
|
||||||
bitboard_t kingbb = pos->bb[us][KING], tmp;
|
bitboard_t kingbb = pos->bb[us][KING];
|
||||||
u64 pinned = mask(from) & pos->blockers & pos->bb[us][ALL_PIECES];
|
u64 pinned = mask(from) & pos->blockers;
|
||||||
|
|
||||||
/* (1) - King
|
/* (1) - King
|
||||||
* For castling, we already tested intermediate squares attacks
|
* For castling, we already tested intermediate squares attacks
|
||||||
* in pseudo move generation, so we only care destination square here.
|
* in pseudo move generation, so we only care destination square here.
|
||||||
* Attention: We need to exclude king from occupation bitboard !
|
* Attention: We need to exclude king from occupation bitboard !
|
||||||
*/
|
*/
|
||||||
if (piece == KING) {
|
if (from == king) {
|
||||||
bitboard_t occ = pos_occ(pos) ^ kingbb;
|
bitboard_t occ = pos_occ(pos) ^ kingbb;
|
||||||
return !sq_attackers(pos, occ, to, them);
|
return !sq_attackers(pos, occ, to, them);
|
||||||
}
|
}
|
||||||
@@ -62,17 +62,16 @@ bool pseudo_is_legal(const pos_t *pos, const move_t move)
|
|||||||
* pinned piece: always illegal
|
* pinned piece: always illegal
|
||||||
*/
|
*/
|
||||||
if (pos->checkers) {
|
if (pos->checkers) {
|
||||||
if (popcount64(pos->checkers) == 1) { /* one checker */
|
if (pinned)
|
||||||
square_t checker = ctz64(pos->checkers);
|
return false;
|
||||||
if (pinned)
|
if (bb_multiple(pos->checkers))
|
||||||
return false;
|
return false;
|
||||||
if (is_enpassant(move)) {
|
square_t checker = ctz64(pos->checkers);
|
||||||
return pawn_push_up(pos->en_passant, them) == checker;
|
if (is_enpassant(move)) {
|
||||||
}
|
return pawn_push_up(pos->en_passant, them) == checker;
|
||||||
bitboard_t between = bb_between[king][checker] | pos->checkers;
|
|
||||||
return mask(to) & between;
|
|
||||||
}
|
}
|
||||||
return false; /* double check */
|
bitboard_t between = bb_between[king][checker] | pos->checkers;
|
||||||
|
return mask(to) & between;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* (3) - pinned pieces
|
/* (3) - pinned pieces
|
||||||
@@ -85,27 +84,24 @@ bool pseudo_is_legal(const pos_t *pos, const move_t move)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* (4) - En-passant
|
/* (4) - En-passant
|
||||||
* We only care the situation where our King and enemy R/Q are on
|
* pinned pieces are already handled.
|
||||||
* 5th relative rank. To do so, we create an occupation bb without
|
* One case is left: when the two "disappearing" pawns would discover
|
||||||
* the 2 pawns.
|
* a R/Q check.
|
||||||
*/
|
*/
|
||||||
if (is_enpassant(move)) {
|
if (is_enpassant(move)) {
|
||||||
/* from rank bitboard */
|
bitboard_t rank5 = us == WHITE? RANK_5bb: RANK_4bb;
|
||||||
bitboard_t rank5 = bb_sqrank[from];
|
|
||||||
/* enemy rooks/queens on from rank */
|
|
||||||
bitboard_t rooks = (pos->bb[them][ROOK] | pos->bb[them][QUEEN]) & rank5;
|
|
||||||
|
|
||||||
if ((kingbb & rank5) && rooks) { /* K and enemy R/Q on rank */
|
if ((pos->bb[us][KING] & rank5)) {
|
||||||
/* captured pawn square (beside from square) */
|
bitboard_t exclude = mask(pos->en_passant + sq_up(them)) | mask(from);
|
||||||
square_t captured = sq_make(sq_file(pos->en_passant), sq_rank(from));
|
bitboard_t rooks = (pos->bb[them][ROOK] | pos->bb[them][QUEEN]) & rank5;
|
||||||
/* occupation bitboard without the two "disappearing" pawns */
|
|
||||||
bitboard_t occ = pos_occ(pos) ^ mask(from) ^ mask(captured);
|
|
||||||
|
|
||||||
bit_for_each64(sq, tmp, rooks) /* check all rooks/queens */
|
bitboard_t occ = pos_occ(pos) ^ exclude;
|
||||||
if (hyperbola_rank_moves(occ, sq) & kingbb)
|
while (rooks) {
|
||||||
|
square_t rook = bb_next(&rooks);
|
||||||
|
if (hyperbola_rank_moves(occ, rook) & kingbb)
|
||||||
return false;
|
return false;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@@ -156,6 +152,31 @@ movelist_t *pos_all_legal(const pos_t *pos, movelist_t *movelist, movelist_t *de
|
|||||||
return dest;
|
return dest;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* pos_gen_check_pseudomoves() - generate position pseudo-legal moves when in check
|
||||||
|
* @pos: position
|
||||||
|
* @movelist: &movelist_t array to store pseudo-moves
|
||||||
|
*
|
||||||
|
* Generate all @pos pseudo moves for player-to-move.
|
||||||
|
* @movelist is filled with the moves.
|
||||||
|
*
|
||||||
|
* Only a few validity checks are done here (i.e. moves are not generated):
|
||||||
|
* - castling, if king is in check
|
||||||
|
* - castling, if king passes an enemy-controlled square (not final square).
|
||||||
|
* When immediately known, a few move flags are also applied in these cases:
|
||||||
|
* - castling: M_CASTLE_{K,Q}
|
||||||
|
* - capture (excl. en-passant): M_CAPTURE
|
||||||
|
* - en-passant: M_EN_PASSANT
|
||||||
|
* - pawn double push: M_DPUSH
|
||||||
|
* - promotion: M_PROMOTION
|
||||||
|
* - promotion and capture
|
||||||
|
*
|
||||||
|
* TODO: move code to specific functions (especially castling, pawn push/capture)
|
||||||
|
*
|
||||||
|
* @Return: The total number of moves.
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* pos_gen_pseudomoves() - generate position pseudo-legal moves
|
* pos_gen_pseudomoves() - generate position pseudo-legal moves
|
||||||
* @pos: position
|
* @pos: position
|
||||||
|
@@ -236,7 +236,7 @@ int main(int __unused ac, __unused char**av)
|
|||||||
s64 ms1 = 0, ms1_total = 0;
|
s64 ms1 = 0, ms1_total = 0;
|
||||||
s64 ms2 = 0, ms2_total = 0;
|
s64 ms2 = 0, ms2_total = 0;
|
||||||
s64 ms3 = 0, ms3_total = 0;
|
s64 ms3 = 0, ms3_total = 0;
|
||||||
int run = 3;
|
int run = 7;
|
||||||
|
|
||||||
if (ac > 1)
|
if (ac > 1)
|
||||||
depth = atoi(av[1]);
|
depth = atoi(av[1]);
|
||||||
@@ -273,12 +273,12 @@ int main(int __unused ac, __unused char**av)
|
|||||||
ms1_total += ms1;
|
ms1_total += ms1;
|
||||||
|
|
||||||
if (sf_count == my_count) {
|
if (sf_count == my_count) {
|
||||||
printf("pt1 OK : line=%03d perft=%lu %'ldms lps=%'lu \"%s\"\n",
|
printf("pt1 OK : line=%3d perft=%lu %'ldms lps=%'lu \"%s\"\n",
|
||||||
test_line, my_count, ms1,
|
test_line, my_count, ms1,
|
||||||
ms1? my_count*1000l/ms1: 0,
|
ms1? my_count*1000l/ms1: 0,
|
||||||
fen);
|
fen);
|
||||||
} else {
|
} else {
|
||||||
printf("pt1 ERR: line=%03d sf=%lu me=%lu \"%s\"\n",
|
printf("pt1 ERR: line=%3d sf=%lu me=%lu \"%s\"\n",
|
||||||
test_line, sf_count, my_count, fen);
|
test_line, sf_count, my_count, fen);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -290,12 +290,12 @@ int main(int __unused ac, __unused char**av)
|
|||||||
ms2_total += ms2;
|
ms2_total += ms2;
|
||||||
|
|
||||||
if (sf_count == my_count) {
|
if (sf_count == my_count) {
|
||||||
printf("pt2 OK : line=%03d perft=%lu %'ldms lps=%'lu \"%s\"\n",
|
printf("pt2 OK : line=%3d perft=%lu %'ldms lps=%'lu \"%s\"\n",
|
||||||
test_line, my_count, ms2,
|
test_line, my_count, ms2,
|
||||||
ms2? my_count*1000l/ms2: 0,
|
ms2? my_count*1000l/ms2: 0,
|
||||||
fen);
|
fen);
|
||||||
} else {
|
} else {
|
||||||
printf("pt2 ERR: line=%03d sf=%lu me=%lu \"%s\"\n",
|
printf("pt2 ERR: line=%3d sf=%lu me=%lu \"%s\"\n",
|
||||||
test_line, sf_count, my_count, fen);
|
test_line, sf_count, my_count, fen);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user