1 /* Copyright (c) 2006 Scott Gasch
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
7 * http://www.apache.org/licenses/LICENSE-2.0
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
26 ULONG g_uSolutions = 0;
30 PositionIsLegal(POSITION *, BOOL);
34 ShowPossibilities(BITV bv)
39 Return a text representation of the possible moves at a square.
51 static char bits[] = "*123456789";
56 memset(&sz, 0, sizeof(sz));
58 for (u = 1; u < 10; u++)
60 if (bv & (1 << (u - 1)))
72 DumpBoard(POSITION *pos)
77 Draw a text representation of the playing board.
81 POSITION *pos : position
93 if ((c % 9) == 0) printf("\n");
94 if ((c == 27) || (c == 54)) printf("-----------------------------------------------------------------------------\n");
95 if (((c % 3) == 0) && ((c % 9) != 0)) printf(" | ");
96 if (pos->rgSquare[c].uValue)
98 printf("[%u] ", (unsigned)pos->rgSquare[c].uValue);
103 ShowPossibilities(pos->rgSquare[c].bvPossibilities));
108 printf("%u empty squares...\n", (unsigned)pos->uEmpty);
116 DumpBoardHtml(POSITION *pos)
121 Draw a text representation of the playing board.
125 POSITION *pos : position
137 if (pos->rgSquare[c].uValue)
139 printf("%u:%u\n", (unsigned)c,
140 (unsigned)pos->rgSquare[c].uValue);
144 printf("%u empty squares...\n", (unsigned)pos->uEmpty);
148 DumpBoardSimple(POSITION *pos) {
153 if (pos->rgSquare[c].uValue) {
154 printf("%u", (unsigned)pos->rgSquare[c].uValue);
164 LiftValue(POSITION *pos, COOR sq)
166 ULONG uValue = pos->rgSquare[sq].uValue;
167 BITV bvMask = (1UL << (uValue - 1));
173 // Make sure it's full
175 if (IS_EMPTY(uValue))
181 // uValue is a possibility on the file/rank/group again.
184 ASSERT(cCol == pos->rgSquare[sq].cCol);
187 pos->rgSquare[c].bvPossibilities |= bvMask;
191 ASSERT(cRow == pos->rgSquare[sq].cRow);
194 pos->rgSquare[c].bvPossibilities |= bvMask;
197 FOREACH_GROUP(c, pos->rgSquare[sq].cGroup, x)
199 pos->rgSquare[c].bvPossibilities |= bvMask;
203 pos->rgSquare[sq].uValue = 0;
204 pos->rgSquare[sq].bvPossibilities |= bvMask;
205 pos->bvRemainingByGroup[pos->rgSquare[sq].cGroup] |= bvMask;
206 pos->bvRemainingByCol[pos->rgSquare[sq].cCol] |= bvMask;
207 pos->bvRemainingByRow[pos->rgSquare[sq].cRow] |= bvMask;
215 PlaceValue(POSITION *pos, COOR sq, ULONG uValue, BOOL fReduce)
220 Put a number in a square.
224 POSITION *pos : board
226 ULONG uValue : number
230 BOOL : TRUE if move is legal, FALSE if it leads to an invalid position
234 BITV bvMask = ~(1UL << (uValue - 1));
240 // Make sure it's empty
242 if (!IS_EMPTY(pos->rgSquare[sq].uValue))
244 if (pos->rgSquare[sq].uValue == uValue)
255 // There can only be one uValue per file/rank/group
258 ASSERT(cCol == pos->rgSquare[sq].cCol);
261 pos->rgSquare[c].bvPossibilities &= bvMask;
265 ASSERT(cRow == pos->rgSquare[sq].cRow);
268 pos->rgSquare[c].bvPossibilities &= bvMask;
271 FOREACH_GROUP(c, pos->rgSquare[sq].cGroup, x)
273 pos->rgSquare[c].bvPossibilities &= bvMask;
276 ASSERT(pos->uEmpty > 0);
278 ASSERT(pos->uEmpty < 81);
279 pos->rgSquare[sq].uValue = uValue;
280 pos->rgSquare[sq].bvPossibilities = (1 << (uValue - 1));
281 pos->bvRemainingByGroup[pos->rgSquare[sq].cGroup] &= bvMask;
282 pos->bvRemainingByCol[pos->rgSquare[sq].cCol] &= bvMask;
283 pos->bvRemainingByRow[pos->rgSquare[sq].cRow] &= bvMask;
285 return(PositionIsLegal(pos, fReduce));
297 Given a bit, return its number.
326 Count the number of bits in a bitvector.
334 ULONG : population count
340 ASSERT(!(x & 0xFFFFFE00));
351 LegalValue(POSITION *pos, COOR c)
354 if (!IS_EMPTY(pos->rgSquare[c].uValue))
356 return(pos->rgSquare[c].uValue);
359 x = pos->rgSquare[c].bvPossibilities;
360 if ((x & 0x1FF) == 0) return(0);
363 y = 1 << (rand() % 9);
366 return(BitNumber(y));
376 PositionIsLegal(POSITION *pos, BOOL fReduce)
381 Determine if a position is legal
385 POSITION *pos : board
389 BOOL : TRUE on success, FALSE on failure
395 BITV bvMaskFull, bvMaskPoss;
399 printf("Is this legal?\n");
400 DumpBoardSimple(pos);
401 printf("----------------------------------------------------------\n");
406 if (IS_EMPTY(pos->rgSquare[c].uValue))
408 x = pos->rgSquare[c].bvPossibilities;
412 printf("Nothing possible at sq %u\n", c);
420 // Note: I don't combine the two loops here because this way we
421 // detect invalid positions (empty squares w/ no legal moves in
422 // them) earlier instead of recursing on obviously bad positions.
426 if (IS_EMPTY(pos->rgSquare[c].uValue))
428 x = pos->rgSquare[c].bvPossibilities;
432 printf("%u at %u is forced...\n", BitNumber(x), c);
434 if ((TRUE == fReduce) &&
435 (FALSE == PlaceValue(pos, c, BitNumber(x), fReduce)))
438 printf("Couldn't place forced %u at sq %u\n",
448 // If there's only one square in a row|col|group that can be
449 // a given number, make the move.
451 for (x = 1; x <= 256; x <<= 1)
453 for (c = 0; c < 9; c++)
458 if (IS_EMPTY(pos->rgSquare[sq].uValue) &&
459 (pos->rgSquare[sq].bvPossibilities & x))
463 if (uCount > 1) break;
469 printf("%u at square %u is forced...\n", BitNumber(x), cOnly);
471 if ((TRUE == fReduce) &&
472 (FALSE == PlaceValue(pos, cOnly, BitNumber(x), fReduce)))
481 if (IS_EMPTY(pos->rgSquare[sq].uValue) &&
482 (pos->rgSquare[sq].bvPossibilities & x))
486 if (uCount > 1) break;
492 printf("%u at square %u is forced...\n", BitNumber(x), cOnly);
494 if ((TRUE == fReduce) &&
495 (FALSE == PlaceValue(pos, cOnly, BitNumber(x), fReduce)))
502 FOREACH_GROUP(sq, c, y)
504 if (IS_EMPTY(pos->rgSquare[sq].uValue) &&
505 (pos->rgSquare[sq].bvPossibilities & x))
509 if (uCount > 1) break;
515 printf("%u at square %u is forced...\n", BitNumber(x), cOnly);
517 if ((TRUE == fReduce) &&
518 (FALSE == PlaceValue(pos, cOnly, BitNumber(x), fReduce)))
526 for (c = 0; c < 9; c++)
528 bvMaskPoss = bvMaskFull = 0;
531 bvMaskPoss |= pos->rgSquare[sq].bvPossibilities;
532 if (!IS_EMPTY(pos->rgSquare[sq].uValue))
534 ASSERT(pos->rgSquare[sq].bvPossibilities ==
535 (1 << pos->rgSquare[sq].uValue));
536 if (bvMaskFull & pos->rgSquare[sq].bvPossibilities)
539 printf("Two %u's in row %u.\n", pos->rgSquare[sq].uValue,
544 bvMaskFull |= pos->rgSquare[sq].bvPossibilities;
547 if (bvMaskPoss != 0x1FF)
550 printf("Not everything is possible in row %u (%x).\n",
556 bvMaskPoss = bvMaskFull = 0;
559 bvMaskPoss |= pos->rgSquare[sq].bvPossibilities;
560 if (!IS_EMPTY(pos->rgSquare[sq].uValue))
562 ASSERT(pos->rgSquare[sq].bvPossibilities ==
563 (1 << pos->rgSquare[sq].uValue));
564 if (bvMaskFull & pos->rgSquare[sq].bvPossibilities)
567 printf("Two %u's in col %u.\n", pos->rgSquare[sq].uValue,
572 bvMaskFull |= pos->rgSquare[sq].bvPossibilities;
575 if (bvMaskPoss != 0x1FF)
578 printf("Not everything is possible in col %u (%x).\n",
584 bvMaskPoss = bvMaskFull = 0;
585 FOREACH_GROUP(sq, c, y)
587 bvMaskPoss |= pos->rgSquare[sq].bvPossibilities;
588 if (!IS_EMPTY(pos->rgSquare[sq].uValue))
590 ASSERT(pos->rgSquare[sq].bvPossibilities ==
591 (1 << pos->rgSquare[sq].uValue));
592 if (bvMaskFull & pos->rgSquare[sq].bvPossibilities)
595 printf("Two %u's in group %u.\n", pos->rgSquare[sq].uValue,
600 bvMaskFull |= pos->rgSquare[sq].bvPossibilities;
603 if (bvMaskPoss != 0x1FF)
606 printf("Not everything is possible in group %u (%x).\n",
617 InitializePosition(POSITION *pos)
622 Initialize a position to empty.
626 POSITION *pos : position
635 memset(pos, 0, sizeof(POSITION));
639 pos->rgSquare[c].bvPossibilities = 0x1FF;
640 pos->rgSquare[c].cGroup = g_cGroup[c];
641 pos->rgSquare[c].cRow = ROW(c);
642 pos->rgSquare[c].cCol = COL(c);
645 for (c = 0; c < 9; c++)
647 pos->bvRemainingByRow[c] = 0x1FF;
648 pos->bvRemainingByCol[c] = 0x1FF;
649 pos->bvRemainingByGroup[c] = 0x1FF;
654 typedef struct _FEWEST
658 BITV bvPossibilities;
663 Sort(FEWEST *p, ULONG uLen)
668 Selection sort to put the FEWEST array in order... this is so that
669 that when we make a guess we are guessing at the square with the
670 fewest possible choices.
674 FEWEST *p : start of array
675 ULONG uLen : number of elements in it
687 for (u = 0; u < uLen; u++)
690 for (v = u + 1; v < uLen; v++)
692 if (p[v].uBitCount < p[uMinPos].uBitCount)
706 Solve(POSITION *pos, ULONG uDepth)
711 Recursively solve a suduko position.
715 POSITION *pos : position
716 ULONG uDepth : number of ply from root
720 BOOL : TRUE if solved, FALSE if no solution exists
733 printf("Depth %u (%u node%s):\n", uDepth,
735 (g_uNodes != 1) ? "" : "s");
736 DumpBoardSimple(pos);
737 printf("---------------------------------------------------\n");
741 // Find the square with the fewest possibilities
746 sFewest[c].bvPossibilities = pos->rgSquare[c].bvPossibilities;
747 sFewest[c].uBitCount = BitCount(pos->rgSquare[c].bvPossibilities);
748 if ((pos->rgSquare[c].uValue == 0) && (sFewest[c].uBitCount == 0))
750 ASSERT(!sFewest[c].bvPossibilities);
752 printf("%u: Found inconsistency at square %u.\n", uDepth, c);
764 if (IS_EMPTY(pos->rgSquare[sFewest[v].c].uValue)) {
765 ASSERT(sFewest[v].uBitCount > 0);
766 for (u = 1; u <= 9; u++) {
769 // Only make guesses that are legal. Don't "guess"
770 // the same thing as a prior solution.
772 if ((sFewest[v].bvPossibilities & (1 << (u - 1))) &&
773 ((g_uSolutions == 0) ||
774 (g_Solution.rgSquare[sFewest[v].c].uValue != u))) {
775 memcpy(&p, pos, sizeof(p));
778 printf("%u: Guessing %u at square %u\n",
779 uDepth, u, sFewest[v].c);
781 if ((FALSE == PlaceValue(pos, sFewest[v].c, u, TRUE)) ||
782 (FALSE == Solve(pos, uDepth + 1)))
785 // Unmake the guess move.
788 printf("%u: Bad guess (%u at %u), taking it back.\n",
789 uDepth, u, sFewest[v].c);
791 memcpy(pos, &p, sizeof(p));
794 // We've learned that the guess is wrong, mask it
795 // off the possibilities bitv.
797 pos->rgSquare[sFewest[v].c].bvPossibilities &=
801 // Are we in a screwed up state now after masking
802 // off that bit? If so something above us in the
803 // callstack is screwed up.
805 if (pos->rgSquare[sFewest[v].c].bvPossibilities == 0)
808 printf("%u: Nothing possible at square %u.\n",
809 uDepth, sFewest[v].c);
817 // This move leads to a win. Count it as a
818 // solution and carry on.
821 printf("%u: Guess of %u at square %u leads to a "
823 uDepth, u, sFewest[v].c);
826 if (g_uSolutions == 1)
828 memcpy(pos, &p, sizeof(p));
838 if (0 == pos->uEmpty)
843 printf("%u: Puzzle is solved, solution number %u\n",
844 uDepth, g_uSolutions);
845 DumpBoardSimple(pos);
847 if (g_uSolutions == 1)
849 memcpy(&g_Solution, pos, sizeof(POSITION));
860 GeneratePuzzle(BOOL fHard, POSITION *pos)
868 1, 7, 12, 14, 17, 27, 31, 35, 37,40, 43,
869 45, 49, 53, 63, 66, 68, 71, 73, 79, 0 };
878 InitializePosition(pos);
883 // Place a number, try to solve it, repeat...
885 while(pos->uEmpty > 45)
888 if (IS_EMPTY(pos->rgSquare[c].uValue))
890 v = LegalValue(pos, c);
894 // See if the rest can be solved by deduction...
896 memcpy(&p, pos, sizeof(p));
897 if ((TRUE == PlaceValue(pos, c, v, TRUE)) &&
900 memcpy(pos, &p, sizeof(p));
901 pos->rgSquare[c].uValue = v;
910 // Throw some random numbers out there on the board...
913 while(cSeed[u] != 0) {
914 if (IS_EMPTY(pos->rgSquare[cSeed[u]].uValue))
916 v = LegalValue(pos, cSeed[u]);
919 (void)PlaceValue(pos, cSeed[u], v, TRUE);
925 // Solve the puzzle within these constraints...
927 g_uSolutions = g_uGuesses = g_uNodes = 0;
928 if (TRUE == Solve(pos, 0))
931 // Now start taking away values until you get a puzzle
932 // that is still uniquely solvable but requires
938 if (!IS_EMPTY(pos->rgSquare[c].uValue)) {
939 InitializePosition(&p);
942 (!IS_EMPTY(pos->rgSquare[x].uValue))) {
944 pos->rgSquare[x].uValue, FALSE);
947 ASSERT(p.uEmpty - 1 == pos->uEmpty);
948 g_uSolutions = g_uGuesses = g_uNodes = 0;
949 if ((TRUE == Solve(&p, 0)) && (g_uSolutions == 1))
952 memcpy(pos, &p, sizeof(p));
953 if ((g_uGuesses > 5) &&
955 (pos->uEmpty > 55)) {
956 printf("%u guesses, %u nodes.\n",
957 g_uGuesses, g_uNodes);
979 main(int argc, char *argv[])
1001 InitializePosition(&pos);
1003 memset(buf, 0, sizeof(buf));
1007 printf("Enter board: ");
1008 scanf("%255s", buf);
1012 if (!strcmp(argv[1], "--create-easy"))
1014 GeneratePuzzle(FALSE, &pos);
1015 DumpBoardHtml(&pos);
1016 DumpBoardSimple(&pos);
1019 else if (!strcmp(argv[1], "--create-hard"))
1021 GeneratePuzzle(TRUE, &pos);
1022 DumpBoardHtml(&pos);
1023 DumpBoardSimple(&pos);
1028 strncpy(buf, argv[1], 255);
1041 if (isdigit(*p) && (*p != '0'))
1043 if (FALSE == PlaceValue(&pos, c, *p - '0', TRUE))
1046 (unsigned)c, (unsigned)(*p - '0'));
1055 g_uSolutions = g_uGuesses = g_uNodes = 0;
1056 if (TRUE == Solve(&pos, 0)) {
1057 memcpy(&pos, &g_Solution, sizeof(pos));
1058 DumpBoardHtml(&pos);
1059 printf("%u solutions, %u nodes, %u guesses.\n",
1060 g_uSolutions, g_uNodes, g_uGuesses);
1064 DumpBoardHtml(&pos);
1065 printf("No solution found...\n");