#include #include #include "uci/state.h" void option_setting_combo( option_setting_t *target, char *option_name, char **combinations, int combinations_count, int default_index, combo_t *combo ) { strncpy(target->option_name, option_name, 32); target->type = OPTION_COMBO; target->data.combo = (option_combo_setting_t) { combinations, combinations_count, default_index }; target->value.combo = combo; *combo = default_index; } void option_setting_spin( option_setting_t *target, const char *option_name, int min, int max, int default_value, spin_t *spin ) { strncpy(target->option_name, option_name, 32); target->type = OPTION_SPIN; target->data.spin = (option_spin_setting_t) { min, max, default_value }; target->value.spin = spin; *spin = default_value; } void option_setting_check( option_setting_t *target, const char *option_name, bool default_value, check_t *check ) { strncpy(target->option_name, option_name, 32); target->type = OPTION_CHECK; target->data.check_default = default_value; target->value.check = check; *check = default_value; } void option_setting_string( option_setting_t *target, const char *option_name, const char *default_value, str_t *string ) { strncpy(target->option_name, option_name, 32); target->type = OPTION_STRING; target->data.string_default = default_value; target->value.string = string; string->length = strlen(default_value); string->data = malloc(string->length); memcpy(string->data, default_value, string->length); } void option_setting_button( option_setting_t *target, const char *option_name, button_t *button ) { strncpy(target->option_name, option_name, 32); target->type = OPTION_BUTTON; target->value.button = button; *button = false; } // 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 && "Failed to print the options"); } } void uci_state_init(uci_state_t *state) { state->signal = UCI_SIGNAL_NONE; state->current_state = UCI_STATE_INITIAL; strncpy(state->name, "Gacrux", 32); strncpy(state->author, "Aargh Rai ", 32); int k = 0; option_setting_spin( state->option_settings + k++, "Threads", 1, 5, 1, &state->threads ); option_setting_spin( state->option_settings + k++, "Hash", 0, 512, 256, &state->hash ); option_setting_button( state->option_settings + k++, "Clear Hash", &state->clear_hash ); option_setting_check( state->option_settings + k++, "UCI_ShowCurrLine", false, &state->uci_showcurrline ); option_setting_check( state->option_settings + k++, "UCI_ShowRefutations", false, &state->uci_showrefutations ); option_setting_check( state->option_settings + k++, "UCI_LimitStrength", false, &state->uci_limitstrength ); option_setting_spin( state->option_settings + k++, "UCI_Elo", 100, 3500, 800, &state->uci_elo ); option_setting_check( state->option_settings + k++, "UCI_AnalyseMode", false, &state->uci_analysemode ); option_setting_string( state->option_settings + k++, "UCI_Opponent", "", &state->uci_opponent ); option_setting_string( state->option_settings + k++, "UCI_EngineAbout", "Gacrux by Aargh Rai, Checkout https://git.aarghrai.com/gacrux", &state->uci_engineabout ); option_setting_string( state->option_settings + k++, "UCI_SetPositionValue", "", &state->uci_setpositionvalue ); } void uci_state_deinit(uci_state_t *state) { int settings_count = sizeof(state->option_settings)/sizeof(option_setting_t); for (int i = 0; i < settings_count; i++) { option_setting_t *s = &state->option_settings[i]; if (s->type == OPTION_STRING && s->value.string && s->value.string->data) { free(s->value.string->data); s->value.string->data = NULL; } } } void apply_option(uci_state_t *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 && "Failed to apply the option"); } memcpy(state->option_settings + i, &setting, sizeof(setting)); return; } if (state->debug) { printf("info invalid option\n"); } } #ifdef TEST_MOD #include bool test_uci_state_init_defaults() { uci_state_t state; uci_state_init(&state); bool ok = true; ok &= state.signal == UCI_SIGNAL_NONE; ok &= state.current_state == UCI_STATE_INITIAL; ok &= state.threads == 1; ok &= state.hash == 256; ok &= state.clear_hash == false; ok &= state.uci_showcurrline == false; ok &= state.uci_showrefutations == false; ok &= state.uci_limitstrength == false; ok &= state.uci_elo == 800; ok &= state.uci_analysemode == false; ok &= strcmp(state.name, "Gacrux") == 0; ok &= strcmp(state.author, "Aargh Rai ") == 0; uci_state_deinit(&state); return ok; } bool test_apply_option_spin_valid() { uci_state_t state; uci_state_init(&state); apply_option(&state, "Threads", "4"); bool ok = state.threads == 4; apply_option(&state, "Hash", "128"); ok &= state.hash == 128; uci_state_deinit(&state); return ok; } bool test_apply_option_spin_below_min() { uci_state_t state; uci_state_init(&state); apply_option(&state, "Threads", "0"); bool ok = state.threads == 1; uci_state_deinit(&state); return ok; } bool test_apply_option_spin_above_max() { uci_state_t state; uci_state_init(&state); apply_option(&state, "Threads", "100"); bool ok = state.threads == 1; uci_state_deinit(&state); return ok; } bool test_apply_option_check() { uci_state_t state; uci_state_init(&state); apply_option(&state, "UCI_AnalyseMode", "true"); bool ok = state.uci_analysemode == true; apply_option(&state, "UCI_AnalyseMode", "false"); ok &= state.uci_analysemode == false; uci_state_deinit(&state); return ok; } bool test_apply_option_button() { uci_state_t state; uci_state_init(&state); apply_option(&state, "Clear Hash", ""); bool ok = state.clear_hash == true; uci_state_deinit(&state); return ok; } bool test_apply_option_string() { uci_state_t state; uci_state_init(&state); apply_option(&state, "UCI_Opponent", "Carlsen"); bool ok = true; ok &= state.uci_opponent.length == 7; ok &= memcmp(state.uci_opponent.data, "Carlsen", 7) == 0; uci_state_deinit(&state); return ok; } bool test_apply_option_unknown_ignored() { uci_state_t state; uci_state_init(&state); state.debug = false; apply_option(&state, "Nonexistent", "42"); bool ok = true; uci_state_deinit(&state); return ok; } bool test_option_settings_count() { uci_state_t state; uci_state_init(&state); int count = sizeof(state.option_settings) / sizeof(option_setting_t); bool ok = count == 11; uci_state_deinit(&state); return ok; } bool test_option_settings_types() { uci_state_t state; uci_state_init(&state); bool ok = true; ok &= state.option_settings[0].type == OPTION_SPIN; // Threads ok &= state.option_settings[1].type == OPTION_SPIN; // Hash ok &= state.option_settings[2].type == OPTION_BUTTON; // Clear Hash ok &= state.option_settings[3].type == OPTION_CHECK; // UCI_ShowCurrLine ok &= state.option_settings[4].type == OPTION_CHECK; // UCI_ShowRefutations ok &= state.option_settings[5].type == OPTION_CHECK; // UCI_LimitStrength ok &= state.option_settings[6].type == OPTION_SPIN; // UCI_Elo ok &= state.option_settings[7].type == OPTION_CHECK; // UCI_AnalyseMode ok &= state.option_settings[8].type == OPTION_STRING; // UCI_Opponent ok &= state.option_settings[9].type == OPTION_STRING; // UCI_EngineAbout ok &= state.option_settings[10].type == OPTION_STRING;// UCI_SetPositionValue uci_state_deinit(&state); return ok; } #endif