1 // SUDOKU PUZZLE SOLVER
2 // press enter after each row, use '0' for empty cell
3
4 // zcc +cpm -vn -O3 -clib=new sudoku.c -o sudoku -create-app
5 // zcc +cpm -vn -SO3 -clib=sdcc_iy --max-allocs-per-node200000 sudoku.c -o sudoku -create-app
6
7 // zcc +zx -vn -startup=1 -O3 -clib=new sudoku.c -o sudoku -create-app
8 // zcc +zx -vn -startup=1 -SO3 -clib=sdcc_iy --max-allocs-per-node200000 sudoku.c -o sudoku -create-app
9
10 // use -DVERBOSE to print list of steps taken
11
12 #pragma printf = "%u %B"
13
14 #ifdef __SPECTRUM
15 #pragma output REGISTER_SP = -1 // do not change stack pointer
16 #endif
17
18 #pragma output CLIB_EXIT_STACK_SIZE = 0 // do not reserve space for registering atexit() functions
19 #pragma output CLIB_MALLOC_HEAP_SIZE = 0 // do not create malloc heap
20 #pragma output CLIB_STDIO_HEAP_SIZE = 0 // do not create stdio heap (cannot open files)
21
22 #include <stdio.h>
23 #include <stdlib.h>
24 #include <string.h>
25 #include <adt/p_list.h>
26 #include <obstack.h>
27 #include <stdint.h>
28
29 struct sudoku_cell
30 {
31 void *next; // doubly linked list links
32 void *prev;
33 int16_t state; // bits 15 = flag, 8:0 set indicates number possible
34 };
35
36 struct sudoku
37 {
38 struct sudoku_cell grid[81]; // 9x9 board
39 p_list_t remain[10]; // remain[N] holds list of cells with N possible numbers
40 };
41
42 struct sudoku puzzle;
43
44 uint16_t changes;
45
46 const uint8_t count[512] = {
47 0, 1, 1, 2, 1, 2, 2, 3, 1, 2, 2, 3, 2, 3, 3, 4, 1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5, /* 0.. 31 */
48 1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5, 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6, /* 32.. 63 */
49 1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5, 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6, /* 64.. 95 */
50 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6, 3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7, /* 96..127 */
51 1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5, 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6, /* 128..159 */
52 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6, 3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7, /* 160..191 */
53 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6, 3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7, /* 192..224 */
54 3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7, 4, 5, 5, 6, 5, 6, 6, 7, 5, 6, 6, 7, 6, 7, 7, 8, /* 225..255 */
55 1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5, 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6, /* 256..287 */
56 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6, 3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7, /* 288..319 */
57 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6, 3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7, /* 320..351 */
58 3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7, 4, 5, 5, 6, 5, 6, 6, 7, 5, 6, 6, 7, 6, 7, 7, 8, /* 352..383 */
59 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6, 3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7, /* 384..415 */
60 3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7, 4, 5, 5, 6, 5, 6, 6, 7, 5, 6, 6, 7, 6, 7, 7, 8, /* 416..447 */
61 3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7, 4, 5, 5, 6, 5, 6, 6, 7, 5, 6, 6, 7, 6, 7, 7, 8, /* 448..479 */
62 4, 5, 5, 6, 5, 6, 6, 7, 5, 6, 6, 7, 6, 7, 7, 8, 5, 6, 6, 7, 6, 7, 7, 8, 6, 7, 7, 8, 7, 8, 8, 9, /* 480..511 */
63 };
64
65 char stack_space[30*sizeof(struct sudoku)+6];
66
67 struct obstack *stack;
68
mark(struct sudoku_cell * sc,uint16_t pstate)69 void mark(struct sudoku_cell *sc, uint16_t pstate)
70 {
71 if ((sc->state < 0) || ((sc->state & pstate) == 0))
72 return;
73
74 p_list_remove(&puzzle.remain[count[sc->state]], sc);
75 sc->state &= ~pstate;
76 p_list_push_front(&puzzle.remain[count[sc->state]], sc);
77
78 ++changes;
79
80 return;
81 }
82
place(struct sudoku_cell * sc,uint16_t pstate,uint8_t peers)83 uint16_t place(struct sudoku_cell *sc, uint16_t pstate, uint8_t peers)
84 {
85 uint8_t i;
86 divu_t coord;
87 struct sudoku_cell *end, *v;
88
89 // COMPUTE ROW, COL
90
91 _divu_(&coord, (uint16_t)(sc - puzzle.grid), 9);
92
93 // coord.quot = row
94 // coord.rem = column
95
96 // VISIT ROW
97
98 if (peers & 0x4)
99 {
100 v = &puzzle.grid[coord.quot * 9];
101 end = v + 9;
102
103 while (v < end)
104 {
105 mark(v,pstate);
106 ++v;
107 }
108 }
109
110 // VISIT COLUMN
111
112 if (peers & 0x2)
113 {
114 v = &puzzle.grid[coord.rem];
115 end = v + 81;
116
117 while (v < end)
118 {
119 mark(v,pstate);
120 v += 9;
121 }
122 }
123
124 // VISIT BLOCK
125
126 if (peers & 0x1)
127 {
128 v = &puzzle.grid[(coord.quot/3)*27 + (coord.rem/3)*3];
129 end = v + 21;
130
131 i = 0;
132 while (v < end)
133 {
134 mark(v,pstate);
135
136 if (++i == 3)
137 {
138 i = 0;
139 v += 7;
140 }
141 else ++v;
142 }
143 }
144
145 return p_list_empty(&puzzle.remain[0]);
146 }
147
buddy(struct sudoku_cell * sc1,struct sudoku_cell * sc2)148 uint8_t buddy(struct sudoku_cell *sc1, struct sudoku_cell *sc2)
149 {
150 divu_t coord1, coord2;
151 uint8_t peers;
152
153 _divu_(&coord1, (uint16_t)(sc1 - puzzle.grid), 9);
154 _divu_(&coord2, (uint16_t)(sc2 - puzzle.grid), 9);
155
156 // coord.quot = row
157 // coord.rem = column
158
159 peers = (coord1.quot/3 == coord2.quot/3) && (coord1.rem/3 == coord2.rem/3);
160 peers += (coord1.rem == coord2.rem) * 2;
161 peers += (coord1.quot == coord2.quot) * 4;
162
163 return peers;
164 }
165
solve_sudoku(void)166 uint16_t solve_sudoku(void)
167 {
168 #ifdef VERBOSE
169 divu_t coord;
170 #endif
171 uint16_t j;
172 uint8_t i;
173 struct sudoku_cell *sc2, *sc1;
174
175 process_solo:
176
177 // PLAY CELLS WITH ONE REMAINING CHOICE
178
179 while (sc1 = p_list_pop_front(&puzzle.remain[1]))
180 {
181 #ifdef VERBOSE
182 _divu_(&coord, (uint16_t)(sc1 - puzzle.grid), 9);
183 printf("Placing %u at (%u,%u)\n", ffs(sc1->state), coord.quot+1, coord.rem+1);
184 #endif
185
186 sc1->state |= 0x8000;
187 if (!place(sc1, sc1->state & 0x01ff, 0x7)) return 0;
188 }
189
190 // INVESTIGATE TUPLES - PAIRS
191
192 #ifdef VERBOSE
193 printf("Investigating Pairs...\n");
194 #endif
195
196 do
197 {
198 changes = 0;
199
200 for (sc2 = p_list_front(&puzzle.remain[2]); sc2; sc2 = p_list_next(sc2))
201 {
202 for (sc1 = p_list_next(sc2); sc1; sc1 = p_list_next(sc1))
203 {
204 if ((sc1->state == sc2->state) && (i = buddy(sc1,sc2)))
205 {
206 #ifdef VERBOSE
207 _divu_(&coord, (uint16_t)(sc1 - puzzle.grid), 9);
208 printf("Pairs at (%u,%u) and ", coord.quot+1, coord.rem+1);
209
210 _divu_(&coord, (uint16_t)(sc2 - puzzle.grid), 9);
211 printf("(%u,%u)\n", coord.quot+1, coord.rem+1);
212 #endif
213
214 sc1->state |= 0x8000;
215 sc2->state |= 0x8000;
216
217 if (!place(sc1, sc1->state & 0x01ff, i)) return 0;
218
219 sc1->state &= 0x01ff;
220 sc2->state &= 0x01ff;
221
222 if (!p_list_empty(&puzzle.remain[1])) goto process_solo;
223 }
224 }
225 }
226
227 } while (changes);
228
229 // TRIAL AND ERROR
230
231 for (i=2; i<10; ++i)
232 if (sc1 = p_list_front(&puzzle.remain[i])) break;
233
234 if (sc1 == 0) return 1;
235
236 j=1;
237 do
238 {
239 if (sc1->state & j)
240 {
241 if ((sc2 = obstack_copy(stack, &puzzle, sizeof(struct sudoku))) == 0)
242 {
243 #ifdef VERBOSE
244 printf("Out of Memory!\n");
245 #endif
246 return 0;
247 }
248
249 #ifdef VERBOSE
250 printf("Trial and Error... %09B\n -> ", sc1->state);
251 #endif
252
253 p_list_remove(&puzzle.remain[count[sc1->state]], sc1);
254 sc1->state = j;
255 p_list_push_front(&puzzle.remain[1], sc1);
256
257 if (solve_sudoku()) return 1;
258
259 memcpy(&puzzle, sc2, sizeof(struct sudoku));
260 obstack_free(stack, sc2);
261
262 #ifdef VERBOSE
263 printf("Backtrack... %09B\n", sc1->state);
264 #endif
265 }
266
267 } while ((j*=2) & 0x1ff);
268
269 return 0;
270 }
271
main()272 main()
273 {
274 uint8_t i, j;
275 int16_t c;
276 struct sudoku_cell *sc;
277
278 stack = (struct obstack *)(stack_space);
279 obstack_init(stack, sizeof(stack_space));
280
281 #ifdef __SPECTRUM
282 printf("\x0cSUDOKU SOLVER\nby aralbrec @ z88dk.org\n");
283 #else
284 printf("\nSUDOKU SOLVER\nby aralbrec @ z88dk.org\n");
285 #endif
286
287 while (1)
288 {
289 memset(&puzzle, 0, sizeof(struct sudoku));
290 obstack_free(stack, 0);
291
292 printf("\n\nEnter Puzzle:\n\n");
293 fflush(stdin);
294
295 sc = &puzzle.grid[0];
296 for (i=0; i<9; ++i)
297 {
298 for (j=0; j<9; ++j)
299 {
300 while ((c = getchar()) == '\n') ;
301 if (c == EOF) return 0;
302
303 if ((c>='1') && (c<='9'))
304 {
305 sc->state = 1 << (c-'1');
306 p_list_push_front(&puzzle.remain[1], sc);
307 }
308 else
309 {
310 sc->state = 0x1ff;
311 p_list_push_front(&puzzle.remain[9], sc);
312 }
313
314 ++sc;
315 }
316 }
317
318 if (solve_sudoku())
319 {
320 printf("\n+-----+-----+-----+\n");
321
322 sc = &puzzle.grid[0];
323 for(i=0; i<9; ++i)
324 {
325 for(j=0; j<9; ++j)
326 {
327 printf("|%u", ffs(sc->state));
328 ++sc;
329 }
330
331 printf("|\n");
332
333 if ((i+1)%3 == 0) printf("+-----+-----+-----+\n");
334 }
335 }
336 else printf("\n\nNO SOLUTION\n\n");
337 }
338 }
339