Add simple contradiction-driven search mechanism

Gets an about 6% improvement
This commit is contained in:
Camden Dixie O'Brien 2025-03-22 13:33:38 +00:00
parent 4e9a787e36
commit 7156efc99c

76
main.c
View File

@ -104,6 +104,70 @@ static update_res_t update(state_t *state, int *x_out, int *y_out)
return FOUND_NOTHING;
}
static update_res_t
search_at(state_t *state, int x, int y, int *x_out, int *y_out)
{
update_res_t res;
state_t with_mine;
memcpy(&with_mine, state, sizeof(state_t));
with_mine.field[x][y] = MINE;
do {
int res_x, res_y;
switch (res = update(&with_mine, &res_x, &res_y)) {
case FOUND_MINE:
break;
case FOUND_SAFE:
with_mine.field[res_x][res_y] = SAFE;
break;
case FOUND_NOTHING:
break;
case FOUND_CONTRADICTION:
*x_out = x;
*y_out = y;
return FOUND_SAFE;
}
} while (res == FOUND_MINE);
state_t with_safe;
memcpy(&with_safe, state, sizeof(state_t));
with_safe.field[x][y] = SAFE;
do {
int res_x, res_y;
switch (res = update(&with_safe, &res_x, &res_y)) {
case FOUND_MINE:
break;
case FOUND_SAFE:
with_safe.field[res_x][res_y] = SAFE;
break;
case FOUND_NOTHING:
break;
case FOUND_CONTRADICTION:
state->field[x][y] = MINE;
return FOUND_MINE;
}
} while (res == FOUND_MINE);
return FOUND_NOTHING;
}
static update_res_t search(state_t *state, int *x_out, int *y_out)
{
for (int y = 0; y < HEIGHT; ++y) {
for (int x = 0; x < WIDTH; ++x) {
if (state->field[x][y] != UNKNOWN)
continue;
if (countadj(state->field, x, y, UNKNOWN) != MAX_ADJ) {
update_res_t res = search_at(state, x, y, x_out, y_out);
if (res == FOUND_MINE || res == FOUND_SAFE)
return res;
}
}
}
return FOUND_NOTHING;
}
static status_t solve(int *turns_out)
{
state_t state = { .mines = 0, .unknown = WIDTH * HEIGHT };
@ -123,7 +187,8 @@ static status_t solve(int *turns_out)
update_res_t res;
do {
res = update(&state, &x, &y);
assert(res != FOUND_CONTRADICTION);
if (res == FOUND_NOTHING)
res = search(&state, &x, &y);
} while (res == FOUND_MINE);
if (check(state.field) != OK) {
@ -169,12 +234,17 @@ int main(void)
}
}
if (nincorrect > 0) {
printf(
"Fail: %d incorrect! (%0.1f%%)\n", nincorrect,
(double)nincorrect / NRUNS);
return 1;
}
const double solved_prop = (double)nsolved / NRUNS;
const double incorrect_prop = (double)nincorrect / NRUNS;
const double first_prop = (double)nfirst / NRUNS;
const double solved_safe_start_prop = (double)nsolved / (NRUNS - nfirst);
printf("Solved %d (%0.1f%%)\n", nsolved, 100 * solved_prop);
printf("%d incorrect (%0.1f%%)\n", nincorrect, 100 * incorrect_prop);
printf("%d died on first turn (%0.1f%%)\n", nfirst, 100 * first_prop);
printf("%0.1f%% solved on safe start\n", 100 * solved_safe_start_prop);