add movegen draft, add king square in pos_t, BRQKN move gen (untested)

This commit is contained in:
2024-02-20 21:00:45 +01:00
parent 403e625cbe
commit 568b39e366
11 changed files with 231 additions and 53 deletions

View File

@@ -51,6 +51,8 @@ LIBS := $(strip -l$(LIB) -lreadline)
CPPFLAGS := -I$(BRINCDIR) -I$(INCDIR)
CPPFLAGS += -DBUG_ON
CPPFLAGS += -DWARN_ON
CPPFLAGS += -NDEBUG #
#CPPFLAGS += -DDEBUG # global
CPPFLAGS += -DDEBUG_DEBUG # enable log() functions
#CPPFLAGS += -DDEBUG_DEBUG_C # enable verbose log() settings
@@ -66,7 +68,7 @@ CPPFLAGS := $(strip $(CPPFLAGS))
##################################### compiler flags
CFLAGS := -std=gnu11
#CFLAGS += -O2
CFLAGS += -O3
CFLAGS += -g
CFLAGS += -Wall
CFLAGS += -Wextra

View File

@@ -20,6 +20,7 @@
#include "piece.h"
#include "board.h"
#include "bitboard.h"
#include "position.h"
/* vectors are clockwise from N */
static int knight_vector[] = {
@@ -110,6 +111,15 @@ void bitboard_init(void)
}
}
bitboard_t bb_knight_moves(bitboard_t notmine, square_t sq)
{
return bb_knight[sq] & notmine;
}
bitboard_t bb_king_moves(bitboard_t notmine, square_t sq)
{
return bb_king[sq] & notmine;
}
/**
* bitboard_print() - print simple bitboard representation
* @title: a string or NULL

View File

@@ -95,6 +95,10 @@ static __always_inline bitboard_t shift_nw(const bitboard_t bb)
}
extern void bitboard_init(void);
extern bitboard_t bb_knight_moves(bitboard_t occ, square_t sq);
extern bitboard_t bb_king_moves(bitboard_t occ, square_t sq);
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);

View File

@@ -68,12 +68,12 @@ typedef enum {
*/
#define FLIP_V(sq) ((sq) ^ 56)
#define FLIP_H(sq) ((sq) ^ 7)
#define FLIP_HV(sq) (FLIP_V(FLIP_H(sq)))
#define FLIP_HV(sq) ((sq) ^ 63) /* FLIP_V ^ FLIP_H */
/* TODO: revert to macros after bitboard migration */
static __always_inline square_t sq_make(file_t file, rank_t rank)
{
return (rank << 3) + file;
return (rank << 6) + file;
}
static __always_inline file_t sq_file(square_t square)
{
@@ -81,7 +81,7 @@ static __always_inline file_t sq_file(square_t square)
}
static __always_inline rank_t sq_rank(square_t square)
{
return square >> 3;
return square >> 6;
}
#define sq_ok(sq) ((sq) >= A1 && (sq) <= H8)

View File

@@ -208,7 +208,7 @@ char *pos2fen(const pos_t *pos, char *fen)
for (rank_t r = RANK_8; r >= RANK_1; --r) {
for (file_t f = FILE_A; f <= FILE_H;) {
square_t sq = sq_make(f, r);
piece_t piece =pos->board[sq];
piece_t piece = pos->board[sq];
if (pos->board[sq] == EMPTY) {
int len = 0;
for (; f <= FILE_H && pos->board[sq_make(f, r)] == EMPTY; f++)

View File

@@ -30,15 +30,29 @@ uchar bb_rank_attacks[64 * 8];
* 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
*
* Rank attacks table:
* bb_rank_hyperbola[512 = 9 bits], indexed by oooooofff where:
* - O = oooooo: occupation of inner 6 bits on rank
* - F = fff: file of sliding piece
* The index is built as (oooooo << 3 + fff), = ((O << 3) + F), where:
* - O = all combinations of 6 bits (loop from 0 to 64)
* - F = all files (loop from 0 to 7)
* To retrieve the index, given an 8 bits mask M=XooooooX, and a file F=fff,
* we get O from M with:
* 1) remove bits 'X' (O = M & 01111110)
* 2) shift left result 2 more bits, as bit 0 is unused and already cleared:
* (O <<= 2)
*
* TODO ? create masks excluding slider (eg. bb_diagonal ^ bb_sq[square]),
* to save one operation in hyperbola_moves().
* TODO ? replace rank attack with this idea, mapping rank to diagonal ?
* See http://timcooijmans.blogspot.com/2014/04/
*
*/
void hyperbola_init()
{
/* generate rank attacks
/* generate rank attacks, not handled by HQ
*/
for (int occ = 0; occ < 64; ++occ) {
for (int file = 0; file < 8; ++file) {
@@ -48,7 +62,7 @@ void hyperbola_init()
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 */
if ((occ << 1) & b) /* piece on b, we stop */
break;
}
/* set f right attacks */
@@ -63,6 +77,24 @@ void hyperbola_init()
}
}
/**
* hyperbola_rank_moves() - generate 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
*
* @Return: The moves mask for piece
*/
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) & 0x7e; /* 01111110 clear bits 0 & 7 */
return ((bitboard_t)bb_rank_attacks[o * 4 + file]) << rank;
}
/**
* hyperbola_moves() - generate hyperbola moves mask for a given sliding piece
* @pieces: occupation bitboard
@@ -80,19 +112,9 @@ static bitboard_t hyperbola_moves(const bitboard_t pieces, const square_t sq,
bitboard_t r = bswap64(o);
square_t r_sq = FLIP_V(sq);
return ( (o - mask(sq) )
^ bswap64(r - mask(r_sq)))
return ( (o - 2 * mask(sq) )
^ bswap64(r - 2 * 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)

View File

@@ -14,6 +14,12 @@
#ifndef _HYPERBOLA_QUINTESSENCE_H
#define _HYPERBOLA_QUINTESSENCE_H
#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);
#endif /* _HYPERBOLA_QUINTESSENCE_H */

View File

@@ -16,19 +16,50 @@
#include "chessdefs.h"
#include "position.h"
#include "pool.h"
//#include "pool.h"
#include "piece.h"
/* move flags
/* 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
*
* 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 ?
*/
typedef unsigned char move_flags_t;
#define M_NORMAL 0x00
#define M_CHECK 0x01 /* unsure if we know */
#define M_CAPTURE 0x02
#define M_EN_PASSANT 0x04
#define M_PROMOTION 0x08
#define M_CASTLE_K 0x10
#define M_CASTLE_Q 0x20
#define move_t u32
#define M_
/* 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_ENPASSANT mask(_M_FLAGS_BEG + 2)
#define M_PROMOTION 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)
#define MOVES_MAX 256
static inline move_t move_make(square_t from, square_t to)
{
return (to << 3) | from;
}
static inline move_t move_from(move_t move)
{
return move & 56;
}
/* moves_print flags
*/
@@ -40,30 +71,23 @@ typedef unsigned char move_flags_t;
#define M_PR_SEPARATE 0x40 /* separate captures */
#define M_PR_LONG 0x80
typedef struct move_s {
piece_t piece;
square_t from, to;
piece_t capture; /* captured piece */
piece_t promotion; /* promoted piece */
move_flags_t flags;
eval_t negamax;
eval_t eval;
eval_t eval_simple;
pos_t *pos;
struct list_head list; /* next move */
} move_t;
typedef struct {
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();
int move_print(int movenum, move_t *move, move_flags_t flags);
void moves_print(pos_t *move, move_flags_t flags);
//pool_t *moves_pool_init();
//void moves_pool_stats();
//int move_print(int movenum, move_t *move, move_flags_t flags);
//void moves_print(pos_t *move, move_flags_t flags);
void move_del(struct list_head *ptr);
int moves_del(pos_t *pos);
//void move_del(struct list_head *ptr);
//int moves_del(pos_t *pos);
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_pawn(pos_t *pos, piece_list_t *piece, bool doit);
//int pseudo_moves_gen(pos_t *pos, piece_list_t *piece, bool doit, bool do_king);
//int pseudo_moves_pawn(pos_t *pos, piece_list_t *piece, bool doit);
int moves_gen(pos_t *pos, bool color, bool doit, bool do_king);
int moves_gen_king_moves(pos_t *pos, bool color, bool doit);

74
src/movegen.c Normal file
View File

@@ -0,0 +1,74 @@
/* movegen.c - move generation
*
* 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 "bitops.h"
#include "bitboard.h"
#include "hyperbola-quintessence.h"
#include "piece.h"
#include "move.h"
//void add_pseudo_move(move_t *pmove, square_t from, square_t to)
//{
// pmov
//}
/**
* gen_all_pseudomoves() - generate all pseudo moves
*
*/
int gen_all_pseudomoves(pos_t *pos)
{
int me = pos->turn, other = OPPONENT(me);
bitboard_t my_pieces = pos->bb[me][ALL_PIECES], notmine = ~my_pieces,
other_pieces = pos->bb[other][ALL_PIECES],
occ = my_pieces | other_pieces, movebits;
int tmp1, tmp2, from, to;
movelist_t moves = pos->moves;
/* sliding pieces */
bit_for_each64(from, tmp1, pos->bb[me][BISHOP]) {
movebits = hyperbola_bishop_moves(occ, from) & notmine;
bit_for_each64(to, tmp2, movebits) {
moves.move[moves.nmoves++] = move_make(from, to);
}
}
bit_for_each64(from, tmp1, pos->bb[me][ROOK]) {
movebits = hyperbola_rook_moves(occ, from) & notmine;
bit_for_each64(to, tmp2, movebits) {
moves.move[moves.nmoves++] = move_make(from, to);
}
}
bit_for_each64(from, tmp1, pos->bb[me][QUEEN]) {
movebits = hyperbola_queen_moves(occ, from) & notmine;
bit_for_each64(to, tmp2, movebits) {
moves.move[moves.nmoves++] = move_make(from, to);
}
}
/* knight */
bit_for_each64(from, tmp1, pos->bb[me][KNIGHT]) {
movebits = bb_knight_moves(occ, from) & notmine;
bit_for_each64(to, tmp2, movebits) {
moves.move[moves.nmoves++] = move_make(from, to);
}
}
/* king */
movebits = bb_king_moves(occ, pos->king[me]) & notmine;
bit_for_each64(to, tmp2, movebits) {
moves.move[moves.nmoves++] = move_make(from, to);
}
/* TODO */
}

30
src/movegen.h Normal file
View File

@@ -0,0 +1,30 @@
/* movegen.h - move generation
*
* 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 MOVEGEN_H
#define MOVEGEN_H
#include "bitops.h"
#include "bitboard.h"
#include "hyperbola-quintessence.h"
#include "piece.h"
#include "move.h"
/**
* gen_all_pseudomoves() - generate all pseudo moves
*
*/
int gen_all_pseudomoves(pos_t *pos);
#endif /* MOVEGEN_H */

View File

@@ -22,6 +22,7 @@
#include "bitboard.h"
#include "chessdefs.h"
#include "piece.h"
#include "move.h"
typedef struct {
u64 node_count; /* evaluated nodes */
@@ -40,11 +41,14 @@ typedef struct {
//bool moves_counted;
bitboard_t bb[2][PIECE_TYPE_MAX]; /* bb[0][PAWN], bb[1][ALL_PIECES] */
square_t king[2]; /* dup with bb, faster retrieval */
bitboard_t controlled[2];
//u16 mobility[2];
//struct list_head pieces[2]; /* pieces list, King is first */
//struct list_head moves[2];
piece_t board[BOARDSIZE];
movelist_t moves;
int nmoves;
} pos_t;
/**
@@ -62,6 +66,8 @@ static inline void pos_set_sq(pos_t *pos, square_t square, piece_t piece)
pos->board[square] = piece;
pos->bb[color][type] |= 1 << square;
pos->bb[color][ALL_PIECES] |= 1 << square;
if (type == KING)
pos->king[color] = square;
}
/**