shithub: moonfish

ref: cdb1c9640d18a431b9bdac35c5e89c4ca6768ae0
dir: /tools/ribbon.c/

View raw version
/* 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;
}