/*! * \brief sudokuTestUniqueness() * * \param[in] array of 81 numbers, 9 lines of 9 numbers each * \param[out] punique 1 if unique, 0 if not * \return 0 if OK, 1 on error * * <pre> * Notes: * (1) This applies the brute force method to all four 90 degree * rotations. If there is more than one solution, it is highly * unlikely that all four results will be the same; * consequently, if they are the same, the solution is * most likely to be unique. * </pre> */ l_int32 sudokuTestUniqueness(l_int32 *array, l_int32 *punique) { l_int32 same1, same2, same3; l_int32 *array1, *array2, *array3; L_SUDOKU *sud, *sud1, *sud2, *sud3; PROCNAME("sudokuTestUniqueness"); if (!punique) return ERROR_INT("&unique not defined", procName, 1); *punique = 0; if (!array) return ERROR_INT("array not defined", procName, 1); sud = sudokuCreate(array); sudokuSolve(sud); array1 = sudokuRotateArray(array, 1); sud1 = sudokuCreate(array1); sudokuSolve(sud1); array2 = sudokuRotateArray(array, 2); sud2 = sudokuCreate(array2); sudokuSolve(sud2); array3 = sudokuRotateArray(array, 3); sud3 = sudokuCreate(array3); sudokuSolve(sud3); sudokuCompareState(sud, sud1, 1, &same1); sudokuCompareState(sud, sud2, 2, &same2); sudokuCompareState(sud, sud3, 3, &same3); *punique = (same1 && same2 && same3); sudokuDestroy(&sud); sudokuDestroy(&sud1); sudokuDestroy(&sud2); sudokuDestroy(&sud3); LEPT_FREE(array1); LEPT_FREE(array2); LEPT_FREE(array3); return 0; }
int main(int argc, char **argv) { l_int32 unique; l_int32 *array; L_SUDOKU *sud; static char mainName[] = "sudokutest"; if (argc != 1 && argc != 2) return ERROR_INT(" Syntax: sudokutest [filein]", mainName, 1); if (argc == 1) { /* Generate a new sudoku by element elimination */ array = sudokuReadString(startsol); sud = sudokuGenerate(array, 3693, 28, 7); sudokuDestroy(&sud); lept_free(array); return 0; } /* Solve the input sudoku */ if ((array = sudokuReadFile(argv[1])) == NULL) return ERROR_INT("invalid input", mainName, 1); if ((sud = sudokuCreate(array)) == NULL) return ERROR_INT("sud not made", mainName, 1); sudokuOutput(sud, L_SUDOKU_INIT); startTimer(); sudokuSolve(sud); fprintf(stderr, "Time: %7.3f sec\n", stopTimer()); sudokuOutput(sud, L_SUDOKU_STATE); sudokuDestroy(&sud); /* Test for uniqueness */ sudokuTestUniqueness(array, &unique); if (unique) fprintf(stderr, "Sudoku is unique\n"); else fprintf(stderr, "Sudoku is NOT unique\n"); lept_free(array); return 0; }
/*! * \brief sudokuGenerate() * * \param[in] array of 81 numbers, 9 rows of 9 numbers each * \param[in] seed random number * \param[in] minelems min non-zero elements allowed; <= 80 * \param[in] maxtries max tries to remove a number and get a valid sudoku * \return l_sudoku, or NULL on error * * <pre> * Notes: * (1) This is a brute force generator. It starts with a completed * sudoku solution and, by removing elements (setting them to 0), * generates a valid (unique) sudoku initial condition. * (2) The process stops when either %minelems, the minimum * number of non-zero elements, is reached, or when the * number of attempts to remove the next element exceeds %maxtries. * (3) No sudoku is known with less than 17 nonzero elements. * </pre> */ L_SUDOKU * sudokuGenerate(l_int32 *array, l_int32 seed, l_int32 minelems, l_int32 maxtries) { l_int32 index, sector, nzeros, removefirst, tries, val, oldval, unique; L_SUDOKU *sud, *testsud; PROCNAME("sudokuGenerate"); if (!array) return (L_SUDOKU *)ERROR_PTR("array not defined", procName, NULL); if (minelems > 80) return (L_SUDOKU *)ERROR_PTR("minelems must be < 81", procName, NULL); /* Remove up to 30 numbers at random from the solution. * Test if the solution is valid -- the initial 'solution' may * have been invalid. Then test if the sudoku with 30 zeroes * is unique -- it almost always will be. */ srand(seed); nzeros = 0; sector = 0; removefirst = L_MIN(30, 81 - minelems); while (nzeros < removefirst) { genRandomIntegerInRange(9, 0, &val); index = 27 * (sector / 3) + 3 * (sector % 3) + 9 * (val / 3) + (val % 3); if (array[index] == 0) continue; array[index] = 0; nzeros++; sector++; sector %= 9; } testsud = sudokuCreate(array); sudokuSolve(testsud); if (testsud->failure) { sudokuDestroy(&testsud); L_ERROR("invalid initial solution\n", procName); return NULL; } sudokuTestUniqueness(testsud->init, &unique); sudokuDestroy(&testsud); if (!unique) { L_ERROR("non-unique result with 30 zeroes\n", procName); return NULL; } /* Remove more numbers, testing at each removal for uniqueness. */ tries = 0; sector = 0; while (1) { if (tries > maxtries) break; if (81 - nzeros <= minelems) break; if (tries == 0) { fprintf(stderr, "Trying %d zeros\n", nzeros); tries = 1; } /* Choose an element to be zeroed. We choose one * at random in succession from each of the nine sectors. */ genRandomIntegerInRange(9, 0, &val); index = 27 * (sector / 3) + 3 * (sector % 3) + 9 * (val / 3) + (val % 3); sector++; sector %= 9; if (array[index] == 0) continue; /* Save the old value in case we need to revert */ oldval = array[index]; /* Is there a solution? If not, try again. */ array[index] = 0; testsud = sudokuCreate(array); sudokuSolve(testsud); if (testsud->failure == TRUE) { sudokuDestroy(&testsud); array[index] = oldval; /* revert */ tries++; continue; } /* Is the solution unique? If not, try again. */ sudokuTestUniqueness(testsud->init, &unique); sudokuDestroy(&testsud); if (!unique) { /* revert and try again */ array[index] = oldval; tries++; } else { /* accept this */ tries = 0; fprintf(stderr, "Have %d zeros\n", nzeros); nzeros++; } } fprintf(stderr, "Final: nelems = %d\n", 81 - nzeros); /* Show that we can recover the solution */ sud = sudokuCreate(array); sudokuOutput(sud, L_SUDOKU_INIT); sudokuSolve(sud); sudokuOutput(sud, L_SUDOKU_STATE); return sud; }
int main(int argc, char *argv[]) { FILE * fin = NULL; int lineCounter = 1; int sudoku[9][9] = {{0}}; int row = 0; int col = 0; int fileOK = 1; int prec, c; if( 2 != argc ) { printf("Argument error!\nUsage: %s <file-name>\n", argv[0]); return 0; } fin = fopen(argv[1], "rb"); if( NULL == fin ) { printf("Cannot open file `%s' for read!\n", argv[1]); return 1; } #define GET_NEXT_CHAR (prec = c, c = fgetc(fin)) while( fileOK && EOF != (GET_NEXT_CHAR) ) { // printf("`%c|%c',", prec, c); switch( c ) { case '#' : while( '\n' != (GET_NEXT_CHAR) ); // fall through; case '\n' : if( 0 != col%9 ) { printf("Error! Unfinished line at L%d, %d %s expected!", lineCounter, (9-col), (9-col==1? "number": "numbers") ); fileOK = 0; } // if unfinished lineCounter++; break; case '%' : if( '\n' == prec && '%' == (GET_NEXT_CHAR) ) { // line starting by `%%', treat as separator if( 0 != row%9 || 0 != col%9 ) { printf("Error!" " Incomplete sudoku before separator at L%d!", lineCounter); fileOK = 0; } // if incomplete } // if separator break; case '0' : case '1' : case '2' : case '3' : case '4' : case '5' : case '6' : case '7' : case '8' : case '9' : sudoku[row][col++] = c-'0'; if( 9 == col ) { col = 0; row++; if( 9 == row ) { // a complete sudoku has been stored, try to solve it. printf(">> Complete sudoku, will now solve...\n"); printSudoku(sudoku); sudokuSolve(sudoku); row = 0; } // if complete } // if line finished break; default : // do nothing; break; } // switch } // while return 0; }