shithub: moonfish

ref: 522fcece1df230a6dd3b380cee723cbdf2c237ef
dir: /main.c/

View raw version
/* moonfish is licensed under the AGPL (v3 or later) */
/* copyright 2023, 2024 zamfofex */

#include <stdlib.h>
#include <errno.h>
#include <string.h>
#include <stdio.h>

#include "moonfish.h"

int main(int argc, char **argv)
{
	static char line[2048];
	
	struct moonfish_analysis *analysis;
	char *arg;
	struct moonfish_move move;
	char name[6];
	long int wtime, btime, *xtime;
	int score;
	int depth;
	struct moonfish_chess chess;
	char *end;
#ifndef moonfish_mini
	long int long_depth;
	long int time;
#endif
	
	if (argc > 1)
	{
		if (argc > 0) fprintf(stderr, "usage: %s\n", argv[0]);
		return 1;
	}
	
	analysis = moonfish_analysis(argv[0]);
	moonfish_chess(&chess);
	
	for (;;)
	{
		errno = 0;
		if (fgets(line, sizeof line, stdin) == NULL)
		{
			if (errno)
			{
				perror(argv[0]);
				return 1;
			}
			
			break;
		}
		
		arg = strtok(line, "\r\n\t ");
		if (arg == NULL) continue;
		
		if (!strcmp(arg, "go"))
		{
			wtime = -1;
			btime = -1;
			depth = -1;
#ifndef moonfish_mini
			time = -1;
#endif
			
			for (;;)
			{
				arg = strtok(NULL, "\r\n\t ");
				if (arg == NULL) break;
				
				if (!strcmp(arg, "wtime") || !strcmp(arg, "btime"))
				{
					if (!strcmp(arg, "wtime")) xtime = &wtime;
					else xtime = &btime;
					
					arg = strtok(NULL, "\r\n\t ");
					if (arg == NULL)
					{
						fprintf(stderr, "%s: malformed 'go' command\n", argv[0]);
						return 1;
					}
					
					errno = 0;
					*xtime = strtol(arg, &end, 10);
					if (errno != 0)
					{
						perror(argv[0]);
						return 1;
					}
					if (*end != 0 || *xtime < 0)
					{
						fprintf(stderr, "%s: malformed time in 'go' command\n", argv[0]);
						return 1;
					}
				}
#ifndef moonfish_mini
				else if (!strcmp(arg, "depth"))
				{
					arg = strtok(NULL, "\r\n\t ");
					
					if (arg == NULL)
					{
						fprintf(stderr, "%s: malformed 'go depth' command\n", argv[0]);
						return 1;
					}
					
					errno = 0;
					long_depth = strtol(arg, &end, 10);
					if (errno != 0)
					{
						perror(argv[0]);
						return 1;
					}
					if (*end != 0 || long_depth < 0 || long_depth > 100)
					{
						fprintf(stderr, "%s: malformed depth in 'go' command\n", argv[0]);
						return 1;
					}
					
					depth = long_depth;
				}
				else if (!strcmp(arg, "movetime"))
				{
					arg = strtok(NULL, "\r\n\t ");
					
					if (arg == NULL)
					{
						fprintf(stderr, "%s: malformed 'go movetime' command\n", argv[0]);
						return 1;
					}
					
					errno = 0;
					time = strtol(arg, &end, 10);
					if (errno != 0)
					{
						perror(argv[0]);
						return 1;
					}
					if (*end != 0 || time < 0)
					{
						fprintf(stderr, "%s: malformed move time in 'go' command\n", argv[0]);
						return 1;
					}
				}
#endif
			}
			
			if (wtime < 0) wtime = 0;
			if (btime < 0) btime = 0;
			
#ifndef moonfish_mini
			if (depth >= 0)
				score = moonfish_best_move_depth(analysis, &move, depth);
			else if (time >= 0)
				score = moonfish_best_move_time(analysis, &move, &depth, time);
			else
#endif
			if (chess.white)
				score = moonfish_best_move_clock(analysis, &move, &depth, wtime, btime);
			else
				score = moonfish_best_move_clock(analysis, &move, &depth, btime, wtime);
			
			printf("info depth %d ", depth);
			if (score >= moonfish_omega || score <= -moonfish_omega)
				printf("score mate %d\n", moonfish_countdown(score));
			else
				printf("score cp %d\n", score);
			moonfish_to_uci(name, &move);
			printf("bestmove %s\n", name);
		}
		else if (!strcmp(arg, "quit"))
		{
			break;
		}
		else if (!strcmp(arg, "position"))
		{
			arg = strtok(NULL, "\r\n\t ");
			if (arg == NULL)
			{
				fprintf(stderr, "incomplete 'position' command\n");
				return 1;
			}
			
			if (!strcmp(arg, "startpos"))
			{
				moonfish_chess(&chess);
			}
#ifndef moonfish_mini
			else if (!strcmp(arg, "fen"))
			{
				arg = strtok(NULL, "\r\n");
				moonfish_fen(&chess, arg);
				
				arg = strstr(arg, "moves");
				if (arg != NULL)
				{
					do arg--;
					while (*arg == '\t' || *arg == ' ');
					strcpy(line, arg);
					strtok(line, "\r\n\t ");
				}
				else
				{
					strtok("", "\r\n\t ");
				}
			}
#endif
			else
			{
				fprintf(stderr, "malformed 'position' command\n");
				return 1;
			}
			
			arg = strtok(NULL, "\r\n\t ");
			if (arg != NULL && !strcmp(arg, "moves"))
			{
				while ((arg = strtok(NULL, "\r\n\t ")) != NULL)
				{
					moonfish_from_uci(&chess, &move, arg);
					moonfish_play(&chess, &move);
				}
			}
			
			moonfish_new(analysis, &chess);
		}
		else if (!strcmp(arg, "uci"))
		{
			printf("id name moonfish\n");
			printf("id author zamfofex\n");
			printf("uciok\n");
		}
		else if (!strcmp(arg, "isready"))
		{
			printf("readyok\n");
		}
#ifndef moonfish_mini
		else if (!strcmp(arg, "debug") || !strcmp(arg, "setoption") || !strcmp(arg, "ucinewgame") || !strcmp(arg, "stop"))
		{
		}
		else
		{
			fprintf(stderr, "%s: unknown command '%s'\n", argv[0], arg);
		}
#endif
		
		fflush(stdout);
	}
	
	moonfish_free(analysis);
	return 0;
}