ariadne/uci.c

195 lines
5.1 KiB
C

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <error.h>
#include <stdbool.h>
#include <ctype.h>
#define MAX_LINE_WIDTH 256
enum CMD_CODES{
UCI = 0,
DEBUG = 1,
ISREADY = 2,
SETOPTION = 3,
REGISTER = 4,
UCINEWGAME = 5,
POSITION = 6,
GO = 7,
STOP = 8,
PONDERHIT = 9,
QUIT = 10
};
const char* CMDS[] = {
"uci",
"debug",
"isready",
"setoption name",
"register",
"ucinewgame",
"position",
"go",
"stop",
"ponderhit",
"quit"
};
#define NUM_CMDS (sizeof (CMDS) / sizeof (const char *))
typedef enum{
CHECK,
SPIN,
COMBO,
BUTTON,
STRING
} option_type;
typedef void button_handler();
typedef union {
bool check;
int spin;
// maybe I could store an array of strings for combo,
// and just have the first one be the one that gets modified,
// the others being the possible variants
char* combo;
button_handler* button_handler;
char* string;
} option_data;
typedef struct {
char* name;
option_type type;
option_data data;
} option;
option options[] = {
{"Ponder", CHECK, false},
{"OwnBook", CHECK, true}
};
void _uci(char* parse_condition){
send_id();
send_opts();
send_uciok();
}
void _debug(char* parse_condition){
if(strcmp("on", parse_condition)){
debug_mode = false;
}else if(strcmp("off", parse_condition)){
debug_mode = true;
}else{
printf("Warning: debug command without [ on | off ]");
}
}
void _isready(char* parse_condition){
while(true){
if(ready){
send_readyok();
break;
}
}
}
void _setoption(char* parse_condition){
int value_pos = find_value_pos();
//bit exessive, but oh well *shrugs*
char option_str[value_pos];
strncpy(option_str, parse_condition, value_pos-1);
char values_str[MAX_LINE_WIDTH];
strncpy(values_str, &parse_condition[value_pos+6], MAX_LINE_WIDTH);
for(int i = 0; i < value_pos-1; i++){
option_str[i] = tolower(option_str[i]);
}
for(int i = 0; i < sizeof(options)/sizeof(option); i++){
if(strncmp(options[i].name, option_str, value_pos-1) == 0){
switch(options[i].type){
case CHECK:
options[i].data = parse_check(values_str);
case SPIN:
options[i].data = parse_spin(values_str);
case COMBO:
// This is missing the info of what the possible strings are, to ensure that it's a valid string.
// Integrating this into my rather neat data structure seems pain, so for now it won't get done
options[i].data = parse_combo(values_str);
case BUTTON:
// Function pointer syntax is hard. This is meant to be a function call to the function pointer in data.
// (this feels cursed as hell, but seemed like the only way to actually implement this x.x)
*((button_handler*) options[i].data)();
case STRING:
//this should really just be a quick verification of the termination
options[i].data = parse_string(values_str);
}
}
}
}
void _register(char* parse_condition){}
void _ucinewgame(char* parse_condition){}
void _position(char* parse_condition){}
void _go(char* parse_condition){}
void _stop(char* parse_condition){
run = false;
}
void _ponderhit(char* parse_condition){
ponder = true;
}
void _quit(char* parse_condition){
//letting the OS do the cleanup .-.
//TODO: merge any threads together, and cleanly exit, rather than this mess x.x
exit(1);
}
//reads a line of the input and parses it as UCI GUI->ENGINE communication
void parse_line(){
char* parse_buff [MAX_LINE_WIDTH];
char* parse_pos = parse_buff;
if(!fgets(parse_buff, MAX_LINE_WIDTH, stdin)){
perror("failed reading input");
exit(-1);
}
int active_command;
for(active_command = 0; active_command<NUM_CMDS; active_command++){
if(strncmp(CMDS[active_command], parse_pos, strlen(CMDS[active_command])) == 0){
break;
}
}
parse_pos+=(strlen(CMDS[active_command])+1);
switch(active_command){
case UCI:
_uci(parse_pos);
break;
case DEBUG:
_debug(parse_pos);
break;
case ISREADY:
_isready(parse_pos);
break;
case SETOPTION:
_setoption(parse_pos);
break;
case REGISTER:
_register(parse_pos);
break;
case UCINEWGAME:
_ucinewgame(parse_pos);
break;
case POSITION:
_position(parse_pos);
break;
case GO:
_go(parse_pos);
break;
case STOP:
_stop(parse_pos);
break;
case PONDERHIT:
_ponderhit(parse_pos);
break;
case QUIT:
_quit(parse_pos);
break;
}
}