add movegen draft, add king square in pos_t, BRQKN move gen (untested)
This commit is contained in:
4
Makefile
4
Makefile
@@ -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
|
||||
|
@@ -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
|
||||
|
@@ -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);
|
||||
|
@@ -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)
|
||||
|
@@ -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++)
|
||||
|
@@ -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)
|
||||
|
@@ -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 */
|
||||
|
84
src/move.h
84
src/move.h
@@ -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
74
src/movegen.c
Normal 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
30
src/movegen.h
Normal 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 */
|
@@ -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;
|
||||
}
|
||||
|
||||
/**
|
||||
|
Reference in New Issue
Block a user