Skip to content

Commit 213428a

Browse files
committed
fix guess-n-check, brute force linked dependencies
1 parent 636b6cf commit 213428a

File tree

1 file changed

+100
-40
lines changed

1 file changed

+100
-40
lines changed

sudoku/sudoku.c

Lines changed: 100 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -17,15 +17,14 @@ static_assert(sizeof(Cell) * 8 > BOARD_SIZE, "Cell width not big enough!");
1717

1818
static const Cell UNKNOWN = (1 << BOARD_SIZE) - 1;
1919

20-
void copyBoard(const Cell src[/*BOARD_SIZE*/][BOARD_SIZE], Cell dest[/*BOARD_SIZE*/][BOARD_SIZE]);
21-
bool changed(const Cell src[/*BOARD_SIZE*/][BOARD_SIZE], Cell dest[/*BOARD_SIZE*/][BOARD_SIZE]);
2220
bool isComplete(const Cell board[/*BOARD_SIZE*/][BOARD_SIZE]);
21+
bool isDifferent(const Cell lhs[/*BOARD_SIZE*/][BOARD_SIZE], const Cell rhs[/*BOARD_SIZE*/][BOARD_SIZE]);
22+
bool isChanged(const Cell src[/*BOARD_SIZE*/][BOARD_SIZE], Cell dest[/*BOARD_SIZE*/][BOARD_SIZE]);
23+
void copyBoard(const Cell src[/*BOARD_SIZE*/][BOARD_SIZE], Cell dest[/*BOARD_SIZE*/][BOARD_SIZE]);
24+
void accumulate(const Cell src[/*BOARD_SIZE*/][BOARD_SIZE], Cell dest[/*BOARD_SIZE*/][BOARD_SIZE]);
2325

24-
void column(Cell board[/*BOARD_SIZE*/][BOARD_SIZE], size_t c, Cell* set[/*BOARD_SIZE*/]);
25-
void row(Cell board[/*BOARD_SIZE*/][BOARD_SIZE], size_t r, Cell* set[/*BOARD_SIZE*/]);
26-
void block(Cell board[/*BOARD_SIZE*/][BOARD_SIZE], size_t b, Cell* set[/*BOARD_SIZE*/]);
27-
28-
bool solveNaked(Cell board[/*BOARD_SIZE*/][BOARD_SIZE]);
26+
typedef struct LinkedCell { struct LinkedCell* prev; size_t row; size_t col; } LinkedCell;
27+
bool solveAtDepth(int depth, LinkedCell* prev, Cell board[/*BOARD_SIZE*/][BOARD_SIZE]);
2928

3029
int bitNum(Cell c) { for (int i = 0; ; ++i) if (1 << (i - 1) >= c) return i; }
3130
void printBoard(const Cell board[/*BOARD_SIZE*/][BOARD_SIZE], bool pretty)
@@ -86,36 +85,80 @@ int main(int argc, char* argv[])
8685
}
8786
}
8887

89-
bool valid, complete;
9088
Cell prev_board[BOARD_SIZE][BOARD_SIZE] = { { 0 } };
91-
while ((valid = solveNaked(board)) && !(complete = isComplete(board)) && changed(board, prev_board)) {
92-
for (size_t i = 0; i < BOARD_SIZE; ++i) {
93-
for (size_t j = 0; j < BOARD_SIZE; ++j) {
94-
Cell accum[BOARD_SIZE][BOARD_SIZE] = { { 0 } };
95-
for (Cell c = 1; c < UNKNOWN; c <<= 1) {
96-
Cell guess[BOARD_SIZE][BOARD_SIZE];
97-
copyBoard(board, guess);
98-
guess[i][j] &= c;
99-
if (guess[i][j] == 0) continue;
100-
if (solveNaked(guess)) {
101-
for (size_t i = 0; i < BOARD_SIZE; ++i) {
102-
for (size_t j = 0; j < BOARD_SIZE; ++j) {
103-
accum[i][j] |= guess[i][j];
104-
}
105-
}
106-
}
107-
}
108-
if (changed(accum, board)) goto break_outer_l;
109-
}
89+
bool valid = false, complete = false;
90+
int max_depth = 0;
91+
while (isChanged(board, prev_board)) {
92+
for (int depth = 0; depth <= BOARD_SIZE * BOARD_SIZE; ++depth) {
93+
if (depth > max_depth) max_depth = depth;
94+
/*if (PRINT_DEBUG)*/ printf("Solving @ depth %i.\n", depth);
95+
96+
valid = solveAtDepth(depth, NULL, board);
97+
if (!valid || isDifferent(board, prev_board)) break;
11098
}
111-
break_outer_l:;
99+
complete = isComplete(board);
100+
if (!valid || complete) break;
112101
}
113102

114-
printf("%s, %s result found! Took %i iterations.\n",
115-
valid ? "Valid" : "Invalid", complete ? "Complete" : "Incomplete", num_iters);
103+
printf("%s, %s result found! Took %i iterations, max search depth %i.\n",
104+
valid ? "Valid" : "Invalid", complete ? "Complete" : "Incomplete", num_iters, max_depth);
116105
printBoard(board, complete);
117106
}
118107

108+
int countBits(Cell val);
109+
110+
bool guessPossibilities(LinkedCell* guessable, Cell board[/*BOARD_SIZE*/][BOARD_SIZE],
111+
Cell accum[/*BOARD_SIZE*/][BOARD_SIZE]);
112+
113+
114+
bool solveAtDepth(int depth, LinkedCell* prev, Cell board[/*BOARD_SIZE*/][BOARD_SIZE])
115+
{
116+
if (depth == 0) {
117+
Cell accum[BOARD_SIZE][BOARD_SIZE] = { { 0 } };
118+
if (!guessPossibilities(prev, board, accum)) return false;
119+
if (/*PRINT_DEBUG && */isChanged(accum, board)) printf("Made progress!\n");
120+
return true;
121+
}
122+
const bool has_prev = prev != NULL;
123+
for (size_t i = has_prev ? prev->row : 0; i < BOARD_SIZE; ++i) {
124+
for (size_t j = has_prev ? prev->col : 0; j < BOARD_SIZE; ++j) {
125+
if (has_prev && i == prev->row && j == prev->col) continue;
126+
if (countBits(board[i][j] <= 1)) continue;
127+
LinkedCell cell = { .prev = prev, .row = i, .col = j };
128+
if (!solveAtDepth(depth - 1, &cell, board)) return false;
129+
}
130+
}
131+
return true;
132+
}
133+
134+
bool solveNaked(Cell board[/*BOARD_SIZE*/][BOARD_SIZE]);
135+
136+
bool guessPossibilities(LinkedCell* guessable, Cell board[/*BOARD_SIZE*/][BOARD_SIZE],
137+
Cell accum[/*BOARD_SIZE*/][BOARD_SIZE])
138+
{
139+
if (guessable == NULL) {
140+
Cell guess[BOARD_SIZE][BOARD_SIZE];
141+
copyBoard(board, guess);
142+
bool valid = solveNaked(guess);
143+
if (valid) accumulate(guess, accum);
144+
return valid;
145+
}
146+
bool any_valid = false;
147+
Cell* cell = &board[guessable->row][guessable->col];
148+
const Cell orig = *cell;
149+
for (Cell c = 1; c <= UNKNOWN; c <<= 1) {
150+
if (!(c & orig)) continue;
151+
*cell = c;
152+
if (guessPossibilities(guessable->prev, board, accum)) any_valid = true;
153+
}
154+
*cell = orig;
155+
return any_valid;
156+
}
157+
158+
void column(Cell board[/*BOARD_SIZE*/][BOARD_SIZE], size_t c, Cell* set[/*BOARD_SIZE*/]);
159+
void row(Cell board[/*BOARD_SIZE*/][BOARD_SIZE], size_t r, Cell* set[/*BOARD_SIZE*/]);
160+
void block(Cell board[/*BOARD_SIZE*/][BOARD_SIZE], size_t b, Cell* set[/*BOARD_SIZE*/]);
161+
119162
bool solveByCells(Cell* cells[/*BOARD_SIZE*/]);
120163
bool solveByPossibilities(Cell* cells[/*BOARD_SIZE*/]);
121164

@@ -125,7 +168,7 @@ bool solveNaked(Cell board[/*BOARD_SIZE*/][BOARD_SIZE])
125168
GroupGetter groupers[] = {column, row, block, NULL};
126169

127170
Cell prev_board[BOARD_SIZE][BOARD_SIZE] = { { 0 } };
128-
while (changed(board, prev_board)) {
171+
while (isChanged(board, prev_board)) {
129172
++num_iters;
130173
Cell* cells[BOARD_SIZE];
131174
for (GroupGetter* groupCells = &groupers[0]; *groupCells != NULL; ++groupCells) {
@@ -151,12 +194,29 @@ bool solveNaked(Cell board[/*BOARD_SIZE*/][BOARD_SIZE])
151194
return true;
152195
}
153196

154-
void copyBoard(const Cell src[/*BOARD_SIZE*/][BOARD_SIZE], Cell dest[/*BOARD_SIZE*/][BOARD_SIZE])
197+
bool isComplete(const Cell board[/*BOARD_SIZE*/][BOARD_SIZE])
155198
{
156-
changed(src, dest);
199+
for (size_t i = 0; i < BOARD_SIZE; ++i) {
200+
for (size_t j = 0; j < BOARD_SIZE; ++j) {
201+
if (countBits(board[i][j]) != 1) {
202+
return false;
203+
}
204+
}
205+
}
206+
return true;
157207
}
158208

159-
bool changed(const Cell src[/*BOARD_SIZE*/][BOARD_SIZE], Cell dest[/*BOARD_SIZE*/][BOARD_SIZE])
209+
bool isDifferent(const Cell lhs[/*BOARD_SIZE*/][BOARD_SIZE], const Cell rhs[/*BOARD_SIZE*/][BOARD_SIZE])
210+
{
211+
for (size_t i = 0; i < BOARD_SIZE; ++i) {
212+
for (size_t j = 0; j < BOARD_SIZE; ++j) {
213+
if (lhs[i][j] != rhs[i][j]) return true;
214+
}
215+
}
216+
return false;
217+
}
218+
219+
bool isChanged(const Cell src[/*BOARD_SIZE*/][BOARD_SIZE], Cell dest[/*BOARD_SIZE*/][BOARD_SIZE])
160220
{
161221
bool res = false;
162222
for (size_t i = 0; i < BOARD_SIZE; ++i) {
@@ -170,18 +230,18 @@ bool changed(const Cell src[/*BOARD_SIZE*/][BOARD_SIZE], Cell dest[/*BOARD_SIZE*
170230
return res;
171231
}
172232

173-
int countBits(Cell val);
233+
void copyBoard(const Cell src[/*BOARD_SIZE*/][BOARD_SIZE], Cell dest[/*BOARD_SIZE*/][BOARD_SIZE])
234+
{
235+
isChanged(src, dest);
236+
}
174237

175-
bool isComplete(const Cell board[/*BOARD_SIZE*/][BOARD_SIZE])
238+
void accumulate(const Cell src[/*BOARD_SIZE*/][BOARD_SIZE], Cell dest[/*BOARD_SIZE*/][BOARD_SIZE])
176239
{
177240
for (size_t i = 0; i < BOARD_SIZE; ++i) {
178241
for (size_t j = 0; j < BOARD_SIZE; ++j) {
179-
if (countBits(board[i][j]) != 1) {
180-
return false;
181-
}
242+
dest[i][j] |= src[i][j];
182243
}
183244
}
184-
return true;
185245
}
186246

187247
void column(Cell board[/*BOARD_SIZE*/][BOARD_SIZE], size_t c, Cell* set[/*BOARD_SIZE*/])

0 commit comments

Comments
 (0)