From a6a21626c7805cd31805ff2e0e64e3cd6abb895f Mon Sep 17 00:00:00 2001 From: Bruno Raoult Date: Sun, 28 Jul 2024 15:14:07 +0200 Subject: [PATCH] uci: complete option/setoption - eval-defs.c: add parameter type in ev_params - util.c: - new str_eq_case() - new str_skip_word - str_token(): split string before token --- Makefile | 2 +- src/eval-defs.c | 36 ++++++++++++---- src/eval-defs.h | 17 +++++++- src/init.c | 3 +- src/uci.c | 107 +++++++++++++++++++++++++++++++++++++++--------- src/util.c | 69 +++++++++++++++++++++++++++---- src/util.h | 5 ++- 7 files changed, 197 insertions(+), 42 deletions(-) diff --git a/Makefile b/Makefile index 43e646d..f504a87 100644 --- a/Makefile +++ b/Makefile @@ -414,7 +414,7 @@ TEST += movedo-test perft-test tt-test PIECE_OBJS := piece.o FEN_OBJS := $(PIECE_OBJS) fen.o position.o bitboard.o board.o \ - hq.o attack.o hash.o init.o misc.o alloc.o move.o \ + hq.o attack.o hash.o init.o util.o alloc.o move.o \ eval.o eval-defs.o eval-simple.o BB_OBJS := $(FEN_OBJS) MOVEGEN_OBJS := $(BB_OBJS) move-gen.o diff --git a/src/eval-defs.c b/src/eval-defs.c index b47992f..62332ac 100644 --- a/src/eval-defs.c +++ b/src/eval-defs.c @@ -18,14 +18,18 @@ #include "position.h" #include "piece.h" #include "eval-defs.h" +#include "util.h" //#include "eval-simple.h" //#include "eval.h" /* eval parameters definition. */ static const struct ev_params ev_param_def [EV_PARAMS_NB] = { - /* default min max setable string */ - [WT_MAT] = { 100, 0, 400, true, "material weight" }, - [WT_PST] = { 100, 0, 400, true, "pst weight" }, + /* type setable def min max name */ + [WT_MAT] = { PAR_SPN, true, 100, 0, 400, "material weight" }, + [WT_PST] = { PAR_SPN, true, 100, 0, 400, "pst weight" }, + [TST_CHK] = { PAR_CHK, true, 1, 0, 0, "test check" }, + [TST_SPN] = { PAR_BTN, true, 0, 0, 0, "test button" }, + }; void param_init() @@ -37,7 +41,7 @@ void param_init() int param_find_name(char *name) { for (int i = 0; i < EV_PARAMS_NB; ++i) - if (!strcmp(ev_param_def[i].name, name)) + if (str_eq_case(ev_param_def[i].name, name)) return i; return -1; } @@ -58,6 +62,14 @@ eval_t param_max(const int num) { return ev_param_def[num].max; } +bool param_setable(const int num) +{ + return ev_param_def[num].setable; +} +int param_type(const int num) +{ + return ev_param_def[num].type; +} /* parameters in use */ eval_t parameters[EV_PARAMS_NB]; @@ -89,7 +101,7 @@ static const struct pst { * rofchade: * https://www.talkchess.com/forum3/viewtopic.php?f=2&t=68311&start=19 */ - "rofchade", + "Rofchade", { /* A8 ..... H8 * ........... @@ -237,7 +249,7 @@ static const struct pst { * https://www.chessprogramming.org/Simplified_Evaluation_Function * Note: ≠ https://github.com/nescitus/cpw-engine */ - "cpw", + "CPW", { /* A8 ..... H8 * ........... @@ -384,7 +396,7 @@ static const struct pst { * sjeng: https://github.com/gcp/sjeng * Rook and Queen from CPW. */ - "sjeng", + "Sjeng", { /* A8 ..... H8 * ........... @@ -530,11 +542,17 @@ int pst_current = PST_DEFAULT; eval_t pst_mg[COLOR_NB][PT_NB][SQUARE_NB]; eval_t pst_eg[COLOR_NB][PT_NB][SQUARE_NB]; +void pst_set(char *str) +{ + pst_init(pst_find(str)); +} + int pst_find(char *str) { - for (int i = 0; i < PST_NB; ++i) - if (!strcmp(pst_defs[i].name, str)) + for (int i = 0; i < PST_NB; ++i) { + if (str_eq_case(pst_defs[i].name, str)) return i; + } return -1; } diff --git a/src/eval-defs.h b/src/eval-defs.h index d2c4977..ab95263 100644 --- a/src/eval-defs.h +++ b/src/eval-defs.h @@ -54,19 +54,31 @@ enum { WT_MAT, WT_PST, + TST_SPN, + TST_CHK, + EV_PARAMS_NB }; +enum { + PAR_CHK, + PAR_SPN, + PAR_BTN, + PAR_STR, +}; + /** * ev_params - parameters definition * @init: eval_t default value * @min, @max: eval_t min and max values + * @type: variable type (PARAM_CHECK, etc...) * @setable: bool setable (proposed in UCI options) * @name: char * human readable name */ struct ev_params { - eval_t init, min, max; + int type; bool setable; /* true: proposed in UCI options */ + eval_t init, min, max; char *name; }; void param_init(void); @@ -76,6 +88,8 @@ char *param_name(const int num); eval_t param_default(const int num); /* get default param value */ eval_t param_min(const int num); eval_t param_max(const int num); +bool param_setable(const int num); +int param_type(const int num); /* parameters in use */ extern eval_t parameters[EV_PARAMS_NB]; @@ -98,6 +112,7 @@ extern int pst_current; extern eval_t pst_mg[COLOR_NB][PT_NB][SQUARE_NB]; extern eval_t pst_eg[COLOR_NB][PT_NB][SQUARE_NB]; +void pst_set(char *str); int pst_find(char *str); void pst_init(int pst); diff --git a/src/init.c b/src/init.c index 3aa598d..8d50d9b 100644 --- a/src/init.c +++ b/src/init.c @@ -32,9 +32,10 @@ void init_all(void) printff("stdout buffering... "); setlinebuf(stdout); - /* for printf() numeric thousands separator */ printff("locale... "); + /* for printf() thousands separator */ setlocale(LC_NUMERIC, ""); + setlocale(LC_CTYPE, "C"); /* pseudo random generator seed */ printff("random generator... "); diff --git a/src/uci.c b/src/uci.c index bef697d..68a0d6d 100644 --- a/src/uci.c +++ b/src/uci.c @@ -13,22 +13,21 @@ #include #include -//#include -//#include #include +#include #include #include "chessdefs.h" #include "util.h" #include "position.h" -#include "uci.h" #include "hist.h" #include "fen.h" #include "move-gen.h" #include "move-do.h" #include "search.h" #include "eval-defs.h" +#include "uci.h" struct command { char *name; /* command name */ @@ -37,19 +36,18 @@ struct command { }; int execute_line (pos_t *, struct command *, char *); - struct command *find_command (char *); -int string_trim (char *str); -/* The names of functions that actually do the manipulation. */ +/* The names of functions that actually do the stuff. + */ /* standard UCI commands */ int do_ucinewgame(pos_t *, char *); int do_uci(pos_t *, char *); int do_isready(pos_t *, char *); int do_quit(pos_t *, char *); -int do_setoption(pos_t *, char *); +int do_setoption(pos_t *, char *); int do_position(pos_t *, char *); /* commands *NOT* in UCI standard */ @@ -65,7 +63,7 @@ struct command commands[] = { { "uci", do_uci, "" }, { "ucinewgame", do_ucinewgame, "" }, { "isready", do_isready, "" }, - { "setoption name", do_setoption, ""}, + { "setoption", do_setoption, ""}, { "position", do_position, "position startpos|fen [moves ...]" }, { "perft", do_perft, "(not UCI) perft [divide] [alt] depth" }, @@ -89,7 +87,7 @@ int execute_line(pos_t *pos, struct command *command, char *args) * @name: &command string * * Look up NAME as the name of a command, and return a pointer to that - * command. Return a NULL pointer if NAME isn't a command name. + * command. Return a NULL pointer if NAME isn't a command name. */ struct command *find_command(char *name) { @@ -236,6 +234,27 @@ int do_uci(__unused pos_t *pos, __unused char *arg) printf(" var %s", pst_name(i)); } printf("\n"); + for (int var = 0; var < EV_PARAMS_NB; ++var) { + if (param_setable(var)) { + int ptyp = param_type(var); + int pmin = param_min(var); + int pmax = param_max(var); + int pval = parameters[var]; + + printf("option name %s ", param_name(var)); + switch(ptyp) { + case PAR_BTN: + printf("type button\n"); + break; + case PAR_CHK: + printf("type check default %s\n", pval? "true": "false"); + break; + case PAR_SPN: + printf("type spin default %d min %d max %d\n", pval, pmin, pmax); + break; + }; + } + } printf("uciok\n"); return 1; } @@ -248,15 +267,67 @@ int do_isready(__unused pos_t *pos, __unused char *arg) int do_setoption(__unused pos_t *pos, __unused char *arg) { - __unused char *name, *value, *saveptr; + char *name, *value = NULL; - /* Note: space in var name are unsupported */ - saveptr = NULL; - name = strtok_r(arg, " ", &saveptr); + if (str_token(arg, "name") != arg) + return 1; + if (!(name = str_skip_word(arg))) + return 1; + /* at this point, we got a valid parameter name */ + value = str_token(name, "value"); /* put '\0' at name end */ + if (value) { + value = str_skip_word(value); + if (!value) + return 1; + } + if (str_eq_case(name, "hash") && value) { + tt_create(atoi(value)); + } else if (str_eq_case(name, "pst")) { + pst_set(value); + } else { + int var = param_find_name(name); + if (var < 0) { + printf("wrong parameter '%s'\n", name); + return 1; + } + char *pname = param_name(var); + printf("found param <%s> = %d\n", pname, var); + if (param_setable(var)) { + int ptyp = param_min(var); + int pmin = param_min(var); + int pmax = param_max(var); + int pval; - value = strstr(arg, "value"); + switch(ptyp) { + case PAR_BTN: + bug_on (value); + printf("do button '%s'\n", pname); + break; + case PAR_CHK: + bug_on (!value); + if (str_eq_case(value, "true")) + pval = 1; + else if (str_eq_case(value, "false")) + pval = 0; + else { + printf("wrong value '%s' to '%s' boolean parameter\n", + value, pname); + return 1; + } + printf("set '%s' to %s\n", pname, pval? "true": "false"); + param_set(var, pval); + break; + case PAR_SPN: + bug_on (!value); + pval = clamp(atoi(value), pmin, pmax); + printf("set '%s' to %d\n", param_name(var), pval); + param_set(var, pval); + break; + } + } + } - return 1; + return 0; } @@ -267,9 +338,7 @@ int do_position(pos_t *pos, char *arg) hist_init(); /* separate "moves" section */ - if ((moves = strstr(arg, "moves"))) { - *(moves - 1) = 0; - } + moves = str_token(arg, "moves"); saveptr = NULL; token = strtok_r(arg, " ", &saveptr); if (!strcmp(token, "startpos")) { @@ -457,7 +526,7 @@ int uci(pos_t *pos) if (! *str) continue; token = strtok_r(str, " ", &saveptr); - if (! (command= find_command(token))) { + if (! (command = find_command(token))) { fprintf(stderr, "Unknown [%s] command. Try 'help'.\n", token); continue; } diff --git a/src/util.c b/src/util.c index d3ce4ab..88546cc 100644 --- a/src/util.c +++ b/src/util.c @@ -150,6 +150,28 @@ u64 rand64(void) return rand_seed * 0x2545f4914f6cdd1dull; } +/** + * str_eq_case - test if two strings are equal ignoring case + * @str1: string1 + * @str2: string2 + * + * Compare @str1 and @str2 byte-by-byte, ignoring case. + * + * @return: true is equal, false otherwise. + */ +bool str_eq_case(char *str1, char *str2) +{ + uchar *s1 = (uchar *) str1; + uchar *s2 = (uchar *) str2; + + for (; *s1 && *s2; ++s1, ++s2) { + if (tolower(*s1) != tolower(*s2)) + break; + } + //printf("d=%lu *s1=%d *s2=%d\n", s1 - (uchar *) str1, *s1, *s2); + return *s2 == *s1; +} + /** * str_trim - cleanup (trim) blank characters in string. * @str: &string to clean @@ -170,6 +192,7 @@ char *str_trim(char *str) char *to = str, *from = str; int state = 1; + bug_on(!str); while (*from) { switch (state) { case 1: /* blanks */ @@ -190,34 +213,62 @@ char *str_trim(char *str) if (to > str) to--; *to = 0; - return to; + return str; } /** - * str_token - find a token in string. + * str_token - split a string from next token. * @str: string to search * @token: token to look for * - * Look for token @token in string @str. - * A token is a string delimited by space characters. However, it may contain + * Look for token @token in string @str, and if found, split @str just before it. + * A token is a string delimited by one space character. However, it may contain * space characters itself. + * @str should normally be normalized with @str_trim(), so that all consecutive + * blank characters are replaced by one, and leading/trailing ones removed. * * @return: @token address if found, NULL otherwise. */ -char *str_token(const char *str, const char *token) +char *str_token(char *str, const char *token) { int len = strlen(token); - const char *found = str; + char *found = str; + + bug_on(!str || !token); + if (!*token) /* nothing to search */ + return str; while (found && *found) { - printf("trying pos=%ld\n", found - str); + //printf("trying pos=%ld\n", found - str); found = strstr(found, token); if (found) { if (!found[len] || isspace(found[len])) break; found = strchr(found, ' ') + 1; - printf("new pos=%ld\n", found - str); + //printf("new pos=%ld\n", found - str); } } - return (char *) found; + if (found > str) /* split string */ + *(found - 1) = 0; + return found; +} + +/** + * str_skip_word - find next word in a string. + * @str: input string + * + * skip current word and following blank char. + * @str must be normalized with @str_trim(), so that all consecutive blank + * characters are already replaced by one, and leading/trailing ones removed. + * Note that 'word' means any sequence of non-space character. + * + * @str is not modified. + * + * @return: next word if found, NULL otherwise. + */ +char *str_skip_word(char *str) +{ + bug_on(!str); + str = strchr(str, ' '); + return str? str + 1: NULL; } diff --git a/src/util.h b/src/util.h index 7249498..dc3c15c 100644 --- a/src/util.h +++ b/src/util.h @@ -53,8 +53,9 @@ void rand_init(u64 seed); u64 rand64(void); +bool str_eq_case(char *str1, char *str2); char *str_trim(char *str); -char *str_token(const char *str, const char *token); - +char *str_token(char *str, const char *token); +char *str_skip_word(char *str); #endif /* UTIL_H */