#include #include #include #include "response.h" #include "../fen.h" #include "../bitboard.h" void apply_option(uci_state *state, char *name, char *buffer) { int settings_count = sizeof(state->option_settings)/sizeof(option_setting_t); for (int i = 0; i < settings_count; i++) { option_setting_t setting = state->option_settings[i]; if (strcmp(setting.option_name, name)) continue; if (OPTION_SPIN == setting.type) { option_spin_setting_t data = setting.data.spin; int num = atoi(buffer); if (num < data.min) return; if (num > data.max) return; *setting.value.spin = num; } else if (OPTION_COMBO == setting.type) { option_combo_setting_t data = setting.data.combo; for (int j = 0; j < data.count; j++) { if (strcmp(data.combination[i], buffer)) continue; *setting.value.combo = j; } } else if (OPTION_CHECK == setting.type) { *setting.value.check = strcmp(buffer, "true") == 0; } else if (OPTION_STRING == setting.type) { free(setting.value.string->data); setting.value.string->length = strlen(buffer); setting.value.string->data = malloc(setting.value.string->length); memcpy(setting.value.string->data, buffer, setting.value.string->length); } else if (OPTION_BUTTON == setting.type) { *setting.value.button = true; } else { assert(0); } return; } if (state->debug) { printf("debug: invalid option\n"); } } // examples from uci_min.txt // option name Nullmove type check default true\n // option name Selectivity type spin default 2 min 0 max 4\n // option name Style type combo default Normal var Solid var Normal var Risky\n // option name NalimovPath type string default c:\\n // option name Clear Hash type button\n void print_setting(option_setting_t setting) { printf("option name %s type ", setting.option_name); // accidently did the yoda style if statement, i am keeping it if (OPTION_SPIN == setting.type) { option_spin_setting_t data = setting.data.spin; printf( "spin default %d min %d max %d\n", data.default_value, data.min, data.max ); } else if (OPTION_COMBO == setting.type) { option_combo_setting_t data = setting.data.combo; printf("combo default %s", data.combination[data.default_index]); for (int i = 0; i < data.count; i++) { printf(" var %s", data.combination[i]); } printf("\n"); } else if (OPTION_CHECK == setting.type) { printf("check default %d\n", setting.data.check_default); } else if (OPTION_STRING == setting.type) { printf("string default %s\n", setting.data.string_default); } else if (OPTION_BUTTON == setting.type) { printf("button\n"); } else { assert(0); } } enum { STATE_INITIAL, STATE_IDLE, STATE_SYNC, STATE_PING, STATE_ACTIVE, STATE_HALT, }; int current_state = STATE_INITIAL; void handle_uci( uci_state *state, engine_messages *engine_message, ucicmd cmd ) { if (current_state == STATE_INITIAL) { return handle_initial(state, cmd); } if (current_state == STATE_IDLE) { return handle_idle(state, cmd); } if (current_state == STATE_SYNC) { return handle_sync(state, cmd); } if (current_state == STATE_PING) { return handle_ping(state, cmd); } if (current_state == STATE_ACTIVE) { return handle_active(state, engine_message, cmd); } return handle_halt(state, cmd); } void handle_initial(uci_state *state, ucicmd cmd) { if (cmd.empty || strcmp(cmd.root, "uci") != 0) return; // TIMEOUT NOTICE: THE FOLLOWING BLOCK SHOULDN'T TAKE MORE THAN 5 SECONDS printf("id name %s\n", state->name); printf("id author %s\n", state->author); int settings_count = sizeof(state->option_settings)/sizeof(option_setting_t); for (int i = 0; i < settings_count; i++) { print_setting(state->option_settings[i]); } // --- printf("uciok\n"); current_state = STATE_IDLE; } void handle_idle( uci_state *state, ucicmd cmd) { if (cmd.empty) return; if (strcmp(cmd.root, "debug") == 0) { state->debug = strcmp(ucicmd_get_arg(cmd, 0), "on") == 0; } else if (strcmp(cmd.root, "setoption") == 0) { char buffer[2048] = {0}; char name[64] = {0}; char *cursor = name; for (int i = 1; i < cmd.args_count; i++) { assert((long)cursor - (long)buffer < 2048); char *arg = ucicmd_get_arg(cmd, i); if (strcmp(arg, "value") == 0) { *(--cursor) = 0; cursor = buffer; continue; } cursor = stpncpy(cursor, arg, MAX_TOKEN_SIZE); *(cursor++) = ' '; } *(--cursor) = 0; apply_option(state, name, buffer); } else if (strcmp(cmd.root, "ucinewgame") == 0) { if (state->moves != NULL) { free(state->moves); state->moves = NULL; state->moves_count = 0; } } else if (strcmp(cmd.root, "position") == 0) { int k = 0; char* mode = ucicmd_get_arg(cmd, 0); if (strcmp(mode, "startpos") == 0) { struct fen_load fen = load_fen( "rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR w KQkq - 0 1" ); if (fen.failed) { printf("info invalid fen\n"); return; } state->position = fen.position; } else if (strcmp(mode, "fen") == 0) { struct fen_load fen = load_fen(ucicmd_get_arg(cmd, k++)); if (fen.failed) { printf("info invalid fen\n"); return; } state->position = fen.position; } else { assert(0); } if (cmd.args_count >= k) return; assert(strcmp(ucicmd_get_arg(cmd, k++), "moves") == 0); assert(state->moves_count <= cmd.args_count - k); int old_move_count = state->moves_count; state->moves_count = cmd.args_count - k; if (state->moves == NULL) { state->moves = malloc( state->moves_count * sizeof(struct uci_move) ); } else { state->moves = realloc( state->moves, state->moves_count * sizeof(struct uci_move) ); } int l = 0; k += old_move_count; l += old_move_count; for (; k < cmd.args_count; k++) { char* move = ucicmd_get_arg(cmd, k); state->moves[l++] = (struct uci_move) { (move[0] - 'a') * 8 + (move[1] - '1'), (move[2] - 'a') * 8 + (move[3] - '1') }; } } else if (strcmp(cmd.root, "stop") == 0) { } else if (strcmp(cmd.root, "quit") == 0) { free(cmd.args); int settings_count = sizeof(state->option_settings)/sizeof(option_setting_t); for (int i = 0; i < settings_count; i++) { option_setting_t setting = state->option_settings[i]; if (OPTION_STRING != setting.type) continue; free(setting.value.string->data); } atomic_store(&state->quit, 1); } else if (strcmp(cmd.root, "isready") == 0) { current_state = STATE_SYNC; } else if (strcmp(cmd.root, "go") == 0) { atomic_store(&state->go, 1); current_state = STATE_ACTIVE; } else { printf("info violation\n"); } } void handle_sync(uci_state *state, ucicmd cmd) { // TIMEOUT NOTICE: THE FOLLOWING BLOCK SHOULDN'T TAKE MORE THAN 5 SECONDS // --- printf("readyok\n"); current_state = STATE_IDLE; } void handle_ping(uci_state *state, ucicmd cmd) { // TIMEOUT NOTICE: THE FOLLOWING BLOCK SHOULDN'T TAKE MORE THAN 1 SECONDS // if (TODO) { // printf("bestmove\n"); // current_state = STATE_IDLE; // } // --- printf("readyok\n"); current_state = STATE_ACTIVE; } void handle_active( uci_state *state, engine_messages* engine_messages, ucicmd cmd ) { for (int i = 0; i < engine_messages->count; i++) { struct engine_message *old = engine_messages->data[i]; if (!old->ready) continue; old->ready = 0; printf( "info depth %d seldepth %d multipv %d score cp %d nodes %d nps %d hashfull %d tbhits %d time %d pv", old->depth, old->seldepth, old->multipv, old->score_cp, old->nodes, old->nps, old->hashfull, old->tbhits, old->time ); for (int j = 0; j < old->pv.count; j++) { struct uci_move move = old->pv.moves[i]; printf( " %c%c%c%c", (move.from / 8) + 'a', (move.from % 8) + '1', (move.to / 8) + 'a', (move.to % 8) + '1' ); } printf("\n"); if (old->best_move.from != 0 && old->best_move.to != 0) { printf( "bestmove %c%c%c%c", (old->best_move.from / 8) + 'a', (old->best_move.from % 8) + '1', (old->best_move.to / 8) + 'a', (old->best_move.to % 8) + '1' ); if (old->ponder.from != 0 && old->ponder.to != 0) { printf( " ponder %c%c%c%c", (old->ponder.from / 8) + 'a', (old->ponder.from % 8) + '1', (old->ponder.to / 8) + 'a', (old->ponder.to % 8) + '1' ); } printf("\n"); } engine_messages->data[i] = old->next; free(old->pv.moves); free(old); } // TODO: this section will call the engine to analysis if (cmd.empty) { return; } if (strcmp(cmd.root, "isready") == 0) { current_state = STATE_PING; } else if (strcmp(cmd.root, "stop") == 0) { current_state = STATE_HALT; } else { printf("info violation\n"); } } void handle_halt(uci_state *state, ucicmd cmd) { // TIMEOUT NOTICE: THE FOLLOWING BLOCK SHOULDN'T TAKE MORE THAN 1 SECONDS // --- printf("bestmove 0000\n"); // TODO: idk get it rn current_state = STATE_IDLE; }