diff --git a/src/position.c b/src/position.c index 969e1ae..72f13c9 100644 --- a/src/position.c +++ b/src/position.c @@ -24,6 +24,7 @@ #include "chessdefs.h" #include "position.h" #include "bitboard.h" +#include "hyperbola-quintessence.h" #include "fen.h" #include "piece.h" #include "util.h" @@ -194,17 +195,83 @@ bitboard_t pos_checkers(const pos_t *pos, const color_t color) * It should be faster than @pos_checkers + @pos_set_pinners_blockers, as * some calculation will be done once. */ -/* - * void pos_set_checkers_pinners_blockers(pos_t *pos) - * { - * bitboard_t b_bb = pos->bb[WHITE][BISHOP] | pos->bb[BLACK][BISHOP]; - * bitboard_t r_bb = pos->bb[WHITE][ROOK] | pos->bb[BLACK][ROOK]; - * bitboard_t q_bb = pos->bb[WHITE][QUEEN] | pos->bb[BLACK][QUEEN]; - * - * /\* find out first piece on every diagonal *\/ - * - * } - */ +void pos_set_checkers_pinners_blockers(pos_t *pos) +{ + int us = pos->turn, them = OPPONENT(us); + bitboard_t occ = pos_occ(pos); + bitboard_t attackers; + bitboard_t checkers = 0, blockers = 0, pinners = 0; + bitboard_t targets, tmpcheckers, tmpblockers, tmppinners, tmpbb; + square_t king = pos->king[us]; + bitboard_t king_bb = mask(king); + int pinner; + + /* bishop type - we attack with a bishop from king position */ + attackers = pos->bb[them][BISHOP] | pos->bb[them][QUEEN]; + + /* targets is all "target" pieces if K was a bishop */ + targets = hyperbola_bishop_moves(occ, king) & occ; + + /* checkers = only opponent B/Q */ + tmpcheckers = targets & attackers; + checkers |= tmpcheckers; + + /* maybe blockers = not checkers */ + tmpblockers = targets & ~tmpcheckers; + + /* we find second targets, by removing only first ones (excl. checkers) */ + targets = hyperbola_bishop_moves(occ ^ tmpblockers, king) ^ tmpcheckers; + + /* pinners = only B/Q */ + tmppinners = targets & attackers; + pinners |= tmppinners; + //tmpblockers = 0; + + /* blockers = we find occupied squares between pinner and king */ + bit_for_each64(pinner, tmpbb, tmppinners) + blockers |= bb_between[pinner][king] & tmpblockers; + //blockers |= tmpblockers; + + /* same for rook type */ + attackers = pos->bb[them][ROOK] | pos->bb[them][QUEEN]; + + /* targets is all "target" pieces if K was a bishop */ + targets = hyperbola_rook_moves(occ, king) & occ; + + /* checkers = only opponent B/Q */ + tmpcheckers = targets & attackers; + checkers |= tmpcheckers; + + /* maybe blockers = not checkers */ + tmpblockers = targets & ~tmpcheckers; + + /* we find second targets, by removing only first ones (excl. checkers) */ + targets = hyperbola_rook_moves(occ ^ tmpblockers, king) ^ tmpcheckers; + + /* pinners = only B/Q */ + tmppinners = targets & attackers; + pinners |= tmppinners; + //tmpblockers = 0; + + /* blockers = we find occupied squares between pinner and king */ + bit_for_each64(pinner, tmpbb, tmppinners) + blockers |= bb_between[pinner][king] & tmpblockers; + //blockers |= tmpblockers; + + /* pawns */ + attackers = pos->bb[them][PAWN]; + targets = pawn_shift_upleft(king_bb, us) | pawn_shift_upright(king_bb, us); + checkers |= targets & attackers; + + /* knight */ + attackers = pos->bb[them][KNIGHT]; + targets = bb_knight_moves(attackers, king); + checkers |= targets; + + pos->checkers = checkers; + pos->pinners = pinners; + pos->blockers = blockers; +} /** * pos_set_pinners_blockers() - set position pinners and blockers. diff --git a/src/position.h b/src/position.h index 0e76a06..e341410 100644 --- a/src/position.h +++ b/src/position.h @@ -159,7 +159,7 @@ void pos_del(pos_t *pos); pos_t *pos_clear(pos_t *pos); bool pos_cmp(const pos_t *pos1, const pos_t *pos2); -//bitboard_t set_king_pinners_blockers(pos_t *pos); +void pos_set_checkers_pinners_blockers(pos_t *pos); void pos_set_pinners_blockers(pos_t *pos); bitboard_t pos_checkers(const pos_t *pos, const color_t color); bitboard_t pos_king_pinners(const pos_t *pos, const color_t color); diff --git a/src/search.c b/src/search.c index 83a61b4..e505d36 100644 --- a/src/search.c +++ b/src/search.c @@ -127,6 +127,37 @@ u64 perft2(pos_t *pos, int depth, int ply) return nodes; } +u64 perft_new_pinners(pos_t *pos, int depth, int ply) +{ + int subnodes, movetmp = 0; + u64 nodes = 0; + movelist_t pseudo = { .nmoves = 0 }; + move_t move; + state_t state; + + if (depth == 0) + return 1; + pos_set_checkers_pinners_blockers(pos); + state = pos->state; + + pos_gen_pseudomoves(pos, &pseudo); + while ((move = pos_next_legal(pos, &pseudo, &movetmp)) != MOVE_NONE) { + move_do(pos, move); + subnodes = perft(pos, depth - 1, ply + 1); + if (ply == 1) { + char movestr[8]; + printf("%s: %d\n", move_str(movestr, move, 0), subnodes); + } + nodes += subnodes; + move_undo(pos, move); + pos->state = state; + } + + if (ply == 1) + printf("Total: %lu\n", nodes); + return nodes; +} + /** * negamax() - search position negamax. * @pos: &position to search diff --git a/src/search.h b/src/search.h index 9fbf9e7..64b358e 100644 --- a/src/search.h +++ b/src/search.h @@ -21,5 +21,6 @@ u64 perft(pos_t *pos, int depth, int ply); u64 perft2(pos_t *pos, int depth, int ply); +u64 perft_new_pinners(pos_t *pos, int depth, int ply); #endif /* SEARCH_H */ diff --git a/test/attack-test.c b/test/attack-test.c index 10b8e29..6ef71fc 100644 --- a/test/attack-test.c +++ b/test/attack-test.c @@ -28,6 +28,7 @@ int main(int __unused ac, __unused char**av) int i = 0; char *fen; pos_t *pos;//, *fishpos = pos_new(); + bitboard_t checkers, pinners, blockers; setlinebuf(stdout); /* line-buffered stdout */ @@ -41,8 +42,22 @@ int main(int __unused ac, __unused char**av) printf("wrong fen %d: [%s]\n", i, fen); continue; } + pos->checkers = pos_checkers(pos, pos->turn); + pos_set_pinners_blockers(pos); + pos_print(pos); + checkers = pos->checkers; + pinners = pos->pinners; + blockers = pos->blockers; + + pos_set_checkers_pinners_blockers(pos); + + printf("******* %s\n", cur_comment()); + bb_print_multi("checkers", 2, checkers, pos->checkers); + bb_print_multi("pinners", 2, pinners, pos->pinners); + bb_print_multi("blockers", 2, blockers, pos->blockers); + pos_del(pos); i++; } diff --git a/test/perft-test.c b/test/perft-test.c index 7ab833a..fc0c92b 100644 --- a/test/perft-test.c +++ b/test/perft-test.c @@ -233,7 +233,9 @@ int main(int __unused ac, __unused char**av) //move_t move; FILE *outfd; int depth = 6; - s64 ms1 = 0, ms1_total = 0, ms2 = 0, ms2_total = 0; + s64 ms1 = 0, ms1_total = 0; + s64 ms2 = 0, ms2_total = 0; + s64 ms3 = 0, ms3_total = 0; int run = 3; if (ac > 1) @@ -288,15 +290,33 @@ int main(int __unused ac, __unused char**av) ms2_total += ms2; if (sf_count == my_count) { - printf("pt2 OK : line=%03d perft=%lu %'ldms lps=%'lu \"%s\"\n\n", + printf("pt2 OK : line=%03d perft=%lu %'ldms lps=%'lu \"%s\"\n", test_line, my_count, ms2, ms2? my_count*1000l/ms2: 0, fen); } else { - printf("pt2 ERR: line=%03d sf=%lu me=%lu \"%s\"\n\n", + printf("pt2 ERR: line=%03d sf=%lu me=%lu \"%s\"\n", test_line, sf_count, my_count, fen); } } + + if (run & 4) { + clock_start(&clock); + my_count = perft_new_pinners(pos, depth, 1); + ms3 = clock_elapsed_ms(&clock); + ms3_total += ms3; + + if (sf_count == my_count) { + printf("pt3 OK : line=%03d perft=%lu %'ldms lps=%'lu \"%s\"\n", + test_line, my_count, ms3, + ms3? my_count*1000l/ms3: 0, + fen); + } else { + printf("pt3 ERR: line=%03d sf=%lu me=%lu \"%s\"\n", + test_line, sf_count, my_count, fen); + } + } + printf("\n"); pos_del(savepos); pos_del(pos); i++; @@ -305,5 +325,7 @@ int main(int __unused ac, __unused char**av) printf("total perft %'ldms\n", ms1_total); if (run & 2) printf("total perft2 %'ldms\n", ms2_total); + if (run & 4) + printf("total perft3 %'ldms\n", ms3_total); return 0; }