0

This is the code I wrote to check if there are multiple solutions to a KenKen puzzle (Similar to Sudoku). Technically it should return true if there are 2 solutions, but it doesn't appear to work because of a logic error in the algorithm.

I can't seem to find the error and after spending a whole day debugging the whole thing step by step I feel like I'll never find out what's wrong.

The code can solve the puzzle without any problems but it doesn't always seem to detect when there are multiple solutions, which is just weird.

    boolean solutionFlag = false;    

    static boolean backtrackingUniqueSolution(int startIndex) {
        for (int i=1; i<=sudokuGridElements.length; i++){
            sudokuGridCells[startIndex] = i;
            if(checkConditons()){
                if(endOfBounds || backtrackingUniqueSolution(startIndex + 1))){
                    if(!solutionFlag){ //Used to "count to 1"
                        solutionFlag = true;
                    } else {
                        return true; //Should return true only after it finds the second solution
                    }
                }
            }
            sudokuGridCells[startIndex] = null;
        }
        return false;
    }

1 Answers1

0

When you find the first solution, you set the flag, but return false, so that you don't know whether a solution was found further up the recursion stack. The flag tells you that, but you must still look for a second solution to get your answer.

You should distinguish between actually finding a solution when the last cell is reached and cutting recursion short when you already have found a second solution. In the first case, do the delayed counting via the flag. In the second case, just return true if a second solution was found, that is when the recursive function has returned true.

boolean solutionFlag = false;    

static boolean multiSolution(int startIndex) {

    for (int i = 1; i <= sudokuGridElements.length; i++) {
        sudokuGridCells[startIndex] = i;

        if(checkConditons()) {
            if (endOfBounds) {
                if (solutionFlag) return true;

                solutionFlag = true;
            } else {
                if (multiSolution(startIndex + 1)) return true;
            }
        }

        sudokuGridCells[startIndex] = null;
    }

    return false;
}

(You could get rid of the non-local state flag, if you made the function return an integer or enumerated value which tells you whether no, a single or many solutions were found.)

M Oehm
  • 28,726
  • 3
  • 31
  • 42
  • Still doesn't work. It's as if it doesn't always find the other solution. I'm really pulling my hair out over this as it should work but it just doesn't. –  Apr 19 '20 at 14:22
  • I really like those "still doesn't work" comments. I tested this code in C with a sudoke solver I still had lying around. I may have made a mistake when translating it into Java (together with the silly long names) for this post. Anyway, you haven't been very specific with _what_ doesn't work in yout post, either. – M Oehm Apr 19 '20 at 14:38
  • (By the way, I have assumed that `endOfBound` is true on the last cell with index 80, not one beyond the last cell.) – M Oehm Apr 19 '20 at 14:43
  • By "still doesn't work" I mean that it still doesn't detect multiple solutions in some sudokus which actually have multiple solutions, while in others it detects them. –  Apr 19 '20 at 23:46
  • Yes, but to me "doesn't work" sounds like "You get an F for this. Sit down." The thing is, you aren't very clear about what works and what doesn't in the question. Without your checking code and without example input, I cannot test my changes. As I said, I tested it in a C sudoke solver, but I would program many things differently. (For example, seeing `for (int i = 1; i <= length; i++)` makes me suspicious and you haven't told me whether my assumption about `endOfBound` is correct. Such information is more useful to me than the fact that you are pulling your hair out over this. `:)`.) – M Oehm Apr 20 '20 at 04:54
  • Sorry. Your assumption about endOfBound is correct. The for loop is there because the cells aren't modelled as a matrix but as an array as KenKen puzzles can be other formats, not only the 9x9 that is standard for Sudoku puzzles, and thus it is more convenient to do so.. –  Apr 20 '20 at 14:02