add hyperbola-quintessence.[ch]}, rank move gen, + file/rook/queen

This commit is contained in:
2024-02-15 10:15:13 +01:00
parent bc28a900be
commit 403e625cbe
8 changed files with 297 additions and 139 deletions

View File

@@ -17,6 +17,7 @@
#include "brlib.h"
#include "chessdefs.h"
#include "piece.h"
#include "board.h"
#include "bitboard.h"
@@ -31,90 +32,78 @@ static int king_vector[8] = {
NORTH, NORTH_EAST, EAST, SOUTH_EAST,
SOUTH, SOUTH_WEST, WEST, NORTH_WEST
};
static int bishop_vector[4] = {
NORTH_EAST, SOUTH_EAST, SOUTH_WEST, NORTH_WEST
};
static int rook_vector[4] = {
NORTH, EAST, SOUTH, WEST
};
bitboard_t sq_bb[SQUARE_MAX];
bitboard_t sq_bbrank[64], sq_bbfile[64], sq_bbdiag[64], sq_bbanti[64];
bitboard_t bb_sq[SQUARE_MAX];
bitboard_t bb_rank[64], bb_file[64], bb_diagonal[64], bb_antidiagonal[64];
bitboard_t knight_attacks[64], king_attacks[64];
bitboard_t pawn_attacks[2];
/* we will create only dest squares for A1-D4 square, then flip
*/
bitboard_t bb_knight[64], bb_king[64];
bitboard_t bb_pawn_push[2][64], bb_bpawn_attack[2][64], bb_pawn_ep[2][64];
/**
* raw_bitboard_print() - print simple bitboard representation
* @bb: the bitboard
* @tit: a string or NULL
* bitboard_init() - initialize general bitboards
*
* Generate the following bitboards :
* bb_sq[64]: square to bitboard
* bb_rank[64]: square to rank
* bb_file[64]: square to file
* bb_diagonal[64]: square to diagonal
* bb_antidiagonal[64]: square to antidiagonal
*
* And the following pseudo move masks:
* bb_knight[64]: knight moves
* bb_king[64]: king moves
* bb_pawn[2][64]: white pawn moves (not attacks)
* bb_pawn_att[2][64]: white pawn attacks
*/
void bitboard_init(void)
{
struct {
union {
struct {
bitboard_t diag;
bitboard_t anti;
bitboard_t vert;
bitboard_t hori;
};
bitboard_t all[4];
};
} tmpmasks[64] = {0};
struct {
int df, dr;
} dirs[4] = {
/* for each square, the 4 masks: file, rank, diagonal, antidiagonal */
struct { int df, dr; } dirs[4] = {
{ 0, 1 }, /* vertical/file */
{ 1, 0 }, /* horizontal/rank */
{ 1, 1 }, /* diagonal */
{ 1, -1 }, /* antidiagonal */
} ;
bitboard_t tmpbb[64][4] = { 0 };
square_t sq;
int dst, dst_f, dst_r;
/* 1) square to bitboard */
for (square_t sq = A1; sq <= H8; ++sq)
bb_sq[sq] = mask(sq);
/* square to bitboard */
for (sq = A1; sq <= H8; ++sq)
sq_bb[sq] = mask(sq);
/* square to rank/file/diagonal/antidiagonal */
for (sq = 0; sq < 64; ++sq) {
/* 2) square to rank/file/diagonal/antidiagonal */
for (square_t sq = 0; sq < 64; ++sq) {
int r = sq_rank(sq), f = sq_file(sq);
for (int mult = -7; mult < 8; ++mult) {
for (int dir = 0; dir < 4; ++dir) {
dst_f = f + mult * dirs[dir].df;
dst_r = r + mult * dirs[dir].dr;
int dst_f = f + mult * dirs[dir].df;
int dst_r = r + mult * dirs[dir].dr;
if (sq_coord_ok(dst_f) && sq_coord_ok(dst_r)) {
dst = sq_make(dst_f, dst_r);
tmpmasks[sq].all[dir] |= mask(dst);
int dst = sq_make(dst_f, dst_r);
tmpbb[sq][dir] |= mask(dst);
}
}
}
}
for (sq = 0; sq < 64; ++sq) {
sq_bbfile[sq] = tmpmasks[sq].all[0];
sq_bbrank[sq] = tmpmasks[sq].all[1];
sq_bbdiag[sq] = tmpmasks[sq].all[2];
sq_bbanti[sq] = tmpmasks[sq].all[3];
for (square_t sq = 0; sq < 64; ++sq) {
bb_file[sq] = tmpbb[sq][0];
bb_rank[sq] = tmpbb[sq][1];
bb_diagonal[sq] = tmpbb[sq][2];
bb_antidiagonal[sq] = tmpbb[sq][3];
}
/* knight and king attacks */
for (sq = A1; sq <= H8; ++sq) {
/* 3) knight and king moves */
for (square_t sq = A1; sq <= H8; ++sq) {
for (int vec = 0; vec < 8; ++vec) {
dst = sq + knight_vector[vec];
int dst = sq + knight_vector[vec];
if (sq_ok(dst)) {
if (sq_dist(dst, sq) == 2) {
knight_attacks[sq] |= sq_bb[dst];
bb_knight[sq] |= bb_sq[dst];
}
}
dst = sq + king_vector[vec];
if (sq_ok(dst)) {
if (sq_dist(dst, sq) == 1) {
king_attacks[sq] |= sq_bb[dst];
bb_king[sq] |= bb_sq[dst];
}
}
}
@@ -134,7 +123,7 @@ void bitboard_print(const char *title, const bitboard_t bitboard)
for (rank_t r = RANK_8; r >= RANK_1; --r) {
printf("%d ", r + 1);
for (file_t f = FILE_A; f <= FILE_H; ++f) {
printf(" %c", bitboard & sq_bb[sq_make(f, r)] ? 'X': '.');
printf(" %c", bitboard & bb_sq[sq_make(f, r)] ? 'X': '.');
}
printf("\n");
}
@@ -150,35 +139,51 @@ void bitboard_print(const char *title, const bitboard_t bitboard)
*
* @n is the number of bitboards to print. If @n -s > 8, it is reduced to 8;
*/
void bitboard_print_multi(const char *title, const int n, ...)
void bitboard_print_multi(const char *title, int n, ...)
{
bitboard_t bb[16];
int i;
bitboard_t bb[8];
va_list ap;
n = min(n, 8);
va_start(ap, n);
for (i = 0; i < n; ++i) {
for (int i = 0; i < n; ++i) { /* save all bitboards */
bb[i] = va_arg(ap, bitboard_t);
}
va_end(ap);
//char c = p? p: 'X';
if (title)
printf("%s\n", title);
for (rank_t r = RANK_8; r >= RANK_1; --r) {
for (i = 0; i < n; ++i) {
for (int i = 0; i < n; ++i) {
printf("%d ", r + 1);
for (file_t f = FILE_A; f <= FILE_H; ++f) {
printf(" %c", bb[i] & sq_bb[sq_make(f, r)] ? 'X': '.');
printf(" %c", bb[i] & bb_sq[sq_make(f, r)] ? 'X': '.');
}
printf(" ");
}
printf("\n");
}
for (i = 0; i < n; ++i) {
for (int i = 0; i < n; ++i) {
printf(" a b c d e f g h");
printf(" ");
}
printf("\n");
return;
}
/**
* bitboard_rank_sprint() - print an u8 rank binary representation
* @str: the destination string
* @bb8: the uchar to print
*/
char *bitboard_rank_sprint(char *str, const uchar bb8)
{
for (file_t f = FILE_A; f <= FILE_H; ++f) {
*(str+f) = bb8 & mask(f) ? '1': '.';
}
//printf(" 0 1 2 3 4 5 6 7\n");
//printf("\n");
return str;
}

View File

@@ -23,16 +23,15 @@
typedef u64 bitboard_t;
/* mapping square -> bitboard */
extern bitboard_t sq_bb[64];
extern bitboard_t bb_sq[64];
/* mapping square -> rank/file/diagonal/antidiagonal */
extern bitboard_t sq_bbrank[64], sq_bbfile[64], sq_bbdiag[64], sq_bbanti[64];
extern bitboard_t knight_attacks[64], king_attacks[64];
extern bitboard_t bb_rank[64], bb_file[64], bb_diagonal[64], bb_antidiagonal[64];
extern bitboard_t bb_knight[64], bb_king[64];
#define mask(i) ( 1ULL << (i) )
typedef enum {
enum {
FILE_Abb = 0x0101010101010101ULL,
FILE_Bbb = 0x0202020202020202ULL,
FILE_Cbb = 0x0404040404040404ULL,
@@ -41,9 +40,9 @@ typedef enum {
FILE_Fbb = 0x2020202020202020ULL,
FILE_Gbb = 0x4040404040404040ULL,
FILE_Hbb = 0x8080808080808080ULL,
} file_bb;
};
typedef enum {
enum {
RANK_1bb = 0x00000000000000ffULL,
RANK_2bb = 0x000000000000ff00ULL,
RANK_3bb = 0x0000000000ff0000ULL,
@@ -52,7 +51,7 @@ typedef enum {
RANK_6bb = 0x0000ff0000000000ULL,
RANK_7bb = 0x00ff000000000000ULL,
RANK_8bb = 0xff00000000000000ULL
} rank_bb;
};
/* https://www.chessprogramming.org/Flipping_Mirroring_and_Rotating#Rotation
*/
@@ -61,8 +60,43 @@ static __always_inline bitboard_t bb_rotate_90(bitboard_t b)
return b;
}
/* TODO: when OK, replace with macros */
static __always_inline bitboard_t shift_n(const bitboard_t bb)
{
return bb << NORTH;
}
static __always_inline bitboard_t shift_ne(const bitboard_t bb)
{
return (bb & ~FILE_Hbb) << NORTH_EAST;
}
static __always_inline bitboard_t shift_e(const bitboard_t bb)
{
return (bb & ~FILE_Hbb) << EAST;
}
static __always_inline bitboard_t shift_se(const bitboard_t bb)
{
return (bb & ~FILE_Hbb) >> -SOUTH_EAST;
}
static __always_inline bitboard_t shift_s(const bitboard_t bb)
{
return bb >> -SOUTH;
}
static __always_inline bitboard_t shift_sw(const bitboard_t bb)
{
return (bb & ~FILE_Abb) >> -SOUTH_WEST;
}
static __always_inline bitboard_t shift_w(const bitboard_t bb)
{
return (bb & ~FILE_Abb) >> -WEST;
}
static __always_inline bitboard_t shift_nw(const bitboard_t bb)
{
return (bb & ~FILE_Abb) << NORTH_WEST;
}
extern void bitboard_init(void);
extern void bitboard_print(const char *title, const bitboard_t bitboard);
extern void bitboard_print_multi(const char *title, const int n, ...);
extern char *bitboard8_sprint(char *str, const uchar bb8);
#endif /* _BITBOARD_H */

View File

@@ -18,16 +18,22 @@
#include "chessdefs.h"
/* a square is defined as
* rrrfff
*/
#define SQ_FILEMASK (007) /* warning, octal */
#define SQ_RANKMASK (070)
typedef enum {
_SSQUARE_ = -1, /* force signed enum */
A1 = 0, B1, C1, D1, E1, F1, G1, H1,
A2, B2, C2, D2, E2, F2, G2, H2,
A3, B3, C3, D3, E3, F3, G3, H3,
A4, B4, C4, D4, E4, F4, G4, H4,
A5, B5, C5, D5, E5, F5, G5, H5,
A6, B6, C6, D6, E6, F6, G6, H6,
A7, B7, C7, D7, E7, F7, G7, H7,
A8, B8, C8, D8, E8, F8, G8, H8,
A2, B2, C2, D2, E2, F2, G2, H2,
A3, B3, C3, D3, E3, F3, G3, H3,
A4, B4, C4, D4, E4, F4, G4, H4,
A5, B5, C5, D5, E5, F5, G5, H5,
A6, B6, C6, D6, E6, F6, G6, H6,
A7, B7, C7, D7, E7, F7, G7, H7,
A8, B8, C8, D8, E8, F8, G8, H8,
SQUARE_MAX = 64,
SQUARE_NONE = 64
} square_t;
@@ -71,65 +77,26 @@ static __always_inline square_t sq_make(file_t file, rank_t rank)
}
static __always_inline file_t sq_file(square_t square)
{
return square & 7;
return square & SQ_FILEMASK;
}
static __always_inline rank_t sq_rank(square_t square)
{
return square >> 3;
}
#define sq_ok(sq) ((sq) >= A1 && (sq) <= H8)
#define sq_coord_ok(c) ((c) >= 0 && (c) < 8)
/* Chebyshev distance: https://www.chessprogramming.org/Distance */
/* Chebyshev distance: max( |r2 - r1|, |f2 - f1| )
* See: https://www.chessprogramming.org/Distance
*/
#define sq_dist(sq1, sq2) (max(abs(sq_file(sq2) - sq_file(sq1)), \
abs(sq_rank(sq2) - sq_rank(sq1))))
/* Manhattan distance */
/* Manhattan distance: |r2 - r1| + |f2 - f1|
*/
#define sq_manh(sq1, sq2) (abs(sq_file(sq2) - sq_file(sq1)) + \
abs(sq_rank(sq2) - sq_rank(sq1)))
// while the orthogonal Manhattan-Distance is the sum of both absolute rank- and file-distance distances.
//Dtaxi = |r2 - r1| + |f2 - f1|
// Chebyshev Distance
//#include "piece.h"
/* definitions for 0x88 representation
*/
//#define SQ88(f, r) (((r) << 4) | (f)) /* from rank,file to sq88 */
//#define F88(s) ((s) & 0x0f) /* from sq88 to file */
//#define R88(s) ((s) >> 4) /* from sq88 to rank */
//#define SETF88(s, r) ((s) &= 0xf0, (s) |= (r))
//#define SETR88(s, f) ((s) &= 0x0f, (s) |= (f)<<4)
//#define SQ88_NOK(s) ((s) & 0x88) /* invalid square */
//#define SQ88_OK(s) (!SQ88_NOK(s))
/* definitions for bitboard representation
*/
//#define BB(f, r) (1ULL << (8 * (r) + (f))) /* from rank,file to bitboard */
//#define SQ88_2_BB(s) (BB(F88(s), R88(s))) /* from sq88 to bitboard */
//#define FILEBB(b) ((b) % 8) /* from sq88 to file */
//#define RANKBB(b) ((b) / 8) /* from sq88 to rank */
//#define SQ88_NOK(s) ((s) & 0x88) /* invalid square */
//#define SQ88_OK(s) (!SQ88_NOK(s))
/* from human to machine
*/
/*
* #define C2FILE(c) (tolower(c) - 'a')
* #define C2RANK(c) (tolower(c) - '1')
* /\* from machine to human
* *\/
* #define FILE2C(f) ((f) + 'a')
* #define RANK2C(r) ((r) + '1')
*/
extern const char *sq_string(const square_t sq);
#endif /* BOARD_H */

View File

@@ -18,7 +18,7 @@
#include <readline/readline.h>
#include <readline/history.h>
#include <br.h>
#include <brlib.h>
#include <list.h>
#include <debug.h>

View File

@@ -0,0 +1,126 @@
/* hyperbola-quintessence.c - hyperbola quintessence functions.
*
* 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 <stdarg.h>
#include "brlib.h"
#include "chessdefs.h"
#include "board.h"
#include "bitboard.h"
#include "hyperbola-quintessence.h"
uchar bb_rank_attacks[64 * 8];
/**
* hyperbola_init() - init hyperbola quintessence attack bitboards
*
* See: https://www.chessprogramming.org/Kindergarten_Bitboards
* and https://www.chessprogramming.org/Hyperbola_Quintessence
*
* Generate the rank attacks bitboard:
* bb_rank_hyperbola[64 * 8], where:
* - 64 = 2^6 = the occupation of inner 6 bits on rank
* - 8 = file of sliding piece
*
*/
void hyperbola_init()
{
/* generate rank attacks
*/
for (int occ = 0; occ < 64; ++occ) {
for (int file = 0; file < 8; ++file) {
uchar attacks = 0;
/* set f left attacks */
for (int slide = file - 1; slide >= 0; --slide) {
int b = bb_sq[slide]; /* bit to consider */
attacks |= b; /* add to attack mask */
if ((occ << 1) & b) /* piece on b, we stop */
break;
}
/* set f right attacks */
for (int slide = file + 1; slide < 8; ++slide) {
int b = bb_sq[slide];
attacks |= b;
if ((occ << 1) & b)
break;
}
bb_rank_attacks[occ * 8 + file] = attacks;
}
}
}
/**
* hyperbola_moves() - generate hyperbola moves mask for a given sliding piece
* @pieces: occupation bitboard
* @sq: piece square
* @mask: mask considered
*
* See https://www.chessprogramming.org/Hyperbola_Quintessence
*
* @Return: The moves mask for piece
*/
static bitboard_t hyperbola_moves(const bitboard_t pieces, const square_t sq,
const bitboard_t mask)
{
bitboard_t o = pieces & mask;
bitboard_t r = bswap64(o);
square_t r_sq = FLIP_V(sq);
return ( (o - mask(sq) )
^ bswap64(r - mask(r_sq)))
& mask;
}
static bitboard_t hyperbola_rank_moves(bitboard_t occ, square_t sq)
{
uint32_t rank = sq & SQ_FILEMASK;
uint32_t file = sq & SQ_RANKMASK;
uint64_t o = (occ >> rank) & 126; /* removes bits 0 & 7 */
return ((bitboard_t)bb_rank_attacks[o * 4 + file]) << rank;
}
static bitboard_t hyperbola_file_moves(bitboard_t occ, square_t sq)
{
return hyperbola_moves(occ, bb_file[sq], sq);
}
static bitboard_t hyperbola_diagonal_moves(bitboard_t occ, square_t sq)
{
return hyperbola_moves(occ, bb_diagonal[sq], sq);
}
static bitboard_t hyperbola_antidiagonal_moves(bitboard_t occ, square_t sq)
{
return hyperbola_moves(occ, bb_antidiagonal[sq], sq);
}
bitboard_t hyperbola_bishop_moves(bitboard_t occ, square_t sq)
{
return hyperbola_diagonal_moves(occ, sq) + hyperbola_antidiagonal_moves(occ, sq);
}
bitboard_t hyperbola_rook_moves(bitboard_t occ, 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)
{
return hyperbola_bishop_moves(occ, sq) + hyperbola_rook_moves(occ, sq);
}

View File

@@ -0,0 +1,19 @@
/* hyperbola-quintessence.h - hyperbola-quintessence definitions.
*
* 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>
*
*/
#ifndef _HYPERBOLA_QUINTESSENCE_H
#define _HYPERBOLA_QUINTESSENCE_H
void hyperbola_init(void);
#endif /* _HYPERBOLA_QUINTESSENCE_H */

View File

@@ -4,28 +4,35 @@
#include <stdio.h>
#include <string.h>
#include "../src/bitboard.h"
#include "../src/position.h"
#include "../src/piece.h"
//#include "../src/fen.h"
#include "../src/bitboard.h"
#include "../src/hyperbola-quintessence.h"
int main(int __unused ac, __unused char**av)
{
char str[128];
char str[256];
bitboard_init();
hyperbola_init();
for (int i = 0; i < 64; ++i) {
char str[128];
sprintf(str, "\ndiag/antidiag/vert %d", i);
bitboard_print_multi(str, 5,
sq_bbfile[i] | sq_bbrank[i] | sq_bbdiag[i] | sq_bbanti[i],
sq_bbfile[i], sq_bbrank[i],
sq_bbdiag[i], sq_bbanti[i]);
}
for (square_t sq = 0; sq < 64; ++sq) {
sprintf(str, "%2d %#lx %#lx knight", sq, sq_bb[sq], knight_attacks[sq]);
bitboard_print(str, knight_attacks[sq]);
sprintf(str, "%2d %#lx %#lx knight", sq, sq_bb[sq], king_attacks[sq]);
bitboard_print(str, king_attacks[sq]);
sprintf(str, "\n%#x:\n %-22s%-22s%-22s%-22s%-22s%-22s%-22s", i,
"sliding", "diagonal", "antidiagonal", "file", "rank", "knight",
"king"
);
bitboard_print_multi(str, 7,
bb_file[i] | bb_rank[i] |
bb_diagonal[i] | bb_antidiagonal[i],
bb_diagonal[i], bb_antidiagonal[i],
bb_file[i], bb_rank[i],
bb_knight[i], bb_king[i]);
}
/*
* for (square_t sq = 0; sq < 64; ++sq) {
* sprintf(str, "%2d %#lx %#lx knight", sq, bb_sq[sq], bb_knight[sq]);
* bitboard_print(str, bb_knight[sq]);
* sprintf(str, "%2d %#lx %#lx knight", sq, bb_sq[sq], bb_king[sq]);
* bitboard_print(str, bb_king[sq]);
* }
*/
return 0;
}

View File

@@ -12,7 +12,7 @@ int main(int ac, char**av)
char revfen[128];
int comp;
debug_init(5, stderr, true);
//debug_init(5, stderr, true);
//pos_pool_init();
pos = pos_new();
if (ac == 1) {