5 Commits

13 changed files with 336 additions and 153 deletions

View File

@@ -205,7 +205,7 @@ cleanobjdir: cleanobj
# "normal" ones, but do not imply to rebuild target.
$(OBJDIR)/%.o: $(SRCDIR)/%.c | $(OBJDIR) $(DEPDIR)
@echo compiling brchess module: $< "->" $@.
$(CC) -c $(ALL_CFLAGS) $< -o $@
@$(CC) -c $(ALL_CFLAGS) $< -o $@
##################################### brlib libraries
.PHONY: cleanbrlib cleanallbrlib brlib
@@ -231,7 +231,7 @@ cleanbindir:
$(call rmdir,$(BINDIR),binaries)
$(TARGET): libs $(OBJ) | $(BINDIR)
@echo generating $@ executable.
@echo generating $@.
$(CC) $(LDFLAGS) $(OBJ) $(LIBS) -o $@
##################################### pre-processed (.i) and assembler (.s) output
@@ -241,11 +241,11 @@ cleanasmcpp:
@$(call rmfiles,$(ASMFILES) $(CPPFILES),asm and pre-processed)
%.i: %.c
@echo generating $@
@echo generating $@ (cpp processed).
@$(CC) -E $(CPPFLAGS) $(CFLAGS) $< -o $@
%.s: %.c
@echo generating $@
@echo generating $@ (asm).
@$(CC) -S -fverbose-asm $(CPPFLAGS) $(CFLAGS) $< -o $@
##################################### LSP (ccls)

View File

@@ -25,6 +25,7 @@ bitboard_t bb_sq[64];
bitboard_t bb_sqrank[64], bb_sqfile[64], bb_sqdiag[64], bb_sqanti[64];
bitboard_t bb_between_excl[64][64];
bitboard_t bb_between[64][64];
bitboard_t bb_line[64][64];
bitboard_t bb_knight[64], bb_king[64];
@@ -139,6 +140,24 @@ void bitboard_init(void)
bb_sqdiag[sq] = tmpbb[sq][2];
bb_sqanti[sq] = tmpbb[sq][3];
}
for (square_t sq1 = 0; sq1 < 64; ++sq1) {
for (square_t sq2 = 0; sq2 < 64; ++sq2) {
if (sq1 != sq2) {
if (bb_sqfile[sq1] == bb_sqfile[sq2])
bb_line[sq1][sq2] = bb_sqfile[sq1];
else if (bb_sqrank[sq1] == bb_sqrank[sq2])
bb_line[sq1][sq2] = bb_sqrank[sq1];
else if (bb_sqdiag[sq1] == bb_sqdiag[sq2])
bb_line[sq1][sq2] = bb_sqdiag[sq1];
else if (bb_sqanti[sq1] == bb_sqanti[sq2])
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 */
for (square_t sq = A1; sq <= H8; ++sq) {

View File

@@ -21,8 +21,6 @@
#include "board.h"
#include "piece.h"
//typedef u64 bitboard_t;
/* mapping square -> bitboard */
extern bitboard_t bb_sq[64];
/* squares between sq1 and sq2, exclusing both */
@@ -30,12 +28,17 @@ extern bitboard_t bb_between_excl[64][64];
/* squares between sq1 and sq2, including sq2 */
extern bitboard_t bb_between[64][64];
/* bb_sqrank[64]: square to rank
/**
* bb_sqrank[64]: square to rank
* bb_sqfile[64]: square to file
* bb_sqdiag[64]: square to diagonal
* bb_sqanti[64]: square to antidiagonal
*/
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 */
extern bitboard_t bb_line[64][64];
/* knight and king moves */
extern bitboard_t bb_knight[64], bb_king[64];
@@ -192,17 +195,24 @@ static __always_inline bitboard_t bb_file(int file)
/**
* bb_sq_aligned() - check if two squares are aligned (same file or rank).
* @sq1: square 1
* @sq2: square 2
* @sq1, @sq2: the two squares.
*
* @sq2 is included in return value, to be non zero if the two squares
* are neighbors.
*
* @return: bitboard of squares between @sq1 and @sq2, including @sq2.
* @return: true if @sq1 and @sq2 are on same line, false otherwise.
*/
static __always_inline bitboard_t bb_sq_aligned(square_t sq1, square_t sq2)
static __always_inline bool bb_sq_aligned(square_t sq1, square_t sq2)
{
return bb_between[sq1][sq2];
return bb_line[sq1][sq2];
}
/**
* bb_sq_aligned3() - check if 3 squares are aligned (same file or rank).
* @sq1, @sq2, @sq3: the three squares.
*
* @return: true if @sq1, @sq2, and @sq3 are aligned, false otherwise.
*/
static __always_inline bool bb_sq_aligned3(square_t sq1, square_t sq2, square_t sq3)
{
return bb_line[sq1][sq2] & mask(sq3);
}
/**

View File

@@ -59,14 +59,28 @@ static __always_inline rank_t sq_rank(square_t square)
#define sq_ok(sq) ((sq) >= A1 && (sq) <= H8)
#define sq_coord_ok(c) ((c) >= 0 && (c) < 8)
/* Chebyshev distance: max( |r2 - r1|, |f2 - f1| )
/**
* sq_dist() - Chebyshev (king) distance between two squares (macro).
* @sq1, @sq2: The two squares.
*
* See: https://www.chessprogramming.org/Distance
* Distance is max( |r2 - r1|, |f2 - f1| )
*
* @Return: the Chebyshev distance.
*/
#define sq_dist(sq1, sq2) (max(abs(sq_file(sq2) - sq_file(sq1)), \
abs(sq_rank(sq2) - sq_rank(sq1))))
/* Manhattan distance: |r2 - r1| + |f2 - f1|
/**
* sq_taxi() - Manhattan (taxi) distance between two squares (macro).
* @sq1, @sq2: The two squares.
*
* See: https://www.chessprogramming.org/Distance
* Distance is |r2 - r1| + |f2 - f1|.
*
* @Return: the Manhattan distance.
*/
#define sq_manh(sq1, sq2) (abs(sq_file(sq2) - sq_file(sq1)) + \
#define sq_taxi(sq1, sq2) (abs(sq_file(sq2) - sq_file(sq1)) + \
abs(sq_rank(sq2) - sq_rank(sq1)))
extern const char *sq_to_string(const square_t sq);

View File

@@ -86,15 +86,16 @@ void hyperbola_init()
}
/**
* hyperbola_rank_moves() - generate rank moves for a sliding piece.
* hyperbola_rank_moves() - get rank moves for a sliding piece.
* @pieces: occupation bitboard
* @sq: piece square
*
* Rank attacks are not handled by HQ, so we do it with a
* Rank attacks are not handled by HQ, so this function uses a pre-calculated
* rank attacks table (@bb_rank_attacks).
*
* @Return: The moves mask for piece
* @Return: bitboard of @piece available pseudo-moves.
*/
static bitboard_t hyperbola_rank_moves(bitboard_t occ, square_t sq)
bitboard_t hyperbola_rank_moves(bitboard_t occ, square_t sq)
{
u32 rank = sq & SQ_RANKMASK;
u32 file = sq & SQ_FILEMASK;
@@ -109,16 +110,19 @@ static bitboard_t hyperbola_rank_moves(bitboard_t occ, square_t sq)
}
/**
* hyperbola_moves() - generate hyperbola moves mask for a given sliding piece
* hyperbola_moves() - get hyperbola pseudo-moves for a sliding piece
* @pieces: occupation bitboard
* @sq: piece square
* @mask: mask considered
* @mask: the appropriate mask (pre-calculated)
*
* See https://www.chessprogramming.org/Hyperbola_Quintessence
* This function can be used for files, diagonal, and anti-diagonal attacks.
* @mask is the corresponding pre-calculated table (@bb_sqfile, @bb_sqdiag,
* or @bb_sqanti).
* See https://www.chessprogramming.org/Hyperbola_Quintessence for details.
*
* @Return: The moves mask for piece
* @Return: bitboard of piece available pseudo-moves.
*/
static bitboard_t hyperbola_moves(const bitboard_t pieces, const square_t sq,
bitboard_t hyperbola_moves(const bitboard_t pieces, const square_t sq,
const bitboard_t mask)
{
bitboard_t o = pieces & mask;
@@ -130,32 +134,77 @@ static bitboard_t hyperbola_moves(const bitboard_t pieces, const square_t sq,
& mask;
}
static bitboard_t hyperbola_file_moves(bitboard_t occ, square_t sq)
/**
* hyperbola_file_moves() - get file pseudo-moves for a sliding piece.
* @pieces: occupation bitboard
* @sq: piece square
*
* @Return: bitboard of piece available pseudo-moves on its file.
*/
bitboard_t hyperbola_file_moves(const bitboard_t occ, const square_t sq)
{
return hyperbola_moves(occ, sq, bb_sqfile[sq]);
}
static bitboard_t hyperbola_diag_moves(bitboard_t occ, square_t sq)
/**
* hyperbola_diag_moves() - get diagonal pseudo-moves for a sliding piece.
* @pieces: occupation bitboard
* @sq: piece square
*
* @Return: bitboard of piece available pseudo-moves on its diagonal.
*/
bitboard_t hyperbola_diag_moves(const bitboard_t occ, const square_t sq)
{
return hyperbola_moves(occ, sq, bb_sqdiag[sq]);
}
static bitboard_t hyperbola_anti_moves(bitboard_t occ, square_t sq)
/**
* hyperbola_anti_moves() - get anti-diagonal pseudo-moves for a sliding piece.
* @pieces: occupation bitboard
* @sq: piece square
*
* @Return: bitboard of piece available pseudo-moves on its anti-diagonal.
*/
bitboard_t hyperbola_anti_moves(const bitboard_t occ, const square_t sq)
{
return hyperbola_moves(occ, sq, bb_sqanti[sq]);
}
bitboard_t hyperbola_bishop_moves(bitboard_t occ, square_t sq)
/**
* hyperbola_bishop_moves() - get bitboard of bishop pseudo-moves
* @occ: occupation bitboard
* @sq: bishop square
*
* @Return: bitboard of bishop available pseudo-moves.
*/
bitboard_t hyperbola_bishop_moves(const bitboard_t occ, const square_t sq)
{
return hyperbola_diag_moves(occ, sq) | hyperbola_anti_moves(occ, sq);
}
bitboard_t hyperbola_rook_moves(bitboard_t occ, square_t sq)
/**
* hyperbola_rook_moves() - get bitboard of rook pseudo-moves
* @occ: occupation bitboard
* @sq: rook square
*
* @Return: bitboard of rook available pseudo-moves.
*/
bitboard_t hyperbola_rook_moves(const bitboard_t occ, const square_t sq)
{
return hyperbola_file_moves(occ, sq) | hyperbola_rank_moves(occ, sq);
}
bitboard_t hyperbola_queen_moves(bitboard_t occ, square_t sq)
/**
* hyperbola_queen_moves() - get bitboard of queen pseudo-moves
* @occ: occupation bitboard
* @sq: queen square
*
* This function is a wrapper over @hyperbola_bishop_moves() and
* @hyperbola_rook_moves().
*
* @Return: bitboard of queen available pseudo-moves.
*/
bitboard_t hyperbola_queen_moves(const bitboard_t occ, const square_t sq)
{
return hyperbola_bishop_moves(occ, sq) | hyperbola_rook_moves(occ, sq);
}

View File

@@ -17,9 +17,17 @@
#include "board.h"
#include "bitboard.h"
void hyperbola_init(void);
extern bitboard_t hyperbola_bishop_moves(bitboard_t occ, square_t sq);
extern bitboard_t hyperbola_rook_moves(bitboard_t occ, square_t sq);
extern bitboard_t hyperbola_queen_moves(bitboard_t occ, square_t sq);
extern void hyperbola_init(void);
extern bitboard_t hyperbola_rank_moves(const bitboard_t occ, const square_t sq);
extern bitboard_t hyperbola_moves(const bitboard_t pieces, const square_t sq,
const bitboard_t mask);
extern bitboard_t hyperbola_file_moves(const bitboard_t occ, const square_t sq);
extern bitboard_t hyperbola_diag_moves(const bitboard_t occ, const square_t sq);
extern bitboard_t hyperbola_anti_moves(const bitboard_t occ, const square_t sq);
extern bitboard_t hyperbola_bishop_moves(const bitboard_t occ, const square_t sq);
extern bitboard_t hyperbola_rook_moves(const bitboard_t occ, const square_t sq);
extern bitboard_t hyperbola_queen_moves(const bitboard_t occ, const square_t sq);
#endif /* _HYPERBOLA_QUINTESSENCE_H */

View File

@@ -27,18 +27,6 @@
#include "move-gen.h"
/**
* gen_castle() - generate c
* @pos: position
*
* Generate all pseudo pawn pushes.
*/
//int gen_pawn_push(pos_t *pos, bitboard_t occ)
//{
//}
/**
* pseudo_is_legal() - check if a move is legal.
* @pos: position
@@ -47,10 +35,11 @@
* We check all possible invalid moves:
* (1) King:
* - K moves to a controlled square
* - Castling:
* (1) Castling:
* - K passes a controlled square - already done in pseudomove gen
*
* (2) En-passant:
*
* (3) En-passant:
* - pinned taking pawn, done in (3)
* - taking and taken pawn on same rank than king, discovered check on rank
*
@@ -103,10 +92,21 @@ bool pseudo_is_legal(pos_t *pos, move_t move)
* gen_all_pseudomoves() - generate all pseudo moves
* @pos: position
*
* Generate all moves, no check is done on validity due to castle rules,
* or check (pinned pieces, etc...).
* Generate all @pos pseudo moves for player-to-move.
* The @pos->moves table is filled with the moves.
*
* @return: The number of 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}
* - pawn capture (incl. en-passant): M_CAPTURE
* - promotion: M_PROMOTION
* - promotion and capture
*
* TODO: move code to specific functions (especially castling, pawn push/capture)
*
* @Return: The total number of moves.
*/
int gen_all_pseudomoves(pos_t *pos)
{
@@ -127,7 +127,7 @@ int gen_all_pseudomoves(pos_t *pos)
int from, to;
/* king */
/* king - MUST BE FIRST ! */
from = pos->king[us];
movebits = bb_king_moves(not_my_pieces, from);
bit_for_each64(to, tmp2, movebits) {
@@ -187,11 +187,28 @@ int gen_all_pseudomoves(pos_t *pos)
//printf("push %d->%d %s->%s", from, to, sq_to_string(from), sq_to_string(to));
moves[nmoves++] = move_make(from, to);
}
/* possible second push */
movebits = pawn_shift_up(movebits & rel_rank3, us) & empty;
bit_for_each64(to, tmp1, movebits) {
from = pawn_push_up(pawn_push_up(to, them), them);
moves[nmoves++] = move_make(from, to);
}
/* pawn: ranks 2-6 captures left, including en-passant */
from_pawns = pos->bb[us][PAWN] & ~rel_rank7; // & ~rel_filea;
movebits = pawn_shift_upleft(from_pawns, us) & enemy_avail;
bit_for_each64(to, tmp1, movebits) {
from = pawn_push_upleft(to, them); /* reverse capture */
moves[nmoves++] = move_make_capture(from, to);
}
/* pawn: ranks 2-6 captures right, including en-passant */
from_pawns = pos->bb[us][PAWN] & ~rel_rank7; // & ~rel_fileh;
movebits = pawn_shift_upright(from_pawns, us) & enemy_avail;
bit_for_each64(to, tmp1, movebits) {
from = pawn_push_upright(to, them);
moves[nmoves++] = move_make_capture(from, to);
}
/* pawn: rank 7 push */
movebits = pawn_shift_up(pos->bb[us][PAWN] & rel_rank7, us) & empty;
bit_for_each64(to, tmp1, movebits) {
@@ -201,44 +218,28 @@ int gen_all_pseudomoves(pos_t *pos)
moves[nmoves++] = move_make_promote(from, to, BISHOP);
moves[nmoves++] = move_make_promote(from, to, KNIGHT);
}
/* pawn: ranks 2-6 captures left, including en-passant */
from_pawns = pos->bb[us][PAWN] & ~rel_rank7; // & ~rel_filea;
movebits = pawn_shift_upleft(from_pawns, us) & enemy_avail;
bit_for_each64(to, tmp1, movebits) {
from = pawn_push_upleft(to, them); /* reverse capture */
moves[nmoves++] = move_make(from, to);
}
/* pawn: rank 7 captures left */
/* pawn promotion: rank 7 captures left */
from_pawns = pos->bb[us][PAWN] & rel_rank7; // & ~rel_filea;
movebits = pawn_shift_upleft(from_pawns, us) & enemy_avail;
bit_for_each64(to, tmp1, movebits) {
from = pawn_push_upleft(to, them); /* reverse capture */
moves[nmoves++] = move_make_promote(from, to, QUEEN);
moves[nmoves++] = move_make_promote(from, to, ROOK);
moves[nmoves++] = move_make_promote(from, to, BISHOP);
moves[nmoves++] = move_make_promote(from, to, KNIGHT);
}
/* pawn: ranks 2-6 captures right, including en-passant */
from_pawns = pos->bb[us][PAWN] & ~rel_rank7; // & ~rel_fileh;
movebits = pawn_shift_upright(from_pawns, us) & enemy_avail;
bit_for_each64(to, tmp1, movebits) {
from = pawn_push_upright(to, them);
moves[nmoves++] = move_make(from, to);
moves[nmoves++] = move_make_promote_capture(from, to, QUEEN);
moves[nmoves++] = move_make_promote_capture(from, to, ROOK);
moves[nmoves++] = move_make_promote_capture(from, to, BISHOP);
moves[nmoves++] = move_make_promote_capture(from, to, KNIGHT);
}
/* pawn: rank 7 captures right */
from_pawns = pos->bb[us][PAWN] & rel_rank7; // & ~rel_fileh;
movebits = pawn_shift_upright(from_pawns, us) & enemy_pieces;
bit_for_each64(to, tmp1, movebits) {
from = pawn_push_upright(to, them); /* reverse capture */
moves[nmoves++] = move_make_promote(from, to, QUEEN);
moves[nmoves++] = move_make_promote(from, to, ROOK);
moves[nmoves++] = move_make_promote(from, to, BISHOP);
moves[nmoves++] = move_make_promote(from, to, KNIGHT);
moves[nmoves++] = move_make_promote_capture(from, to, QUEEN);
moves[nmoves++] = move_make_promote_capture(from, to, ROOK);
moves[nmoves++] = move_make_promote_capture(from, to, BISHOP);
moves[nmoves++] = move_make_promote_capture(from, to, KNIGHT);
}
/* castle - Attention ! We consider that castle flags are correct,
/* castle - Attention ! Castling flags are assumed correct
*/
if (!pos->checkers) {
bitboard_t rel_rank1 = BB_REL_RANK(RANK_1, us);

View File

@@ -20,49 +20,51 @@
/* move structure:
* 3 2 2 1 1 1 1 1 1
* 1 5 4 8 7 5 4 2 1 6 5 0
* UUUUUUU FFFFFFF ppp ccc tttttt ffffff
* 1 5 3 8 7 5 4 2 1 6 5 0
* UUUUUUUU FFFFFF ppp ccc tttttt ffffff
*
* bits range type mask get desc
* ffffff 0-5 square_t 3f &63 from
* tttttt 6-11 square_t fc0 (>>6)&63 to
* ccc 12-14 piece_type_t 7000 (>>12)&7 captured
* ppp 15-17 piece_type_t 38000 (>>15)&7 promoted
* FFFFFFF 18-24 N/A 1fc0000 N/A flags
* UUUUUUU 25-31 unused fe000000 N/A future usage ?
* bits len range type mask get desc
* ffffff 6 0-5 square_t 3f &63 from
* tttttt 6 6-11 square_t fc0 (>>6)&63 to
* ccc 3 12-14 piece_type_t 7000 (>>12)&7 captured
* ppp 3 15-17 piece_type_t 38000 (>>15)&7 promoted
* FFFFFF 6 18-23 move_flags_t fc0000 N/A flags
* UUUUUUUU 8 24-31 unused fe000000 N/A future usage ?
*/
#define move_t u32
typedef u32 move_t;
/* move flags */
#define M_FLAGS_BEG 18
#define M_HAS_FLAGS mask(M_FLAGS_BEG + 0) /* probably unused */
#define M_CAPTURE mask(M_FLAGS_BEG + 1)
#define M_EPASSANT mask(M_FLAGS_BEG + 2)
#define M_PROMOTE mask(M_FLAGS_BEG + 3)
#define M_CASTLE_K mask(M_FLAGS_BEG + 4)
#define M_CASTLE_Q mask(M_FLAGS_BEG + 5)
#define M_CHECK mask(M_FLAGS_BEG + 6) /* probably unknown/useless */
#define M_FLAGS (M_CAPTURE | M_ENPASSANT | M_PROMOTION | \
M_CASTLE_K | M_CASTLE_Q | M_CHECK)
#define M_NORMAL (~M_FLAGS)
typedef enum {
M_START = 18,
M_CAPTURE = (1 << (M_START + 0)),
M_ENPASSANT = (1 << (M_START + 1)),
M_PROMOTION = (1 << (M_START + 2)),
M_CASTLE_K = (1 << (M_START + 3)), /* maybe only one ? */
M_CASTLE_Q = (1 << (M_START + 4)), /* maybe only one ? */
M_CHECK = (1 << (M_START + 5)) /* maybe unknown/useless ? */
} move_type_t;
#define MOVES_MAX 256
static inline move_t move_make(square_t from, square_t to)
{
return (to << 6) | from;
}
typedef struct __movelist_s {
move_t move[MOVES_MAX];
int nmoves; /* total moves (fill) */
int curmove; /* current move (use) */
} movelist_t;
static inline move_t move_make_flags(square_t from, square_t to, int flags)
{
return move_make(from, to) | flags;
}
static inline move_t move_make_promote(square_t from, square_t to, piece_type_t piece)
{
return move_make(from, to) | M_PROMOTE | (piece << 15);
}
/* move flags */
//#define M_FLAGS_BEG 18
//#define M_HAS_FLAGS mask(M_FLAGS_BEG + 0) /* probably useless */
//#define M_CAPTURE mask(M_FLAGS_BEG + 0)
//#define M_EN_PASSANT mask(M_FLAGS_BEG + 1)
//#define M_PROMOTION mask(M_FLAGS_BEG + 2)
//#define M_CASTLE_K mask(M_FLAGS_BEG + 3) /* maybe only one ? */
//#define M_CASTLE_Q mask(M_FLAGS_BEG + 4) /* maybe only one ? */
//#define M_CHECK mask(M_FLAGS_BEG + 5) /* probably unknown/useless */
//#define M_FLAGS (M_CAPTURE | M_ENPASSANT | M_PROMOTION |
// M_CASTLE_K | M_CASTLE_Q | M_CHECK)
//#define M_NORMAL (~M_FLAGS)
static inline square_t move_from(move_t move)
{
@@ -73,6 +75,43 @@ static inline square_t move_to(move_t move)
return (move >> 6) & 077;
}
static inline piece_t move_promoted(move_t move)
{
return (move >> 15) & 07;
}
static inline piece_t move_captured(move_t move)
{
return (move >> 12) & 07;
}
static inline move_t move_make(square_t from, square_t to)
{
return (to << 6) | from;
}
static inline move_t move_make_flags(square_t from, square_t to, move_type_t flags)
{
return move_make(from, to) | flags;
}
static inline move_t move_make_capture(square_t from, square_t to)
{
return move_make_flags(from, to, M_CAPTURE);
}
static inline move_t move_make_promote(square_t from, square_t to,
piece_type_t promoted)
{
return move_make_flags(from, to, M_PROMOTION) | (promoted << 15);
}
static inline move_t move_make_promote_capture(square_t from, square_t to,
piece_type_t promoted)
{
return move_make_flags(from, to, M_CAPTURE | M_PROMOTION) | (promoted << 15);
}
/* moves_print flags
*/
#define M_PR_CAPT 0x01
@@ -83,12 +122,6 @@ static inline square_t move_to(move_t move)
#define M_PR_SEPARATE 0x40 /* separate captures */
#define M_PR_LONG 0x80
typedef struct __movelist_s {
move_t move[MOVES_MAX];
int nmoves; /* total moves (fill) */
int curmove; /* current move (use) */
} movelist_t;
//pool_t *moves_pool_init();
//void moves_pool_stats();

View File

@@ -147,41 +147,41 @@ bitboard_t pos_pinners(const pos_t *pos, const color_t color)
}
/**
* pos_check() - extensive position consistenci check.
* pos_check() - extensive position consistency check.
* @pos: &position
* @strict: if not zero, call bug_on() on any error.
* @strict: if true, call bug_on() on any error.
*
* Check (hopefully) if position is valid:
* - pawns on first or 8th rank
* - number of pawns per color > 8
* - total number of pieces per color > 16 or zero
* - number of kings per color != 1
* - discrepancy between bitboards per piece and ALL_PIECES per color
* - discrepancy between bitboards and board
* - side-to-move already checking opponent king.
* - side to move in check more than twice
* Perform some validity check on position @pos:
* - pawns on 1st or 8th rank
* - number of pawns > 8 (per color)
* - total number of pieces > 16 or zero (per color)
* - number of kings != 1 (per color)
* - discrepancy between board and king (per color)
* - discrepancy between piece bitboards and ALL_PIECES bitboards (per color)
* - discrepancy between bitboards and board (per color)
* - side-to-move already checking opponent king
* - side-to-move in check more than twice
* - kings distance is 1
*
* In case of errors, and @abort is true, @bug_on() is called, and program will
* In case of errors, and @strict is true, @bug_on() is called, and program will
* be terminated.
* This function should be called with @abort == 0 during initialization phase
* (eg after fen parsing), and with @abort != 0 otherwise (as we have some data
* This function should be called with @strict == false during initialization phase
* (eg after fen parsing), and with @strict == true otherwise (as we have some data
* corruption).
*
* TODO: add more checks:
* - kings attacking each other
*
* @Return: 0 if no error detected
* the number of detected error if @abort == 0.
* this function does not return if @abort != 0 and errors are found.
* @Return: Number of detected error (only if @strict is false).
*/
int pos_check(const pos_t *pos, const int fatal)
int pos_check(const pos_t *pos, const bool strict)
{
int n, count = 0, bbcount = 0, error = 0;
bitboard_t tmp;
/* pawns on 1st ot 8th rank */
n = popcount64((pos->bb[WHITE][PAWN] | pos->bb[BLACK][PAWN]) &
(RANK_1bb | RANK_8bb));
error += warn_on(n != 0);
tmp = (pos->bb[WHITE][PAWN] | pos->bb[BLACK][PAWN]) & (RANK_1bb | RANK_8bb);
error += warn_on(tmp);
for (color_t color = WHITE; color <= BLACK; ++color) {
/* pawn count */
@@ -190,6 +190,8 @@ int pos_check(const pos_t *pos, const int fatal)
/* king count */
n = popcount64(pos->bb[color][KING]);
error += warn_on(n != 1);
/* king mismatch with board */
error += warn_on(PIECE(pos->board[pos->king[color]]) != KING);
/* pieces count */
n = popcount64(pos->bb[color][ALL_PIECES]);
error += warn_on(n == 0 || n > 16);
@@ -212,8 +214,10 @@ int pos_check(const pos_t *pos, const int fatal)
error += warn_on(pos_checkers(pos, OPPONENT(pos->turn)));
/* is color to play in check more than twice ? */
error += warn_on(popcount64(pos_checkers(pos, OPPONENT(pos->turn))) > 2);
/* kings distance is less than 2 */
error += warn_on(sq_dist(pos->king[WHITE], pos->king[BLACK]) < 2);
bug_on(fatal && error);
bug_on(strict && error);
return error;
}

View File

@@ -144,7 +144,7 @@ extern bitboard_t pos_pinners(const pos_t *pos, const color_t color);
//extern char *pos_checkers2str(const pos_t *pos, char *str);
//extern char *pos_pinners2str(const pos_t *pos, char *str);
extern int pos_check(const pos_t *pos, const int strict);
extern int pos_check(const pos_t *pos, const bool strict);
extern void pos_print(const pos_t *pos);
extern void pos_print_mask(const pos_t *pos, const bitboard_t mask);

50
test/attack-test.c Normal file
View File

@@ -0,0 +1,50 @@
/* attack-test.c - basic square attack tests.
*
* Copyright (C) 2024 Bruno Raoult ("br")
* Licensed under the GNU General Public License v3.0 or later.
* Some rights reserved. See COPYING.
*
* You should have received a copy of the GNU General Public License along with this
* program. If not, see <https://www.gnu.org/licenses/gpl-3.0-standalone.html>.
*
* SPDX-License-Identifier: GPL-3.0-or-later <https://spdx.org/licenses/GPL-3.0-or-later.html>
*
*/
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include "chessdefs.h"
#include "fen.h"
#include "position.h"
#include "move-gen.h"
#include "attack.h"
#include "common-test.h"
int main(int __unused ac, __unused char**av)
{
int i = 0;
char *fen;
pos_t *pos;//, *fishpos = pos_new();
setlinebuf(stdout); /* line-buffered stdout */
bitboard_init();
hyperbola_init();
while ((fen = next_fen(ATTACK))) {
//printf(">>>>> %s\n", test[i]);
printf("original fen %d: [%p][%s]\n", i, fen, fen);
if (!(pos = fen2pos(NULL, fen))) {
printf("wrong fen %d: [%s]\n", i, fen);
continue;
}
pos_print(pos);
pos_del(pos);
i++;
}
return 0;
}

View File

@@ -61,10 +61,6 @@ struct fentest {
"checkers: g2 g7",
"8/6R1/8/6k1/8/8/K5R1/8 b - - 1 1"
},
{ ATTACK,
"checkers: d5 e3, pinners: a1 h1 a4 h5",
"3k4/8/8/3r3b/b7/1N2n3/4B3/rN1K1R1r w - - 1 0"
},
{ ATTACK,
"checkers: d5 e3, pinners: none (2 pieces between attacker & K)",
"3k4/8/8/3r3b/b7/1N2nn2/2n1B3/rNBK1Rbr w - - 1 1"

View File

@@ -207,7 +207,6 @@ int main(int __unused ac, __unused char**av)
continue;
}
pos_print(pos);
/* print movelists */
send_stockfish_fen(outfd, fishpos, fen);
gen_all_pseudomoves(pos);