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