ref: cdb1c9640d18a431b9bdac35c5e89c4ca6768ae0
dir: /tools/ribbon.c/
/* moonfish is licensed under the AGPL (v3 or later) */
/* copyright 2024 zamfofex */
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
static void moonfish_usage0(char *argv0)
{
fprintf(stderr, "usage: %s <options>... <cmds>...\n", argv0);
fprintf(stderr, "options:\n");
fprintf(stderr, " --openings=<file-name> an opening book for the tournament (one FEN per line)\n");
fprintf(stderr, " --battle=<command> the command to make the two bots play each other\n");
fprintf(stderr, " --time=<time-control> default time control for each bot\n");
exit(1);
}
static char *moonfish_option(char *name, char ***argv)
{
size_t length;
if (**argv == NULL) return NULL;
if (!strcmp(**argv, name))
{
(*argv)++;
return *(*argv)++;
}
length = strlen(name);
if (!strncmp(**argv, name, length) && (**argv)[length] == '=')
return *(*argv)++ + length + 1;
return NULL;
}
static void moonfish_options(char *argv0, FILE **openings, char **battle, char **time, char ***argv)
{
char *arg;
for (;;)
{
arg = moonfish_option("--openings", argv);
if (arg != NULL)
{
*openings = fopen(arg, "r");
if (*openings == NULL)
{
perror(argv0);
exit(1);
}
continue;
}
arg = moonfish_option("--battle", argv);
if (arg != NULL)
{
*battle = arg;
continue;
}
arg = moonfish_option("--time", argv);
if (arg != NULL)
{
*time = arg;
continue;
}
break;
}
}
static int moonfish_brackets(char *command)
{
int count, max_count;
max_count = 0;
count = 0;
for (;;)
{
if (*command == ']')
{
count++;
}
else
{
if (count > max_count) max_count = count;
count = 0;
}
if (*command++ == '\0') break;
}
return max_count + 1;
}
int main(int argc, char **argv)
{
static char line[2048];
char *argv0;
FILE *openings;
int bot_count;
int brackets;
int i, j, k;
int opening_count;
char *battle, *time;
char *arg, *buffer;
if (argc < 1) return 1;
argv0 = *argv++;
openings = NULL;
battle = "moonfish-battle";
time = NULL;
moonfish_options(argv0, &openings, &battle, &time, &argv);
if (argv[0] != NULL)
{
if (!strcmp(argv[0], "--"))
argv++;
else if (**argv == '-')
moonfish_usage0(argv0);
}
printf("# makefile generated by '%s'\n\n", argv0);
printf(".PHONY: all\n\n");
printf("n = basename '$@' .pgn | cut -d- -f\n");
/* todo: support BSD Make somehow... */
/* maybe even POSIX Make */
printf("n1 = $($(shell $n1))\n");
printf("n2 = $($(shell $n2))\n");
printf("n3 = $($(shell $n3))\n\n");
bot_count = 0;
for (;;)
{
if (argv[bot_count] == NULL) break;
brackets = moonfish_brackets(argv[bot_count]);
printf("bot%d = ", bot_count + 1);
for (i = 0 ; i < brackets ; i++) printf("[");
printf(" ");
if (time != NULL) printf("--time=%s ", time);
printf("%s", argv[bot_count]);
printf(" ");
for (i = 0 ; i < brackets ; i++) printf("]");
printf("\n");
bot_count++;
}
if (bot_count == 0) fprintf(stderr, "warning: no bots established for tournament\n");
printf("\n");
if (openings == NULL)
{
printf("all:");
for (i = 0 ; i < bot_count ; i++)
for (j = 0 ; j < bot_count ; j++)
{
if (i == j) continue;
printf(" \\\n\tbot%d-bot%d.pgn", i + 1, j + 1);
}
printf("\n\n");
printf(".DEFAULT:\n");
printf("\t@%s $(n1) $(n2) > $@.on\n", battle);
printf("\t@mv $@.on $@\n");
return 0;
}
opening_count = 0;
for (;;)
{
errno = 0;
if (fgets(line, sizeof line, openings) == NULL)
{
if (errno == 0) break;
perror(argv0);
return 1;
}
arg = line + strspn(line, "\r\n\t ");
if (arg[0] == '#') continue;
arg = strtok_r(arg, "\r\n#", &buffer);
if (arg == NULL) continue;
printf("opening%d = ", opening_count + 1);
printf("%s\n", arg);
opening_count++;
}
if (opening_count == 0) fprintf(stderr, "warning: empty opening book\n");
printf("\n");
printf("all:");
for (i = 0 ; i < bot_count ; i++)
for (j = 0 ; j < bot_count ; j++)
{
if (i == j) continue;
for (k = 0 ; k < opening_count ; k++)
printf(" \\\n\topening%d-bot%d-bot%d.pgn", k + 1, i + 1, j + 1);
}
printf("\n\n");
printf(".DEFAULT:\n");
printf("\t@%s --fen='$(n1)' $(n2) $(n3) > $@.on\n", battle);
printf("\t@mv $@.on $@\n");
return 0;
}