Add error checking and better reporting
This commit is contained in:
parent
02a0dd9763
commit
040148f782
47
main.c
47
main.c
@ -7,15 +7,13 @@
|
||||
|
||||
#include <assert.h>
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <sys/time.h>
|
||||
|
||||
#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;
|
||||
}
|
||||
|
37
puzz.c
37
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;
|
||||
|
8
puzz.h
8
puzz.h
@ -12,14 +12,16 @@
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
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
|
||||
|
Loading…
x
Reference in New Issue
Block a user