shithub: moonfish

ref: a03b6067b6a3064f49b7f99b60bec83129fb4884
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>

#include "tools.h"

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];
	static char *format = "<cmds>...";
	static struct moonfish_arg args[] =
	{
		{"F", "openings", "<file-name>", NULL, "an opening book for the tournament (one FEN per line)"},
		{"X", "battle", "<command>", "moonfish-battle", "the command to make the two bots play each other"},
		{"T", "time", "<time-control>", NULL, "default time control for each bot"},
		{NULL, NULL, NULL, NULL, NULL},
	};
	
	FILE *openings;
	int bot_count;
	int brackets;
	int i, j, k;
	int opening_count;
	char *battle, *time;
	char *arg, *buffer;
	char **commands;
	int command_count;
	
	commands = moonfish_args(args, format, argc, argv);
	command_count = argc - (commands - argv);
	if (command_count < 1) moonfish_usage(args, format, argv[0]);
	
	openings = NULL;
	battle = args[1].value;
	time = args[2].value;
	if (args[0].value != NULL)
	{
		openings = fopen(args[0].value, "r");
		if (openings == NULL)
		{
			perror(argv[0]);
			return 1;
		}
	}
	
	printf("# makefile generated by '%s'\n\n", argv[0]);
	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 (commands[bot_count] == NULL) break;
		
		brackets = moonfish_brackets(commands[bot_count]);
		
		printf("bot%d = ", bot_count + 1);
		for (i = 0 ; i < brackets ; i++) printf("[");
		printf(" ");
		
		if (time != NULL) printf("--time=%s ", time);
		
		/* todo: skip leading whitespace */
		if (commands[bot_count][0] == '-')
			printf("-- ");
		
		/* todo: escape for makefile... */
		printf("%s", commands[bot_count]);
		
		printf(" ");
		for (i = 0 ; i < brackets ; i++) printf("]");
		printf("\n");
		
		bot_count++;
	}
	
	if (bot_count < 2) fprintf(stderr, "warning: too few 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(argv[0]);
			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;
}