diff --git a/main.c b/main.c index 6d103cd..655fe50 100644 --- a/main.c +++ b/main.c @@ -7,15 +7,13 @@ #include #include -#include #include #include #include #include -#define NRUNS 1000 - -enum { UNKNOWN = 0xfe, KILLER = 0xfd }; +#define NRUNS 10000 +#define MAX_ADJ 8 typedef enum { FOUND_MINE, @@ -60,12 +58,14 @@ static void getadj(puzz_t field, int *x, int *y, uint8_t val) static update_res_t update(state_t *state, int *x_out, int *y_out) { state->mines = state->unknown = 0; + for (int y = 0; y < HEIGHT; ++y) { for (int x = 0; x < WIDTH; ++x) { state->mines += state->field[x][y] == MINE ? 1 : 0; state->unknown += state->field[x][y] == UNKNOWN ? 1 : 0; } } + for (int y = 0; y < HEIGHT; ++y) { for (int x = 0; x < WIDTH; ++x) { if (state->field[x][y] == UNKNOWN || state->field[x][y] == MINE) @@ -93,7 +93,7 @@ static update_res_t update(state_t *state, int *x_out, int *y_out) return FOUND_NOTHING; } -static status_t solve(void) +static status_t solve(int *turns_out) { state_t state = { .mines = 0, .unknown = WIDTH * HEIGHT }; memset(state.field, UNKNOWN, sizeof(puzz_t)); @@ -102,7 +102,9 @@ static status_t solve(void) int y = rand() % HEIGHT; status_t status; + int turns = 0; do { + ++turns; if (state.field[x][y] != MINE && (status = probe(x, y, state.field)) == DEAD) break; @@ -112,12 +114,20 @@ static status_t solve(void) update_res = update(&state, &x, &y); while (update_res == FOUND_MINE); + if (check(state.field) != OK) { + printf("Incorrect inference! State:\n"); + print(state.field); + printsoln(); + return INCORRECT; + } + if (update_res == FOUND_NOTHING) { x = rand() % WIDTH; y = rand() % HEIGHT; } - } while (state.mines < NMINES); + } while (state.mines < NMINES || state.unknown > 0); + *turns_out = turns; return status; } @@ -130,14 +140,31 @@ int main(void) } srand(tv.tv_usec); - int nsolved = 0; + int nsolved = 0, nfirst = 0, nincorrect = 0, turns; for (int i = 0; i < NRUNS; ++i) { gen(); - nsolved += solve() == OK ? 1 : 0; + switch (solve(&turns)) { + case DEAD: + if (turns == 1) + ++nfirst; + break; + case OK: + ++nsolved; + break; + case INCORRECT: + ++nincorrect; + break; + } } - const double prop = (double)nsolved / NRUNS; - printf("Solved %d/%d (%0.1f%%)\n", nsolved, NRUNS, 100 * prop); + 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); return 0; } diff --git a/puzz.c b/puzz.c index 2f39c03..e797830 100644 --- a/puzz.c +++ b/puzz.c @@ -38,17 +38,35 @@ void gen(void) } } -void print(void) +void print(puzz_t puzz) { - puts("Solution:"); for (int y = 0; y < HEIGHT; ++y) { - for (int x = 0; x < WIDTH; ++x) - putchar(soln[x][y] == MINE ? 'x' : '0' + soln[x][y]); + for (int x = 0; x < WIDTH; ++x) { + char c; + switch (puzz[x][y]) { + case MINE: + c = 'x'; + break; + case UNKNOWN: + c = '.'; + break; + default: + c = '0' + puzz[x][y]; + break; + } + putchar(c); + } putchar('\n'); } putchar('\n'); } +void printsoln(void) +{ + puts("Solution:"); + print(soln); +} + static void scan_copy(int x, int y, puzz_t out) { assert(x >= 0 && x < WIDTH); @@ -84,6 +102,17 @@ status_t probe(int x, int y, puzz_t out) return OK; } +status_t check(puzz_t puzz) +{ + for (int y = 0; y < HEIGHT; ++y) { + for (int x = 0; x < WIDTH; ++x) { + if (puzz[x][y] != UNKNOWN && puzz[x][y] != soln[x][y]) + return INCORRECT; + } + } + return OK; +} + int countadj(puzz_t field, int x, int y, uint8_t val) { int n = 0; diff --git a/puzz.h b/puzz.h index 5a052ba..34e66ce 100644 --- a/puzz.h +++ b/puzz.h @@ -12,14 +12,16 @@ #include -enum { MINE = 0xff }; +enum { MINE = 0xff, UNKNOWN = 0xfe }; typedef uint8_t puzz_t[WIDTH][HEIGHT]; -typedef enum { DEAD, OK } status_t; +typedef enum { DEAD, OK, INCORRECT } status_t; void gen(void); -void print(void); +void print(puzz_t puzz); +void printsoln(void); status_t probe(int x, int y, puzz_t out); +status_t check(puzz_t puzz); int countadj(puzz_t field, int x, int y, uint8_t val); #endif