bodichess main loop (move gen/eval/fen init/print pos/print moves)

This commit is contained in:
2021-11-14 11:35:03 +01:00
parent 451afea6b5
commit 5bf5d6bae9
8 changed files with 468 additions and 12 deletions

1
.gitignore vendored
View File

@@ -10,6 +10,7 @@ move
bits bits
eval eval
debug debug
bodichess
*.s *.s
/test/ /test/
/obj/ /obj/

View File

@@ -22,8 +22,9 @@ CC=gcc
.SECONDEXPANSION: .SECONDEXPANSION:
OBJ=$(addprefix $(OBJDIR)/,$(SRC_S:.c=.o)) OBJ=$(addprefix $(OBJDIR)/,$(SRC_S:.c=.o))
BIN=fen pool piece move debug eval bits BIN=fen pool piece move debug eval bits bodichess
LIBS = -lreadline -lncurses
CFLAGS += -std=gnu99 CFLAGS += -std=gnu99
#CFLAGS += -O2 #CFLAGS += -O2
@@ -72,15 +73,21 @@ clean:
#$(OBJ): $(OBJDIR)/%.o: $(SRCDIR)/%.c #$(OBJ): $(OBJDIR)/%.o: $(SRCDIR)/%.c
# @mkdir -p $(@D) # @mkdir -p $(@D)
# $(CC) -c $(CFLAGS) -o $@ $< # $(CC) -c $(CFLAGS) -o $@ $<
$(OBJDIR)/%.o: $(SRCDIR)/%.c $(OBJDIR)/%.o:
@mkdir -p $(@D) @mkdir -p $(@D)
@echo compiling $@. @echo compiling $@.
@$(CC) -c $(CFLAGS) -o $@ $< @$(CC) -c $(CFLAGS) -o $@ $<
#fen: CFLAGS+=-DBIN_$$@ #fen: CFLAGS+=-DBIN_$$@
#$(BIN): $$(subst $(OBJDIR)/$$@.o,,$(OBJ)) $(SRCDIR)/$$@.c
# @echo compiling $@.
# @$(CC) -DBIN_$@ $(CFLAGS) $^ $(LIBS) -o $@
# TODO: find a better dependancy graph
$(BIN): $$(subst $(OBJDIR)/$$@.o,,$(OBJ)) $(SRCDIR)/$$@.c $(BIN): $$(subst $(OBJDIR)/$$@.o,,$(OBJ)) $(SRCDIR)/$$@.c
@echo compiling $@. @echo compiling $@.
@$(CC) -DBIN_$@ $(CFLAGS) $^ -o $@ @echo NEED_TO_CHANGE_THIS=$^
@$(CC) -DBIN_$@ $(CFLAGS) $^ $(LIBS) -o $@
#pool: CFLAGS+=-DPOOLBIN #pool: CFLAGS+=-DPOOLBIN
#pool: $$(subst $(OBJDIR)/$$@.o,,$(OBJ)) $(SRCDIR)/$$@.c #pool: $$(subst $(OBJDIR)/$$@.o,,$(OBJ)) $(SRCDIR)/$$@.c

View File

@@ -1,4 +1,7 @@
./obj/bits.o:: src/bits.c src/bits.h src/debug.h ./obj/bits.o:: src/bits.c src/bits.h src/debug.h
./obj/bodichess.o:: src/bodichess.c src/chessdefs.h src/bits.h src/debug.h \
src/board.h src/piece.h src/list.h src/pool.h src/move.h src/position.h \
src/fen.h src/eval.h src/bodichess.h
./obj/debug.o:: src/debug.c src/debug.h ./obj/debug.o:: src/debug.c src/debug.h
./obj/eval.o:: src/eval.c src/eval.h src/position.h src/chessdefs.h src/bits.h \ ./obj/eval.o:: src/eval.c src/eval.h src/position.h src/chessdefs.h src/bits.h \
src/debug.h src/board.h src/piece.h src/list.h src/pool.h src/debug.h src/board.h src/piece.h src/list.h src/pool.h

423
src/bodichess.c Normal file
View File

@@ -0,0 +1,423 @@
/* bodichess.c - main loop.
*
* Copyright (C) 2021 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 <https://www.gnu.org/licenses/gpl-3.0-standalone.htmlL>.
*
* SPDX-License-Identifier: GPL-3.0-or-later <https://spdx.org/licenses/GPL-3.0-or-later.html>
*
*/
#include <stdio.h>
#include <err.h>
#include <stdlib.h>
#include <string.h>
#include <readline/readline.h>
#include <readline/history.h>
#include "chessdefs.h"
#include "board.h"
#include "piece.h"
#include "move.h"
#include "list.h"
#include "debug.h"
#include "fen.h"
#include "eval.h"
#include "bodichess.h"
typedef struct {
char *name; /* User printable name */
int (*func)(pos_t *, char *); /* function doing the job */
char *doc; /* function doc */
} COMMAND;
/* 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);
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_pos (pos_t *, char*);
int do_genmoves(pos_t *, char*);
int do_prmoves(pos_t *, char*);
int do_eval (pos_t *, char*);
int do_quit (pos_t *, char*);
COMMAND commands[] = {
{ "help", do_help, "Display this text" },
{ "?", do_help, "Synonym for 'help'" },
{ "fen", do_fen, "Set position to FEN" },
{ "pos", do_pos, "Print current position" },
{ "quit", do_quit, "Quit" },
{ "genmv", do_genmoves, "Generate next move list" },
{ "prmv", do_prmoves, "Generate next move list" },
{ "eval", do_eval, "Eval current position" },
{ NULL, (int (*)()) NULL, NULL }
};
static int done=0;
int bodichess(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 = &quote_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,
__attribute__((unused)) int start,
__attribute__((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;
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. */
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 ((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(__attribute__((unused)) pos_t *pos,
__attribute__((unused)) char *arg)
{
eval_t res = eval(pos);
printf("eval=%ld (%.3f pawns)\n", res, (float)res/100);
return 1;
}
int do_fen(pos_t *pos, char *arg)
{
log_f(1, "%s\n", arg);
fen2pos(pos, arg);
return 1;
}
int do_pos (pos_t *pos,
__attribute__((unused)) char *arg)
{
log_f(1, "%s\n", arg);
pos_print(pos);
return 1;
}
int do_genmoves(pos_t *pos,
__attribute__((unused)) char *arg)
{
log_f(1, "%s\n", arg);
moves_gen(pos, OPPONENT(pos->turn), false);
moves_gen(pos, pos->turn, true);
return 1;
}
int do_prmoves(pos_t *pos,
__attribute__((unused)) char *arg)
{
log_f(1, "%s\n", arg);
moves_print(pos, M_PR_SEPARATE);
return 1;
}
int do_quit(__attribute__((unused)) pos_t *pos,
__attribute__((unused)) char *arg)
{
return done = 1;
}
/* Print out help for ARG, or for all of the commands if ARG is
not present. */
int do_help(__attribute__((unused)) pos_t *pos,
__attribute__((unused)) char *arg)
{
register int i;
int printed = 0;
for (i = 0; commands[i].name; i++) {
if (!*arg || (strcmp (arg, commands[i].name) == 0)) {
printf ("%s\t\t%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);
}
/*
static char *read_line(void)
{
char *line = NULL;
ssize_t bufsize = 0; // have getline allocate a buffer for us
if (getline(&line, &bufsize, stdin) == -1){
if (feof(stdin)) {
exit(EXIT_SUCCESS); // We recieved an EOF
} else {
perror("readline");
exit(EXIT_FAILURE);
}
}
return line;
}
*/
/*
int bodichess(pos_t *pos)
{
while (1) {
printf("bodichess> ");
if (side == computer_side) // programme joue
{
//recherche du meilleur coup a profondeur max_depth
bestMove = programme_joue(max_depth, 1);
jouer_coup(bestMove);
affiche_echiquier();
affiche_infos();
affiche_resultat();
continue;
}
printf("isa> ");
//printf("Taper help pour voir les commandes dispos\n");
if (scanf("%s", s) == EOF) //ferme le programme
return 0;
if (!strcmp(s, "d")) //affichage de l'échiquier et des infos
{
affiche_echiquier();
continue;
}
debug_init(1);
piece_pool_init();
moves_pool_init();
pos_pool_init();
pos = pos_get();
}
*/
#ifdef BIN_bodichess
/** main()
* options:
int bodichess(pos_t *pos)
*
*/
static int usage(char *prg)
{
fprintf(stderr, "Usage: %s [-ilw] [file...]\n", prg);
return 1;
}
#include <unistd.h>
int main(int ac, char **av)
{
pos_t *pos;
int opt;
debug_init(1);
piece_pool_init();
moves_pool_init();
pos_pool_init();
pos = pos_get();
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);
}
}
printf("optind = %d ac = %d\n", optind, ac);
if (optind < ac)
return usage(*av);
return bodichess(pos);
}
#endif /* BIN_bodichess */

21
src/bodichess.h Normal file
View File

@@ -0,0 +1,21 @@
/* bodichess.h - main loop.
*
* Copyright (C) 2021 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 <https://www.gnu.org/licenses/gpl-3.0-standalone.htmlL>.
*
* SPDX-License-Identifier: GPL-3.0-or-later <https://spdx.org/licenses/GPL-3.0-or-later.html>
*
*/
#ifndef BODICHESS_H
#define BODICHESS_H
#include "position.h"
int bodichess(pos_t *pos);
#endif /* BODICHESS_H */

View File

@@ -18,4 +18,4 @@
pos_t *fen2pos(pos_t *pos, char *fen); pos_t *fen2pos(pos_t *pos, char *fen);
#endif #endif /* FEN_H */

View File

@@ -13,6 +13,7 @@
#include <malloc.h> #include <malloc.h>
#include <ctype.h> #include <ctype.h>
#include "chessdefs.h" #include "chessdefs.h"
#include "board.h" #include "board.h"
#include "piece.h" #include "piece.h"
@@ -379,7 +380,7 @@ int pseudo_moves_gen(pos_t *pos, piece_list_t *ppiece, bool doit)
u64 bb_new; u64 bb_new;
# ifdef DEBUG_MOVE # ifdef DEBUG_MOVE
log_f(1, "pos:%p turn:%s piece:%d [%s %s] at %#04x[%c%c]\n", log_f(2, "pos:%p turn:%s piece:%d [%s %s] at %#04x[%c%c]\n",
pos, pos,
IS_WHITE(pos->turn)? "white": "black", IS_WHITE(pos->turn)? "white": "black",
piece, piece,
@@ -413,7 +414,7 @@ int pseudo_moves_gen(pos_t *pos, piece_list_t *ppiece, bool doit)
/* king: do not move to opponent controlled square */ /* king: do not move to opponent controlled square */
if (piece == KING && pos->controlled[OPPONENT(vcolor)] & bb_new) { if (piece == KING && pos->controlled[OPPONENT(vcolor)] & bb_new) {
# ifdef DEBUG_MOVE # ifdef DEBUG_MOVE
log_i(1, "%s king cannot move to %c%c\n", log_i(2, "%s king cannot move to %c%c\n",
IS_WHITE(color)? "white": "black", IS_WHITE(color)? "white": "black",
FILE2C(GET_F(new)), RANK2C(GET_R(new))); FILE2C(GET_F(new)), RANK2C(GET_R(new)));
# endif # endif
@@ -424,7 +425,7 @@ int pseudo_moves_gen(pos_t *pos, piece_list_t *ppiece, bool doit)
//bitboard_print(pos->occupied[vcolor]); //bitboard_print(pos->occupied[vcolor]);
//bitboard_print(pos->occupied[OPPONENT(vcolor)]); //bitboard_print(pos->occupied[OPPONENT(vcolor)]);
# ifdef DEBUG_MOVE # ifdef DEBUG_MOVE
log_i(1, "BB: skipping %#llx [%c%c] (same color piece)\n", log_i(2, "BB: skipping %#llx [%c%c] (same color piece)\n",
new, FILE2C(GET_F(new)), RANK2C(GET_R(new))); new, FILE2C(GET_F(new)), RANK2C(GET_R(new)));
# endif # endif
break; break;
@@ -455,7 +456,7 @@ int moves_gen(pos_t *pos, bool color, bool doit)
int count = 0; int count = 0;
# ifdef DEBUG_MOVE # ifdef DEBUG_MOVE
log_f(1, "color:%s doit:%d\n", color? "Black": "White", doit); log_f(2, "color:%s doit:%d\n", color? "Black": "White", doit);
# endif # endif
piece_list = &pos->pieces[color]; piece_list = &pos->pieces[color];
@@ -477,7 +478,7 @@ int moves_gen(pos_t *pos, bool color, bool doit)
int move_doit(pos_t *pos, move_t *move) int move_doit(pos_t *pos, move_t *move)
{ {
# ifdef DEBUG_MOVE_TOTO # ifdef DEBUG_MOVE_TOTO
log_f(1, "color:%s doit:%d\n", color? "Black": "White", doit); log_f(2, "color:%s doit:%d\n", color? "Black": "White", doit);
# endif # endif
if (pos && move) if (pos && move)
return 1; return 1;
@@ -501,7 +502,7 @@ int main(int ac, char**av)
} else { } else {
fen2pos(pos, av[1]); fen2pos(pos, av[1]);
} }
printf("turn = %d opponent = %d\n", pos->turn, OPPONENT(pos->turn)); //printf("turn = %d opponent = %d\n", pos->turn, OPPONENT(pos->turn));
moves_gen(pos, OPPONENT(pos->turn), false); moves_gen(pos, OPPONENT(pos->turn), false);
moves_gen(pos, pos->turn, true); moves_gen(pos, pos->turn, true);
pos_print(pos); pos_print(pos);
@@ -511,4 +512,4 @@ int main(int ac, char**av)
//bitboard_print2(castle_squares[0].controlled, castle_squares[1].controlled); //bitboard_print2(castle_squares[0].controlled, castle_squares[1].controlled);
//bitboard_print2(castle_squares[0].occupied, castle_squares[1].occupied); //bitboard_print2(castle_squares[0].occupied, castle_squares[1].occupied);
} }
#endif #endif /* BIN_move */

View File

@@ -48,4 +48,4 @@ pool_t *pos_pool_init();
pos_t *pos_get(); pos_t *pos_get();
pos_t *pos_dup(pos_t *pos); pos_t *pos_dup(pos_t *pos);
#endif #endif /* POSITION_H */