-
Notifications
You must be signed in to change notification settings - Fork 1
/
solve_mask.c
2142 lines (1850 loc) · 68.1 KB
/
solve_mask.c
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
/**
* @file
* Implements algorithms to solve sudoku puzzles.
*
* This program is a Sudoku solver.
* It proceeds with 4 logicals rules
* - cell exclusion
* - candidate exclusion
* - region exclusion
* - backtracking, only if the previous 3 rules have failed
*
* An article (below) issued Feb 01, 2006 explains the two firsts rules in detail :
* Sudoku & Graph Theory
*
* By Eytan Suchard, Raviv Yatom, and Eitan Shapir, Dr. Dobb's Journal
* Feb 01, 2006
* URL:http://www.ddj.com/cpp/184406436
*
* Eytan, Raviv, and Eitan are software engineers in Israel. They can be contacted
* at esuchard@012.net.il, ravivyatom@bezeqint .net, and eitans@ima.co.il,
* respectively.
*
* Sudoku is a logic puzzle in which there are 81 cells (vertices) filled with
* numbers between 1 and 9. In each row, the numbers 1,2,3,..,9 must appear without
* repetition. Likewise, the numbers 1,2,3,..,9 must appear without repetition in
* the columns. In addition to the row and column constraints, the numbers
* 1,2,3,..,9 must appear in the nine nonoverlapping 3×3 subsquares without
* repetition. So in short, the puzzle board is separated into nine blocks, with
* nine cells in each block.
*
* Two rules, "Chain Exclusion" and "Pile Exclusion", can be used to successfully
* to fill in missing numbers for solving logical Sudoku puzzles (together with
* region intersection analysis.)
* Illogical Sudoku puzzles can also be solved, but require guesses.
*
* We refer to possible numbers that should be assigned to a row, column, or one of
* the nine 3×3 subsquares as a "Permutation Bipartite Graph" or nodes. A node
* consists of a vector of n>1,n=2,3,4... vertices and all possible numbers that
* can be assigned to these vertices, such that there exists at least one possible
* match between the vertices of the vector and the numbers 1,2,...n.
* For example, the following are nodes:
*
* ({1,2,3,5},{2,3},{2,3,4},{3,4},{4,5}, n=5
* ({1,2,3,7},{3,6},{3,4},{1,4},{5,6,7},{4,6},{2,7},
* {8,9},{8,9}, n=9
*
* A possible match for the first vector is easy:
*
* 1 -> {1,2,3,5}
* 2 -> {2,3}
* 3 -> {2,3,4}
* 4 -> {3,4}
* 5 -> {4,5}
*
* A possible match for the second vector is more tricky:
*
* 2 -> {1,2,3,7}
* 3 -> {3,6}
* 4 -> {3,4}
* 1 -> {1,4}
* 5 -> {5,6,7}
* 6 -> {4,6}
* 7 -> {2,7}
* 8 -> {8,9}
* 9 -> {8,9}
*
* A number can be only assigned to a vertex that contains the possibility of
* assigning that number. For instance, only the following possibilities are
* accepted:
*
* 7 -> {2,7} or 2 -> {2,7}.
*
* Pile Exclusion and Chain Exclusion provide the basis of logical elimination
* rules.
*
* To understand Pile Exclusion, consider the following nodes:
*
* ({1,2,3,5},{3,6},{3,4},{5,6},{1,7,8,9},{4,6},{5,7,8,9},
* {4,6},{6,7,8,9},{1,4}, n=9
*
* The numbers 7,8,9 appear only in three vertices:
*
* {1,7,8,9},{5,7,8,9},{6,7,8,9}
*
* Because there is at least one possible match in the Permutation Bipartite Graph,
* one vertex will be matched to 7, one to 8, and one to 9. Thus, you can erase the
* other numbers from these three vertices to get the following three augmented
* vertices:
*
* {1,7,8,9} -> {7,8,9}
* {5,7,8,9} -> {7,8,9}
* {6,7,8,9} -> {7,8,9}
*
* and the entire Permutation Bipartite Graph becomes:
*
* ({1,2,3,5},{3,6},{3,4},{5,6},{7,8,9},{7,8,9},{4,6},
* {7,8,9},{1,4}), n=9
*
* As for Chain Exclusion, consider these nodes:
*
* ({1,2,3,7},{3,6},{3,4},{1,4},{5,6,7},{4,6},{2,7},{8,9},
* {8,9}, n=9
*
* In the second, third, and sixth positions in the vertices vector, you have:
*
* {3,6},{3,4},{4,6}
*
* Only the numbers 3,4,6 can be assigned to these vertices. From this, you infer
* that 3,4,6 are not a matching option in any of the remaining vertices. Thus, you
* can erase these numbers from all the other vertices, resulting in a new, more
* simple graph:
*
* ({1,2,7},{3,6},{3,4},{1},{5,7},{4,6},{2,7},{8,9},
* {8,9}, n=9
*
* You can do the same thing with {1}, so that the resulting graph is:
*
* ({2,7},{3,6},{3,4},{1},{5,7},{4,6},{2,7},{8,9},
* {8,9}, n=9
*
* Denis Berthier
* Pattern-Based Constraint Satisfaction and Logic Puzzles (c) 2012
* - For any valid Sudoku resolution rule, the rule deduced from it by permuting
* systematically the word "row" and "column" is valid.
*
* - For any valid Sudoku resolution rule mentioning only numbers, rows and columns
* (i.e. neither blocks nor squares nor any property referring to such objects),
* any rule deduced from it by any systematic permutation of the words "number",
* "row" and "column" is valid.
*
* - For any valid Sudoku resolution rule mentioning only numbers, rows and columns
* (i.e. neither blocks nor squares nor any property referring to such objects),
* if such rule displays a systematic symmetry between rows and columns but it can
* be proved without using the axiom on columns, then the rule deduced from it by
* systematically replacing the word "row" by "block" and the word "column" by
* "square" is valid.
*/
#define _XOPEN_SOURCE
#define _XOPEN_SOURCE_EXTENDED
/***********************************************************************************
* Author: Laurent Farhi *
* Name: solve.c *
* Language: C *
* Copyright (C) 2009, All rights reserved. *
* *
* CONTACT: *
* Email: lfarhi@sfr.fr *
* *
* LICENSE: *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 2 of the License, or *
* (at your option) any later version. *
* *
* This program is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU General Public License for more details. *
* *
* You should have received a copy of the GNU General Public License *
* along with this program; if not, write to the Free Software *
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA *
***********************************************************************************/
#include <stdlib.h>
#include <stdio.h>
#include <stdarg.h>
#include <string.h>
#include <ctype.h>
#include "solve.h"
#include "../knuth_dancing_links/dancing_links.h"
#include "finally.h"
#include <libintl.h>
#include <assert.h>
#ifdef __USE_GNU_GETTEXT
// Internationalization
// The library code doesn’t call setlocale (LC_ALL, ""). It’s the responsibility of the main program to set the locale.
#define PACKAGE "SUDOKU_SOLVER"
#define _(String) dgettext (PACKAGE, String)
#else
#define _(String) String
#define bindtextdomain(PACKAGE, String)
#endif
/// Version of the implementation.
#define SUDOKU_SOLVE_VERSION "2.1"
/// Maximum length of messages to be displayed.
#define SUDOKU_MAX_MESSAGE_LENGTH 10001
/// Append text to the end of a string.
/// @param [in] str String to be appended.
/// @param [in] size Maximum length of the string.
/// @param [in] ... Variable list of arguments following the printf convention.
static int
strnadd (char *str, size_t size, ...)
{
int ret;
va_list ap;
va_start (ap, size);
const char *format = va_arg (ap, const char *);
ret = vsnprintf (str + strlen (str), size - 1 - strlen (str), format, ap);
va_end (ap);
return ret;
}
#define MESSAGE_APPEND(rule, ...) \
strnadd (rule, sizeof(rule) / sizeof(*rule), __VA_ARGS__)
//snprintf (rule + strlen (rule), sizeof(rule) / sizeof(*rule) - 1 - strlen (rule), __VA_ARGS__)
//////// Event handler /////////
// Grid changed event
/// Definition of a list event handlers.
typedef struct sudoku_grid_event_handler_list
{
sudoku_grid_event_handler handler; ///< Function pointer
struct sudoku_grid_event_handler_list *next; ///< Pointer to the next element of the list
} sudoku_grid_event_handler_list;
/// Handlers to be called on grid initialization.
static sudoku_grid_event_handler_list *sudokuOnInitEventHandlers = 0;
/// Handlers to be called on grid change.
static sudoku_grid_event_handler_list *sudokuOnChangeEventHandlers = 0;
/// Handlers to be called on grid solved.
static sudoku_grid_event_handler_list *sudokuOnSolvedEventHandlers = 0;
void
sudoku_grid_event_handler_add (sudokuGridEventType type, sudoku_grid_event_handler handler)
{
sudokuGridEventType t[3] = { ON_INIT, ON_CHANGE, ON_SOLVED };
sudoku_grid_event_handler_list *const hls[3] =
{ sudokuOnInitEventHandlers, sudokuOnChangeEventHandlers, sudokuOnSolvedEventHandlers };
for (int i = 0; i < 3; i++)
{
for (sudoku_grid_event_handler_list * ptr = hls[i]; ptr; ptr = ptr->next)
if (ptr->handler == handler) // handler already registered
t[i] = 0;
if (type & t[i])
{
sudoku_grid_event_handler_list *const pev = malloc (sizeof (*pev));
if (pev == 0)
{
fprintf (stderr, _("Memory allocation error (%s, %s, %i)\n"), __func__, __FILE__, __LINE__);
exit (-1);
}
pev->handler = handler;
pev->next = 0;
if (hls[i] == 0)
{
switch (t[i])
{
case ON_INIT:
sudokuOnInitEventHandlers = pev;
break;
case ON_CHANGE:
sudokuOnChangeEventHandlers = pev;
break;
case ON_SOLVED:
sudokuOnSolvedEventHandlers = pev;
break;
}
}
else
{
sudoku_grid_event_handler_list *ptr;
for (ptr = hls[i]; ptr->next != 0; ptr = ptr->next)
if (ptr->handler == handler || ptr->next->handler == handler) // handler already registered
{
free (pev);
return;
}
ptr->next = pev;
}
}
}
}
/// Remove handler from the lists of handlers.
/// @param [in] type Types (or'ed) of handler to remove.
/// @param [in] handler Handler to be removed. 0 will remove all handlers.
void
sudoku_grid_event_handler_remove (sudokuGridEventType type, sudoku_grid_event_handler handler)
{
sudokuGridEventType t[3] = { ON_INIT, ON_CHANGE, ON_SOLVED };
sudoku_grid_event_handler_list *hls[3] =
{ sudokuOnInitEventHandlers, sudokuOnChangeEventHandlers, sudokuOnSolvedEventHandlers };
sudoku_grid_event_handler_list *ptr, *next;
for (int i = 0; i < 3; i++)
{
if (type & t[i])
{
if (!hls[i])
return;
while (hls[i] && (!handler || hls[i]->handler == handler))
{
ptr = hls[i]->next;
free (hls[i]);
hls[i] = ptr;
switch (t[i])
{
case ON_INIT:
sudokuOnInitEventHandlers = ptr;
break;
case ON_CHANGE:
sudokuOnChangeEventHandlers = ptr;
break;
case ON_SOLVED:
sudokuOnSolvedEventHandlers = ptr;
break;
}
}
if (!hls[i])
return;
for (ptr = hls[i]; ptr && ptr->next;)
{
if (ptr->next->handler == handler)
{
next = ptr->next->next;
free (ptr->next);
ptr->next = next;
}
else
ptr = ptr->next;
}
}
}
}
/// Call handler of type #ON_INIT.
/// @param [in] id Game identifier.
/// @param [in] evt_args Event arguments.
static void
sudoku_on_init (uintptr_t id, sudoku_grid_event_args evt_args)
{
for (sudoku_grid_event_handler_list * ptr = sudokuOnInitEventHandlers; ptr != 0; ptr = ptr->next)
if (ptr->handler)
(ptr->handler) (id, evt_args);
}
/// Call handler of type #ON_CHANGE.
/// @param [in] id Game identifier.
/// @param [in] evt_args Event arguments.
static void
sudoku_on_change (uintptr_t id, sudoku_grid_event_args evt_args)
{
for (sudoku_grid_event_handler_list * ptr = sudokuOnChangeEventHandlers; ptr != 0; ptr = ptr->next)
if (ptr->handler)
(ptr->handler) (id, evt_args);
}
/// Call handler of type #ON_SOLVED.
/// @param [in] id Game identifier.
/// @param [in] evt_args Event arguments.
static void
sudoku_on_solved (uintptr_t id, sudoku_grid_event_args evt_args)
{
for (sudoku_grid_event_handler_list * ptr = sudokuOnSolvedEventHandlers; ptr != 0; ptr = ptr->next)
if (ptr->handler)
(ptr->handler) (id, evt_args);
}
/// Definition of message handlers.
typedef struct sudoku_message_handler_list
{
sudoku_message_handler handler; ///< Pointer to handler function
struct sudoku_message_handler_list *next; ///< Pointer to the next element of the list.
} sudoku_message_handler_list;
/// Handlers to be called on message.
static sudoku_message_handler_list *sudokuOnMessageHandlers;
/// Add handler to the lists of handlers.
/// @param [in] handler Handler to be added.
void
sudoku_message_handler_add (sudoku_message_handler handler)
{
for (sudoku_message_handler_list * ptr = sudokuOnMessageHandlers; ptr; ptr = ptr->next)
if (ptr->handler == handler) // handler already registered
return;
sudoku_message_handler_list *const pev = malloc (sizeof (*pev));
if (pev == 0)
{
fprintf (stderr, _("Memory allocation error (%s, %s, %i)\n"), __func__, __FILE__, __LINE__);
exit (-1);
}
pev->handler = handler;
pev->next = 0;
if (sudokuOnMessageHandlers == 0)
sudokuOnMessageHandlers = pev;
else
{
sudoku_message_handler_list *ptr;
for (ptr = sudokuOnMessageHandlers; ptr->next != 0; ptr = ptr->next)
/* nothing */ ;
ptr->next = pev;
}
}
/// Remove handler to the lists of handlers.
/// @param[in] handler Handler to be removed.
void
sudoku_message_handler_remove (sudoku_message_handler handler)
{
sudoku_message_handler_list *ptr, *next;
if (!sudokuOnMessageHandlers)
return;
while (sudokuOnMessageHandlers && (!handler || sudokuOnMessageHandlers->handler == handler))
{
ptr = sudokuOnMessageHandlers->next;
free (sudokuOnMessageHandlers);
sudokuOnMessageHandlers = ptr;
}
if (!sudokuOnMessageHandlers)
return;
for (ptr = sudokuOnMessageHandlers; ptr && ptr->next;)
{
if (ptr->next->handler == handler)
{
next = ptr->next->next;
free (ptr->next);
ptr->next = next;
}
else
ptr = ptr->next;
}
}
/// Call handler on message.
/// @param[in] id Game identifier.
/// @param[in] evt_args Event arguments.
static void
sudoku_on_message (uintptr_t id, sudoku_message_args evt_args)
{
sudoku_message_handler_list *ptr = sudokuOnMessageHandlers;
for (ptr = sudokuOnMessageHandlers; ptr != 0; ptr = ptr->next)
if (ptr->handler)
(ptr->handler) (id, evt_args);
}
/// Constructs message arguments for handler.
/// @param[in] message Message to be emitted.
/// @param[in] verbosity Level of message.
/// @returns message argument.
static sudoku_message_args
get_message_args (const char *message, int verbosity)
{
sudoku_message_args sudokuMessageArgs;
sudokuMessageArgs.rule = message;
sudokuMessageArgs.verbosity = verbosity;
return (sudokuMessageArgs);
}
/// Clear all event handlers
void
sudoku_all_handlers_clear (void)
{
sudoku_grid_event_handler_remove (ON_INIT | ON_CHANGE | ON_SOLVED, 0);
sudoku_message_handler_remove (0);
}
/////////////////////////////////////////////////////////////////////////
///////////////////////////////// internationalization //////////////////
/////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////
///////////////////////////////// ELIMINATION METHOD ////////////////////
/////////////////////////////////////////////////////////////////////////
/// Array of number of bits sets for the integer value of the index of array.
/// @remark `unsigned int` is at least 16 bits in size
static unsigned int NB_BITS[1 << GRID_SIZE];
static unsigned int SUBSETS[1 << GRID_SIZE];
static unsigned int SUBSET_INDEX[GRID_SIZE + 1];
/// Alphabet.
static char ALPHABET[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
/// Digits.
static char DIGIT[] = "123456789abcdefghijklmnopqrstuvwxyz@";
/// Names of values.
static char VALUE_NAME[GRID_SIZE + 1];
/// Code of empty cell
enum
{
EMPTY_CELL = '0', // compile-time constant
};
/// Names of rows.
static char ROW_NAME[GRID_SIZE + 1];
/// Names of columns.
static char COLUMN_NAME[GRID_SIZE + 1];
/// Names of regions.
static char REGION_NAME[GRID_SIZE * 3][20];
/// Names of segments.
static char INTERSECTION_NAME[GRID_SIZE * SQUARE_SIZE * 2][50];
const GridReferential sudoku_grid_referential = { ROW_NAME, COLUMN_NAME, VALUE_NAME, EMPTY_CELL };
/// Definition of a cell.
typedef struct
{
/// Bit mask of possible values in the cell, amongst 9 (size of unsigned is at least 16 bits.)
unsigned int value;
/// Cell name
char name[3];
/// Set to 1 if the value of the cell is initially set.
char given;
} cell;
/// Definition of a region.
typedef struct
{
cell *cell[GRID_SIZE]; ///< The 9 cells of the region (row, column or square).
int changed; ///< Flag inidicating the region has been modified by application of a rule.
const char *name; ///< Name of the region, for displaying purpose.
struct _grid *grid; ///< owner grid
} region;
/// Definition of a segment (intersection of a square with a line or a column).
// An intersection (iii) between (e.g.) a square and a line
// 'i' indicates the cells at intersection
// '1' indicated the cells outside of the intersection in the square
// '2' indicated the cells outside of the intersection in the line
//
// ... 111 ...
// ... 111 ...
// 222 iii 222
//
// There as many intersections as nb_squares x nb_lines in a square + nb_squares x nb_columns in a square
// i.e. GRID_SIZE * SQUARE_SIZE * 2
typedef struct
{
cell *r1_cell[GRID_SIZE - SQUARE_SIZE]; ///< The 6 cells of the first region
cell *r2_cell[GRID_SIZE - SQUARE_SIZE]; ///< The 6 cells of the second region
int changed; ///< Flag inidicating the intersection has been modified by application of a rule.
const char *name; ///< Name of the intersection, for displaying purpose.
struct _grid *grid; ///< owner grid
} intersection;
/// Definition of a grid.
typedef struct _grid
{
uintptr_t id; ///< Grid identifier
cell cell[GRID_SIZE][GRID_SIZE]; ///< 81 cells
intersection intersection[GRID_SIZE * SQUARE_SIZE * 2]; ///< 27 groups of 3 horizontal cells + 27 groups of 3 vertical cells
region region[GRID_SIZE * 3]; ///< 9 rows, 9 columns, 9 squares
} grid;
/// Definition of counters for statistic purposes.
typedef struct
{
int nbSolutions; ///< Number of solutions found
int nbRules; ///< Number of rules
int backtrackingTries; ///< Number of backtracking hypothesis
int backtrackingLevel; ///< Backtracking depth
int backtrackingSteps; ///< Backtracking depth
int rC[GRID_SIZE]; ///< Number of candidate exclusion per depth
int rV[GRID_SIZE]; ///< Number of value exclusion per depth
int rR[GRID_SIZE]; ///< Number of region exclusion per depth
int rI; ///< Number of intersection exclusion
char theSolution[GRID_SIZE * GRID_SIZE][20]; ///< Last solution found
} counters;
/// Definition of region types.
typedef enum // Fixed constant values since the enumeration may be used in arithmetics
{
ROW = 0,
COLUMN = 1,
SQUARE = 2,
} regionType;
/// Converts a bit into a value.
/// @param[in] bit to be converted.
/// @return value
static char
VALUE (unsigned int bit)
{
if (NB_BITS[bit] != 1)
return 0;
else
for (const char *d = VALUE_NAME; *d && bit; (bit >>= 1), (d++))
if (bit & 1)
return *d;
return EMPTY_CELL;
}
/// Converts a bit pattern into values.
/// @param[in] bits pattern to be converted.
/// @return string of values.
static const char *
VALUES (unsigned int bits)
{
static char _v[GRID_SIZE * 2];
int pos = 0;
for (const char *d = VALUE_NAME; *d && bits; (bits >>= 1), (d++))
if (bits & 1)
{
_v[pos++] = *d;
_v[pos++] = ' ';
}
if (pos)
pos--;
_v[pos] = 0;
return _v;
}
static int grid_cell_changed (grid *, cell *);
static int grid_countEmptyCells (grid *);
/// Eliminates values from an intersection.
/// @param [in,out] inter Intersection
/// @param [in,out] stats Statistic data
/// @return Number of possible values in intersection
static int
intersection_skim (intersection * inter, counters * stats)
{
unsigned int values[2] = { 0, 0 };
for (int i = 0; i < GRID_SIZE - SQUARE_SIZE; i++)
{
values[0] |= inter->r1_cell[i]->value;
values[1] |= inter->r2_cell[i]->value;
}
unsigned int intersection = values[0] ^ values[1];
if (intersection)
{
stats->nbRules += NB_BITS[intersection];
stats->rI += NB_BITS[intersection];
if (sudokuOnMessageHandlers)
{
char rule[SUDOKU_MAX_MESSAGE_LENGTH] = "";
if (NB_BITS[intersection] > 1)
MESSAGE_APPEND (rule,
_("%s: the values (%s) can only lie in %s.\n"), inter->name, VALUES (intersection),
inter->name);
else
MESSAGE_APPEND (rule,
_("%s: the value (%s) can only lie in %s.\n"), inter->name, VALUES (intersection), inter->name);
if (*rule)
sudoku_on_message (inter->grid->id, get_message_args (rule, 1));
}
for (int i = 0; i < GRID_SIZE - SQUARE_SIZE; i++)
{
unsigned int oldval = inter->r1_cell[i]->value;
inter->r1_cell[i]->value &= ~intersection;
if (oldval != inter->r1_cell[i]->value)
if (grid_cell_changed (inter->grid, inter->r1_cell[i]))
{
int nbCells = GRID_SIZE * GRID_SIZE - grid_countEmptyCells (inter->grid);
sprintf (stats->theSolution[nbCells - 1], "%2i. %s=%c", nbCells, inter->r1_cell[i]->name,
VALUE (inter->r1_cell[i]->value));
}
}
for (int i = 0; i < GRID_SIZE - SQUARE_SIZE; i++)
{
unsigned int oldval = inter->r2_cell[i]->value;
inter->r2_cell[i]->value &= ~intersection;
if (oldval != inter->r2_cell[i]->value)
if (grid_cell_changed (inter->grid, inter->r2_cell[i]))
{
int nbCells = GRID_SIZE * GRID_SIZE - grid_countEmptyCells (inter->grid);
sprintf (stats->theSolution[nbCells - 1], "%2i. %s=%c", nbCells, inter->r2_cell[i]->name,
VALUE (inter->r2_cell[i]->value));
}
}
}
return NB_BITS[intersection];
}
/// Eliminates regions (rows and columns) for a value
/// @param [in] g Grid
/// @param [in] value Value to be removed.
/// @param [in,out] stats Statistic data
/// @return skimming depth
static int
value_skim (grid * g, unsigned int value, counters * stats)
{
unsigned int rows;
unsigned int columns;
unsigned int bits;
int stop = 0;
for (unsigned int depth = 1; depth <= GRID_SIZE && !stop; depth++)
{
for (unsigned int index = SUBSET_INDEX[depth - 1]; index < SUBSET_INDEX[depth]; index++)
{
bits = SUBSETS[index];
////////////////////////////////////////////
// row exclusion rule
////////////////////////////////////////////
rows = bits;
columns = 0;
for (unsigned int row = 0; row < GRID_SIZE; row++)
{
if (rows & 1)
for (unsigned int col = 0; col < GRID_SIZE; col++)
if (g->cell[row][col].value & (1 << (value - 1)))
columns |= (1 << col); // columns of all cells in 'rows' of subset which contain value
rows >>= 1;
}
if (NB_BITS[columns] < NB_BITS[bits])
return (-1); // Invalid grid
else if (NB_BITS[columns] == NB_BITS[bits])
{
// other lines than thoses of 'rows' don't contain value in those 'columns'
unsigned int skimLevel = 0;
unsigned int otherrows = ~bits;
for (unsigned int row = 0; row < GRID_SIZE; row++)
{
if (otherrows & 1)
{
unsigned int cols = columns;
for (unsigned int col = 0; col < GRID_SIZE; col++)
{
if (cols & 1)
{
unsigned int oldval = g->cell[row][col].value;
g->cell[row][col].value &= ~(1 << (value - 1));
if (oldval != g->cell[row][col].value)
{
skimLevel = NB_BITS[bits];
if (grid_cell_changed (g, &g->cell[row][col]))
{
int nbCells = GRID_SIZE * GRID_SIZE - grid_countEmptyCells (g);
sprintf (stats->theSolution[nbCells - 1], "%2i. %s=%c", nbCells, g->cell[row][col].name,
VALUE (g->cell[row][col].value));
}
if (g->cell[row][col].value == 0)
return (-1); // Invalid grid
}
}
cols >>= 1;
}
}
otherrows >>= 1;
}
if (skimLevel)
{
if (sudokuOnMessageHandlers)
{
unsigned int d = 0;
char noprint = 0;
if (NB_BITS[bits] == 1)
for (unsigned int rows = bits; rows; rows >>= 1, d++)
for (unsigned int col = 0; col < GRID_SIZE; col++)
if (g->cell[d][col].value & (1 << (value - 1)) && g->cell[d][col].given)
noprint = 1;
char rule[SUDOKU_MAX_MESSAGE_LENGTH] = "";
// Display:
char row_names[2 * NB_BITS[bits] + 1];
char col_names[2 * NB_BITS[bits] + 1];
d = 0;
for (unsigned int rows = bits; rows; rows >>= 1, d++)
if (rows & 1)
{
row_names[2 * NB_BITS[rows] - 2] = ' ';
row_names[2 * NB_BITS[rows] - 1] = ROW_NAME[d];
}
row_names[2 * NB_BITS[bits]] = '\0';
d = 0;
for (unsigned int cols = columns; cols; cols >>= 1, d++)
if (cols & 1)
{
col_names[2 * NB_BITS[cols] - 2] = ' ';
col_names[2 * NB_BITS[cols] - 1] = COLUMN_NAME[d];
}
col_names[2 * NB_BITS[columns]] = '\0';
if (NB_BITS[bits] > 1)
{
MESSAGE_APPEND (rule, _("Value %i in each one of the %i rows [%s] lie only in one of the columns [%s].\n\
-> Value %i in each one of the %i columns [%s] can only lie in the rows [%s].\n"), value, NB_BITS[bits], row_names, col_names, value, NB_BITS[bits], col_names, row_names);
sudoku_on_message (g->id, get_message_args (rule, 1));
}
else if (!noprint)
{
MESSAGE_APPEND (rule, _("Value %i in row [%s] lies only in column [%s].\n\
-> Value %i in column [%s] can only lie in the row [%s].\n"), value, row_names, col_names, value, col_names, row_names);
sudoku_on_message (g->id, get_message_args (rule, 3));
}
}
stats->nbRules++;
stats->rR[skimLevel - 1]++;
if (skimLevel > 1)
return (skimLevel);
else
stop = skimLevel;
} // if (skimLevel)
} // if (NB_BITS[values] == NB_BITS[bits])
////////////////////////////////////////////
// column exclusion rule
////////////////////////////////////////////
columns = bits;
rows = 0;
for (unsigned int col = 0; col < GRID_SIZE; col++)
{
if (columns & 1)
for (unsigned int row = 0; row < GRID_SIZE; row++)
if (g->cell[row][col].value & (1 << (value - 1)))
rows |= (1 << row); // columns of all cells in 'rows' of subset which contain value
columns >>= 1;
}
if (NB_BITS[rows] < NB_BITS[bits])
return (-1); // Invalid grid
else if (NB_BITS[rows] == NB_BITS[bits])
{
// other lines than thoses of 'rows' don't contain value in those 'columns'
unsigned int skimLevel = 0;
unsigned int othercols = ~bits;
for (unsigned int col = 0; col < GRID_SIZE; col++)
{
if (othercols & 1)
{
unsigned int lrows = rows;
for (unsigned int row = 0; row < GRID_SIZE; row++)
{
if (lrows & 1)
{
unsigned int oldval = g->cell[row][col].value;
g->cell[row][col].value &= ~(1 << (value - 1));
if (oldval != g->cell[row][col].value)
{
skimLevel = NB_BITS[bits];
if (grid_cell_changed (g, &g->cell[row][col]))
{
int nbCells = GRID_SIZE * GRID_SIZE - grid_countEmptyCells (g);
sprintf (stats->theSolution[nbCells - 1], "%2i. %s=%c", nbCells, g->cell[row][col].name,
VALUE (g->cell[row][col].value));
}
if (g->cell[row][col].value == 0)
return (-1); // Invalid grid
}
}
lrows >>= 1;
}
}
othercols >>= 1;
}
if (skimLevel)
{
if (sudokuOnMessageHandlers)
{
unsigned int d = 0;
char noprint = 0;
if (NB_BITS[bits] == 1)
for (unsigned int columns = bits; columns; columns >>= 1, d++)
for (unsigned int row = 0; row < GRID_SIZE; row++)
if (g->cell[row][d].value & (1 << (value - 1)) && g->cell[row][d].given)
noprint = 1;
char rule[SUDOKU_MAX_MESSAGE_LENGTH] = "";
// Display:
char row_names[2 * NB_BITS[bits] + 1];
char col_names[2 * NB_BITS[bits] + 1];
d = 0;
for (unsigned int lrows = rows; lrows; lrows >>= 1, d++)
if (lrows & 1)
{
row_names[2 * NB_BITS[lrows] - 2] = ' ';
row_names[2 * NB_BITS[lrows] - 1] = ROW_NAME[d];
}
row_names[2 * NB_BITS[rows]] = '\0';
d = 0;
for (unsigned int cols = bits; cols; cols >>= 1, d++)
if (cols & 1)
{
col_names[2 * NB_BITS[cols] - 2] = ' ';
col_names[2 * NB_BITS[cols] - 1] = COLUMN_NAME[d];
}
col_names[2 * NB_BITS[bits]] = '\0';
if (NB_BITS[bits] > 1)
{
MESSAGE_APPEND (rule, _("Value %i in each one of the %i columns [%s] lie only in one of the rows [%s].\n\
-> Value %i in each one of the %i rows [%s] can only lie in the columns [%s].\n"), value, NB_BITS[bits], col_names, row_names, value, NB_BITS[bits], row_names, col_names);
sudoku_on_message (g->id, get_message_args (rule, 1));
}
else if (!noprint)
{
MESSAGE_APPEND (rule, _("Value %i in column [%s] lies only in row [%s].\n\
-> Value %i in row [%s] can only lie in the column [%s].\n"), value, col_names, row_names, value, row_names, col_names);
sudoku_on_message (g->id, get_message_args (rule, 3));
}
}
stats->nbRules++;
stats->rR[skimLevel - 1]++;
if (skimLevel > 1)
return (skimLevel);
else
stop = skimLevel;
} // if (skimLevel)
} // if (NB_BITS[values] == NB_BITS[bits])
} // for (unsigned int index=SUBSET_INDEX[depth-1] ; index<SUBSET_INDEX[depth] ; index++)
} // for (unsigned int depth = 1 ; depth<=9 && !stop ; depth++)
return stop;
}
/// Eliminates values from a region.
/// @param [in,out] reg Region
/// @param [in,out] stats Statistic data
/// @return Number of possible values in region
static int
region_skim (region * reg, counters * stats)
{
unsigned int cells;
unsigned int values;
unsigned int bits;
int stop = 0;
for (unsigned int depth = 1; depth <= GRID_SIZE && !stop; depth++)
{
for (unsigned int index = SUBSET_INDEX[depth - 1]; index < SUBSET_INDEX[depth]; index++)
{
bits = SUBSETS[index];
////////////////////////////////////////////
// candidate exclusion rule
////////////////////////////////////////////
cells = bits;
values = 0;
for (unsigned int cell = 0; cell < GRID_SIZE; cell++)
{
if (cells & 1)
values |= reg->cell[cell]->value; // values of all cells in 'cells' of subset
cells >>= 1;
}
if (NB_BITS[values] < NB_BITS[bits])