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.
27 ULONG g_uSolutions = 0;
31 PositionIsLegal(POSITION *, BOOL);
35 ShowPossibilities(BITV bv)
40 Return a text representation of the possible moves at a square.
52 static char bits[] = "*123456789";
57 memset(&sz, 0, sizeof(sz));
59 for (u = 1; u < 10; u++)
61 if (bv & (1 << (u - 1)))
73 DumpBoard(POSITION *pos)
78 Draw a text representation of the playing board.
82 POSITION *pos : position
94 if ((c % 9) == 0) printf("\n");
95 if ((c == 27) || (c == 54)) printf("-----------------------------------------------------------------------------\n");
96 if (((c % 3) == 0) && ((c % 9) != 0)) printf(" | ");
97 if (pos->rgSquare[c].uValue)
99 printf("[%u] ", (unsigned)pos->rgSquare[c].uValue);
104 ShowPossibilities(pos->rgSquare[c].bvPossibilities));
109 printf("%u empty squares...\n", (unsigned)pos->uEmpty);
117 DumpBoardHtml(POSITION *pos)
122 Draw a text representation of the playing board.
126 POSITION *pos : position
138 if (pos->rgSquare[c].uValue)
140 printf("%u:%u\n", (unsigned)c,
141 (unsigned)pos->rgSquare[c].uValue);
145 printf("%u empty squares...\n", (unsigned)pos->uEmpty);
149 DumpBoardSimple(POSITION *pos) {
154 if (pos->rgSquare[c].uValue) {
155 printf("%u", (unsigned)pos->rgSquare[c].uValue);
165 LiftValue(POSITION *pos, COOR sq)
167 ULONG uValue = pos->rgSquare[sq].uValue;
168 BITV bvMask = (1UL << (uValue - 1));
174 // Make sure it's full
176 if (IS_EMPTY(uValue))
182 // uValue is a possibility on the file/rank/group again.
185 ASSERT(cCol == pos->rgSquare[sq].cCol);
188 pos->rgSquare[c].bvPossibilities |= bvMask;
192 ASSERT(cRow == pos->rgSquare[sq].cRow);
195 pos->rgSquare[c].bvPossibilities |= bvMask;
198 FOREACH_GROUP(c, pos->rgSquare[sq].cGroup, x)
200 pos->rgSquare[c].bvPossibilities |= bvMask;
204 pos->rgSquare[sq].uValue = 0;
205 pos->rgSquare[sq].bvPossibilities |= bvMask;
206 pos->bvRemainingByGroup[pos->rgSquare[sq].cGroup] |= bvMask;
207 pos->bvRemainingByCol[pos->rgSquare[sq].cCol] |= bvMask;
208 pos->bvRemainingByRow[pos->rgSquare[sq].cRow] |= bvMask;
216 PlaceValue(POSITION *pos, COOR sq, ULONG uValue, BOOL fReduce)
221 Put a number in a square.
225 POSITION *pos : board
227 ULONG uValue : number
231 BOOL : TRUE if move is legal, FALSE if it leads to an invalid position
235 BITV bvMask = ~(1UL << (uValue - 1));
241 // Make sure it's empty
243 if (!IS_EMPTY(pos->rgSquare[sq].uValue))
245 if (pos->rgSquare[sq].uValue == uValue)
256 // There can only be one uValue per file/rank/group
259 ASSERT(cCol == pos->rgSquare[sq].cCol);
262 pos->rgSquare[c].bvPossibilities &= bvMask;
266 ASSERT(cRow == pos->rgSquare[sq].cRow);
269 pos->rgSquare[c].bvPossibilities &= bvMask;
272 FOREACH_GROUP(c, pos->rgSquare[sq].cGroup, x)
274 pos->rgSquare[c].bvPossibilities &= bvMask;
277 ASSERT(pos->uEmpty > 0);
279 ASSERT(pos->uEmpty < 81);
280 pos->rgSquare[sq].uValue = uValue;
281 pos->rgSquare[sq].bvPossibilities = (1 << (uValue - 1));
282 pos->bvRemainingByGroup[pos->rgSquare[sq].cGroup] &= bvMask;
283 pos->bvRemainingByCol[pos->rgSquare[sq].cCol] &= bvMask;
284 pos->bvRemainingByRow[pos->rgSquare[sq].cRow] &= bvMask;
286 return(PositionIsLegal(pos, fReduce));
298 Given a bit, return its number.
327 Count the number of bits in a bitvector.
335 ULONG : population count
341 ASSERT(!(x & 0xFFFFFE00));
352 LegalValue(POSITION *pos, COOR c)
355 if (!IS_EMPTY(pos->rgSquare[c].uValue))
357 return(pos->rgSquare[c].uValue);
360 x = pos->rgSquare[c].bvPossibilities;
361 if ((x & 0x1FF) == 0) return(0);
364 y = 1 << (rand() % 9);
367 return(BitNumber(y));
377 PositionIsLegal(POSITION *pos, BOOL fReduce)
382 Determine if a position is legal
386 POSITION *pos : board
390 BOOL : TRUE on success, FALSE on failure
396 BITV bvMaskFull, bvMaskPoss;
400 printf("Is this legal?\n");
401 DumpBoardSimple(pos);
402 printf("----------------------------------------------------------\n");
407 if (IS_EMPTY(pos->rgSquare[c].uValue))
409 x = pos->rgSquare[c].bvPossibilities;
413 printf("Nothing possible at sq %u\n", c);
421 // Note: I don't combine the two loops here because this way we
422 // detect invalid positions (empty squares w/ no legal moves in
423 // them) earlier instead of recursing on obviously bad positions.
427 if (IS_EMPTY(pos->rgSquare[c].uValue))
429 x = pos->rgSquare[c].bvPossibilities;
433 printf("%u at %u is forced...\n", BitNumber(x), c);
435 if ((TRUE == fReduce) &&
436 (FALSE == PlaceValue(pos, c, BitNumber(x), fReduce)))
439 printf("Couldn't place forced %u at sq %u\n",
449 // If there's only one square in a row|col|group that can be
450 // a given number, make the move.
452 for (x = 1; x <= 256; x <<= 1)
454 for (c = 0; c < 9; c++)
459 if (IS_EMPTY(pos->rgSquare[sq].uValue) &&
460 (pos->rgSquare[sq].bvPossibilities & x))
464 if (uCount > 1) break;
470 printf("%u at square %u is forced...\n", BitNumber(x), cOnly);
472 if ((TRUE == fReduce) &&
473 (FALSE == PlaceValue(pos, cOnly, BitNumber(x), fReduce)))
482 if (IS_EMPTY(pos->rgSquare[sq].uValue) &&
483 (pos->rgSquare[sq].bvPossibilities & x))
487 if (uCount > 1) break;
493 printf("%u at square %u is forced...\n", BitNumber(x), cOnly);
495 if ((TRUE == fReduce) &&
496 (FALSE == PlaceValue(pos, cOnly, BitNumber(x), fReduce)))
503 FOREACH_GROUP(sq, c, y)
505 if (IS_EMPTY(pos->rgSquare[sq].uValue) &&
506 (pos->rgSquare[sq].bvPossibilities & x))
510 if (uCount > 1) break;
516 printf("%u at square %u is forced...\n", BitNumber(x), cOnly);
518 if ((TRUE == fReduce) &&
519 (FALSE == PlaceValue(pos, cOnly, BitNumber(x), fReduce)))
527 for (c = 0; c < 9; c++)
529 bvMaskPoss = bvMaskFull = 0;
532 bvMaskPoss |= pos->rgSquare[sq].bvPossibilities;
533 if (!IS_EMPTY(pos->rgSquare[sq].uValue))
535 ASSERT(pos->rgSquare[sq].bvPossibilities ==
536 (1 << pos->rgSquare[sq].uValue));
537 if (bvMaskFull & pos->rgSquare[sq].bvPossibilities)
540 printf("Two %u's in row %u.\n", pos->rgSquare[sq].uValue,
545 bvMaskFull |= pos->rgSquare[sq].bvPossibilities;
548 if (bvMaskPoss != 0x1FF)
551 printf("Not everything is possible in row %u (%x).\n",
557 bvMaskPoss = bvMaskFull = 0;
560 bvMaskPoss |= pos->rgSquare[sq].bvPossibilities;
561 if (!IS_EMPTY(pos->rgSquare[sq].uValue))
563 ASSERT(pos->rgSquare[sq].bvPossibilities ==
564 (1 << pos->rgSquare[sq].uValue));
565 if (bvMaskFull & pos->rgSquare[sq].bvPossibilities)
568 printf("Two %u's in col %u.\n", pos->rgSquare[sq].uValue,
573 bvMaskFull |= pos->rgSquare[sq].bvPossibilities;
576 if (bvMaskPoss != 0x1FF)
579 printf("Not everything is possible in col %u (%x).\n",
585 bvMaskPoss = bvMaskFull = 0;
586 FOREACH_GROUP(sq, c, y)
588 bvMaskPoss |= pos->rgSquare[sq].bvPossibilities;
589 if (!IS_EMPTY(pos->rgSquare[sq].uValue))
591 ASSERT(pos->rgSquare[sq].bvPossibilities ==
592 (1 << pos->rgSquare[sq].uValue));
593 if (bvMaskFull & pos->rgSquare[sq].bvPossibilities)
596 printf("Two %u's in group %u.\n", pos->rgSquare[sq].uValue,
601 bvMaskFull |= pos->rgSquare[sq].bvPossibilities;
604 if (bvMaskPoss != 0x1FF)
607 printf("Not everything is possible in group %u (%x).\n",
618 InitializePosition(POSITION *pos)
623 Initialize a position to empty.
627 POSITION *pos : position
636 memset(pos, 0, sizeof(POSITION));
640 pos->rgSquare[c].bvPossibilities = 0x1FF;
641 pos->rgSquare[c].cGroup = g_cGroup[c];
642 pos->rgSquare[c].cRow = ROW(c);
643 pos->rgSquare[c].cCol = COL(c);
646 for (c = 0; c < 9; c++)
648 pos->bvRemainingByRow[c] = 0x1FF;
649 pos->bvRemainingByCol[c] = 0x1FF;
650 pos->bvRemainingByGroup[c] = 0x1FF;
655 typedef struct _FEWEST
659 BITV bvPossibilities;
664 Sort(FEWEST *p, ULONG uLen)
669 Selection sort to put the FEWEST array in order... this is so that
670 that when we make a guess we are guessing at the square with the
671 fewest possible choices.
675 FEWEST *p : start of array
676 ULONG uLen : number of elements in it
688 for (u = 0; u < uLen; u++)
691 for (v = u + 1; v < uLen; v++)
693 if (p[v].uBitCount < p[uMinPos].uBitCount)
707 Solve(POSITION *pos, ULONG uDepth)
712 Recursively solve a suduko position.
716 POSITION *pos : position
717 ULONG uDepth : number of ply from root
721 BOOL : TRUE if solved, FALSE if no solution exists
734 printf("Depth %u (%u node%s):\n", uDepth,
736 (g_uNodes != 1) ? "" : "s");
737 DumpBoardSimple(pos);
738 printf("---------------------------------------------------\n");
742 // Find the square with the fewest possibilities
747 sFewest[c].bvPossibilities = pos->rgSquare[c].bvPossibilities;
748 sFewest[c].uBitCount = BitCount(pos->rgSquare[c].bvPossibilities);
749 if ((pos->rgSquare[c].uValue == 0) && (sFewest[c].uBitCount == 0))
751 ASSERT(!sFewest[c].bvPossibilities);
753 printf("%u: Found inconsistency at square %u.\n", uDepth, c);
765 if (IS_EMPTY(pos->rgSquare[sFewest[v].c].uValue)) {
766 ASSERT(sFewest[v].uBitCount > 0);
767 for (u = 1; u <= 9; u++) {
770 // Only make guesses that are legal. Don't "guess"
771 // the same thing as a prior solution.
773 if ((sFewest[v].bvPossibilities & (1 << (u - 1))) &&
774 ((g_uSolutions == 0) ||
775 (g_Solution.rgSquare[sFewest[v].c].uValue != u))) {
776 memcpy(&p, pos, sizeof(p));
779 printf("%u: Guessing %u at square %u\n",
780 uDepth, u, sFewest[v].c);
782 if ((FALSE == PlaceValue(pos, sFewest[v].c, u, TRUE)) ||
783 (FALSE == Solve(pos, uDepth + 1)))
786 // Unmake the guess move.
789 printf("%u: Bad guess (%u at %u), taking it back.\n",
790 uDepth, u, sFewest[v].c);
792 memcpy(pos, &p, sizeof(p));
795 // We've learned that the guess is wrong, mask it
796 // off the possibilities bitv.
798 pos->rgSquare[sFewest[v].c].bvPossibilities &=
802 // Are we in a screwed up state now after masking
803 // off that bit? If so something above us in the
804 // callstack is screwed up.
806 if (pos->rgSquare[sFewest[v].c].bvPossibilities == 0)
809 printf("%u: Nothing possible at square %u.\n",
810 uDepth, sFewest[v].c);
818 // This move leads to a win. Count it as a
819 // solution and carry on.
822 printf("%u: Guess of %u at square %u leads to a "
824 uDepth, u, sFewest[v].c);
827 if (g_uSolutions == 1)
829 memcpy(pos, &p, sizeof(p));
839 if (0 == pos->uEmpty)
844 printf("%u: Puzzle is solved, solution number %u\n",
845 uDepth, g_uSolutions);
846 DumpBoardSimple(pos);
848 if (g_uSolutions == 1)
850 memcpy(&g_Solution, pos, sizeof(POSITION));
861 GeneratePuzzle(BOOL fHard, POSITION *pos)
869 1, 7, 12, 14, 17, 27, 31, 35, 37,40, 43,
870 45, 49, 53, 63, 66, 68, 71, 73, 79, 0 };
879 InitializePosition(pos);
884 // Place a number, try to solve it, repeat...
886 while(pos->uEmpty > 45)
889 if (IS_EMPTY(pos->rgSquare[c].uValue))
891 v = LegalValue(pos, c);
895 // See if the rest can be solved by deduction...
897 memcpy(&p, pos, sizeof(p));
898 if ((TRUE == PlaceValue(pos, c, v, TRUE)) &&
901 memcpy(pos, &p, sizeof(p));
902 pos->rgSquare[c].uValue = v;
911 // Throw some random numbers out there on the board...
914 while(cSeed[u] != 0) {
915 if (IS_EMPTY(pos->rgSquare[cSeed[u]].uValue))
917 v = LegalValue(pos, cSeed[u]);
920 (void)PlaceValue(pos, cSeed[u], v, TRUE);
926 // Solve the puzzle within these constraints...
928 g_uSolutions = g_uGuesses = g_uNodes = 0;
929 if (TRUE == Solve(pos, 0))
932 // Now start taking away values until you get a puzzle
933 // that is still uniquely solvable but requires
939 if (!IS_EMPTY(pos->rgSquare[c].uValue)) {
940 InitializePosition(&p);
943 (!IS_EMPTY(pos->rgSquare[x].uValue))) {
945 pos->rgSquare[x].uValue, FALSE);
948 ASSERT(p.uEmpty - 1 == pos->uEmpty);
949 g_uSolutions = g_uGuesses = g_uNodes = 0;
950 if ((TRUE == Solve(&p, 0)) && (g_uSolutions == 1))
953 memcpy(pos, &p, sizeof(p));
954 if ((g_uGuesses > 5) &&
956 (pos->uEmpty > 55)) {
957 printf("%u guesses, %u nodes.\n",
958 g_uGuesses, g_uNodes);
980 main(int argc, char *argv[])
1002 InitializePosition(&pos);
1004 memset(buf, 0, sizeof(buf));
1008 printf("Enter board: ");
1009 scanf("%255s", buf);
1013 if (!strcmp(argv[1], "--create-easy"))
1015 GeneratePuzzle(FALSE, &pos);
1016 DumpBoardHtml(&pos);
1017 DumpBoardSimple(&pos);
1020 else if (!strcmp(argv[1], "--create-hard"))
1022 GeneratePuzzle(TRUE, &pos);
1023 DumpBoardHtml(&pos);
1024 DumpBoardSimple(&pos);
1029 strncpy(buf, argv[1], 255);
1042 if (isdigit(*p) && (*p != '0'))
1044 if (FALSE == PlaceValue(&pos, c, *p - '0', TRUE))
1047 (unsigned)c, (unsigned)(*p - '0'));
1056 g_uSolutions = g_uGuesses = g_uNodes = 0;
1057 if (TRUE == Solve(&pos, 0)) {
1058 memcpy(&pos, &g_Solution, sizeof(pos));
1059 DumpBoardHtml(&pos);
1060 printf("%u solutions, %u nodes, %u guesses.\n",
1061 g_uSolutions, g_uNodes, g_uGuesses);
1065 DumpBoardHtml(&pos);
1066 printf("No solution found...\n");