Compare commits
5 Commits
87e7695873
...
6ee4cd1642
Author | SHA1 | Date | |
---|---|---|---|
6ee4cd1642 | |||
b7fdcca66d | |||
890cb05296 | |||
301ca24783 | |||
d81dca6e23 |
8
Makefile
8
Makefile
@@ -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)
|
||||
|
@@ -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) {
|
||||
|
@@ -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);
|
||||
}
|
||||
|
||||
/**
|
||||
|
20
src/board.h
20
src/board.h
@@ -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);
|
||||
|
@@ -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);
|
||||
}
|
||||
|
@@ -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 */
|
||||
|
@@ -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);
|
||||
|
115
src/move.h
115
src/move.h
@@ -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();
|
||||
|
||||
|
@@ -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;
|
||||
}
|
||||
|
||||
|
@@ -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
50
test/attack-test.c
Normal 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;
|
||||
}
|
@@ -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"
|
||||
|
@@ -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);
|
||||
|
Reference in New Issue
Block a user