But I practically followed DC's implementation to the letter:
DC:
Code: Select all
move_t *gen_piece_moves(const Board *B, uint64_t targets, move_t *mlist, bool king_moves)
/* Generates piece moves, when the board is not in check. Uses targets to filter the tss, eg.
* targets = ~friends (all moves), empty (quiet moves only), enemies (captures only). */
{
assert(!king_moves || !board_is_check(B)); // do not use when in check (use gen_evasion)
const int us = B->turn;
assert(!(targets & B->all[us]));
uint64_t fss;
// Knight Moves
fss = B->b[us][Knight];
while (fss) {
int fsq = next_bit(&fss);
uint64_t tss = NAttacks[fsq] & targets;
while (tss) {
int tsq = next_bit(&tss);
mlist = serialize_moves(B, fsq, tsq, mlist);
}
}
// Rook Queen moves
fss = get_RQ(B, us);
while (fss) {
int fsq = next_bit(&fss);
uint64_t tss = targets & rook_attack(fsq, B->st->occ);
while (tss) {
int tsq = next_bit(&tss);
mlist = serialize_moves(B, fsq, tsq, mlist);
}
}
// Bishop Queen moves
fss = get_BQ(B, us);
while (fss) {
int fsq = next_bit(&fss);
uint64_t tss = targets & bishop_attack(fsq, B->st->occ);
while (tss) {
int tsq = next_bit(&tss);
mlist = serialize_moves(B, fsq, tsq, mlist);
}
}
// King moves (king_moves == false is only used for check escapes)
if (king_moves) {
int fsq = B->king_pos[us];
// here we also filter direct self checks, which shouldn't be sent to serial_moves
uint64_t tss = KAttacks[fsq] & targets & ~B->st->attacks;
while (tss) {
int tsq = next_bit(&tss);
mlist = serialize_moves(B, fsq, tsq, mlist);
}
}
return mlist;
}
Code: Select all
// add_quiet_moves()
static void add_quiet_moves(list_t * list, const board_t * board) {
int me;
const sq_t * ptr;
int from, to;
uint64 piece_bb;
uint64 attacks;
uint64 me_bb;
ASSERT(list!=NULL);
ASSERT(board!=NULL);
me = board->turn;
me_bb = COLOUR_IS_WHITE(me) ? WHITE_BB : BLACK_BB;
// piece moves
// knight
piece_bb = KNIGHT_BB & me_bb;
while (piece_bb) {
from = next_bit(&piece_bb);
attacks = knight_attacks(1ULL << from) & EMPTY_BB;
while (attacks) {
to = next_bit(&attacks);
LIST_ADD(list,MOVE_MAKE(from,to));
}
}
// bishop and queen
piece_bb = (BISHOP_BB | QUEEN_BB) & me_bb;
while (piece_bb) {
from = next_bit(&piece_bb);
attacks = bishop_attacks(from,OCC_BB) & EMPTY_BB;
while (attacks) {
to = next_bit(&attacks);
LIST_ADD(list,MOVE_MAKE(from,to));
}
}
// rook and queen
piece_bb = (ROOK_BB | QUEEN_BB) & me_bb;
while (piece_bb) {
from = next_bit(&piece_bb);
attacks = rook_attacks(from,OCC_BB) & EMPTY_BB;
while (attacks) {
to = next_bit(&attacks);
LIST_ADD(list,MOVE_MAKE(from,to));
}
}
// king
piece_bb = KING_BB & me_bb;
while (piece_bb) {
from = next_bit(&piece_bb);
attacks = king_attacks(1ULL << from) & EMPTY_BB;
while (attacks) {
to = next_bit(&attacks);
LIST_ADD(list,MOVE_MAKE(from,to));
}
}
/**** THIS ISN'T MINE - THIS IS FABIEN'S CODE ****/
// pawn moves
if (COLOUR_IS_WHITE(me)) {
for (ptr = &board->pawn[me][0]; (from=*ptr) != SquareNone; ptr++) {
// non promotes
if (SQUARE_RANK(from) != Rank7) {
to = from + 16;
if (board->square[to] == Empty) {
ASSERT(!SQUARE_IS_PROMOTE(to));
LIST_ADD(list,MOVE_MAKE(from,to));
if (SQUARE_RANK(from) == Rank2) {
to = from + 32;
if (board->square[to] == Empty) {
ASSERT(!SQUARE_IS_PROMOTE(to));
LIST_ADD(list,MOVE_MAKE(from,to));
}
}
}
}
}
} else { // black
for (ptr = &board->pawn[me][0]; (from=*ptr) != SquareNone; ptr++) {
// non promotes
if (SQUARE_RANK(from) != Rank2) {
to = from - 16;
if (board->square[to] == Empty) {
ASSERT(!SQUARE_IS_PROMOTE(to));
LIST_ADD(list,MOVE_MAKE(from,to));
if (SQUARE_RANK(from) == Rank7) {
to = from - 32;
if (board->square[to] == Empty) {
ASSERT(!SQUARE_IS_PROMOTE(to));
LIST_ADD(list,MOVE_MAKE(from,to));
}
}
}
}
}
}
}
I ran the test again between Fruit 2.1 and Fruit 2.1 Bitboard. 10- 0= 0+
Matthew:out