diff --git a/Makefile b/Makefile index f504a87..cc829a3 100644 --- a/Makefile +++ b/Makefile @@ -420,7 +420,7 @@ BB_OBJS := $(FEN_OBJS) MOVEGEN_OBJS := $(BB_OBJS) move-gen.o ATTACK_OBJS := $(MOVEGEN_OBJS) MOVEDO_OBJS := $(ATTACK_OBJS) move-do.o -PERFT_OBJS := $(MOVEDO_OBJS) search.o +PERFT_OBJS := $(MOVEDO_OBJS) perft.o TT_OBJS := $(MOVEDO_OBJS) TEST := $(addprefix $(BINDIR)/,$(TEST)) diff --git a/src/perft.c b/src/perft.c new file mode 100644 index 0000000..a05e285 --- /dev/null +++ b/src/perft.c @@ -0,0 +1,131 @@ +/* perft.c - perft functions. + * + * Copyright (C) 2023-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 . + * + * SPDX-License-Identifier: GPL-3.0-or-later + * + */ + +#include + +#include + +#include "perft.h" +#include "move-gen.h" +#include "move-do.h" + +/** + * perft() - Perform perft on position + * @pos: &position to search + * @depth: Wanted depth. + * @ply: current perft depth level (root = 1) + * @divide: output total for 1st level moves. + * + * Run perft on a position. This function displays the available moves at @depth + * level for each possible first move, and the total of moves. + * + * This version uses the algorithm: + * if last depth + * return 1; + * gen legal moves + * loop for legal move + * do-move + * perft (depth -1) + * undo-move + * + * @return: total moves found at @depth level. + */ +u64 perft(pos_t *pos, int depth, int ply, bool divide) +{ + u64 subnodes = 0, nodes = 0; + movelist_t movelist; + move_t *move, *last; + state_t state; + + pos_set_checkers_pinners_blockers(pos); + + pos_legal(pos, pos_gen_pseudo(pos, &movelist)); + last = movelist.move + movelist.nmoves; + for (move = movelist.move; move < last; ++move) { + if (depth == 1) { + subnodes = 1; + } else { + move_do(pos, *move, &state); + if (depth == 2) { + movelist_t movelist2; + pos_set_checkers_pinners_blockers(pos); + subnodes = pos_legal(pos, pos_gen_pseudo(pos, &movelist2))->nmoves; + } else if (ply >= 3) { + hentry_t *entry = tt_probe_perft(pos->key, depth); + if (entry != TT_MISS) { + subnodes = HASH_PERFT_VAL(entry->data); + } else { + subnodes = perft(pos, depth - 1, ply + 1, divide); + tt_store_perft(pos->key, depth, subnodes); + } + } else { + subnodes = perft(pos, depth - 1, ply + 1, divide); + } + move_undo(pos, *move, &state); + } + nodes += subnodes; + if (ply == 1 && divide) { + char movestr[8]; + printf("%s: %lu\n", move_to_str(movestr, *move, 0), subnodes); + } + } + + return nodes; +} + +/** + * perft_alt() - Perform perft on position, experimental version. + * @pos: &position to search + * @depth: Wanted depth. + * @ply: current perft depth level (root = 1) + * @divide: output total for 1st level moves. + * + * Run perft on a position. This function displays the available moves at @depth + * level for each possible first move, and the total of moves. + * + * @return: total moves found at @depth level. + */ +u64 perft_alt(pos_t *pos, int depth, int ply, bool divide) +{ + u64 subnodes = 0, nodes = 0; + movelist_t movelist; + move_t *move, *last; + state_t state; + + pos_set_checkers_pinners_blockers(pos); + + pos_legal(pos, pos_gen_pseudo(pos, &movelist)); + last = movelist.move + movelist.nmoves; + for (move = movelist.move; move < last; ++move) { + if (depth == 1) { + subnodes = 1; + } else { + move_do_alt(pos, *move, &state); + if (depth == 2) { + movelist_t movelist2; + pos_set_checkers_pinners_blockers(pos); + subnodes = pos_legal(pos, pos_gen_pseudo(pos, &movelist2))->nmoves; + } else { + subnodes = perft_alt(pos, depth - 1, ply + 1, divide); + } + move_undo_alt(pos, *move, &state); + } + nodes += subnodes; + if (ply == 1 && divide) { + char movestr[8]; + printf("%s: %lu\n", move_to_str(movestr, *move, 0), subnodes); + } + } + + return nodes; +} diff --git a/src/perft.h b/src/perft.h new file mode 100644 index 0000000..810475c --- /dev/null +++ b/src/perft.h @@ -0,0 +1,22 @@ +/* perft.h.h - perft. + * + * Copyright (C) 2021-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 . + * + * SPDX-License-Identifier: GPL-3.0-or-later + * + */ + +#ifndef PERFT_H +#define PERFT_H + +#include "position.h" + +u64 perft(pos_t *pos, int depth, int ply, bool output); +u64 perft_alt(pos_t *pos, int depth, int ply, bool output); + +#endif /* PERFT_H */ diff --git a/src/search.c b/src/search.c index 59c1a63..816c846 100644 --- a/src/search.c +++ b/src/search.c @@ -1,4 +1,4 @@ -/* search.c - perft + search. +/* search.c - search for perfect move. * * Copyright (C) 2023-2024 Bruno Raoult ("br") * Licensed under the GNU General Public License v3.0 or later. @@ -21,117 +21,6 @@ #include "search.h" #include "attack.h" -/** - * perft() - Perform perft on position - * @pos: &position to search - * @depth: Wanted depth. - * @ply: current perft depth level (root = 1) - * @divide: output total for 1st level moves. - * - * Run perft on a position. This function displays the available moves at @depth - * level for each possible first move, and the total of moves. - * - * This version uses the algorithm: - * if last depth - * return 1; - * gen legal moves - * loop for legal move - * do-move - * perft (depth -1) - * undo-move - * - * @return: total moves found at @depth level. - */ -u64 perft(pos_t *pos, int depth, int ply, bool divide) -{ - u64 subnodes = 0, nodes = 0; - movelist_t movelist; - move_t *move, *last; - state_t state; - - pos_set_checkers_pinners_blockers(pos); - - pos_legal(pos, pos_gen_pseudo(pos, &movelist)); - last = movelist.move + movelist.nmoves; - for (move = movelist.move; move < last; ++move) { - if (depth == 1) { - subnodes = 1; - } else { - move_do(pos, *move, &state); - if (depth == 2) { - movelist_t movelist2; - pos_set_checkers_pinners_blockers(pos); - subnodes = pos_legal(pos, pos_gen_pseudo(pos, &movelist2))->nmoves; - } else if (ply >= 3) { - hentry_t *entry = tt_probe_perft(pos->key, depth); - if (entry != TT_MISS) { - subnodes = HASH_PERFT_VAL(entry->data); - } else { - subnodes = perft(pos, depth - 1, ply + 1, divide); - tt_store_perft(pos->key, depth, subnodes); - } - } else { - subnodes = perft(pos, depth - 1, ply + 1, divide); - } - move_undo(pos, *move, &state); - } - nodes += subnodes; - if (ply == 1 && divide) { - char movestr[8]; - printf("%s: %lu\n", move_to_str(movestr, *move, 0), subnodes); - } - } - - return nodes; -} - -/** - * perft_alt() - Perform perft on position, experimental version. - * @pos: &position to search - * @depth: Wanted depth. - * @ply: current perft depth level (root = 1) - * @divide: output total for 1st level moves. - * - * Run perft on a position. This function displays the available moves at @depth - * level for each possible first move, and the total of moves. - * - * @return: total moves found at @depth level. - */ -u64 perft_alt(pos_t *pos, int depth, int ply, bool divide) -{ - u64 subnodes = 0, nodes = 0; - movelist_t movelist; - move_t *move, *last; - state_t state; - - pos_set_checkers_pinners_blockers(pos); - - pos_legal(pos, pos_gen_pseudo(pos, &movelist)); - last = movelist.move + movelist.nmoves; - for (move = movelist.move; move < last; ++move) { - if (depth == 1) { - subnodes = 1; - } else { - move_do_alt(pos, *move, &state); - if (depth == 2) { - movelist_t movelist2; - pos_set_checkers_pinners_blockers(pos); - subnodes = pos_legal(pos, pos_gen_pseudo(pos, &movelist2))->nmoves; - } else { - subnodes = perft_alt(pos, depth - 1, ply + 1, divide); - } - move_undo_alt(pos, *move, &state); - } - nodes += subnodes; - if (ply == 1 && divide) { - char movestr[8]; - printf("%s: %lu\n", move_to_str(movestr, *move, 0), subnodes); - } - } - - return nodes; -} - /** * negamax() - search position negamax. * @pos: &position to search diff --git a/src/search.h b/src/search.h index e6019e4..fa5766c 100644 --- a/src/search.h +++ b/src/search.h @@ -19,7 +19,4 @@ //eval_t negamax(pos_t *pos, int depth, int color); //eval_t pvs(pos_t *pos, int depth, int alpha, int beta, int color); -u64 perft(pos_t *pos, int depth, int ply, bool output); -u64 perft_alt(pos_t *pos, int depth, int ply, bool output); - #endif /* SEARCH_H */ diff --git a/src/uci.c b/src/uci.c index 68a0d6d..7faed06 100644 --- a/src/uci.c +++ b/src/uci.c @@ -26,6 +26,7 @@ #include "move-gen.h" #include "move-do.h" #include "search.h" +#include "perft.h" #include "eval-defs.h" #include "uci.h" diff --git a/test/perft-test.c b/test/perft-test.c index a2034a1..d8cab81 100644 --- a/test/perft-test.c +++ b/test/perft-test.c @@ -25,7 +25,7 @@ #include "move.h" #include "move-do.h" #include "move-gen.h" -#include "search.h" +#include "perft.h" #include "common-test.h"