diff --git a/src/brchess.c-move-to-temp-migration-bitboard__brchess.c b/src/brchess.c-move-to-temp-migration-bitboard__brchess.c new file mode 100644 index 0000000..2661fdf --- /dev/null +++ b/src/brchess.c-move-to-temp-migration-bitboard__brchess.c @@ -0,0 +1,522 @@ +/* brchess.c - main loop. + * + * Copyright (C) 2021-2023 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 +#include +#include + +#include +#include +#include + +#include "brchess.h" +#include "chessdefs.h" +#include "board.h" +#include "piece.h" +#include "move.h" +#include "fen.h" +#include "eval.h" +#include "eval-simple.h" +#include "search.h" + +struct command { + char *name; /* User printable name */ + int (*func)(pos_t *, char *); /* function doing the job */ + char *doc; /* function doc */ +}; + +/* readline example inspired by : + * - https://thoughtbot.com/blog/tab-completion-in-gnu-readline + * - http://web.mit.edu/gnu/doc/html/rlman_2.html + */ +char **commands_completion(const char *, int, int); +char *commands_generator(const char *, int); +char *escape(const char *); +int quote_detector(char *, int); +int execute_line (pos_t *, char *line); +struct command *find_command (char *); +char *stripwhite (char *string); + +/* The names of functions that actually do the manipulation. */ +int do_help(pos_t *, char*); +int do_fen(pos_t *, char*); +int do_init(pos_t *, char*); +int do_pos(pos_t *, char*); +int do_genmoves(pos_t *, char*); +int do_prmoves(pos_t *, char*); +//int do_prmovepos(pos_t *pos, char *arg); +int do_prpieces(pos_t *pos, char *arg); +int do_memstats(pos_t *, char*); +int do_eval(pos_t *, char*); +int do_simple_eval(pos_t *, char*); +int do_move(pos_t *, char*); +int do_quit(pos_t *, char*); +int do_debug(pos_t *, char*); +int do_depth(pos_t *, char*); +int do_search(pos_t *, char*); +int do_pvs(pos_t *, char*); + +struct command commands[] = { + { "help", do_help, "Display this text" }, + { "?", do_help, "Synonym for 'help'" }, + { "fen", do_fen, "Set position to FEN" }, + { "init", do_init, "Set position to normal start position" }, + { "pos", do_pos, "Print current position" }, + { "quit", do_quit, "Quit" }, + { "genmove", do_genmoves, "Generate move list for " }, + { "prmoves", do_prmoves, "Print position move list" }, +// { "prmovepos", do_prmovepos, "Print Nth move resulting position" }, + { "prpieces", do_prpieces, "Print Pieces (from pieces lists)" }, + { "memstats", do_memstats, "Generate next move list" }, + { "eval", do_eval, "Eval current position" }, + { "simple-eval", do_simple_eval, "Simple eval current position" }, + { "do_move", do_move, "execute nth move on current position" }, + { "debug", do_debug, "Set log level to LEVEL" }, + { "depth", do_depth, "Set search depth to N" }, + { "search", do_search, "Search best move (negamax)" }, + { "pvs", do_pvs, "Search best move (Principal Variation Search)" }, + { NULL, (int(*)()) NULL, NULL } +}; + +static int done=0; +static int depth=1; + +int brchess(pos_t *pos) +{ + char *buffer, *s; + + rl_attempted_completion_function = commands_completion; + rl_completer_quote_characters = "'\""; + rl_completer_word_break_characters = " "; + rl_char_is_quoted_p = "e_detector; + + while (!done) { + buffer = readline("chess> "); + if (!buffer) + break; + /* Remove leading and trailing whitespace from the line. + * Then, if there is anything left, add it to the history list + * and execute it. + */ + s = stripwhite(buffer); + + if (*s) { + add_history(s); + execute_line(pos, s); + } + free(buffer); + } + + return 0; +} + +//char **commands_completion(const char *text, int start, int end) +char **commands_completion(const char *text, __unused int start, __unused int end) +{ + rl_attempted_completion_over = 1; + return rl_completion_matches(text, commands_generator); +} + +char *commands_generator(const char *text, int state) +{ + static int list_index, len; + char *name; + + if (!state) { + list_index = 0; + len = strlen(text); + } + + while ((name = commands[list_index++].name)) { + if (rl_completion_quote_character) { + name = strdup(name); + } else { + name = escape(name); + } + + if (strncmp(name, text, len) == 0) { + return name; + } else { + free(name); + } + } + + return NULL; +} + +char *escape(const char *original) +{ + size_t original_len; + size_t i, j; + char *escaped, *resized_escaped; + + original_len = strlen(original); + + if (original_len > SIZE_MAX / 2) { + errx(1, "string too long to escape"); + } + + if ((escaped = malloc(2 * original_len + 1)) == NULL) { + err(1, NULL); + } + + for (i = 0, j = 0; i < original_len; ++i, ++j) { + if (original[i] == ' ') { + escaped[j++] = '\\'; + } + escaped[j] = original[i]; + } + escaped[j] = '\0'; + + if ((resized_escaped = realloc(escaped, j)) == NULL) { + free(escaped); + resized_escaped = NULL; + err(1, NULL); + } + + return resized_escaped; +} + +int quote_detector(char *line, int index) +{ + return index > 0 + && line[index - 1] == '\\' + &&!quote_detector(line, index - 1); +} + +/* Execute a command line. */ +int execute_line(pos_t *pos, char *line) +{ + register int i; + struct command *command; + char *word; + + /* Isolate the command word. */ + i = 0; + while (line[i] && whitespace(line[i])) + i++; + word = line + i; + + while (line[i] && !whitespace(line[i])) + i++; + + if (line[i]) + line[i++] = '\0'; + + command = find_command(word); + + if (!command) { + fprintf(stderr, "%s: Unknown command.\n", word); + return -1; + } + + /* Get argument to command, if any. */ + while (whitespace(line[i])) + i++; + + word = line + i; + + /* return command number */ + return (*command->func)(pos, word); +} + +/* 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. */ +struct command *find_command(char *name) +{ + register int i; + + for (i = 0; commands[i].name; i++) + if (strcmp(name, commands[i].name) == 0) + return &commands[i]; + + return (struct command *)NULL; +} + +/* Strip whitespace from the start and end of STRING. Return a pointer + into STRING. */ +char *stripwhite(char *string) +{ + register char *s, *t; + + for (s = string; whitespace(*s); s++) + ; + + if (*s == 0) + return s; + + t = s + strlen(s) - 1; + while (t > s && whitespace(*t)) + t--; + *++t = '\0'; + + return s; +} + +int do_eval(__unused pos_t *pos, __unused char *arg) +{ + eval_t material[2], control[2], mobility[2]; + for (int color = WHITE; color <= BLACK; ++color) { + material[color] = eval_material(pos, color); + control[color] = eval_square_control(pos, color); + mobility[color] = eval_mobility(pos, color); + printf("%s: material=%d mobility=%d controlled=%d\n", + color? "Black": "White", material[color], + mobility[color], control[color]); + } + eval_t res = eval(pos); + printf("eval = %d centipawns\n", res); + return 1; +} + +int do_simple_eval(__unused pos_t *pos, __unused char *arg) +{ + eval_t eval = eval_simple(pos); + printf("eval = %d centipawns\n", eval); + return 1; +} + +int do_fen(pos_t *pos, char *arg) +{ + fen2pos(pos, arg); + return 1; +} + +int do_init(pos_t *pos, __unused char *arg) +{ + pos_startpos(pos); + return 1; +} + +int do_pos(pos_t *pos, __unused char *arg) +{ + pos_print(pos); + return 1; +} + +int do_genmoves(pos_t *pos, __unused char *arg) +{ + moves_gen_all(pos); + return 1; +} + +int do_prmoves(pos_t *pos, __unused char *arg) +{ + uint debug_level = debug_level_get(); + debug_level_set(1); + moves_print(pos, M_PR_SEPARATE | M_PR_NUM | M_PR_LONG); + debug_level_set(debug_level); + return 1; +} + +/* + * int do_prmovepos(pos_t *pos, char *arg) + * { + * struct list_head *p_cur, *tmp; + * int movenum = atoi(arg), cur = 0; /\* starts with 0 *\/ + * move_t *move; + * + * log_f(1, "%s\n", arg); + * list_for_each_safe(p_cur, tmp, &pos->moves[pos->turn]) { + * move = list_entry(p_cur, move_t, list); + * if (cur++ == movenum) { + * pos_print(move->newpos); + * break; + * } + * } + * + * return 1; + * } + */ + +int do_prpieces(pos_t *pos, __unused char *arg) +{ + log_f(1, "%s\n", arg); + pos_pieces_print(pos); + return 1; +} + +int do_memstats(__unused pos_t *pos,__unused char *arg) +{ + moves_pool_stats(); + piece_pool_stats(); + pos_pool_stats(); + return 1; +} + +int do_move(__unused pos_t *pos, __unused char *arg) +{ + int i = 1, nmove = atoi(arg); + move_t *move; + pos_t *newpos; + + if (list_empty(&pos->moves[pos->turn])) { + log_f(1, "No moves list.\n"); + return 0; + } + list_for_each_entry(move, &pos->moves[pos->turn], list) { + if (i == nmove) + goto doit; + i++; + } + log_f(1, "Invalid <%d> move, should be <1-%d>.\n", nmove, i); + return 0; +doit: + newpos = move_do(pos, move); + pos_print(newpos); + + return 1; +} + +int do_quit(__unused pos_t *pos, __unused char *arg) +{ + return done = 1; +} + +int do_debug(__unused pos_t *pos, __unused char *arg) +{ + debug_level_set(atoi(arg)); + return 1; +} + +/* Print out help for ARG, or for all of the commands if ARG is + not present. */ +int do_help(__unused pos_t *pos, __unused char *arg) +{ + int i; + int printed = 0; + + for (i = 0; commands[i].name; i++) { + if (!*arg || (strcmp(arg, commands[i].name) == 0)) { + printf("%-11.11s%s.\n", commands[i].name, commands[i].doc); + printed++; + } + } + + if (!printed) { + printf("No commands match `%s'. Possibilties are:\n", arg); + + for (i = 0; commands[i].name; i++) { + /* Print in six columns. */ + if (printed == 6) { + printed = 0; + printf("\n"); + } + + printf("%s\t", commands[i].name); + printed++; + } + + if (printed) + printf("\n"); + } + return 0; +} + +int do_depth(__unused pos_t *pos, char *arg) +{ + depth = atoi(arg); + printf("depth = %d\n", depth); + return 1; + +} + +int do_search(pos_t *pos, __unused char *arg) +{ + int debug_level = debug_level_get(); + float timer1, timer2, nodes_sec; + + timer1 = debug_timer_elapsed(); + negamax(pos, depth, pos->turn == WHITE ? 1 : -1); + timer2 = debug_timer_elapsed(); + nodes_sec = (float) pos->node_count / ((float) (timer2 - timer1) / (float)NANOSEC); + log(1, "best="); + debug_level_set(1); + move_print(0, pos->bestmove, 0); + debug_level_set(debug_level); + log(1, " negamax=%d\n", pos->bestmove->negamax); + printf("Depth:%d Nodes:%luK time:%.02fs (%.0f kn/s)\n", depth, + pos->node_count / 1000, (timer2 - timer1)/NANOSEC, nodes_sec/1000); + return 1; +} + +int do_pvs(pos_t *pos, __unused char *arg) +{ + int debug_level = debug_level_get(); + float timer1, timer2, nodes_sec; + eval_t _pvs; + + timer1 = debug_timer_elapsed(); + moves_gen_eval_sort(pos); + _pvs = pvs(pos, depth, EVAL_MIN, EVAL_MAX, pos->turn == WHITE ? 1 : -1); + timer2 = debug_timer_elapsed(); + nodes_sec = (float) pos->node_count / ((float) (timer2 - timer1) / (float)NANOSEC); + log(1, "best="); + if (pos->bestmove) { + debug_level_set(1); + move_print(0, pos->bestmove, 0); + debug_level_set(debug_level); + log(1, " pvs=%d stored=%d\n", _pvs, pos->bestmove->negamax); + } else { + log(1, ""); + } + printf("Depth:%d Nodes:%luK time:%.02fs (%.0f kn/s)\n", depth, + pos->node_count / 1000, (timer2 - timer1)/NANOSEC, nodes_sec/1000); + return 1; +} + +/** main() + * options: + int brchess(pos_t *pos) + * + */ +static int usage(char *prg) +{ + fprintf(stderr, "Usage: %s [-ilw] [file...]\n", prg); + return 1; +} + +#include + +int main(int ac, char **av) +{ + pos_t *pos; + int opt; + + piece_pool_init(); + moves_pool_init(); + pos_pool_init(); + pos = pos_get(); + debug_init(1, stderr, true); + eval_simple_init(); + + while ((opt = getopt(ac, av, "d:f:")) != -1) { + switch (opt) { + case 'd': + debug_level_set(atoi(optarg)); + break; + case 'f': + fen2pos(pos, optarg); + break; + default: + return usage(*av); + } + } + if (optind < ac) + return usage(*av); + + return brchess(pos); +}