3 Commits

8 changed files with 136 additions and 87 deletions

View File

@@ -20,6 +20,9 @@
#include "hyperbola-quintessence.h" #include "hyperbola-quintessence.h"
#include "attack.h" #include "attack.h"
// #define DEBUG_ATTACK_ATTACKERS1
/** /**
* sq_attackers() - find attackers on a square * sq_attackers() - find attackers on a square
* @pos: position * @pos: position
@@ -36,9 +39,6 @@
* *
* @Return: a bitboard of attackers. * @Return: a bitboard of attackers.
*/ */
// #define DEBUG_ATTACK_ATTACKERS1
bitboard_t sq_attackers(const pos_t *pos, const square_t sq, const color_t c) bitboard_t sq_attackers(const pos_t *pos, const square_t sq, const color_t c)
{ {
bitboard_t attackers = 0, tmp; bitboard_t attackers = 0, tmp;
@@ -96,24 +96,24 @@ bitboard_t sq_attackers(const pos_t *pos, const square_t sq, const color_t c)
} }
/** /**
* sq_pinners() - find pinners on a square * sq_pinners() - get "pinners" on a square
* @pos: position * @pos: position
* @sq: square to test * @sq: square to test
* @c: attacker color * @color: attacker color
* *
* Find all @c pieces which are separated from @sq by only one piece (of * Find all @c pieces which are separated from @sq by only one piece (of
* any color). * any color).
* *
* @Return: a bitboard of attackers. * @Return: bitboard of pinners.
*/ */
bitboard_t sq_pinners(const pos_t *pos, const square_t sq, const color_t c) bitboard_t sq_pinners(const pos_t *pos, const square_t sq, const color_t color)
{ {
bitboard_t attackers, pinners = 0; bitboard_t attackers, pinners = 0;
bitboard_t occ = pos_occ(pos); bitboard_t occ = pos_occ(pos);
bitboard_t maybe_pinner, tmp, lines; bitboard_t maybe_pinner, tmp, lines;
/* bishop type */ /* bishop type */
attackers = pos->bb[c][BISHOP] | pos->bb[c][QUEEN]; attackers = pos->bb[color][BISHOP] | pos->bb[color][QUEEN];
/* occupancy on sq diag and antidiag */ /* occupancy on sq diag and antidiag */
lines = (bb_sqdiag[sq] | bb_sqanti[sq]) & occ; lines = (bb_sqdiag[sq] | bb_sqanti[sq]) & occ;
bit_for_each64(maybe_pinner, tmp, attackers) { bit_for_each64(maybe_pinner, tmp, attackers) {
@@ -124,7 +124,7 @@ bitboard_t sq_pinners(const pos_t *pos, const square_t sq, const color_t c)
} }
/* same for rook type */ /* same for rook type */
attackers = pos->bb[c][ROOK] | pos->bb[c][QUEEN]; attackers = pos->bb[color][ROOK] | pos->bb[color][QUEEN];
lines = (bb_sqrank[sq] | bb_sqfile[sq]) & occ; lines = (bb_sqrank[sq] | bb_sqfile[sq]) & occ;
bit_for_each64(maybe_pinner, tmp, attackers) { bit_for_each64(maybe_pinner, tmp, attackers) {
bitboard_t between = bb_between_excl[maybe_pinner][sq]; bitboard_t between = bb_between_excl[maybe_pinner][sq];

View File

@@ -133,7 +133,8 @@ static int fen_check(pos_t *pos)
if (!(error = pos_check(pos, 0))) { if (!(error = pos_check(pos, 0))) {
/* TODO: Should it really be here ? */ /* TODO: Should it really be here ? */
pos->checkers = pos_checkers(pos, pos->turn); pos->checkers = pos_checkers(pos, pos->turn);
pos->pinners = pos_pinners(pos, pos->turn); pos->pinners = pos_king_pinners(pos, pos->turn);
pos->blockers = pos_king_blockers(pos, pos->turn, pos->pinners);
} }
return error ? -1: warning; return error ? -1: warning;
} }

View File

@@ -30,66 +30,59 @@
/** /**
* pseudo_is_legal() - check if a move is legal. * pseudo_is_legal() - check if a move is legal.
* @pos: position * @pos: position
* @move: move_t * @move: move_t to verify
*
* We check all possible invalid moves:
* (1) King:
* - K moves to a controlled square
* (1) Castling:
* - K passes a controlled square - already done in pseudomove gen
*
*
* (3) En-passant:
* - pinned taking pawn, done in (3)
* - taking and taken pawn on same rank than king, discovered check on rank
*
* (3) Pinned pieces:
* - if destination square quits "pinned line"
* *
* @return: true if move is valid, false otherwise. * @return: true if move is valid, false otherwise.
*/ */
bool pseudo_is_legal(pos_t *pos, move_t move) bool pseudo_is_legal(pos_t *pos, move_t move)
{ {
int from = move_from(move); color_t us = pos->turn, them = OPPONENT(us);
int to = move_to(move); square_t from = move_from(move), to = move_to(move);
int us = pos->turn; int piece = PIECE(pos->board[from]), sq;
int them = OPPONENT(us); bitboard_t tmp;
int piece = pos->board[from];
/* (1) - castling, skipped */ /* (1) - King
* For castling, we already tested intermediate squares attacks
* in pseudo move generation, so we only care destination square here.
*/
if (piece == KING)
return !sq_attackers(pos, to, them);
/* (2) - King */ /* (2) - pinned pieces
if (piece == KING) { * We verify here that pinned piece P stays on line King-P.
/* For castling, we already intermediate and destination squares */
* attacks in pseudo move generation, so we only care destination if (mask(from) & pos->blockers & pos->bb[us][ALL_PIECES]) {
* square here. bitboard_t line = bb_line[from][pos->king[us]];
*/ return line & mask(to); /* to is not on pin line */
return sq_attackers(pos, to, them) ? false: true;
} }
/* 3 - en-passant */ /* (3) - En-passant
* We only care the situation where our King and enemy R/Q are on
* from rank ()
/*
* if (bb_test(pins, from) && !bb_test(Ray[king][from], to))
* return false;
* // En-passant special case: also illegal if self-check through the en-passant captured pawn
* if (to == pos->epSquare && piece == PAWN) {
* const int us = pos->turn, them = opposite(us);
* bitboard_t occ = pos_pieces(pos);
* bb_clear(&occ, from);
* bb_set(&occ, to);
* bb_clear(&occ, to + push_inc(them));
* return !(bb_rook_attacks(king, occ) & pos_pieces_cpp(pos, them, ROOK, QUEEN)) &&
* !(bb_bishop_attacks(king, occ) & pos_pieces_cpp(pos, them, BISHOP, QUEEN));
* } else
* return true;
*/ */
if (move & M_CAPTURE && PIECE(pos->board[to]) == EMPTY) {
/* from square rank bitboard */
bitboard_t rank5 = bb_sqrank[sq_rank(from)];
/* enemy rooks/queens on from rank */
bitboard_t rooks = (pos->bb[them][ROOK] | pos->bb[them][QUEEN]) & rank5;
if ((pos->bb[us][KING] & rank5) && rooks) { /* K and enemy R/Q on rank */
/* captured pawn square (beside from square) */
square_t captured = sq_make(sq_file(pos->en_passant), sq_rank(from));
/* 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 */
if (hyperbola_rank_moves(occ, sq) & pos->bb[us][KING])
return false;
}
return true;
}
return true; return true;
} }
/** /**
* gen_all_pseudomoves() - generate all pseudo moves * pos_gen_pseudomoves() - generate position pseudo-legal moves
* @pos: position * @pos: position
* *
* Generate all @pos pseudo moves for player-to-move. * Generate all @pos pseudo moves for player-to-move.
@@ -108,9 +101,10 @@ bool pseudo_is_legal(pos_t *pos, move_t move)
* *
* @Return: The total number of moves. * @Return: The total number of moves.
*/ */
int gen_all_pseudomoves(pos_t *pos) int pos_gen_pseudomoves(pos_t *pos)
{ {
color_t us = pos->turn, them = OPPONENT(us); color_t us = pos->turn;
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 not_my_pieces = ~my_pieces;
@@ -277,3 +271,24 @@ int gen_all_pseudomoves(pos_t *pos)
*/ */
return (pos->moves.nmoves = nmoves); return (pos->moves.nmoves = nmoves);
} }
/**
* pos_legalmoves() - generate position legal moves from pseudo-legal ones.
* @pos: position
* @dest: address where to store legal moves
*
* The pseudo-legal moves must be already calculated before calling this function.
*
* @Return: @dest
*/
movelist_t *pos_legalmoves(pos_t *pos, movelist_t *dest)
{
int pseudo;
movelist_t *src = &pos->moves;
dest->nmoves = 0;
for (pseudo = 0; pseudo < src->nmoves; ++pseudo) {
if (pseudo_is_legal(pos, src->move[pseudo]))
dest->move[dest->nmoves++] = src->move[pseudo];
}
return dest;
}

View File

@@ -21,7 +21,8 @@
#include "piece.h" #include "piece.h"
#include "move.h" #include "move.h"
bool pseudo_is_legal(pos_t *pos, move_t move); extern bool pseudo_is_legal(pos_t *pos, move_t move);
int gen_all_pseudomoves(pos_t *pos); extern int pos_gen_pseudomoves(pos_t *pos);
extern movelist_t *pos_legalmoves(pos_t *pos, movelist_t *dest);
#endif /* MOVEGEN_H */ #endif /* MOVEGEN_H */

View File

@@ -89,8 +89,8 @@
*/ */
/** /**
* move_print() - print a move * moves_print() - print movelist moves.
* @pos: position * @moves: &movelist_t moves list
* @flags: moves selection and display options. * @flags: moves selection and display options.
* *
* Possible flags are: * Possible flags are:
@@ -101,15 +101,12 @@
* M_PR_NL: print a newline after move * M_PR_NL: print a newline after move
* M_PR_EVAL: print move eval * M_PR_EVAL: print move eval
*/ */
void moves_print(pos_t *pos, __unused int flags) void moves_print(movelist_t *moves, __unused int flags)
{ {
move_t *moves = pos->moves.move; printf("%2d:", moves->nmoves);
int nmoves = pos->moves.nmoves; for (int m = 0; m < moves->nmoves; ++m) {
square_t from = move_from(moves->move[m]);
printf("%2d:", nmoves); square_t to = move_to(moves->move[m]);
for (int m = 0; m < nmoves; ++m) {
square_t from = move_from(moves[m]);
square_t to = move_to(moves[m]);
printf(" %s-%s", sq_to_string(from), sq_to_string(to)); printf(" %s-%s", sq_to_string(from), sq_to_string(to));
} }
printf("\n"); printf("\n");
@@ -133,14 +130,14 @@ static int _moves_cmp_bysquare(const void *p1, const void *p2)
} }
/** /**
* move_sort_by_sq() - sort moves by from/to squares ascending * move_sort_by_sq() - sort moves list by from/to squares ascending
* @pos: position. * @moves: &movelist_t
* *
* Used for perft, for easier comparison. * Used for perft, for easier comparison.
*/ */
void move_sort_by_sq(pos_t *pos) void move_sort_by_sq(movelist_t *moves)
{ {
qsort(pos->moves.move, pos->moves.nmoves, sizeof(move_t), _moves_cmp_bysquare); qsort(moves->move, moves->nmoves, sizeof(move_t), _moves_cmp_bysquare);
} }
/* /*

View File

@@ -127,8 +127,8 @@ static inline move_t move_make_promote_capture(square_t from, square_t to,
//int move_print(int movenum, move_t *move, move_flags_t flags); //int move_print(int movenum, move_t *move, move_flags_t flags);
extern void moves_print(pos_t *pos, int flags); extern void moves_print(movelist_t *moves, int flags);
extern void move_sort_by_sq(pos_t *pos); extern void move_sort_by_sq(movelist_t *moves);
//extern int pseudo_moves_castle(pos_t *pos, bool color, bool doit, bool do_king); //extern int pseudo_moves_castle(pos_t *pos, bool color, bool doit, bool do_king);
//int pseudo_moves_gen(pos_t *pos, piece_list_t *piece, bool doit, bool do_king); //int pseudo_moves_gen(pos_t *pos, piece_list_t *piece, bool doit, bool do_king);

View File

@@ -132,18 +132,46 @@ bitboard_t pos_checkers(const pos_t *pos, const color_t color)
} }
/** /**
* pos_pinners() - find all pinners on a king. * pos_king_pinners() - get the "pinners" on a king "pinners".
* @pos: &position * @pos: &position
* @color: king color * @color: king color.
* *
* Get a bitboard of all pinners on @color king. * get position "pinners" on @color king. Here, pinner means a piece separated from king
* Just a wrapper over @sq_pinners(). * by one piece (any color) only.
* This is just a wrapper over @sq_pinners().
* *
* @return: a bitboard of pinners. * @return: pinners bitboard.
*/ */
bitboard_t pos_pinners(const pos_t *pos, const color_t color) bitboard_t pos_king_pinners(const pos_t *pos, const color_t color)
{ {
return sq_pinners(pos, pos->king[color], OPPONENT(color)); return sq_pinners(pos, pos->king[color], OPPONENT(pos->turn));
}
/**
* pos_king_blockers() - get the pin blockers on a king.
* @pos: &position
* @color: king color.
* @pinners: pinners bitboard.
*
* get @pinners blockers pieces on @color king.
*
* @return: blockers bitboard.
*/
bitboard_t pos_king_blockers(const pos_t *pos, const color_t color, const bitboard_t pinners)
{
bitboard_t tmp, blockers = 0, occ = pos_occ(pos);
square_t pinner, king = pos->king[color];
bit_for_each64(pinner, tmp, pinners) {
bitboard_t blocker = bb_between_excl[pinner][king] & occ;
warn_on(popcount64(blocker) != 1);
if (popcount64(blocker) != 1) {
printf("n blockers = %d\n", popcount64(blocker));
bb_print("blockers", blocker);
}
blockers |= blocker;
}
return blockers;
} }
/** /**
@@ -233,6 +261,7 @@ void pos_print(const pos_t *pos)
printf("fen %s\n", pos2fen(pos, str)); printf("fen %s\n", pos2fen(pos, str));
printf("checkers: %s\n", pos_checkers2str(pos, str, sizeof(str))); printf("checkers: %s\n", pos_checkers2str(pos, str, sizeof(str)));
printf("pinners : %s\n", pos_pinners2str(pos, str, sizeof(str))); printf("pinners : %s\n", pos_pinners2str(pos, str, sizeof(str)));
printf("blockers: %s\n", pos_blockers2str(pos, str, sizeof(str)));
} }
/** /**

View File

@@ -39,10 +39,13 @@ typedef struct __pos_s {
bitboard_t controlled[2]; /* unsure */ bitboard_t controlled[2]; /* unsure */
bitboard_t checkers; /* opponent checkers */ bitboard_t checkers; /* opponent checkers */
bitboard_t pinners; /* opponent pinners */ bitboard_t pinners; /* opponent pinners */
bitboard_t blockers; /* pieces blocking pin */
piece_t board[BOARDSIZE]; piece_t board[BOARDSIZE];
movelist_t moves; movelist_t moves;
} pos_t; } pos_t;
#define pos_pinned(p) (p->blockers & p->bb[p->turn][ALL_PIECES])
/** /**
* pos_set_sq - unconditionally set a piece on a square * pos_set_sq - unconditionally set a piece on a square
* @pos: position * @pos: position
@@ -120,7 +123,7 @@ static __always_inline int pos_between_count(const pos_t *pos,
/** /**
* pos_checkers2str() - get of string of checkers. * pos_checkers2str() - get of string of checkers.
* @pos: position * @p: position
* @str: destination string * @str: destination string
* @len: max @str len. * @len: max @str len.
* *
@@ -128,8 +131,9 @@ static __always_inline int pos_between_count(const pos_t *pos,
* *
* @return: @str. * @return: @str.
*/ */
#define pos_checkers2str(pos, str, len) bb_sq2str((pos)->checkers, (str), (len)) #define pos_checkers2str(p, str, len) bb_sq2str(p->checkers, str, len)
#define pos_pinners2str(pos, str, len) bb_sq2str((pos)->pinners, (str), (len)) #define pos_pinners2str(p, str, len) bb_sq2str(p->pinners, str, len)
#define pos_blockers2str(p, str, len) bb_sq2str(p->blockers, str, len)
//void bitboard_print(bitboard_t bb, char *title); //void bitboard_print(bitboard_t bb, char *title);
//void bitboard_print2(bitboard_t bb1, bitboard_t bb2, char *title); //void bitboard_print2(bitboard_t bb1, bitboard_t bb2, char *title);
@@ -140,7 +144,9 @@ extern void pos_del(pos_t *pos);
extern pos_t *pos_clear(pos_t *pos); extern pos_t *pos_clear(pos_t *pos);
extern bitboard_t pos_checkers(const pos_t *pos, const color_t color); extern bitboard_t pos_checkers(const pos_t *pos, const color_t color);
extern bitboard_t pos_pinners(const pos_t *pos, const color_t color); extern bitboard_t pos_king_pinners(const pos_t *pos, const color_t color);
extern bitboard_t pos_king_blockers(const pos_t *pos, const color_t color, const bitboard_t );
//extern bitboard_t set_king_pinners_blockers(pos_t *pos);
//extern char *pos_checkers2str(const pos_t *pos, char *str); //extern char *pos_checkers2str(const pos_t *pos, char *str);
//extern char *pos_pinners2str(const pos_t *pos, char *str); //extern char *pos_pinners2str(const pos_t *pos, char *str);