merge movegen-review. Performance issue was in perft, not movegen !
This commit is contained in:
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
|
||||||
|
32
Makefile
32
Makefile
@@ -21,7 +21,7 @@ RMDIR := rmdir
|
|||||||
MAKE := make
|
MAKE := make
|
||||||
|
|
||||||
SRCDIR := ./src
|
SRCDIR := ./src
|
||||||
INCDIR := ./src # used by ./test sources
|
INCDIR := ./src # used by ./test sources
|
||||||
OBJDIR := ./obj
|
OBJDIR := ./obj
|
||||||
BINDIR := ./bin
|
BINDIR := ./bin
|
||||||
DEPDIR := ./dep
|
DEPDIR := ./dep
|
||||||
@@ -34,13 +34,13 @@ BRLIBDIR := $(BRLIB)/lib
|
|||||||
CCLSROOT := .ccls-root
|
CCLSROOT := .ccls-root
|
||||||
CCLSFILE := compile_commands.json
|
CCLSFILE := compile_commands.json
|
||||||
|
|
||||||
SRC := $(wildcard $(SRCDIR)/*.c) # project sources
|
SRC := $(wildcard $(SRCDIR)/*.c) # project sources
|
||||||
SRC_FN := $(notdir $(SRC)) # source basename
|
SRC_FN := $(notdir $(SRC)) # source basename
|
||||||
OBJ := $(addprefix $(OBJDIR)/,$(SRC_FN:.c=.o))
|
OBJ := $(addprefix $(OBJDIR)/,$(SRC_FN:.c=.o))
|
||||||
|
|
||||||
TSTSRC := $(wildcard $(TSTDIR)/*.c)
|
TSTSRC := $(wildcard $(TSTDIR)/*.c)
|
||||||
|
|
||||||
LIB := br_$(shell uname -m) # library name
|
LIB := br_$(shell uname -m) # library name
|
||||||
LIBS := $(strip -l$(LIB) -lreadline)
|
LIBS := $(strip -l$(LIB) -lreadline)
|
||||||
|
|
||||||
DEP_FN := $(SRC_FN)
|
DEP_FN := $(SRC_FN)
|
||||||
@@ -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
|
||||||
|
|
||||||
@@ -64,16 +63,16 @@ CPPFLAGS += -DWARN_ON # brlib bug.h
|
|||||||
#CPPFLAGS += -DDEBUG_DEBUG # enable log() functions
|
#CPPFLAGS += -DDEBUG_DEBUG # enable log() functions
|
||||||
#CPPFLAGS += -DDEBUG_DEBUG_C # enable log() settings
|
#CPPFLAGS += -DDEBUG_DEBUG_C # enable log() settings
|
||||||
#CPPFLAGS += -DDEBUG_POOL # memory pools management
|
#CPPFLAGS += -DDEBUG_POOL # memory pools management
|
||||||
#CPPFLAGS += -DDEBUG_POS # position.c
|
#CPPFLAGS += -DDEBUG_POS # position.c
|
||||||
#CPPFLAGS += -DDEBUG_MOVE # move generation
|
#CPPFLAGS += -DDEBUG_MOVE # move generation
|
||||||
|
|
||||||
# fen.c
|
# fen.c
|
||||||
#CPPFLAGS += -DDEBUG_FEN # FEN decoding
|
#CPPFLAGS += -DDEBUG_FEN # FEN decoding
|
||||||
|
|
||||||
# attack.c
|
# attack.c
|
||||||
#CPPFLAGS += -DDEBUG_ATTACK_ATTACKERS1 # sq_attackers details
|
#CPPFLAGS += -DDEBUG_ATTACK_ATTACKERS1 # sq_attackers details
|
||||||
CPPFLAGS += -DDEBUG_ATTACK_ATTACKERS # sq_attackers
|
CPPFLAGS += -DDEBUG_ATTACK_ATTACKERS # sq_attackers
|
||||||
CPPFLAGS += -DDEBUG_ATTACK_PINNERS # sq_pinners details
|
CPPFLAGS += -DDEBUG_ATTACK_PINNERS # sq_pinners details
|
||||||
|
|
||||||
#CPPFLAGS += -DDEBUG_EVAL # eval functions
|
#CPPFLAGS += -DDEBUG_EVAL # eval functions
|
||||||
#CPPFLAGS += -DDEBUG_PIECE # piece list management
|
#CPPFLAGS += -DDEBUG_PIECE # piece list management
|
||||||
@@ -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,12 +40,8 @@
|
|||||||
*/
|
*/
|
||||||
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);
|
||||||
|
|
||||||
|
|
||||||
//pos_print_raw(pos, 1);
|
|
||||||
|
|
||||||
/* bishop / queen */
|
/* bishop / queen */
|
||||||
if (hyperbola_bishop_moves(occ, sq) & (pos->bb[c][BISHOP] | pos->bb[c][QUEEN]))
|
if (hyperbola_bishop_moves(occ, sq) & (pos->bb[c][BISHOP] | pos->bb[c][QUEEN]))
|
||||||
return true;
|
return true;
|
||||||
@@ -55,7 +51,7 @@ bool sq_is_attacked(const pos_t *pos, const bitboard_t occ, const square_t sq, c
|
|||||||
return true;
|
return true;
|
||||||
|
|
||||||
/* pawn */
|
/* pawn */
|
||||||
if ((pawn_shift_upleft(sqbb, opp) | pawn_shift_upright(sqbb, opp)) & pos->bb[c][PAWN])
|
if (bb_pawn_attacks[opp][sq] & pos->bb[c][PAWN])
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
/* knight */
|
/* knight */
|
||||||
|
@@ -27,7 +27,7 @@ bitboard_t bb_between_excl[64][64];
|
|||||||
bitboard_t bb_between[64][64];
|
bitboard_t bb_between[64][64];
|
||||||
bitboard_t bb_line[64][64];
|
bitboard_t bb_line[64][64];
|
||||||
|
|
||||||
bitboard_t bb_knight[64], bb_king[64];
|
bitboard_t bb_knight[64], bb_king[64], bb_pawn_attacks[2][64];
|
||||||
|
|
||||||
/* vectors are clockwise from N */
|
/* vectors are clockwise from N */
|
||||||
static int knight_vector[] = {
|
static int knight_vector[] = {
|
||||||
@@ -105,7 +105,9 @@ void bitboard_init(void)
|
|||||||
} ;
|
} ;
|
||||||
bitboard_t tmpbb[64][4] = { 0 };
|
bitboard_t tmpbb[64][4] = { 0 };
|
||||||
|
|
||||||
/* 1) square to bitboard, and in-between-sq2-excluded */
|
/* 1) square to bitboard
|
||||||
|
* in-between, sq2 excluded
|
||||||
|
*/
|
||||||
for (square_t sq1 = A1; sq1 <= H8; ++sq1) {
|
for (square_t sq1 = A1; sq1 <= H8; ++sq1) {
|
||||||
bb_sq[sq1] = mask(sq1);
|
bb_sq[sq1] = mask(sq1);
|
||||||
for (square_t sq2 = A1; sq2 <= H8; ++sq2)
|
for (square_t sq2 = A1; sq2 <= H8; ++sq2)
|
||||||
@@ -151,18 +153,18 @@ void bitboard_init(void)
|
|||||||
bb_line[sq1][sq2] = bb_sqdiag[sq1];
|
bb_line[sq1][sq2] = bb_sqdiag[sq1];
|
||||||
else if (bb_sqanti[sq1] == bb_sqanti[sq2])
|
else if (bb_sqanti[sq1] == bb_sqanti[sq2])
|
||||||
bb_line[sq1][sq2] = bb_sqanti[sq1];
|
bb_line[sq1][sq2] = bb_sqanti[sq1];
|
||||||
|
|
||||||
//if (bb_line[sq1][sq2]) {
|
|
||||||
// printf("bb_line[%d][%d] = %16lx\n", sq1, sq2, bb_line[sq1][sq2]);
|
|
||||||
//}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* 3) knight and king moves */
|
/* 3) pawn, knight and king attacks
|
||||||
|
*/
|
||||||
for (square_t sq = A1; sq <= H8; ++sq) {
|
for (square_t sq = A1; sq <= H8; ++sq) {
|
||||||
//rank_t r1 = sq_rank(sq);
|
if (sq >= A2)
|
||||||
//file_t f1 = sq_file(sq);
|
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];
|
||||||
if (sq_ok(dst)) {
|
if (sq_ok(dst)) {
|
||||||
|
@@ -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"
|
||||||
@@ -39,9 +39,8 @@ extern bitboard_t bb_sqrank[64], bb_sqfile[64], bb_sqdiag[64], bb_sqanti[64];
|
|||||||
/* line (rank, file, diagonal or anti-diagonal) between two squares */
|
/* line (rank, file, diagonal or anti-diagonal) between two squares */
|
||||||
extern bitboard_t bb_line[64][64];
|
extern bitboard_t bb_line[64][64];
|
||||||
|
|
||||||
/* knight and king moves */
|
/* pawn, knight and king attacks */
|
||||||
extern bitboard_t bb_knight[64], bb_king[64];
|
extern bitboard_t bb_knight[64], bb_king[64], bb_pawn_attacks[2][64];
|
||||||
|
|
||||||
|
|
||||||
/* TODO (maybe C23?) when we can ensure an enum can be u64
|
/* TODO (maybe C23?) when we can ensure an enum can be u64
|
||||||
*
|
*
|
||||||
@@ -183,13 +182,64 @@ 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));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* bb_shift() - shift bitboard
|
||||||
|
* @bb: bitboard
|
||||||
|
*
|
||||||
|
* No control is done on off-board shifting (i.e. shifting -1 from A2 gives H3).
|
||||||
|
*
|
||||||
|
* @return: true if @bb has more than 1 bit, false otherwise.
|
||||||
|
*/
|
||||||
|
static __always_inline bitboard_t bb_shift(bitboard_t bb, int shift)
|
||||||
|
{
|
||||||
|
return shift >= 0 ? bb << shift : bb >> -shift;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
#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_file(f, c) bb_file(sq_rel_rank(f, 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).
|
||||||
@@ -219,7 +269,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,17 +310,20 @@ 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))
|
||||||
#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) | \
|
||||||
|
pawn_shift_upright(bb, c))
|
||||||
|
|
||||||
/* pawn move (for single pawn) - NO SQUARE CONTROL HERE !
|
/* pawn move (for single pawn) - NO SQUARE CONTROL HERE !
|
||||||
* 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);
|
||||||
|
@@ -45,6 +45,7 @@
|
|||||||
* @return: Relative rank.
|
* @return: Relative rank.
|
||||||
*/
|
*/
|
||||||
#define sq_rel_rank(rank, c) ((rank_t)((7 * (c)) ^ rank))
|
#define sq_rel_rank(rank, c) ((rank_t)((7 * (c)) ^ rank))
|
||||||
|
#define sq_rel_file(file, c) ((file_t)((7 * (c)) ^ file))
|
||||||
|
|
||||||
/* castle_t bits structure
|
/* castle_t bits structure
|
||||||
*/
|
*/
|
||||||
@@ -134,6 +135,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 {
|
||||||
|
@@ -52,14 +52,17 @@ pos_t *move_do(pos_t *pos, const move_t move) //, state_t *state)
|
|||||||
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);
|
square_t from = move_from(move), to = move_to(move);
|
||||||
piece_t piece = pos->board[from];
|
piece_t piece = pos->board[from];
|
||||||
|
piece_t captured = pos->board[to];
|
||||||
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;
|
||||||
pos->en_passant = SQUARE_NONE;
|
pos->en_passant = SQUARE_NONE;
|
||||||
pos->turn = them;
|
pos->turn = them;
|
||||||
|
pos->captured = captured;
|
||||||
|
|
||||||
bug_on(pcolor != us);
|
bug_on(pcolor != us);
|
||||||
|
|
||||||
@@ -68,9 +71,9 @@ pos_t *move_do(pos_t *pos, const move_t move) //, state_t *state)
|
|||||||
new_piece = MAKE_PIECE(move_promoted(move), us);
|
new_piece = MAKE_PIECE(move_promoted(move), us);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (is_capture(move)) {
|
if (captured != EMPTY) {
|
||||||
pos->clock_50 = 0;
|
pos->clock_50 = 0;
|
||||||
pos->captured = pos->board[to]; /* save capture info */
|
//pos->captured = pos->board[to]; /* save capture info */
|
||||||
bug_on(pos->board[to] == EMPTY || COLOR(pos->captured) != them);
|
bug_on(pos->board[to] == EMPTY || COLOR(pos->captured) != them);
|
||||||
pos_clr_sq(pos, to); /* clear square */
|
pos_clr_sq(pos, to); /* clear square */
|
||||||
} else if (is_castle(move)) { /* handle rook move */
|
} else if (is_castle(move)) { /* handle rook move */
|
||||||
@@ -88,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 = pawn_push_up(from, 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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -155,18 +158,18 @@ 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);
|
||||||
|
|
||||||
pos_clr_sq(pos, to); /* always clear "to" and set "from" */
|
pos_clr_sq(pos, to); /* always clear "to" ... */
|
||||||
pos_set_sq(pos, from, piece);
|
pos_set_sq(pos, from, piece); /* ... and set "from" */
|
||||||
|
|
||||||
if (PIECE(piece) == KING)
|
if (PIECE(piece) == KING)
|
||||||
pos->king[us] = from;
|
pos->king[us] = from;
|
||||||
|
|
||||||
if (is_capture(move)) {
|
if (pos->captured != EMPTY) {
|
||||||
pos_set_sq(pos, to, pos->captured); /* restore captured piece */
|
pos_set_sq(pos, to, pos->captured); /* restore captured piece */
|
||||||
} else if (is_castle(move)) { /* make reverse rook move */
|
} else if (is_castle(move)) { /* make reverse rook move */
|
||||||
square_t rookfrom, rookto;
|
square_t rookfrom, rookto;
|
||||||
@@ -180,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));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
440
src/move-gen.c
440
src/move-gen.c
@@ -36,76 +36,78 @@
|
|||||||
*/
|
*/
|
||||||
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];
|
bitboard_t occ = pos_occ(pos);
|
||||||
|
u64 pinned = mask(from) & pos->blockers;
|
||||||
|
u64 checkers = pos->checkers;
|
||||||
|
|
||||||
/* (1) - King
|
/* (1) - Castling & King
|
||||||
* For castling, we already tested intermediate squares attacks
|
* For castling, we need to check intermediate squares attacks only.
|
||||||
* in pseudo move generation, so we only care destination square here.
|
* Attention: To test if K is in check after moving, we need to exclude
|
||||||
* Attention: We need to exclude king from occupation bitboard !
|
* king from occupation bitboard (to catch king moving away from checker
|
||||||
|
* on same line) !
|
||||||
*/
|
*/
|
||||||
if (piece == KING) {
|
if (unlikely(from == king)) {
|
||||||
bitboard_t occ = pos_occ(pos) ^ kingbb;
|
if (unlikely(is_castle(move))) {
|
||||||
return !sq_attackers(pos, occ, to, them);
|
square_t dir = to > from? 1: -1;
|
||||||
|
if (sq_attackers(pos, occ, from + dir, them))
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return !sq_attackers(pos, occ ^ kingbb, to, them);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* (2) - King is in check
|
/* (2) - King is in check
|
||||||
* Double-check is already handled, as only K moves were generated.
|
* Double-check is already handled in (1), as only K moves were generated
|
||||||
|
* by pseudo legal move generator.
|
||||||
* Here, allowed dest squares are only on King-checker line, or on checker
|
* Here, allowed dest squares are only on King-checker line, or on checker
|
||||||
* square.
|
* square.
|
||||||
* attacker.
|
* attacker.
|
||||||
* Special cases:
|
* Special cases:
|
||||||
* e.p., legal if the taken 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 (popcount64(pos->checkers) == 1) { /* one checker */
|
if (pinned)
|
||||||
square_t checker = ctz64(pos->checkers);
|
return false;
|
||||||
if (pinned)
|
if (bb_multiple(checkers))
|
||||||
return false;
|
return false;
|
||||||
if (is_enpassant(move)) {
|
square_t checker = ctz64(checkers);
|
||||||
return pawn_push_up(pos->en_passant, them) == checker;
|
if (is_enpassant(move)) {
|
||||||
}
|
return pos->en_passant + sq_up(them) == checker;
|
||||||
bitboard_t between = bb_between[king][checker] | pos->checkers;
|
|
||||||
return mask(to) & between;
|
|
||||||
}
|
}
|
||||||
return false; /* double check */
|
return true;
|
||||||
|
//bitboard_t between = bb_between[king][checker] | pos->checkers;
|
||||||
|
//return mask(to) & between;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* (3) - pinned pieces
|
/* (3) - pinned pieces
|
||||||
* We verify here that pinned piece P stays on line King-P.
|
* We verify here that pinned piece P stays on line King-P.
|
||||||
*/
|
*/
|
||||||
//if (mask(from) & pos->blockers & pos->bb[us][ALL_PIECES]) {
|
if (mask(from) & pos->blockers) {
|
||||||
if (pinned) {
|
return bb_line[from][king] & mask(to); /* is to on pinner line ? */
|
||||||
bitboard_t line = bb_line[from][king];
|
|
||||||
return line & mask(to); /* to is not on pin line */
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* (4) - En-passant
|
/* (4) - En-passant
|
||||||
* We only care the situation where our King and enemy R/Q are on
|
* pinned pieces are handled in pinned section.
|
||||||
* 5th relative rank. To do so, we create an occupation bb without
|
* One case not handled anywhere else: when the two "disappearing" pawns
|
||||||
* the 2 pawns.
|
* would discover a R/Q horizontal 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(us)) | 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 */
|
while (rooks) {
|
||||||
if (hyperbola_rank_moves(occ, sq) & kingbb)
|
square_t rook = bb_next(&rooks);
|
||||||
|
if (hyperbola_rank_moves(occ ^ exclude, rook) & kingbb)
|
||||||
return false;
|
return false;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@@ -156,6 +158,94 @@ movelist_t *pos_all_legal(const pos_t *pos, movelist_t *movelist, movelist_t *de
|
|||||||
return dest;
|
return dest;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* gen_pseudo_king() - generate king pseudo-legal moves.
|
||||||
|
* @pos: position
|
||||||
|
* @movelist: &movelist_t array to store pseudo-moves
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
static inline __unused move_t *gen_pseudo_king(move_t *moves, square_t from,
|
||||||
|
bitboard_t mask)
|
||||||
|
{
|
||||||
|
//color_t us = pos->turn;
|
||||||
|
//square_t from = pos->king[us];
|
||||||
|
//bitboard_t not_my_pieces = ~pos->bb[us][ALL_PIECES];
|
||||||
|
bitboard_t to_bb = bb_king_moves(mask, from);
|
||||||
|
square_t to;
|
||||||
|
while (moves) {
|
||||||
|
to = bb_next(&to_bb);
|
||||||
|
*moves++ = move_make(from, to);
|
||||||
|
}
|
||||||
|
return moves;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* gen_pseudo_escape() - generate position pseudo-legal moves when in check
|
||||||
|
* @pos: square_t king position
|
||||||
|
* @mask: possible destinations to consider
|
||||||
|
* @moves: &move_t array to store pseudo-moves
|
||||||
|
*
|
||||||
|
* Generate all @pos pseudo moves for player-to-move, when in check.
|
||||||
|
* @movelist is filled with the moves.
|
||||||
|
*
|
||||||
|
* If king is doubles-checked, only King moves will be generated.
|
||||||
|
* Otherwise, only moves where destination in between King or checker, or checker
|
||||||
|
* square.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
/*
|
||||||
|
* static void __always_inline gen_pseudo_escape(pos_t *pos, movelist_t *movelist)
|
||||||
|
* {
|
||||||
|
* color_t us = pos->turn;
|
||||||
|
* color_t them = OPPONENT(us);
|
||||||
|
* square_t king = pos->king[us];
|
||||||
|
*
|
||||||
|
* gen_pseudo_king(pos, movelist);
|
||||||
|
*
|
||||||
|
* }
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* move_make_promotions() - generate all promotions for given pawn and dest.
|
||||||
|
* @moves: &move_t array where to store moves
|
||||||
|
* @from: pawn position
|
||||||
|
* @to: promotion square
|
||||||
|
*
|
||||||
|
* Generate all (Q/R/B/N) promotion moves on @to for pawn @from.
|
||||||
|
*
|
||||||
|
* @Return: New @moves (incremented by 4).
|
||||||
|
*/
|
||||||
|
static inline move_t *move_make_promotions(move_t *moves, square_t from, square_t to)
|
||||||
|
{
|
||||||
|
for (piece_type_t pt = QUEEN; pt >= KNIGHT; --pt)
|
||||||
|
*moves++ = move_make_promote(from, to, pt);
|
||||||
|
return moves;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* pos_gen_pseudomoves() - generate position pseudo-legal moves
|
* pos_gen_pseudomoves() - generate position pseudo-legal moves
|
||||||
* @pos: position
|
* @pos: position
|
||||||
@@ -185,60 +275,88 @@ int pos_gen_pseudomoves(pos_t *pos, movelist_t *movelist)
|
|||||||
color_t them = OPPONENT(us);
|
color_t them = OPPONENT(us);
|
||||||
|
|
||||||
bitboard_t my_pieces = pos->bb[us][ALL_PIECES];
|
bitboard_t my_pieces = pos->bb[us][ALL_PIECES];
|
||||||
bitboard_t not_my_pieces = ~my_pieces;
|
|
||||||
bitboard_t enemy_pieces = pos->bb[them][ALL_PIECES];
|
bitboard_t enemy_pieces = pos->bb[them][ALL_PIECES];
|
||||||
|
bitboard_t dest_squares = ~my_pieces;
|
||||||
bitboard_t occ = my_pieces | enemy_pieces;
|
bitboard_t occ = my_pieces | enemy_pieces;
|
||||||
bitboard_t empty = ~occ;
|
bitboard_t empty = ~occ;
|
||||||
|
|
||||||
bitboard_t movebits, from_pawns;
|
bitboard_t from_bb, to_bb;
|
||||||
bitboard_t tmp1, tmp2;
|
bitboard_t tmp_bb;
|
||||||
move_t *moves = movelist->move;
|
move_t *moves = movelist->move;
|
||||||
int *nmoves = &movelist->nmoves;
|
//int *nmoves = &movelist->nmoves;
|
||||||
int from, to;
|
square_t from, to;
|
||||||
|
square_t king = pos->king[us];
|
||||||
|
|
||||||
*nmoves = 0;
|
//*nmoves = 0;
|
||||||
|
|
||||||
/* king - MUST BE FIRST (we stop if doubler check) */
|
/* king - MUST BE FIRST (we stop if doubler check) */
|
||||||
from = pos->king[us];
|
to_bb = bb_king_moves(dest_squares, king);
|
||||||
movebits = bb_king_moves(not_my_pieces, from);
|
while(to_bb) {
|
||||||
bit_for_each64(to, tmp1, movebits & empty) {
|
to = bb_next(&to_bb);
|
||||||
moves[(*nmoves)++] = move_make(from, to);
|
*moves++ = move_make(king, to);
|
||||||
}
|
|
||||||
bit_for_each64(to, tmp1, movebits & enemy_pieces) {
|
|
||||||
moves[(*nmoves)++] = move_make_capture(from, to);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (popcount64(pos->checkers) > 1) /* double check, we stop here */
|
if (bb_multiple(pos->checkers)) /* double check, we stop here */
|
||||||
return *nmoves;
|
goto finish;
|
||||||
|
|
||||||
|
if (pos->checkers) {
|
||||||
|
/* one checker: we limit destination squares to line between
|
||||||
|
* checker and king + checker square (think: knight).
|
||||||
|
*/
|
||||||
|
square_t checker = ctz64(pos->checkers);
|
||||||
|
dest_squares &= bb_between[king][checker] | pos->checkers;
|
||||||
|
enemy_pieces &= dest_squares;
|
||||||
|
} else {
|
||||||
|
/* no checker: castling moves
|
||||||
|
* Attention ! Castling flags are assumed correct
|
||||||
|
*/
|
||||||
|
bitboard_t rel_rank1 = bb_rel_rank(RANK_1, us);
|
||||||
|
//square_t from_square[2] = { E1, E8 }; /* verify king is on E1/E8 */
|
||||||
|
//bug_on(can_castle(pos->castle, us) && from != from_square[us]);
|
||||||
|
/* For castle, we check the opponent attacks on squares between from and to.
|
||||||
|
* To square attack check will be done in gen_is_legal.
|
||||||
|
*/
|
||||||
|
if (can_oo(pos->castle, us)) {
|
||||||
|
bitboard_t occmask = rel_rank1 & (FILE_Fbb | FILE_Gbb);
|
||||||
|
if (!(occ & occmask)) {
|
||||||
|
*moves++ = move_make_flags(king, king + 2, M_CASTLE_K);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (can_ooo(pos->castle, us)) {
|
||||||
|
bitboard_t occmask = rel_rank1 & (FILE_Bbb | FILE_Cbb | FILE_Dbb);
|
||||||
|
if (!(occ & occmask)) { // &&
|
||||||
|
*moves++ = move_make_flags(king, king - 2, M_CASTLE_Q);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
/* sliding pieces */
|
/* sliding pieces */
|
||||||
bit_for_each64(from, tmp1, pos->bb[us][BISHOP] | pos->bb[us][QUEEN]) {
|
from_bb = pos->bb[us][BISHOP] | pos->bb[us][QUEEN];
|
||||||
movebits = hyperbola_bishop_moves(occ, from) & not_my_pieces;
|
while (from_bb) {
|
||||||
bit_for_each64(to, tmp2, movebits & empty) {
|
from = bb_next(&from_bb);
|
||||||
moves[(*nmoves)++] = move_make(from, to);
|
to_bb = hyperbola_bishop_moves(occ, from) & dest_squares;
|
||||||
}
|
while(to_bb) {
|
||||||
bit_for_each64(to, tmp2, movebits & enemy_pieces) {
|
to = bb_next(&to_bb);
|
||||||
moves[(*nmoves)++] = move_make_capture(from, to);
|
*moves++ = move_make(from, to);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
bit_for_each64(from, tmp1, pos->bb[us][ROOK] | pos->bb[us][QUEEN]) {
|
from_bb = pos->bb[us][ROOK] | pos->bb[us][QUEEN];
|
||||||
movebits = hyperbola_rook_moves(occ, from) & not_my_pieces;
|
while (from_bb) {
|
||||||
bit_for_each64(to, tmp2, movebits & empty) {
|
from = bb_next(&from_bb);
|
||||||
moves[(*nmoves)++] = move_make(from, to);
|
to_bb = hyperbola_rook_moves(occ, from) & dest_squares;
|
||||||
}
|
while(to_bb) {
|
||||||
bit_for_each64(to, tmp2, movebits & enemy_pieces) {
|
to = bb_next(&to_bb);
|
||||||
moves[(*nmoves)++] = move_make_capture(from, to);
|
*moves++ = move_make(from, to);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* knight */
|
/* knight */
|
||||||
bit_for_each64(from, tmp1, pos->bb[us][KNIGHT]) {
|
from_bb = pos->bb[us][KNIGHT];
|
||||||
movebits = bb_knight_moves(not_my_pieces, from);
|
while (from_bb) {
|
||||||
bit_for_each64(to, tmp2, movebits & empty) {
|
from = bb_next(&from_bb);
|
||||||
moves[(*nmoves)++] = move_make(from, to);
|
to_bb = bb_knight_moves(dest_squares, from);
|
||||||
}
|
while(to_bb) {
|
||||||
bit_for_each64(to, tmp2, movebits & enemy_pieces) {
|
to = bb_next(&to_bb);
|
||||||
moves[(*nmoves)++] = move_make_capture(from, to);
|
*moves++ = move_make(from, to);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -246,91 +364,117 @@ int pos_gen_pseudomoves(pos_t *pos, movelist_t *movelist)
|
|||||||
bitboard_t rel_rank8 = bb_rel_rank(RANK_8, us);
|
bitboard_t rel_rank8 = bb_rel_rank(RANK_8, us);
|
||||||
bitboard_t rel_rank3 = bb_rel_rank(RANK_3, us);
|
bitboard_t rel_rank3 = bb_rel_rank(RANK_3, us);
|
||||||
|
|
||||||
/* pawn: ranks 2-6 push 1 and 2 squares */
|
/* pawn: push */
|
||||||
movebits = pawn_shift_up(pos->bb[us][PAWN], us) & empty;
|
int shift = sq_up(us);
|
||||||
bit_for_each64(to, tmp1, movebits & ~rel_rank8) {
|
tmp_bb = bb_shift(pos->bb[us][PAWN], shift) & empty;
|
||||||
from = pawn_push_up(to, them); /* reverse push */
|
|
||||||
moves[(*nmoves)++] = move_make(from, to);
|
to_bb = tmp_bb & ~rel_rank8 & dest_squares; /* non promotion */
|
||||||
|
while(to_bb) {
|
||||||
|
to = bb_next(&to_bb);
|
||||||
|
from = to - shift;
|
||||||
|
*moves++ = move_make(from, to);
|
||||||
}
|
}
|
||||||
bit_for_each64(to, tmp1, movebits & rel_rank8) { /* promotions */
|
to_bb = tmp_bb & rel_rank8 & dest_squares; /* promotions */
|
||||||
from = pawn_push_up(to, them); /* reverse push */
|
while(to_bb) {
|
||||||
moves[(*nmoves)++] = move_make_promote(from, to, QUEEN);
|
to = bb_next(&to_bb);
|
||||||
moves[(*nmoves)++] = move_make_promote(from, to, ROOK);
|
from = to - shift;
|
||||||
moves[(*nmoves)++] = move_make_promote(from, to, BISHOP);
|
moves = move_make_promotions(moves, from, to);
|
||||||
moves[(*nmoves)++] = move_make_promote(from, to, KNIGHT);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* possible second push */
|
/* possible second push */
|
||||||
movebits = pawn_shift_up(movebits & rel_rank3, us) & empty;
|
to_bb = bb_shift(tmp_bb & rel_rank3, shift) & empty & dest_squares;
|
||||||
bit_for_each64(to, tmp1, movebits) {
|
while(to_bb) {
|
||||||
from = pawn_push_up(pawn_push_up(to, them), them);
|
to = bb_next(&to_bb);
|
||||||
moves[(*nmoves)++] = move_make_flags(from, to, M_DPUSH);
|
from = to - shift - shift;
|
||||||
|
*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 */
|
||||||
movebits = pawn_shift_upleft(pos->bb[us][PAWN], us) & enemy_pieces;
|
bitboard_t filter = ~bb_rel_file(FILE_A, us);
|
||||||
bit_for_each64(to, tmp1, movebits & ~rel_rank8) {
|
shift = sq_upleft(us);
|
||||||
from = pawn_push_upleft(to, them); /* reverse capture */
|
tmp_bb = bb_shift(pos->bb[us][PAWN] & filter, shift) & enemy_pieces;
|
||||||
moves[(*nmoves)++] = move_make_capture(from, to);
|
|
||||||
|
to_bb = tmp_bb & ~rel_rank8;
|
||||||
|
while (to_bb) {
|
||||||
|
to = bb_next(&to_bb);
|
||||||
|
from = to - shift;
|
||||||
|
*moves++ = move_make(from, to);
|
||||||
}
|
}
|
||||||
bit_for_each64(to, tmp1, movebits & rel_rank8) {
|
to_bb = tmp_bb & rel_rank8;
|
||||||
from = pawn_push_upleft(to, them); /* reverse capture */
|
while (to_bb) {
|
||||||
moves[(*nmoves)++] = move_make_promote_capture(from, to, QUEEN);
|
to = bb_next(&to_bb);
|
||||||
moves[(*nmoves)++] = move_make_promote_capture(from, to, ROOK);
|
from = to - shift;
|
||||||
moves[(*nmoves)++] = move_make_promote_capture(from, to, BISHOP);
|
moves = move_make_promotions(moves, from, to);
|
||||||
moves[(*nmoves)++] = move_make_promote_capture(from, to, KNIGHT);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* pawn: captures right */
|
/* pawn: captures right */
|
||||||
movebits = pawn_shift_upright(pos->bb[us][PAWN], us) & enemy_pieces;
|
filter = ~bb_rel_file(FILE_H, us);
|
||||||
bit_for_each64(to, tmp1, movebits & ~rel_rank8) {
|
shift = sq_upright(us);
|
||||||
from = pawn_push_upright(to, them); /* reverse capture */
|
tmp_bb = bb_shift(pos->bb[us][PAWN] & filter, shift) & enemy_pieces;
|
||||||
moves[(*nmoves)++] = move_make_capture(from, to);
|
to_bb = tmp_bb & ~rel_rank8;
|
||||||
|
while (to_bb) {
|
||||||
|
to = bb_next(&to_bb);
|
||||||
|
from = to - shift;
|
||||||
|
*moves++ = move_make(from, to);
|
||||||
}
|
}
|
||||||
bit_for_each64(to, tmp1, movebits & rel_rank8) {
|
to_bb = tmp_bb & rel_rank8;
|
||||||
from = pawn_push_upright(to, them); /* reverse capture */
|
while (to_bb) {
|
||||||
moves[(*nmoves)++] = move_make_promote_capture(from, to, QUEEN);
|
to = bb_next(&to_bb);
|
||||||
moves[(*nmoves)++] = move_make_promote_capture(from, to, ROOK);
|
from = to - shift;
|
||||||
moves[(*nmoves)++] = move_make_promote_capture(from, to, BISHOP);
|
moves = move_make_promotions(moves, from, to);
|
||||||
moves[(*nmoves)++] = move_make_promote_capture(from, to, KNIGHT);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* pawn: en-passant */
|
/* pawn: en-passant
|
||||||
if ((to = pos->en_passant) != SQUARE_NONE) {
|
* TODO: special case when in-check here ?
|
||||||
movebits = mask(to);
|
|
||||||
from_pawns = pos->bb[us][PAWN]
|
|
||||||
& (pawn_shift_upleft(movebits, them) | pawn_shift_upright(movebits, them));
|
|
||||||
bit_for_each64(from, tmp1, from_pawns) {
|
|
||||||
moves[(*nmoves)++] = move_make_enpassant(from, to);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* castle - Attention ! Castling flags are assumed correct
|
|
||||||
*/
|
*/
|
||||||
if (!pos->checkers) {
|
if ((to = pos->en_passant) != SQUARE_NONE) {
|
||||||
bitboard_t rel_rank1 = bb_rel_rank(RANK_1, us);
|
from_bb = bb_pawn_attacks[them][to] & pos->bb[us][PAWN];
|
||||||
from = pos->king[us];
|
while (from_bb) {
|
||||||
square_t from_square[2] = { E1, E8 }; /* verify king is on E1/E8 */
|
from = bb_next(&from_bb);
|
||||||
bug_on(can_castle(pos->castle, us) && from != from_square[us]);
|
*moves++ = move_make_enpassant(from, to);
|
||||||
/* For castle, we check the opponent attacks on squares between from and to.
|
|
||||||
* To square attack check will be done in gen_is_legal.
|
|
||||||
*/
|
|
||||||
if (can_oo(pos->castle, us)) {
|
|
||||||
bitboard_t occmask = rel_rank1 & (FILE_Fbb | FILE_Gbb);
|
|
||||||
if (!(occ & occmask) &&
|
|
||||||
!sq_attackers(pos, occ, from+1, them)) { /* f1/f8 */
|
|
||||||
moves[(*nmoves)++] = move_make_flags(from, from + 2, M_CASTLE_K);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (can_ooo(pos->castle, us)) {
|
|
||||||
bitboard_t occmask = rel_rank1 & (FILE_Bbb | FILE_Cbb | FILE_Dbb);
|
|
||||||
if (!(occ & occmask) &&
|
|
||||||
!sq_attackers(pos, occ, from-1, them)) { /* d1/d8 */
|
|
||||||
moves[(*nmoves)++] = move_make_flags(from, from - 2, M_CASTLE_Q);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
/*
|
||||||
|
* 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
|
||||||
*/
|
*/
|
||||||
return *nmoves;
|
finish:
|
||||||
|
return movelist->nmoves = moves - movelist->move;
|
||||||
}
|
}
|
||||||
|
@@ -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;
|
||||||
|
tmppinners = targets & attackers;
|
||||||
|
while (tmppinners) {
|
||||||
|
pinner = bb_next(&tmppinners);
|
||||||
|
pinners |= mask(pinner);
|
||||||
|
blockers |= bb_between[pinner][king] & maybeblockers;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/* we find second targets, by removing only first ones (excl. checkers) */
|
/* pawns & knights */
|
||||||
targets = hyperbola_rook_moves(occ ^ tmpblockers, king) ^ tmpcheckers;
|
checkers |= bb_pawn_attacks[us][king] & pos->bb[them][PAWN];
|
||||||
|
checkers |= bb_knight[king] & pos->bb[them][KNIGHT];
|
||||||
/* pinners = only B/Q */
|
|
||||||
tmppinners = targets & attackers;
|
|
||||||
pinners |= tmppinners;
|
|
||||||
//tmpblockers = 0;
|
|
||||||
|
|
||||||
/* blockers = we find occupied squares between pinner and king */
|
|
||||||
bit_for_each64(pinner, tmpbb, tmppinners)
|
|
||||||
blockers |= bb_between[pinner][king] & tmpblockers;
|
|
||||||
//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);
|
||||||
|
57
src/search.c
57
src/search.c
@@ -1,4 +1,4 @@
|
|||||||
/* search.c - search good moves.
|
/* search.c - perft + search.
|
||||||
*
|
*
|
||||||
* Copyright (C) 2023-2024 Bruno Raoult ("br")
|
* Copyright (C) 2023-2024 Bruno Raoult ("br")
|
||||||
* Licensed under the GNU General Public License v3.0 or later.
|
* Licensed under the GNU General Public License v3.0 or later.
|
||||||
@@ -13,7 +13,7 @@
|
|||||||
|
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
|
|
||||||
#include "brlib.h"
|
#include <brlib.h>
|
||||||
|
|
||||||
#include "position.h"
|
#include "position.h"
|
||||||
#include "move-gen.h"
|
#include "move-gen.h"
|
||||||
@@ -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,68 +83,26 @@ 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;
|
||||||
|
|
||||||
pos_gen_pseudomoves(pos, &pseudo);
|
pos_gen_pseudomoves(pos, &pseudo);
|
||||||
while ((move = pos_next_legal(pos, &pseudo, &movetmp)) != MOVE_NONE) {
|
while ((move = pos_next_legal(pos, &pseudo, &movetmp)) != MOVE_NONE) {
|
||||||
move_do(pos, move);
|
move_do(pos, move);
|
||||||
subnodes = perft(pos, depth - 1, ply + 1);
|
subnodes = perft_new_pinners(pos, depth - 1, ply + 1);
|
||||||
if (ply == 1) {
|
if (ply == 1) {
|
||||||
char movestr[8];
|
char movestr[8];
|
||||||
printf("%s: %d\n", move_str(movestr, move, 0), subnodes);
|
printf("%s: %d\n", move_str(movestr, move, 0), subnodes);
|
||||||
|
@@ -46,16 +46,24 @@ int main(int __unused ac, __unused char**av)
|
|||||||
sprintf(str, "between: %-22s%-22s%-22s%-22s%-22s%-22s%-22s%-22s",
|
sprintf(str, "between: %-22s%-22s%-22s%-22s%-22s%-22s%-22s%-22s",
|
||||||
"c3-c6", "c3-f6", "c3-f3", "c3-e1", "c3-c1", "c3-a1", "c3-a3", "c3-a5");
|
"c3-c6", "c3-f6", "c3-f3", "c3-e1", "c3-c1", "c3-a1", "c3-a3", "c3-a5");
|
||||||
bb_print_multi(str, 8,
|
bb_print_multi(str, 8,
|
||||||
bb_between[C3][C6], bb_between[C3][F6],
|
bb_between[C3][C6], bb_between[C3][F6],
|
||||||
bb_between[C3][F3], bb_between[C3][E1],
|
bb_between[C3][F3], bb_between[C3][E1],
|
||||||
bb_between[C3][C1], bb_between[C3][A1],
|
bb_between[C3][C1], bb_between[C3][A1],
|
||||||
bb_between[C3][A3], bb_between[C3][A5]);
|
bb_between[C3][A3], bb_between[C3][A5]);
|
||||||
sprintf(str, "between: %-22s%-22s%-22s%-22s%-22s%-22s%-22s%-22s",
|
sprintf(str, "between: %-22s%-22s%-22s%-22s%-22s%-22s%-22s%-22s",
|
||||||
"c4-c6", "c4-f6", "c4-f3", "c4-e1", "c4-c1", "c4-a1", "c4-a3", "c4-a5");
|
"c4-c6", "c4-f6", "c4-f3", "c4-e1", "c4-c1", "c4-a1", "c4-a3", "c4-a5");
|
||||||
bb_print_multi(str, 8,
|
bb_print_multi(str, 8,
|
||||||
bb_between[C4][C6], bb_between[C4][F6],
|
bb_between[C4][C6], bb_between[C4][F6],
|
||||||
bb_between[C4][F3], bb_between[C4][E1],
|
bb_between[C4][F3], bb_between[C4][E1],
|
||||||
bb_between[C4][C1], bb_between[C4][A1],
|
bb_between[C4][C1], bb_between[C4][A1],
|
||||||
bb_between[C4][A3], bb_between[C4][A5]);
|
bb_between[C4][A3], bb_between[C4][A5]);
|
||||||
|
sprintf(str, "Pwn att: %-22s%-22s%-22s%-22s%-22s%-22s%-22s%-22s",
|
||||||
|
"White a2", "Black a2", "White h7", "Black h7",
|
||||||
|
"White c3", "Black c3", "White e5", "Black e5");
|
||||||
|
bb_print_multi(str, 8,
|
||||||
|
bb_pawn_attacks[WHITE][A2], bb_pawn_attacks[BLACK][A2],
|
||||||
|
bb_pawn_attacks[WHITE][H7], bb_pawn_attacks[BLACK][H7],
|
||||||
|
bb_pawn_attacks[WHITE][C3], bb_pawn_attacks[BLACK][C3],
|
||||||
|
bb_pawn_attacks[WHITE][E5], bb_pawn_attacks[BLACK][E5]);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@@ -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,
|
||||||
@@ -391,10 +390,6 @@ struct fentest {
|
|||||||
"simple movedo/undo: only 2 W knights",
|
"simple movedo/undo: only 2 W knights",
|
||||||
"8/1k6/8/8/8/8/6K1/1NN5 w - - 0 1"
|
"8/1k6/8/8/8/8/6K1/1NN5 w - - 0 1"
|
||||||
},
|
},
|
||||||
{ __LINE__, MOVEDO | PERFT,
|
|
||||||
"simple movedo/undo: only 2 W knights",
|
|
||||||
"8/1k6/8/8/8/8/6K1/1NN5 w - - 0 1"
|
|
||||||
},
|
|
||||||
{ __LINE__, MOVEDO | PERFT,
|
{ __LINE__, MOVEDO | PERFT,
|
||||||
"simple movedo/undo: only 2 W knights",
|
"simple movedo/undo: only 2 W knights",
|
||||||
"5n2/1k6/8/8/5K2/8/P7/1N6 w - - 0 1"
|
"5n2/1k6/8/8/5K2/8/P7/1N6 w - - 0 1"
|
||||||
|
@@ -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 = 3;
|
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();
|
||||||
@@ -262,9 +260,7 @@ int main(int __unused ac, __unused char**av)
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
sf_count = send_stockfish_fen(outfd, fishpos, &fishmoves, fen, depth);
|
sf_count = send_stockfish_fen(outfd, fishpos, &fishmoves, fen, depth);
|
||||||
//pos_gen_pseudomoves(pos, &pseudo);
|
|
||||||
savepos = pos_dup(pos);
|
savepos = pos_dup(pos);
|
||||||
//int j = 0;
|
|
||||||
|
|
||||||
if (run & 1) {
|
if (run & 1) {
|
||||||
clock_start(&clock);
|
clock_start(&clock);
|
||||||
@@ -273,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=%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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
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=%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);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -320,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