#include #include #include #include "uci/internals/response.h" #include "uci/state.h" #include "fen.h" void handle_uci(uci_state_t *state, uci_cmd_t cmd) { if (state->current_state == UCI_STATE_INITIAL) { return handle_initial(state, cmd); } if (state->current_state == UCI_STATE_IDLE) { return handle_idle(state, cmd); } if (state->current_state == UCI_STATE_SYNC) { return handle_sync(state, cmd); } if (state->current_state == UCI_STATE_PING) { return handle_ping(state, cmd); } if (state->current_state == UCI_STATE_ACTIVE) { return handle_active(state, cmd); } return handle_halt(state, cmd); } void handle_initial(uci_state_t *state, uci_cmd_t 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"); state->current_state = UCI_STATE_IDLE; } void handle_idle(uci_state_t *state, uci_cmd_t cmd) { if (cmd.empty) return; if (strcmp(cmd.root, "debug") == 0) { state->debug = strcmp(uci_cmd_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 = uci_cmd_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) { } else if (strcmp(cmd.root, "position") == 0) { int k = 0; char* mode = uci_cmd_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" ); assert(fen.failed == 0); state->position = fen.position; } else if (strcmp(mode, "fen") == 0) { struct fen_load fen = load_fen(uci_cmd_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(uci_cmd_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; k += old_move_count; for (; k < cmd.args_count; k++) { char* move = uci_cmd_get_arg(cmd, k); add_ipc_move( state->moves, (ipc_move_t) { (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); } state->signal = UCI_SIGNAL_QUIT; } else if (strcmp(cmd.root, "isready") == 0) { state->current_state = UCI_STATE_SYNC; } else if (strcmp(cmd.root, "go") == 0) { go_args_t info = (go_args_t) {0}; for (int i = 0; i < cmd.args_count; i++) { if (strcmp(uci_cmd_get_arg(cmd, i), "searchmoves") == 0) { ipc_moves_init(&info.searchmoves); for (i++; i < cmd.args_count; i++) { char* move_str = uci_cmd_get_arg(cmd, i); if (move_str[1] < '0' || move_str[1] > '9') break; add_ipc_move(&info.searchmoves, (ipc_move_t) { (move_str[0] - 'a') * 8 + (move_str[1] - '1'), (move_str[2] - 'a') * 8 + (move_str[3] - '1') }); } i--; // it was harsh on my eyes, that's why i did this formatting } else if (strcmp(uci_cmd_get_arg(cmd, i), "ponder") == 0) { info.ponder = true; } else if (strcmp(uci_cmd_get_arg(cmd, i), "wtime") == 0) { info.wtime = atoi(uci_cmd_get_arg(cmd, ++i)); } else if (strcmp(uci_cmd_get_arg(cmd, i), "btime") == 0) { info.btime = atoi(uci_cmd_get_arg(cmd, ++i)); } else if (strcmp(uci_cmd_get_arg(cmd, i), "winc") == 0) { info.winc = atoi(uci_cmd_get_arg(cmd, ++i)); } else if (strcmp(uci_cmd_get_arg(cmd, i), "binc") == 0) { info.binc = atoi(uci_cmd_get_arg(cmd, ++i)); } else if (strcmp(uci_cmd_get_arg(cmd, i), "movestogo") == 0) { info.movestogo = atoi(uci_cmd_get_arg(cmd, ++i)); } else if (strcmp(uci_cmd_get_arg(cmd, i), "depth") == 0) { info.depth = atoi(uci_cmd_get_arg(cmd, ++i)); } else if (strcmp(uci_cmd_get_arg(cmd, i), "nodes") == 0) { info.nodes = atoi(uci_cmd_get_arg(cmd, ++i)); } else if (strcmp(uci_cmd_get_arg(cmd, i), "mate") == 0) { info.mate = atoi(uci_cmd_get_arg(cmd, ++i)); } else if (strcmp(uci_cmd_get_arg(cmd, i), "movetime") == 0) { info.movetime = atoi(uci_cmd_get_arg(cmd, ++i)); } else if (strcmp(uci_cmd_get_arg(cmd, i), "infinite") == 0) { info.infinite = true; } else if (strcmp(uci_cmd_get_arg(cmd, i), "perft") == 0) { info.perft = atoi(uci_cmd_get_arg(cmd, ++i)); } } memcpy(&state->go_args, &info, sizeof(info)); state->signal = UCI_SIGNAL_GO; state->current_state = UCI_STATE_ACTIVE; } else { printf("info violation\n"); } } void handle_sync(uci_state_t *state, uci_cmd_t cmd) { // TIMEOUT NOTICE: THE FOLLOWING BLOCK SHOULDN'T TAKE MORE THAN 5 SECONDS // --- printf("readyok\n"); state->current_state = UCI_STATE_IDLE; } void handle_ping(uci_state_t *state, uci_cmd_t cmd) { // TIMEOUT NOTICE: THE FOLLOWING BLOCK SHOULDN'T TAKE MORE THAN 1 SECONDS // if (TODO) { // printf("bestmove\n"); // current_state = UCI_STATE_IDLE; // } // --- printf("readyok\n"); state->current_state = UCI_STATE_ACTIVE; } void handle_active(uci_state_t *state, uci_cmd_t cmd) { if (cmd.empty) { return; } if (strcmp(cmd.root, "isready") == 0) { state->current_state = UCI_STATE_PING; } else if (strcmp(cmd.root, "stop") == 0) { state->current_state = UCI_STATE_HALT; } else { printf("info violation\n"); } } void handle_halt(uci_state_t *state, uci_cmd_t cmd) { // TIMEOUT NOTICE: THE FOLLOWING BLOCK SHOULDN'T TAKE MORE THAN 1 SECONDS state->signal = UCI_SIGNAL_STOP; // --- state->current_state = UCI_STATE_IDLE; }