diff --git a/sud.c b/sud.c index 2723a2d..5b6d331 100644 --- a/sud.c +++ b/sud.c @@ -22,12 +22,15 @@ #include #include -#define FILLP_RCP 3 +#define REM_PROB_NUMER 2 +#define REM_PROB_DENOM 3 + +#define MAX_FILL_ATTEMPTS 32 static void initposs(struct sudoku *sud) { - for (unsigned r = 0; r < SIDELEN; ++r) { - for (unsigned c = 0; c < SIDELEN; ++c) { + for (unsigned r = 0; r < NDIGITS; ++r) { + for (unsigned c = 0; c < NDIGITS; ++c) { sud->cells[r][c].det = false; for (unsigned i = 0; i < NDIGITS; ++i) sud->cells[r][c].pvals[i] = true; @@ -35,21 +38,66 @@ static void initposs(struct sudoku *sud) } } +static void clear(struct sudoku *sud, unsigned r, unsigned c) +{ + unsigned tr, tc, val; + + /* Set undetermined with all possible values */ + sud->cells[r][c].det = false; + for (unsigned i = 0; i < NDIGITS; ++i) + sud->cells[r][c].pvals[i] = true; + + /* Update cell's possible values based off column. */ + for (tr = 0; tr < NDIGITS; ++tr) { + if (tr == r || !sud->cells[tr][c].det) + continue; + val = sud->cells[tr][c].val; + sud->cells[r][c].pvals[val] = false; + } + + /* Update possible values of cells in same row. */ + for (tc = 0; tc < NDIGITS; ++tc) { + if (tc == c || !sud->cells[r][tc].det) + continue; + val = sud->cells[r][tc].val; + sud->cells[r][c].pvals[val] = false; + } + + /* Update possible values of cells in same segment. */ + const unsigned segr0 = SEGLEN * (r / SEGLEN); + const unsigned segc0 = SEGLEN * (c / SEGLEN); + for (tr = segr0; tr < segr0 + SEGLEN; ++tr) { + for (tc = segc0; tc < segc0 + SEGLEN; ++tc) { + if ((tr == r && tc == c) || !sud->cells[tr][tc].det) + continue; + val = sud->cells[tr][tc].val; + sud->cells[r][c].pvals[val] = false; + } + } +} + void gen(struct sudoku *sud) { + /* Generate a completed sudoku. */ +retry: initposs(sud); + for (unsigned r = 0; r < NDIGITS; ++r) { + for (unsigned c = 0; c < NDIGITS; ++c) { + unsigned val, n = 0; + do { + val = (unsigned)(rand() % NDIGITS); + ++n; + if (n >= MAX_FILL_ATTEMPTS) + goto retry; + } while (update(sud, r, c, val) == NOT_ALLOWED); + } + } - for (unsigned r = 0; r < SIDELEN; ++r) { - for (unsigned c = 0; c < SIDELEN; ++c) { - if (rand() % FILLP_RCP == 0) { - assert(!sud->cells[r][c].det); - - unsigned val, n = 0; - do { - val = (unsigned)(rand() % NDIGITS); - ++n; - } while (update(sud, r, c, val) == NOT_ALLOWED); - } + /* Remove cells with probability of `1 / REMOVE_PROB_RECIP`. */ + for (unsigned r = 0; r < NDIGITS; ++r) { + for (unsigned c = 0; c < NDIGITS; ++c) { + if (rand() % REM_PROB_DENOM < REM_PROB_NUMER) + clear(sud, r, c); } } } @@ -66,14 +114,14 @@ enum update_res update(struct sudoku *sud, unsigned r, unsigned c, unsigned val) return NOT_ALLOWED; /* Update possible values of cells in same column. */ - for (tr = 0; tr < SIDELEN; ++tr) { + for (tr = 0; tr < NDIGITS; ++tr) { if (tr == r || sud->cells[tr][c].det) continue; sud->cells[tr][c].pvals[val] = false; } /* Update possible values of cells in same row. */ - for (tc = 0; tc < SIDELEN; ++tc) { + for (tc = 0; tc < NDIGITS; ++tc) { if (tc == c || sud->cells[r][tc].det) continue; sud->cells[r][tc].pvals[val] = false; @@ -99,7 +147,7 @@ enum update_res update(struct sudoku *sud, unsigned r, unsigned c, unsigned val) void print(const struct sudoku *sud) { - for (unsigned r = 0; r < SIDELEN; ++r) { + for (unsigned r = 0; r < NDIGITS; ++r) { /* * Print horizontal divider if on a segment boundary (but not * at the start). @@ -107,7 +155,7 @@ void print(const struct sudoku *sud) if (r != 0 && r % SEGLEN == 0) puts("------+-------+------"); - for (unsigned c = 0; c < SIDELEN; ++c) { + for (unsigned c = 0; c < NDIGITS; ++c) { /* * Print vertical divider if on a segment boundary (but * not at the start). diff --git a/sud.h b/sud.h index ec976e1..40178a7 100644 --- a/sud.h +++ b/sud.h @@ -21,7 +21,6 @@ #include -#define SIDELEN 9 #define SEGLEN 3 #define NDIGITS 9 @@ -34,7 +33,7 @@ struct cellstate { }; struct sudoku { - struct cellstate cells[SIDELEN][SIDELEN]; + struct cellstate cells[NDIGITS][NDIGITS]; }; enum update_res { NOT_ALLOWED, ALREADY_DET, OK };