From c5a1936e3b4451101da34615d8355c4ec244ab0b Mon Sep 17 00:00:00 2001 From: Bruno Raoult Date: Thu, 27 Jun 2024 10:09:30 +0200 Subject: [PATCH] UCI moves && games states list --- Makefile | 8 +++- src/brchess.c | 73 +++++++++++++++++++++------- src/chessdefs.h | 5 +- src/hist.c | 123 ++++++++++++++++++++++++++++++++++++++++++++++++ src/hist.h | 59 +++++++++++++++++++++++ src/move-do.c | 1 - src/move.c | 31 ++++++++++++ src/move.h | 12 +++-- 8 files changed, 287 insertions(+), 25 deletions(-) create mode 100644 src/hist.c create mode 100644 src/hist.h diff --git a/Makefile b/Makefile index 362d3b3..971b987 100644 --- a/Makefile +++ b/Makefile @@ -148,6 +148,9 @@ else ifeq ($(BUILD),perf) CFLAGS += -g # symbols (gdb, perf, etc.) CFLAGS += -ginline-points # inlined funcs debug info CFLAGS += -funroll-loops +else ifeq ($(BUILD),debug) + CFLAGS += -O0 + CFLAGS += -g # symbols (gdb, perf, etc.) # for gprof #CFLAGS += -pg # Next one may be useful for valgrind (when invalid instructions) @@ -207,7 +210,7 @@ $(sort all $(MAKECMDGOALS)): else ##################################### General targets -.PHONY: all release dev perf compile clean cleanall +.PHONY: all release dev perf debug compile clean cleanall all: testing $(TARGET) @@ -220,6 +223,9 @@ dev: perf: $(MAKE) BUILD=perf clean all +debug: + $(MAKE) BUILD=debug clean all + compile: brlib objs libs: brlib diff --git a/src/brchess.c b/src/brchess.c index 56b4a05..d121f4b 100644 --- a/src/brchess.c +++ b/src/brchess.c @@ -26,6 +26,9 @@ #include "hash.h" #include "fen.h" #include "search.h" +#include "hist.h" +#include "move-gen.h" +#include "move-do.h" struct command { char *name; /* User printable name */ @@ -252,6 +255,7 @@ int do_ucinewgame(__unused pos_t *pos, __unused char *arg) { pos_clear(pos); tt_clear(); + hist_init(); return 1; } @@ -275,37 +279,74 @@ int do_position(pos_t *pos, char *arg) { char *saveptr, *token, *fen, *moves; + hist_init(); + /* separate "moves" section */ - saveptr = NULL; if ((moves = strstr(arg, "moves"))) { *(moves - 1) = 0; - token = strtok_r(moves, " ", &saveptr); + } + saveptr = NULL; + token = strtok_r(arg, " ", &saveptr); + if (!strcmp(token, "startpos")) { + startpos(pos); + do_diagram(pos, ""); + } else if (!strcmp(token, "fen")) { + fen = strtok_r(NULL, " ", &saveptr); + fen2pos(pos, fen); + } else { + puts("fuck"); + } + + if (moves) { + saveptr = NULL; + moves = strtok_r(moves, " ", &saveptr); moves = strtok_r(NULL, "", &saveptr); printf("moves = %s\n", moves); do_moves(pos, moves); } - saveptr = NULL; - token = strtok_r(arg, " ", &saveptr); - if (!strcmp(token, "startpos")) { - startpos(pos); - } else if (!strcmp(token, "fen")) { - fen = strtok_r(NULL, "", &saveptr); - fen2pos(pos, fen); - } return 1; } +static move_t *move_find_move(move_t target, movelist_t *list) +{ + move_t *move = list->move, *last = move + list->nmoves; + + for (; move < last; ++move) { + if (move_from(target) == move_from(*move) && + move_to(target) == move_to(*move) && + move_to(target) == move_to(*move) && + move_promoted(target) == move_promoted(*move)) + return move; + } + return NULL; +} + int do_moves(__unused pos_t *pos, char *arg) { - char *saveptr = NULL, *move; - + char *saveptr = NULL, *token, check[8]; + move_t move, *foundmove; + state_t state; + movelist_t movelist; saveptr = NULL; - move = strtok_r(arg, " ", &saveptr); - while (move) { - printf("move: [%s]\n", move); - move = strtok_r(NULL, " ", &saveptr); + token = strtok_r(arg, " ", &saveptr); + while (token) { + move = move_from_str(pos, token); + move_to_str(check, move, 0); + + printf("move: [%s] %s\n", token, check); + pos_set_checkers_pinners_blockers(pos); + pos_legal(pos, pos_gen_pseudo(pos, &movelist)); + foundmove = move_find_move(move, &movelist); + if (!foundmove) { + printf("illegal move"); + return 1; + } + move_do(pos, *foundmove, &state); + hist_push(&state, &move); + token = strtok_r(NULL, " ", &saveptr); } + hist_static_print(); return 1; } diff --git a/src/chessdefs.h b/src/chessdefs.h index e07eb93..e759368 100644 --- a/src/chessdefs.h +++ b/src/chessdefs.h @@ -97,9 +97,10 @@ typedef u64 bitboard_t; */ //typedef s32 eval_t; -/* forward enum definition is impossible in C11, to simplify - * cross-dependancies, all important enum are moved here. +/* forward enum definition is impossible in C11. + * To simplify cross-dependancies, all important enum are moved here. */ + typedef enum { _SSQUARE_ = -1, /* force signed enum */ A1 = 0, B1, C1, D1, E1, F1, G1, H1, diff --git a/src/hist.c b/src/hist.c new file mode 100644 index 0000000..01cdc66 --- /dev/null +++ b/src/hist.c @@ -0,0 +1,123 @@ +/* hist.c - history management. + * + * 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 . + * + * SPDX-License-Identifier: GPL-3.0-or-later + * + */ + +#include +#include + +#include "position.h" +#include "hash.h" +#include "move.h" +#include "hist.h" + +hist_t hist = { + .nstates = 1, + { { .move = MOVE_NO_MOVE, .key = U64(0), .prev = &hist.state[0] } }, +}; + +/** + * hist_init() - initialize history states data. + * + * This should be done every time a new position must be handled. + */ +void hist_init(void) +{ + hist.nstates = 1; + hist.state[0].key = U64(0); + hist.state[0].move = MOVE_NO_MOVE; + hist.state[0].prev = &hist.state[0]; +} + +/** + * hist_push() - add a state and move to hist + * @st: &state_t to add + * @move: &move_t to add in @st + */ +void hist_push(state_t *st, move_t *move) +{ + int last = hist.nstates++; + + bug_on(last >= HIST_SIZE); + hist.state[last] = *st; + hist.state[last].prev = &hist.state[last - 1]; + hist.state[last].move = *move; +} + +/** + * hist_pop() - return last state from hist entry, and remove it from list + * + * Not used, only for debug. + */ +state_t *hist_pop(void) +{ + return hist.state + --hist.nstates; +} + +/** + * hist_last() - return last state from hist. + */ +state_t *hist_last(void) +{ + return hist.state + hist.nstates - 1; +} + +/** + * hist_prev() - return a state's ancestor. + * @st: &state_t state + * + * No test is done on ancestor. Caller should check it is different + * from HIST_START. + */ +state_t *hist_prev(state_t *st) +{ + return st->prev; +} + +/** + * hist_prev2() - return a state's second ancestor. + * @st: &state_t state + * + * No test is done on ancestors. Caller should check it is different + * from HIST_START. + */ +state_t *hist_prev2(state_t *st) +{ + return st->prev->prev; +} + +/** + * hist_prev4() - return a state's 4th ancestor. + * @st: &state_t state + * + * No test is done on ancestors. Caller should check it is different + * from HIST_START. + */ +state_t *hist_prev4(state_t *st) +{ + return st->prev->prev->prev->prev; +} + +/** + * hist_print() - print hist entries + */ +void hist_static_print(void) +{ + char movestr[8]; + + printf("rev history: "); + for (state_t *p = hist_last(); p != HIST_START; p = hist_prev(p)) { + printf("%s(%lx) ", + p->move == MOVE_NO_MOVE? "none": move_to_str(movestr, p->move, 0), + hash_short(p->key)); + } + printf("\n"); +} diff --git a/src/hist.h b/src/hist.h new file mode 100644 index 0000000..a693aa9 --- /dev/null +++ b/src/hist.h @@ -0,0 +1,59 @@ +/* hist.h - history management. + * + * 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 . + * + * SPDX-License-Identifier: GPL-3.0-or-later + * + */ + +#ifndef HIST_H +#define HIST_H + +#include +#include + +#include "position.h" +#include "hash.h" + +#define HIST_SIZE 4096 /* I know, I know... */ + +/** + * hist - history states data. + * + * This variable is of type hist_t, which contains: + * @state: state_t array, size HIST_SIZE + * @nstates: current number of @state + * + * hist contains moves already played. + * + * Only HIST_SIZE - 1 hist elements are available, as the first element is + * used as a sentinel value (hist[0].state.prev = &hist[0].state). + * This first element allows multiple backards searches (p->prev->prev). + * + * hist is only written by main thread, and read by other threads/processes, + * therefore is never duplicated (even after a fork(), due to COW). + */ +typedef struct { + int nstates; + state_t state[HIST_SIZE]; +} hist_t; + +extern hist_t hist; + +#define HIST_START (hist.state) + +void hist_init(void); +void hist_push(state_t *st, move_t *move); +state_t *hist_pop(void); +state_t *hist_last(void); +state_t *hist_prev(state_t *st); +state_t *hist_prev2(state_t *st); +state_t *hist_prev4(state_t *st); +void hist_static_print(void); + +#endif /* HIST_H */ diff --git a/src/move-do.c b/src/move-do.c index 6aab1f9..9f57160 100644 --- a/src/move-do.c +++ b/src/move-do.c @@ -80,7 +80,6 @@ pos_t *move_do(pos_t *pos, const move_t move, state_t *state) if (captured != EMPTY) { pos->clock_50 = 0; - //pos->captured = pos->board[to]; /* save capture info */ bug_on(pos->board[to] == EMPTY || COLOR(pos->captured) != them); key ^= zobrist_pieces[captured][to]; pos_clr_sq(pos, to); /* clear square */ diff --git a/src/move.c b/src/move.c index a8a094f..bbe5464 100644 --- a/src/move.c +++ b/src/move.c @@ -116,6 +116,37 @@ char *move_to_str(char *dst, const move_t move, __unused const int flags) return dst; } +/** + * move_from_str() - create a move from a position and UCI move string + * @pos: &pos_t + * @str: uci move string + * + * string and corresponding move are considered valid (no check is done). + * + * @return move, or NULL if error. + */ +move_t move_from_str(const pos_t *pos, const char *str) +{ + move_t move; + square_t from = sq_from_string(str); + square_t to = sq_from_string(str + 2); + piece_type_t piece = PIECE(pos->board[from]); + piece_type_t promoted = piece_t_from_char(*(str+5)); + + if (piece == KING && sq_dist(from, to) > 1) { /* castling */ + move = move_make_flags(from, to, M_CASTLE); + } else if (piece == PAWN && /* en-passant */ + sq_file(from) != sq_file(to) && + pos->board[to] == EMPTY) { + move = move_make_enpassant(from, to); + } else if (promoted != NO_PIECE_TYPE) { /* promotion */ + move = move_make_promote(from, to, promoted); + } else { + move = move_make(from, to); + } + return move; +} + /** * moves_print() - print movelist moves. * @moves: &movelist_t moves list diff --git a/src/move.h b/src/move.h index 0af6e27..2d7ca97 100644 --- a/src/move.h +++ b/src/move.h @@ -29,11 +29,7 @@ * ppp 3 12 12-14 piece_type_t 070000 (>>12) &07 promoted * FFF 3 15 15-17 move_flags_t 0700000 (>>15) &07 flags */ -typedef s32 move_t; - -/* special move_t values */ -#define MOVE_NONE ((move_t) -1) -#define MOVE_NULL ((move_t) 0) /* hack: from = to = A1 */ +typedef u32 move_t; enum { M_OFF_FROM = 0, @@ -50,6 +46,11 @@ typedef enum { // M_CHECK = (3 << M_OFF_FLAGS) /* maybe unknown/useless ? */ } move_flags_t; +/* special move_t values */ +#define MOVE_NULL 0 /* hack: from = to = A1 */ +#define MOVE_NONE 07777 /* hack: from = to = H8 */ +#define MOVE_NO_MOVE 01010 /* hack: from = to = A2 */ + #define move_set_flags(move, flags) ((move) | (flags)) #define move_flags(move) ((move) & M_FLAGS_MASK) @@ -144,6 +145,7 @@ static inline move_t move_make_promote(square_t from, square_t to, //int move_print(int movenum, move_t *move, move_flags_t flags); char *move_to_str(char *dst, const move_t move, __unused const int flags); +move_t move_from_str(const pos_t *pos, const char *str); void moves_print(movelist_t *moves, int flags); void move_sort_by_sq(movelist_t *moves);