Compare commits
7 Commits
e8240c6cab
...
movegen-re
Author | SHA1 | Date | |
---|---|---|---|
926dfa0765 | |||
374116b1e7 | |||
9b5c2253b1 | |||
e301e6c726 | |||
e78eae21e6 | |||
711306c92a | |||
660722fadc |
1
.gitignore
vendored
1
.gitignore
vendored
@@ -4,6 +4,7 @@ vgcore.*
|
|||||||
*.i
|
*.i
|
||||||
*.old
|
*.old
|
||||||
*.save
|
*.save
|
||||||
|
perf.data
|
||||||
/GPATH
|
/GPATH
|
||||||
/GRTAGS
|
/GRTAGS
|
||||||
/GTAGS
|
/GTAGS
|
||||||
|
16
Makefile
16
Makefile
@@ -56,7 +56,6 @@ CPPFILES := $(SRC:.c=.i) $(TSTSRC:.c=.i)
|
|||||||
CPPFLAGS := -I$(BRINCDIR) -I$(INCDIR)
|
CPPFLAGS := -I$(BRINCDIR) -I$(INCDIR)
|
||||||
|
|
||||||
CPPFLAGS += -DNDEBUG # assert
|
CPPFLAGS += -DNDEBUG # assert
|
||||||
|
|
||||||
CPPFLAGS += -DBUG_ON # brlib bug.h
|
CPPFLAGS += -DBUG_ON # brlib bug.h
|
||||||
CPPFLAGS += -DWARN_ON # brlib bug.h
|
CPPFLAGS += -DWARN_ON # brlib bug.h
|
||||||
|
|
||||||
@@ -88,9 +87,16 @@ CPPFLAGS := $(strip $(CPPFLAGS))
|
|||||||
CFLAGS := -std=gnu11
|
CFLAGS := -std=gnu11
|
||||||
|
|
||||||
### dev OR release
|
### dev OR release
|
||||||
|
|
||||||
# dev
|
# dev
|
||||||
#CFLAGS += -O1
|
# CFLAGS += -O1
|
||||||
#CFLAGS += -g
|
CFLAGS += -g # symbols (gdb, perf, etc.)
|
||||||
|
CFLAGS += -ginline-points # inlined funcs debug info
|
||||||
|
# for gprof
|
||||||
|
#CFLAGS += -pg
|
||||||
|
# Next one may be useful for valgrind (when invalid instructions)
|
||||||
|
#CFLAGS += -mno-tbm
|
||||||
|
|
||||||
# release
|
# release
|
||||||
CFLAGS += -Ofast
|
CFLAGS += -Ofast
|
||||||
|
|
||||||
@@ -99,10 +105,6 @@ CFLAGS += -flto
|
|||||||
CFLAGS += -Wall
|
CFLAGS += -Wall
|
||||||
CFLAGS += -Wextra
|
CFLAGS += -Wextra
|
||||||
CFLAGS += -Wmissing-declarations
|
CFLAGS += -Wmissing-declarations
|
||||||
# for gprof
|
|
||||||
#CFLAGS += -pg
|
|
||||||
# Next one may be useful for valgrind (when invalid instructions)
|
|
||||||
# CFLAGS += -mno-tbm
|
|
||||||
|
|
||||||
CFLAGS := $(strip $(CFLAGS))
|
CFLAGS := $(strip $(CFLAGS))
|
||||||
|
|
||||||
|
@@ -40,7 +40,6 @@
|
|||||||
*/
|
*/
|
||||||
bool sq_is_attacked(const pos_t *pos, const bitboard_t occ, const square_t sq, const color_t c)
|
bool sq_is_attacked(const pos_t *pos, const bitboard_t occ, const square_t sq, const color_t c)
|
||||||
{
|
{
|
||||||
bitboard_t sqbb = mask(sq);
|
|
||||||
color_t opp = OPPONENT(c);
|
color_t opp = OPPONENT(c);
|
||||||
|
|
||||||
/* bishop / queen */
|
/* bishop / queen */
|
||||||
|
@@ -160,10 +160,10 @@ void bitboard_init(void)
|
|||||||
/* 3) pawn, knight and king attacks
|
/* 3) pawn, knight and king attacks
|
||||||
*/
|
*/
|
||||||
for (square_t sq = A1; sq <= H8; ++sq) {
|
for (square_t sq = A1; sq <= H8; ++sq) {
|
||||||
if (sq >= A2 && sq <= H7) {
|
if (sq >= A2)
|
||||||
bb_pawn_attacks[WHITE][sq] = pawn_attacks_bb(mask(sq), WHITE);
|
|
||||||
bb_pawn_attacks[BLACK][sq] = pawn_attacks_bb(mask(sq), BLACK);
|
bb_pawn_attacks[BLACK][sq] = pawn_attacks_bb(mask(sq), BLACK);
|
||||||
}
|
if (sq <= H7)
|
||||||
|
bb_pawn_attacks[WHITE][sq] = pawn_attacks_bb(mask(sq), WHITE);
|
||||||
|
|
||||||
for (int vec = 0; vec < 8; ++vec) {
|
for (int vec = 0; vec < 8; ++vec) {
|
||||||
int dst = sq + knight_vector[vec];
|
int dst = sq + knight_vector[vec];
|
||||||
|
@@ -314,6 +314,7 @@ static __always_inline bitboard_t shift_nw(const bitboard_t bb)
|
|||||||
#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))
|
||||||
#define pawn_shift_upright(bb, c) ((c) == WHITE ? shift_ne(bb): shift_sw(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) | \
|
#define pawn_attacks_bb(bb, c) (pawn_shift_upleft(bb, c) | \
|
||||||
pawn_shift_upright(bb, c))
|
pawn_shift_upright(bb, c))
|
||||||
|
|
||||||
@@ -321,8 +322,8 @@ static __always_inline bitboard_t shift_nw(const bitboard_t bb)
|
|||||||
* Need to make functions with control instead.
|
* Need to make functions with control instead.
|
||||||
*/
|
*/
|
||||||
#define pawn_push_up(sq, c) ((sq) + ((c) == WHITE ? NORTH: SOUTH))
|
#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_upleft(sq, c) ((sq) + ((c) == WHITE ? NORTH_WEST: SOUTH_EAST))
|
||||||
#define pawn_push_upright(sq, c) ((sq) + ((c) == WHITE ? NORTH_EAST: SOUTH_WEST))
|
//#define pawn_push_upright(sq, c) ((sq) + ((c) == WHITE ? NORTH_EAST: SOUTH_WEST))
|
||||||
|
|
||||||
bitboard_t bitboard_between_excl(square_t sq1, square_t sq2);
|
bitboard_t bitboard_between_excl(square_t sq1, square_t sq2);
|
||||||
void bitboard_init(void);
|
void bitboard_init(void);
|
||||||
|
@@ -56,6 +56,7 @@ pos_t *move_do(pos_t *pos, const move_t move) //, state_t *state)
|
|||||||
piece_type_t ptype = PIECE(piece);
|
piece_type_t ptype = PIECE(piece);
|
||||||
color_t pcolor = COLOR(piece);
|
color_t pcolor = COLOR(piece);
|
||||||
piece_t new_piece = piece;
|
piece_t new_piece = piece;
|
||||||
|
int up = sq_up(us);
|
||||||
|
|
||||||
++pos->clock_50;
|
++pos->clock_50;
|
||||||
++pos->plycount;
|
++pos->plycount;
|
||||||
@@ -90,9 +91,9 @@ pos_t *move_do(pos_t *pos, const move_t move) //, state_t *state)
|
|||||||
} else if (ptype == PAWN) { /* pawn non capture or e.p. */
|
} else if (ptype == PAWN) { /* pawn non capture or e.p. */
|
||||||
pos->clock_50 = 0;
|
pos->clock_50 = 0;
|
||||||
if (is_dpush(move)) /* if pawn double push, set e.p. */
|
if (is_dpush(move)) /* if pawn double push, set e.p. */
|
||||||
pos->en_passant = from + sq_up(us);
|
pos->en_passant = from + up;
|
||||||
else if (is_enpassant(move)) { /* clear grabbed pawn */
|
else if (is_enpassant(move)) { /* clear grabbed pawn */
|
||||||
square_t grabbed = pawn_push_up(to, them);
|
square_t grabbed = to - up;
|
||||||
pos_clr_sq(pos, grabbed);
|
pos_clr_sq(pos, grabbed);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -157,7 +158,7 @@ pos_t *move_undo(pos_t *pos, const move_t move)//, const state_t *state)
|
|||||||
color_t them = pos->turn, us = OPPONENT(them);
|
color_t them = pos->turn, us = OPPONENT(them);
|
||||||
square_t from = move_from(move), to = move_to(move);
|
square_t from = move_from(move), to = move_to(move);
|
||||||
piece_t piece = pos->board[to];
|
piece_t piece = pos->board[to];
|
||||||
|
int up = sq_up(them);
|
||||||
|
|
||||||
if (is_promotion(move))
|
if (is_promotion(move))
|
||||||
piece = MAKE_PIECE(PAWN, us);
|
piece = MAKE_PIECE(PAWN, us);
|
||||||
@@ -182,7 +183,7 @@ pos_t *move_undo(pos_t *pos, const move_t move)//, const state_t *state)
|
|||||||
pos_set_sq(pos, rookto, pos->board[rookfrom]);
|
pos_set_sq(pos, rookto, pos->board[rookfrom]);
|
||||||
pos_clr_sq(pos, rookfrom);
|
pos_clr_sq(pos, rookfrom);
|
||||||
} else if (is_enpassant(move)) { /* restore grabbed pawn */
|
} else if (is_enpassant(move)) { /* restore grabbed pawn */
|
||||||
square_t grabbed = pawn_push_up(to, them);
|
square_t grabbed = to + up;
|
||||||
pos_set_sq(pos, grabbed, MAKE_PIECE(PAWN, them));
|
pos_set_sq(pos, grabbed, MAKE_PIECE(PAWN, them));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -42,6 +42,7 @@ bool pseudo_is_legal(const pos_t *pos, const move_t move)
|
|||||||
bitboard_t kingbb = pos->bb[us][KING];
|
bitboard_t kingbb = pos->bb[us][KING];
|
||||||
bitboard_t occ = pos_occ(pos);
|
bitboard_t occ = pos_occ(pos);
|
||||||
u64 pinned = mask(from) & pos->blockers;
|
u64 pinned = mask(from) & pos->blockers;
|
||||||
|
u64 checkers = pos->checkers;
|
||||||
|
|
||||||
/* (1) - Castling & King
|
/* (1) - Castling & King
|
||||||
* For castling, we need to check intermediate squares attacks only.
|
* For castling, we need to check intermediate squares attacks only.
|
||||||
@@ -49,12 +50,12 @@ bool pseudo_is_legal(const pos_t *pos, const move_t move)
|
|||||||
* king from occupation bitboard (to catch king moving away from checker
|
* king from occupation bitboard (to catch king moving away from checker
|
||||||
* on same line) !
|
* on same line) !
|
||||||
*/
|
*/
|
||||||
if (is_castle(move)) {
|
if (unlikely(from == king)) {
|
||||||
|
if (unlikely(is_castle(move))) {
|
||||||
square_t dir = to > from? 1: -1;
|
square_t dir = to > from? 1: -1;
|
||||||
if (sq_attackers(pos, occ, from + dir, them))
|
if (sq_attackers(pos, occ, from + dir, them))
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
if (from == king) {
|
|
||||||
return !sq_attackers(pos, occ ^ kingbb, to, them);
|
return !sq_attackers(pos, occ ^ kingbb, to, them);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -68,18 +69,18 @@ bool pseudo_is_legal(const pos_t *pos, const move_t move)
|
|||||||
* e.p., legal if the grabbed pawn is giving check
|
* e.p., legal if the grabbed pawn is giving check
|
||||||
* pinned piece: always illegal
|
* pinned piece: always illegal
|
||||||
*/
|
*/
|
||||||
if (pos->checkers) {
|
if (checkers) {
|
||||||
if (pinned)
|
if (pinned)
|
||||||
return false;
|
return false;
|
||||||
if (bb_multiple(pos->checkers))
|
if (bb_multiple(checkers))
|
||||||
return false;
|
return false;
|
||||||
square_t checker = ctz64(pos->checkers);
|
square_t checker = ctz64(checkers);
|
||||||
if (is_enpassant(move)) {
|
if (is_enpassant(move)) {
|
||||||
return pos->en_passant + sq_up(them) == checker;
|
return pos->en_passant + sq_up(them) == checker;
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
bitboard_t between = bb_between[king][checker] | pos->checkers;
|
//bitboard_t between = bb_between[king][checker] | pos->checkers;
|
||||||
return mask(to) & between;
|
//return mask(to) & between;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* (3) - pinned pieces
|
/* (3) - pinned pieces
|
||||||
@@ -388,6 +389,30 @@ int pos_gen_pseudomoves(pos_t *pos, movelist_t *movelist)
|
|||||||
*moves++ = move_make_flags(from, to, M_DPUSH);
|
*moves++ = move_make_flags(from, to, M_DPUSH);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* 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 */
|
/* pawn: captures left */
|
||||||
bitboard_t filter = ~bb_rel_file(FILE_A, us);
|
bitboard_t filter = ~bb_rel_file(FILE_A, us);
|
||||||
shift = sq_upleft(us);
|
shift = sq_upleft(us);
|
||||||
@@ -427,18 +452,26 @@ int pos_gen_pseudomoves(pos_t *pos, movelist_t *movelist)
|
|||||||
* TODO: special case when in-check here ?
|
* TODO: special case when in-check here ?
|
||||||
*/
|
*/
|
||||||
if ((to = pos->en_passant) != SQUARE_NONE) {
|
if ((to = pos->en_passant) != SQUARE_NONE) {
|
||||||
to_bb = mask(to);
|
from_bb = bb_pawn_attacks[them][to] & pos->bb[us][PAWN];
|
||||||
/* if e.p not on file H, we may add an e.p move to "up-left" */
|
while (from_bb) {
|
||||||
filter = ~bb_rel_file(FILE_A, us);
|
from = bb_next(&from_bb);
|
||||||
shift = sq_upleft(us);
|
*moves++ = move_make_enpassant(from, to);
|
||||||
if (bb_shift(pos->bb[us][PAWN] & filter, shift) & to_bb)
|
|
||||||
*moves++ = move_make_enpassant(to - shift, to);
|
|
||||||
|
|
||||||
filter = ~bb_rel_file(FILE_H, us);
|
|
||||||
shift = sq_upright(us);
|
|
||||||
if (bb_shift(pos->bb[us][PAWN] & filter, shift) & to_bb)
|
|
||||||
*moves++ = move_make_enpassant(to - shift, to);
|
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
/*
|
||||||
|
* to_bb = mask(to);
|
||||||
|
* /\* if e.p not on file H, we may add an e.p move to "up-left" *\/
|
||||||
|
* filter = ~bb_rel_file(FILE_A, us);
|
||||||
|
* shift = sq_upleft(us);
|
||||||
|
* if (bb_shift(pos->bb[us][PAWN] & filter, shift) & to_bb)
|
||||||
|
* *moves++ = move_make_enpassant(to - shift, to);
|
||||||
|
*
|
||||||
|
* filter = ~bb_rel_file(FILE_H, us);
|
||||||
|
* shift = sq_upright(us);
|
||||||
|
* if (bb_shift(pos->bb[us][PAWN] & filter, shift) & to_bb)
|
||||||
|
* *moves++ = move_make_enpassant(to - shift, to);
|
||||||
|
* }
|
||||||
|
*/
|
||||||
|
|
||||||
/* TODO: add function per piece, and type, for easier debug
|
/* TODO: add function per piece, and type, for easier debug
|
||||||
*/
|
*/
|
||||||
|
@@ -116,7 +116,7 @@ pos_t *pos_clear(pos_t *pos)
|
|||||||
*
|
*
|
||||||
* @return: true if equal, false otherwise.
|
* @return: true if equal, false otherwise.
|
||||||
*/
|
*/
|
||||||
bool pos_cmp(const pos_t *pos1, const pos_t *pos2)
|
bool pos_cmp(__unused const pos_t *pos1, __unused const pos_t *pos2)
|
||||||
{
|
{
|
||||||
#define _cmpf(a) (pos1->a != pos2->a)
|
#define _cmpf(a) (pos1->a != pos2->a)
|
||||||
bool ret = false;
|
bool ret = false;
|
||||||
@@ -201,9 +201,8 @@ void pos_set_checkers_pinners_blockers(pos_t *pos)
|
|||||||
bitboard_t occ = pos_occ(pos);
|
bitboard_t occ = pos_occ(pos);
|
||||||
bitboard_t attackers;
|
bitboard_t attackers;
|
||||||
bitboard_t checkers = 0, blockers = 0, pinners = 0;
|
bitboard_t checkers = 0, blockers = 0, pinners = 0;
|
||||||
bitboard_t targets, tmpcheckers, tmpblockers, tmppinners, tmpbb;
|
bitboard_t targets, tmpcheckers, maybeblockers, tmppinners;
|
||||||
square_t king = pos->king[us];
|
square_t king = pos->king[us];
|
||||||
bitboard_t king_bb = mask(king);
|
|
||||||
int pinner;
|
int pinner;
|
||||||
|
|
||||||
/* bishop type - we attack with a bishop from king position */
|
/* bishop type - we attack with a bishop from king position */
|
||||||
@@ -216,57 +215,45 @@ void pos_set_checkers_pinners_blockers(pos_t *pos)
|
|||||||
tmpcheckers = targets & attackers;
|
tmpcheckers = targets & attackers;
|
||||||
checkers |= tmpcheckers;
|
checkers |= tmpcheckers;
|
||||||
|
|
||||||
/* maybe blockers = not checkers */
|
/* maybe blockers = we remove checkers, to look "behind" */
|
||||||
tmpblockers = targets & ~tmpcheckers;
|
maybeblockers = targets & ~tmpcheckers;
|
||||||
|
|
||||||
/* we find second targets, by removing only first ones (excl. checkers) */
|
/* we find second targets, by removing first ones (excl. checkers) */
|
||||||
targets = hyperbola_bishop_moves(occ ^ tmpblockers, king) ^ tmpcheckers;
|
if (maybeblockers) {
|
||||||
|
targets = hyperbola_bishop_moves(occ ^ maybeblockers, king) ^ tmpcheckers;
|
||||||
|
|
||||||
/* pinners = only B/Q */
|
/* pinners = only B/Q */
|
||||||
tmppinners = targets & attackers;
|
tmppinners = targets & attackers;
|
||||||
pinners |= tmppinners;
|
|
||||||
//tmpblockers = 0;
|
|
||||||
|
|
||||||
/* blockers = we find occupied squares between pinner and king */
|
/* blockers = we find occupied squares between pinner and king */
|
||||||
bit_for_each64(pinner, tmpbb, tmppinners)
|
while (tmppinners) {
|
||||||
blockers |= bb_between[pinner][king] & tmpblockers;
|
pinner = bb_next(&tmppinners);
|
||||||
//blockers |= tmpblockers;
|
pinners |= mask(pinner);
|
||||||
|
blockers |= bb_between[pinner][king] & maybeblockers;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/* same for rook type */
|
/* same for rook type */
|
||||||
attackers = pos->bb[them][ROOK] | pos->bb[them][QUEEN];
|
attackers = pos->bb[them][ROOK] | pos->bb[them][QUEEN];
|
||||||
|
|
||||||
/* targets is all "target" pieces if K was a bishop */
|
|
||||||
targets = hyperbola_rook_moves(occ, king) & occ;
|
targets = hyperbola_rook_moves(occ, king) & occ;
|
||||||
|
|
||||||
/* checkers = only opponent B/Q */
|
|
||||||
tmpcheckers = targets & attackers;
|
tmpcheckers = targets & attackers;
|
||||||
checkers |= tmpcheckers;
|
checkers |= tmpcheckers;
|
||||||
|
|
||||||
/* maybe blockers = not checkers */
|
maybeblockers = targets & ~tmpcheckers;
|
||||||
tmpblockers = targets & ~tmpcheckers;
|
if (maybeblockers) {
|
||||||
|
targets = hyperbola_rook_moves(occ ^ maybeblockers, king) ^ tmpcheckers;
|
||||||
/* we find second targets, by removing only first ones (excl. checkers) */
|
|
||||||
targets = hyperbola_rook_moves(occ ^ tmpblockers, king) ^ tmpcheckers;
|
|
||||||
|
|
||||||
/* pinners = only B/Q */
|
|
||||||
tmppinners = targets & attackers;
|
tmppinners = targets & attackers;
|
||||||
pinners |= tmppinners;
|
while (tmppinners) {
|
||||||
//tmpblockers = 0;
|
pinner = bb_next(&tmppinners);
|
||||||
|
pinners |= mask(pinner);
|
||||||
|
blockers |= bb_between[pinner][king] & maybeblockers;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/* blockers = we find occupied squares between pinner and king */
|
/* pawns & knights */
|
||||||
bit_for_each64(pinner, tmpbb, tmppinners)
|
checkers |= bb_pawn_attacks[us][king] & pos->bb[them][PAWN];
|
||||||
blockers |= bb_between[pinner][king] & tmpblockers;
|
checkers |= bb_knight[king] & pos->bb[them][KNIGHT];
|
||||||
//blockers |= tmpblockers;
|
|
||||||
|
|
||||||
/* pawns */
|
|
||||||
attackers = pos->bb[them][PAWN];
|
|
||||||
targets = pawn_shift_upleft(king_bb, us) | pawn_shift_upright(king_bb, us);
|
|
||||||
checkers |= targets & attackers;
|
|
||||||
|
|
||||||
/* knight */
|
|
||||||
attackers = pos->bb[them][KNIGHT];
|
|
||||||
targets = bb_knight_moves(attackers, king);
|
|
||||||
checkers |= targets;
|
|
||||||
|
|
||||||
pos->checkers = checkers;
|
pos->checkers = checkers;
|
||||||
pos->pinners = pinners;
|
pos->pinners = pinners;
|
||||||
@@ -366,10 +353,10 @@ 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.
|
* @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(__unused const pos_t *pos, __unused const bool strict)
|
||||||
{
|
{
|
||||||
int n, count = 0, bbcount = 0, error = 0;
|
int n, count = 0, bbcount = 0, error = 0;
|
||||||
bitboard_t tmp;
|
__unused bitboard_t tmp;
|
||||||
|
|
||||||
/* pawns on 1st ot 8th rank */
|
/* pawns on 1st ot 8th rank */
|
||||||
tmp = (pos->bb[WHITE][PAWN] | pos->bb[BLACK][PAWN]) & (RANK_1bb | RANK_8bb);
|
tmp = (pos->bb[WHITE][PAWN] | pos->bb[BLACK][PAWN]) & (RANK_1bb | RANK_8bb);
|
||||||
@@ -391,7 +378,7 @@ bool pos_ok(const pos_t *pos, const bool strict)
|
|||||||
}
|
}
|
||||||
for (square_t sq = 0; sq < 64; ++sq) {
|
for (square_t sq = 0; sq < 64; ++sq) {
|
||||||
piece_t piece = pos->board[sq];
|
piece_t piece = pos->board[sq];
|
||||||
bitboard_t match;
|
__unused bitboard_t match;
|
||||||
if (piece == EMPTY)
|
if (piece == EMPTY)
|
||||||
continue;
|
continue;
|
||||||
color_t c = COLOR(piece);
|
color_t c = COLOR(piece);
|
||||||
|
51
src/search.c
51
src/search.c
@@ -45,12 +45,13 @@ u64 perft(pos_t *pos, int depth, int ply)
|
|||||||
{
|
{
|
||||||
int subnodes, movetmp = 0;
|
int subnodes, movetmp = 0;
|
||||||
u64 nodes = 0;
|
u64 nodes = 0;
|
||||||
movelist_t pseudo = { .nmoves = 0 };
|
movelist_t pseudo;
|
||||||
move_t move;
|
move_t move;
|
||||||
state_t state;
|
state_t state;
|
||||||
|
|
||||||
if (depth == 0)
|
if (depth == 0)
|
||||||
return 1;
|
return 1;
|
||||||
|
pseudo.nmoves = 0;
|
||||||
pos->checkers = pos_checkers(pos, pos->turn);
|
pos->checkers = pos_checkers(pos, pos->turn);
|
||||||
pos_set_pinners_blockers(pos);
|
pos_set_pinners_blockers(pos);
|
||||||
state = pos->state;
|
state = pos->state;
|
||||||
@@ -74,7 +75,7 @@ u64 perft(pos_t *pos, int depth, int ply)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* perft2() - Perform perft on position
|
* perft_new_pinners() - Perform perft on position
|
||||||
* @pos: &position to search
|
* @pos: &position to search
|
||||||
* @depth: Wanted depth.
|
* @depth: Wanted depth.
|
||||||
* @ply: perft depth level.
|
* @ply: perft depth level.
|
||||||
@@ -82,61 +83,19 @@ u64 perft(pos_t *pos, int depth, int ply)
|
|||||||
* Run perft on a position. This function displays the available moves at @depth
|
* Run perft on a position. This function displays the available moves at @depth
|
||||||
* level for each possible first move, and the total of moves.
|
* level for each possible first move, and the total of moves.
|
||||||
*
|
*
|
||||||
* This version uses the algorithm:
|
|
||||||
* if (king in check)
|
|
||||||
* finish;
|
|
||||||
* if last depth
|
|
||||||
* return 1;
|
|
||||||
* gen pseudo-legal moves
|
|
||||||
* foreach pseudo-legal move...
|
|
||||||
*
|
|
||||||
* @return: total moves found at @depth level.
|
* @return: total moves found at @depth level.
|
||||||
*/
|
*/
|
||||||
u64 perft2(pos_t *pos, int depth, int ply)
|
|
||||||
{
|
|
||||||
int subnodes, nmove = 0;
|
|
||||||
u64 nodes = 0;
|
|
||||||
movelist_t pseudo = { .nmoves = 0 };
|
|
||||||
move_t move;
|
|
||||||
state_t state;
|
|
||||||
|
|
||||||
if (depth == 0)
|
|
||||||
return 1;
|
|
||||||
pos->checkers = pos_checkers(pos, pos->turn);
|
|
||||||
pos_set_pinners_blockers(pos);
|
|
||||||
state = pos->state;
|
|
||||||
|
|
||||||
pos_gen_pseudomoves(pos, &pseudo);
|
|
||||||
|
|
||||||
for (nmove = 0; nmove < pseudo.nmoves; ++nmove ) {
|
|
||||||
move = pseudo.move[nmove];
|
|
||||||
move_do(pos, move);
|
|
||||||
if (!is_in_check(pos, OPPONENT(pos->turn))) {
|
|
||||||
subnodes = perft2(pos, depth - 1, ply + 1);
|
|
||||||
nodes += subnodes;
|
|
||||||
if (ply == 1) {
|
|
||||||
char movestr[8];
|
|
||||||
printf("%s: %d\n", move_str(movestr, move, 0), subnodes);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
move_undo(pos, move);
|
|
||||||
pos->state = state;
|
|
||||||
}
|
|
||||||
if (ply == 1)
|
|
||||||
printf("Total: %lu\n", nodes);
|
|
||||||
return nodes;
|
|
||||||
}
|
|
||||||
|
|
||||||
u64 perft_new_pinners(pos_t *pos, int depth, int ply)
|
u64 perft_new_pinners(pos_t *pos, int depth, int ply)
|
||||||
{
|
{
|
||||||
int subnodes, movetmp = 0;
|
int subnodes, movetmp = 0;
|
||||||
u64 nodes = 0;
|
u64 nodes = 0;
|
||||||
movelist_t pseudo = { .nmoves = 0 };
|
movelist_t pseudo;
|
||||||
move_t move;
|
move_t move;
|
||||||
state_t state;
|
state_t state;
|
||||||
|
|
||||||
if (depth == 0)
|
if (depth == 0)
|
||||||
return 1;
|
return 1;
|
||||||
|
pseudo.nmoves = 0;
|
||||||
pos_set_checkers_pinners_blockers(pos);
|
pos_set_checkers_pinners_blockers(pos);
|
||||||
state = pos->state;
|
state = pos->state;
|
||||||
|
|
||||||
|
@@ -35,10 +35,9 @@ struct fentest {
|
|||||||
""
|
""
|
||||||
},
|
},
|
||||||
*/
|
*/
|
||||||
/* tests rank movegen bug - FIXED
|
|
||||||
*/
|
/* ***************** TEMP TESTS ABOVE ************************** */
|
||||||
//"4k3/pppppppp/8/8/8/8/PPPPPPPP/2BRK3 w - - 0 1",
|
|
||||||
//"4k3/pppppppp/8/8/8/8/PPPPPPPP/1B1R1K2 w - - 0 1",
|
|
||||||
{ __LINE__, MOVEGEN | MOVEDO | PERFT,
|
{ __LINE__, MOVEGEN | MOVEDO | PERFT,
|
||||||
"illegal white e.p.",
|
"illegal white e.p.",
|
||||||
"3k4/8/5K2/3pP3/8/2b5/8/8 w - d6 0 1",
|
"3k4/8/5K2/3pP3/8/2b5/8/8 w - d6 0 1",
|
||||||
@@ -92,43 +91,43 @@ struct fentest {
|
|||||||
* },
|
* },
|
||||||
*/
|
*/
|
||||||
{ __LINE__, ATTACK,
|
{ __LINE__, ATTACK,
|
||||||
"checkers: a1 h1",
|
"only 3 K moves (but impossible situation)",
|
||||||
"1k6/8/8/8/8/8/8/r2K3r w - - 1 1"
|
"1k6/8/8/8/8/8/8/r2K3r w - - 0 1"
|
||||||
},
|
},
|
||||||
{ __LINE__, ATTACK,
|
{ __LINE__, ATTACK,
|
||||||
"checkers: a8 h8",
|
"checkers: a8 h8",
|
||||||
"R2k3R/8/8/8/8/8/8/1K6 b - - 1 1"
|
"R2k3R/8/8/8/8/8/8/1K6 b - - 0 1"
|
||||||
},
|
},
|
||||||
{ __LINE__, ATTACK,
|
{ __LINE__, ATTACK,
|
||||||
"checkers: b3 g3",
|
"checkers: b3 g3",
|
||||||
"1k6/8/8/8/8/1r1K2r1/8/8 w - - 1 1"
|
"1k6/8/8/8/8/1r1K2r1/8/8 w - - 0 1"
|
||||||
},
|
},
|
||||||
|
|
||||||
{ __LINE__, ATTACK,
|
{ __LINE__, ATTACK,
|
||||||
"checkers: b6 g6",
|
"checkers: b6 g6",
|
||||||
"8/8/1R1k2R1/8/8/8/8/1K6 b - - 1 1"
|
"8/8/1R1k2R1/8/8/8/8/1K6 b - - 0 1"
|
||||||
},
|
},
|
||||||
|
|
||||||
{ __LINE__, ATTACK,
|
{ __LINE__, ATTACK,
|
||||||
"checkers: g2 g7",
|
"checkers: g2 g7",
|
||||||
"8/k5r1/8/8/6K1/8/6r1/8 w - - 1 1"
|
"8/k5r1/8/8/6K1/8/6r1/8 w - - 0 1"
|
||||||
},
|
},
|
||||||
{ __LINE__, ATTACK,
|
{ __LINE__, ATTACK,
|
||||||
"checkers: g2 g7",
|
"checkers: g2 g7",
|
||||||
"8/6R1/8/6k1/8/8/K5R1/8 b - - 1 1"
|
"8/6R1/8/6k1/8/8/K5R1/8 b - - 0 1"
|
||||||
},
|
},
|
||||||
{ __LINE__, ATTACK,
|
{ __LINE__, ATTACK,
|
||||||
"checkers: d5 e3, pinners: none (2 pieces between attacker & K)",
|
"checkers: d5 e3, pinners: none (2 pieces between attacker & K)",
|
||||||
"3k4/8/8/3r3b/b7/1N2nn2/2n1B3/rNBK1Rbr w - - 1 1"
|
"3k4/8/8/3r3b/b7/1N2nn2/2n1B3/rNBK1Rbr w - - 0 1"
|
||||||
},
|
},
|
||||||
|
|
||||||
{ __LINE__, ATTACK,
|
{ __LINE__, ATTACK,
|
||||||
"checkers: d4 e6 pinners: h4 a5 a8 h8",
|
"checkers: d4 e6 pinners: h4 a5 a8 h8",
|
||||||
"Rn1k1r1R/4b3/1n2N3/B7/3R3B/8/8/3K4 b - - 1 1"
|
"Rn1k1r1R/4b3/1n2N3/B7/3R3B/8/8/3K4 b - - 0 1"
|
||||||
},
|
},
|
||||||
{ __LINE__, ATTACK,
|
{ __LINE__, ATTACK,
|
||||||
"checkers: d5 e3, pinners: a1 h1 a4 h5",
|
"checkers: d5 e3, pinners: a1 h1 a4 h5",
|
||||||
"3k4/8/8/3r3b/b7/1N2n3/4B3/rN1K1R1r w - - 1 0"
|
"3k4/8/8/3r3b/b7/1N2n3/4B3/rN1K1R1r w - - 0 1"
|
||||||
},
|
},
|
||||||
|
|
||||||
{ __LINE__, MOVEGEN | MOVEDO | PERFT,
|
{ __LINE__, MOVEGEN | MOVEDO | PERFT,
|
||||||
|
@@ -232,16 +232,15 @@ int main(int __unused ac, __unused char**av)
|
|||||||
movelist_t fishmoves;
|
movelist_t fishmoves;
|
||||||
//move_t move;
|
//move_t move;
|
||||||
FILE *outfd;
|
FILE *outfd;
|
||||||
int depth = 6;
|
|
||||||
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;
|
|
||||||
int run = 7;
|
int depth = 6, run = 3;
|
||||||
|
|
||||||
if (ac > 1)
|
if (ac > 1)
|
||||||
depth = atoi(av[1]);
|
depth = atoi(av[1]);
|
||||||
if (ac > 2)
|
if (ac > 2)
|
||||||
run = atoi(av[2]);
|
run = atoi(av[2]) & 3;
|
||||||
printf("depth = %d run=%d\n", depth, run);
|
printf("depth = %d run=%d\n", depth, run);
|
||||||
|
|
||||||
if (!run)
|
if (!run)
|
||||||
@@ -253,7 +252,6 @@ int main(int __unused ac, __unused char**av)
|
|||||||
bitboard_init();
|
bitboard_init();
|
||||||
hyperbola_init();
|
hyperbola_init();
|
||||||
|
|
||||||
|
|
||||||
CLOCK_DEFINE(clock, CLOCK_PROCESS);
|
CLOCK_DEFINE(clock, CLOCK_PROCESS);
|
||||||
while ((fen = next_fen(PERFT | MOVEDO))) {
|
while ((fen = next_fen(PERFT | MOVEDO))) {
|
||||||
test_line = cur_line();
|
test_line = cur_line();
|
||||||
@@ -271,46 +269,29 @@ 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=%3d 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=%3d 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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (run & 2) {
|
if (run & 2) {
|
||||||
clock_start(&clock);
|
clock_start(&clock);
|
||||||
my_count = perft2(pos, depth, 1);
|
my_count = perft_new_pinners(pos, depth, 1);
|
||||||
ms2 = clock_elapsed_ms(&clock);
|
ms2 = clock_elapsed_ms(&clock);
|
||||||
ms2_total += ms2;
|
ms2_total += ms2;
|
||||||
|
|
||||||
if (sf_count == my_count) {
|
if (sf_count == my_count) {
|
||||||
printf("pt2 OK : line=%3d 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=%3d sf=%lu me=%lu \"%s\"\n",
|
printf("pt2 ERR: line=%3d sf=%'lu me=%'lu \"%s\"\n",
|
||||||
test_line, sf_count, my_count, fen);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (run & 4) {
|
|
||||||
clock_start(&clock);
|
|
||||||
my_count = perft_new_pinners(pos, depth, 1);
|
|
||||||
ms3 = clock_elapsed_ms(&clock);
|
|
||||||
ms3_total += ms3;
|
|
||||||
|
|
||||||
if (sf_count == my_count) {
|
|
||||||
printf("pt3 OK : line=%3d perft=%lu %'ldms lps=%'lu \"%s\"\n",
|
|
||||||
test_line, my_count, ms3,
|
|
||||||
ms3? my_count*1000l/ms3: 0,
|
|
||||||
fen);
|
|
||||||
} else {
|
|
||||||
printf("pt3 ERR: line=%3d sf=%lu me=%lu \"%s\"\n",
|
|
||||||
test_line, sf_count, my_count, fen);
|
test_line, sf_count, my_count, fen);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -318,12 +299,12 @@ int main(int __unused ac, __unused char**av)
|
|||||||
pos_del(savepos);
|
pos_del(savepos);
|
||||||
pos_del(pos);
|
pos_del(pos);
|
||||||
i++;
|
i++;
|
||||||
|
/* to run first test only */
|
||||||
|
// exit(0);
|
||||||
}
|
}
|
||||||
if (run & 1)
|
if (run & 1)
|
||||||
printf("total perft %'ldms\n", ms1_total);
|
printf("total perft %'ldms\n", ms1_total);
|
||||||
if (run & 2)
|
if (run & 2)
|
||||||
printf("total perft2 %'ldms\n", ms2_total);
|
printf("total perft2 %'ldms\n", ms2_total);
|
||||||
if (run & 4)
|
|
||||||
printf("total perft3 %'ldms\n", ms3_total);
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user