Mercurial > hgrepos > Python2 > PyMuPDF
diff mupdf-source/thirdparty/leptonica/src/sudoku.c @ 2:b50eed0cc0ef upstream
ADD: MuPDF v1.26.7: the MuPDF source as downloaded by a default build of PyMuPDF 1.26.4.
The directory name has changed: no version number in the expanded directory now.
| author | Franz Glasner <fzglas.hg@dom66.de> |
|---|---|
| date | Mon, 15 Sep 2025 11:43:07 +0200 |
| parents | |
| children |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/mupdf-source/thirdparty/leptonica/src/sudoku.c Mon Sep 15 11:43:07 2025 +0200 @@ -0,0 +1,859 @@ +/*====================================================================* + - Copyright (C) 2001 Leptonica. All rights reserved. + - + - Redistribution and use in source and binary forms, with or without + - modification, are permitted provided that the following conditions + - are met: + - 1. Redistributions of source code must retain the above copyright + - notice, this list of conditions and the following disclaimer. + - 2. Redistributions in binary form must reproduce the above + - copyright notice, this list of conditions and the following + - disclaimer in the documentation and/or other materials + - provided with the distribution. + - + - THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + - ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + - LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + - A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL ANY + - CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + - EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + - PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + - PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + - OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + - NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + - SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + *====================================================================*/ + + +/*! + * \file sudoku.c + * <pre> + * + * Solve a sudoku by brute force search + * + * Read input data from file or string + * l_int32 *sudokuReadFile() + * l_int32 *sudokuReadString() + * + * Create/destroy + * L_SUDOKU *sudokuCreate() + * void sudokuDestroy() + * + * Solve the puzzle + * l_int32 sudokuSolve() + * static l_int32 sudokuValidState() + * static l_int32 sudokuNewGuess() + * static l_int32 sudokuTestState() + * + * Test for uniqueness + * l_int32 sudokuTestUniqueness() + * static l_int32 sudokuCompareState() + * static l_int32 *sudokuRotateArray() + * + * Generation + * L_SUDOKU *sudokuGenerate() + * + * Output + * l_int32 sudokuOutput() + * + * Solving sudokus is a somewhat addictive pastime. The rules are + * simple but it takes just enough concentration to make it rewarding + * when you find a number. And you get 50 to 60 such rewards each time + * you complete one. The downside is that you could have been doing + * something more creative, like keying out a new plant, staining + * the deck, or even writing a computer program to discourage your + * wife from doing sudokus. + * + * My original plan for the sudoku solver was somewhat grandiose. + * The program would model the way a person solves the problem. + * It would examine each empty position and determine how many possible + * numbers could fit. The empty positions would be entered in a priority + * queue keyed on the number of possible numbers that could fit. + * If there existed a position where only a single number would work, + * it would greedily take it. Otherwise it would consider a + * positions that could accept two and make a guess, with backtracking + * if an impossible state were reached. And so on. + * + * Then one of my colleagues announced she had solved the problem + * by brute force and it was fast. At that point the original plan was + * dead in the water, because the two top requirements for a leptonica + * algorithm are (1) as simple as possible and (2) fast. The brute + * force approach starts at the UL corner, and in succession at each + * blank position it finds the first valid number (testing in + * sequence from 1 to 9). When no number will fit a blank position + * it backtracks, choosing the next valid number in the previous + * blank position. + * + * This is an inefficient method for pruning the space of solutions + * (imagine backtracking from the LR corner back to the UL corner + * and starting over with a new guess), but it nevertheless gets + * the job done quickly. I have made no effort to optimize + * it, because it is fast: a 5-star (highest difficulty) sudoku might + * require a million guesses and take 0.05 sec. (This BF implementation + * does about 20M guesses/sec at 3 GHz.) + * + * Proving uniqueness of a sudoku solution is tricker than finding + * a solution (or showing that no solution exists). A good indication + * that a solution is unique is if we get the same result solving + * by brute force when the puzzle is also rotated by 90, 180 and 270 + * degrees. If there are multiple solutions, it seems unlikely + * that you would get the same solution four times in a row, using a + * brute force method that increments guesses and scans LR/TB. + * The function sudokuTestUniqueness() does this. + * + * And given a function that can determine uniqueness, it is + * easy to generate valid sudokus. We provide sudokuGenerate(), + * which starts with some valid initial solution, and randomly + * removes numbers, stopping either when a minimum number of non-zero + * elements are left, or when it becomes difficult to remove another + * element without destroying the uniqueness of the solution. + * + * For further reading, see the Wikipedia articles: + * (1) http://en.wikipedia.org/wiki/Algorithmics_of_sudoku + * (2) http://en.wikipedia.org/wiki/Sudoku + * + * How many 9x9 sudokus are there? Here are the numbers. + * ~ From ref(1), there are about 6 x 10^27 "latin squares", where + * each row and column has all 9 digits. + * ~ There are 7.2 x 10^21 actual solutions, having the added + * constraint in each of the 9 3x3 squares. (The constraint + * reduced the number by the fraction 1.2 x 10^(-6).) + * ~ There are a mere 5.5 billion essentially different solutions (EDS), + * when symmetries (rotation, reflection, permutation and relabelling) + * are removed. + * ~ Thus there are 1.3 x 10^12 solutions that can be derived by + * symmetry from each EDS. Can we account for these? + * ~ Sort-of. From an EDS, you can derive (3!)^8 = 1.7 million solutions + * by simply permuting rows and columns. (Do you see why it is + * not (3!)^6 ?) + * ~ Also from an EDS, you can derive 9! solutions by relabelling, + * and 4 solutions by rotation, for a total of 1.45 million solutions + * by relabelling and rotation. Then taking the product, by symmetry + * we can derive 1.7M x 1.45M = 2.45 trillion solutions from each EDS. + * (Something is off by about a factor of 2 -- close enough.) + * + * Another interesting fact is that there are apparently 48K EDS sudokus + * (with unique solutions) that have only 17 givens. No sudokus are known + * with less than 17, but there exists no proof that this is the minimum. + * </pre> + */ + +#ifdef HAVE_CONFIG_H +#include <config_auto.h> +#endif /* HAVE_CONFIG_H */ + +#include "allheaders.h" + +static l_int32 sudokuValidState(l_int32 *state); +static l_int32 sudokuNewGuess(L_SUDOKU *sud); +static l_int32 sudokuTestState(l_int32 *state, l_int32 index); +static l_int32 sudokuCompareState(L_SUDOKU *sud1, L_SUDOKU *sud2, + l_int32 quads, l_int32 *psame); +static l_int32 *sudokuRotateArray(l_int32 *array, l_int32 quads); + +/* --------------------------------------------------------------- */ +/* An example of a valid solution */ +/* --------------------------------------------------------------- * +static const char valid_solution[] = "3 8 7 2 6 4 1 9 5 " + "2 6 5 8 9 1 4 3 7 " + "1 4 9 5 3 7 6 8 2 " + "5 2 3 7 1 6 8 4 9 " + "7 1 6 9 4 8 2 5 3 " + "8 9 4 3 5 2 7 1 6 " + "9 7 2 1 8 5 3 6 4 " + "4 3 1 6 7 9 5 2 8 " + "6 5 8 4 2 3 9 7 1 "; +*/ + + +/*---------------------------------------------------------------------* + * Read input data from file or string * + *---------------------------------------------------------------------*/ +/*! + * \brief sudokuReadFile() + * + * \param[in] filename formatted sudoku file + * \return array of 81 numbers, or NULL on error + * + * <pre> + * Notes: + * (1) The file format has: + * * any number of comment lines beginning with '#' + * * a set of 9 lines, each having 9 digits (0-9) separated + * by a space + * </pre> + */ +l_int32 * +sudokuReadFile(const char *filename) +{ +char *str, *strj; +l_uint8 *data; +l_int32 i, j, nlines, val, index, error; +l_int32 *array; +size_t size; +SARRAY *saline, *sa1, *sa2; + + if (!filename) + return (l_int32 *)ERROR_PTR("filename not defined", __func__, NULL); + data = l_binaryRead(filename, &size); + sa1 = sarrayCreateLinesFromString((char *)data, 0); + sa2 = sarrayCreate(9); + + /* Filter out the comment lines; verify that there are 9 data lines */ + nlines = sarrayGetCount(sa1); + for (i = 0; i < nlines; i++) { + str = sarrayGetString(sa1, i, L_NOCOPY); + if (str[0] != '#') + sarrayAddString(sa2, str, L_COPY); + } + LEPT_FREE(data); + sarrayDestroy(&sa1); + nlines = sarrayGetCount(sa2); + if (nlines != 9) { + sarrayDestroy(&sa2); + L_ERROR("file has %d lines\n", __func__, nlines); + return (l_int32 *)ERROR_PTR("invalid file", __func__, NULL); + } + + /* Read the data into the array, verifying that each data + * line has 9 numbers. */ + error = FALSE; + array = (l_int32 *)LEPT_CALLOC(81, sizeof(l_int32)); + for (i = 0, index = 0; i < 9; i++) { + str = sarrayGetString(sa2, i, L_NOCOPY); + saline = sarrayCreateWordsFromString(str); + if (sarrayGetCount(saline) != 9) { + error = TRUE; + sarrayDestroy(&saline); + break; + } + for (j = 0; j < 9; j++) { + strj = sarrayGetString(saline, j, L_NOCOPY); + if (sscanf(strj, "%d", &val) != 1) + error = TRUE; + else + array[index++] = val; + } + sarrayDestroy(&saline); + if (error) break; + } + sarrayDestroy(&sa2); + + if (error) { + LEPT_FREE(array); + return (l_int32 *)ERROR_PTR("invalid data", __func__, NULL); + } + + return array; +} + + +/*! + * \brief sudokuReadString() + * + * \param[in] str formatted input data + * \return array of 81 numbers, or NULL on error + * + * <pre> + * Notes: + * (1) The string is formatted as 81 single digits, each separated + * by 81 spaces. + * </pre> + */ +l_int32 * +sudokuReadString(const char *str) +{ +l_int32 i; +l_int32 *array; + + if (!str) + return (l_int32 *)ERROR_PTR("str not defined", __func__, NULL); + + /* Read in the initial solution */ + array = (l_int32 *)LEPT_CALLOC(81, sizeof(l_int32)); + for (i = 0; i < 81; i++) { + if (sscanf(str + 2 * i, "%d ", &array[i]) != 1) { + LEPT_FREE(array); + return (l_int32 *)ERROR_PTR("invalid format", __func__, NULL); + } + } + + return array; +} + + +/*---------------------------------------------------------------------* + * Create/destroy sudoku * + *---------------------------------------------------------------------*/ +/*! + * \brief sudokuCreate() + * + * \param[in] array 81 numbers, 9 rows of 9 numbers each + * \return l_sudoku, or NULL on error + * + * <pre> + * Notes: + * (1) The input array has 0 for the unknown values, and 1-9 + * for the known initial values. It is generated from + * a file using sudokuReadInput(), which checks that the file + * data has 81 numbers in 9 rows. + * </pre> + */ +L_SUDOKU * +sudokuCreate(l_int32 *array) +{ +l_int32 i, val, locs_index; +L_SUDOKU *sud; + + if (!array) + return (L_SUDOKU *)ERROR_PTR("array not defined", __func__, NULL); + + locs_index = 0; /* into locs array */ + sud = (L_SUDOKU *)LEPT_CALLOC(1, sizeof(L_SUDOKU)); + sud->locs = (l_int32 *)LEPT_CALLOC(81, sizeof(l_int32)); + sud->init = (l_int32 *)LEPT_CALLOC(81, sizeof(l_int32)); + sud->state = (l_int32 *)LEPT_CALLOC(81, sizeof(l_int32)); + for (i = 0; i < 81; i++) { + val = array[i]; + sud->init[i] = val; + sud->state[i] = val; + if (val == 0) + sud->locs[locs_index++] = i; + } + sud->num = locs_index; + sud->failure = FALSE; + sud->finished = FALSE; + return sud; +} + + +/*! + * \brief sudokuDestroy() + * + * \param[in,out] psud will be set to null before returning + * \return void + */ +void +sudokuDestroy(L_SUDOKU **psud) +{ +L_SUDOKU *sud; + + if (psud == NULL) { + L_WARNING("ptr address is NULL\n", __func__); + return; + } + if ((sud = *psud) == NULL) + return; + + LEPT_FREE(sud->locs); + LEPT_FREE(sud->init); + LEPT_FREE(sud->state); + LEPT_FREE(sud); + *psud = NULL; +} + + +/*---------------------------------------------------------------------* + * Solve the puzzle * + *---------------------------------------------------------------------*/ +/*! + * \brief sudokuSolve() + * + * \param[in] sud l_sudoku starting in initial state + * \return 1 on success, 0 on failure to solve note reversal of + * typical unix returns + */ +l_int32 +sudokuSolve(L_SUDOKU *sud) +{ + if (!sud) + return ERROR_INT("sud not defined", __func__, 0); + + if (!sudokuValidState(sud->init)) + return ERROR_INT("initial state not valid", __func__, 0); + + while (1) { + if (sudokuNewGuess(sud)) + break; + if (sud->finished == TRUE) + break; + } + + if (sud->failure == TRUE) { + lept_stderr("Failure after %d guesses\n", sud->nguess); + return 0; + } + + lept_stderr("Solved after %d guesses\n", sud->nguess); + return 1; +} + + +/*! + * \brief sudokuValidState() + * + * \param[in] state array of size 81 + * \return 1 if valid, 0 if invalid + * + * <pre> + * Notes: + * (1) This can be used on either the initial state (init) + * or on the current state (state) of the l_soduku. + * All values of 0 are ignored. + * </pre> + */ +static l_int32 +sudokuValidState(l_int32 *state) +{ +l_int32 i; + + if (!state) + return ERROR_INT("state not defined", __func__, 0); + + for (i = 0; i < 81; i++) { + if (!sudokuTestState(state, i)) + return 0; + } + + return 1; +} + + +/*! + * \brief sudokuNewGuess() + * + * \param[in] sud l_sudoku + * \return 0 if OK; 1 if no solution is possible + * + * <pre> + * Notes: + * (1) This attempts to increment the number in the current + * location. If it can't, it backtracks (sets the number + * in the current location to zero and decrements the + * current location). If it can, it tests that number, + * and if the number is valid, moves forward to the next + * empty location (increments the current location). + * (2) If there is no solution, backtracking will eventually + * exhaust possibilities for the first location. + * </pre> + */ +static l_int32 +sudokuNewGuess(L_SUDOKU *sud) +{ +l_int32 index, val, valid; +l_int32 *locs, *state; + + locs = sud->locs; + state = sud->state; + index = locs[sud->current]; /* 0 to 80 */ + val = state[index]; + if (val == 9) { /* backtrack or give up */ + if (sud->current == 0) { + sud->failure = TRUE; + return 1; + } + state[index] = 0; + sud->current--; + } else { /* increment current value and test */ + sud->nguess++; + state[index]++; + valid = sudokuTestState(state, index); + if (valid) { + if (sud->current == sud->num - 1) { /* we're done */ + sud->finished = TRUE; + return 0; + } else { /* advance to next position */ + sud->current++; + } + } + } + + return 0; +} + + +/*! + * \brief sudokuTestState() + * + * \param[in] state current state: array of 81 values + * \param[in] index into state element that we are testing + * \return 1 if valid; 0 if invalid no error checking + */ +static l_int32 +sudokuTestState(l_int32 *state, + l_int32 index) +{ +l_int32 i, j, val, row, rowstart, rowend, col; +l_int32 blockrow, blockcol, blockstart, rowindex, locindex; + + if ((val = state[index]) == 0) /* automatically valid */ + return 1; + + /* Test row. Test val is at (x, y) = (index % 9, index / 9) */ + row = index / 9; + rowstart = 9 * row; + for (i = rowstart; i < index; i++) { + if (state[i] == val) + return 0; + } + rowend = rowstart + 9; + for (i = index + 1; i < rowend; i++) { + if (state[i] == val) + return 0; + } + + /* Test column */ + col = index % 9; + for (j = col; j < index; j += 9) { + if (state[j] == val) + return 0; + } + for (j = index + 9; j < 81; j += 9) { + if (state[j] == val) + return 0; + } + + /* Test local 3x3 block */ + blockrow = 3 * (row / 3); + blockcol = 3 * (col / 3); + blockstart = 9 * blockrow + blockcol; + for (i = 0; i < 3; i++) { + rowindex = blockstart + 9 * i; + for (j = 0; j < 3; j++) { + locindex = rowindex + j; + if (index == locindex) continue; + if (state[locindex] == val) + return 0; + } + } + + return 1; +} + + +/*---------------------------------------------------------------------* + * Test for uniqueness * + *---------------------------------------------------------------------*/ +/*! + * \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_ok +sudokuTestUniqueness(l_int32 *array, + l_int32 *punique) +{ +l_int32 same1, same2, same3; +l_int32 *array1, *array2, *array3; +L_SUDOKU *sud, *sud1, *sud2, *sud3; + + if (!punique) + return ERROR_INT("&unique not defined", __func__, 1); + *punique = 0; + if (!array) + return ERROR_INT("array not defined", __func__, 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; +} + + +/*! + * \brief sudokuCompareState() + * + * \param[in] sud1, sud2 two l_Sudoku states (solutions) + * \param[in] quads rotation of sud2 input with respect to sud1, + * in units of 90 degrees cw + * \param[out] psame 1 if all 4 results are identical; 0 otherwise + * \return 0 if OK, 1 on error + * + * <pre> + * Notes: + * (1) The input to sud2 has been rotated by %quads relative to the + * input to sud1. Therefore, we must rotate the solution to + * sud1 by the same amount before comparing it to the + * solution to sud2. + * </pre> + */ +static l_int32 +sudokuCompareState(L_SUDOKU *sud1, + L_SUDOKU *sud2, + l_int32 quads, + l_int32 *psame) +{ +l_int32 i, same; +l_int32 *array; + + if (!psame) + return ERROR_INT("&same not defined", __func__, 1); + *psame = 0; + if (!sud1) + return ERROR_INT("sud1 not defined", __func__, 1); + if (!sud2) + return ERROR_INT("sud1 not defined", __func__, 1); + if (quads < 1 || quads > 3) + return ERROR_INT("valid quads in {1,2,3}", __func__, 1); + + same = TRUE; + if ((array = sudokuRotateArray(sud1->state, quads)) == NULL) + return ERROR_INT("array not made", __func__, 1); + for (i = 0; i < 81; i++) { + if (array[i] != sud2->state[i]) { + same = FALSE; + break; + } + } + *psame = same; + LEPT_FREE(array); + return 0; +} + + +/*! + * \brief sudokuRotateArray() + * + * \param[in] array 81 numbers; 9 lines of 9 numbers each + * \param[in] quads 1-3; number of 90 degree cw rotations + * \return rarray rotated array, or NULL on error + */ +static l_int32 * +sudokuRotateArray(l_int32 *array, + l_int32 quads) +{ +l_int32 i, j, sindex, dindex; +l_int32 *rarray; + + if (!array) + return (l_int32 *)ERROR_PTR("array not defined", __func__, NULL); + if (quads < 1 || quads > 3) + return (l_int32 *)ERROR_PTR("valid quads in {1,2,3}", __func__, NULL); + + rarray = (l_int32 *)LEPT_CALLOC(81, sizeof(l_int32)); + if (quads == 1) { + for (j = 0, dindex = 0; j < 9; j++) { + for (i = 8; i >= 0; i--) { + sindex = 9 * i + j; + rarray[dindex++] = array[sindex]; + } + } + } else if (quads == 2) { + for (i = 8, dindex = 0; i >= 0; i--) { + for (j = 8; j >= 0; j--) { + sindex = 9 * i + j; + rarray[dindex++] = array[sindex]; + } + } + } else { /* quads == 3 */ + for (j = 8, dindex = 0; j >= 0; j--) { + for (i = 0; i < 9; i++) { + sindex = 9 * i + j; + rarray[dindex++] = array[sindex]; + } + } + } + + return rarray; +} + + +/*---------------------------------------------------------------------* + * Generation * + *---------------------------------------------------------------------*/ +/*! + * \brief sudokuGenerate() + * + * \param[in] array 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; + + if (!array) + return (L_SUDOKU *)ERROR_PTR("array not defined", __func__, NULL); + if (minelems > 80) + return (L_SUDOKU *)ERROR_PTR("minelems must be < 81", __func__, 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) { + genRandomIntOnInterval(0, 8, 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", __func__); + return NULL; + } + sudokuTestUniqueness(testsud->init, &unique); + sudokuDestroy(&testsud); + if (!unique) { + L_ERROR("non-unique result with 30 zeroes\n", __func__); + 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) { + lept_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. */ + genRandomIntOnInterval(0, 8, 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; + lept_stderr("Have %d zeros\n", nzeros); + nzeros++; + } + } + lept_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; +} + + +/*---------------------------------------------------------------------* + * Output * + *---------------------------------------------------------------------*/ +/*! + * \brief sudokuOutput() + * + * \param[in] sud l_sudoku at any stage + * \param[in] arraytype L_SUDOKU_INIT, L_SUDOKU_STATE + * \return 0 if OK; 1 on error + * + * <pre> + * Notes: + * (1) Prints either the initial array or the current state + * of the solution. + * </pre> + */ +l_int32 +sudokuOutput(L_SUDOKU *sud, + l_int32 arraytype) +{ +l_int32 i, j; +l_int32 *array; + + if (!sud) + return ERROR_INT("sud not defined", __func__, 1); + if (arraytype == L_SUDOKU_INIT) + array = sud->init; + else if (arraytype == L_SUDOKU_STATE) + array = sud->state; + else + return ERROR_INT("invalid arraytype", __func__, 1); + + for (i = 0; i < 9; i++) { + for (j = 0; j < 9; j++) + lept_stderr("%d ", array[9 * i + j]); + lept_stderr("\n"); + } + return 0; +}
