Search code examples
algorithmruntime-errorsudokubacktrackingscilab

Sudoku Solver Scilab


I am trying to write a program that solves sudoku's using backtracking. I'm using scilab at the moment. I keep getting errors in my recursive algorithm, I must be doing something wrong. Any help is welcome.

I put my error code at the bottom.

///////////////////////////////////////////////////////////////////////////
//////////////////////////   Check Sudoku   ///////////////////////////////
///////////////////////////////////////////////////////////////////////////

function r=OneToNine(V) // function checks if the given vector V contains 1 to 9
r = %T                  // this works
u = %F
index = 1
while r == %T & index < 10
    for i=1 : length(V)
        if V(i)==index then 
            u = %T
        end
    end
    index=index+1
    if u == %F then r = %F
        else u = %F
    end          
end
if length(V) > 9 then r = %F
end
endfunction

function y=check(M) // Checks if the given matrix M is a solved sudoku
y = %T              // this works too

if size(M,1)<>9 | size(M,2)<>9 then // if it has more or less than 9 rows and columns
    y = %F                          // we return false
end

for i=1 : size(M,1)                 // if not all rows have 1-9 we return false
    if OneToNine(M(i,:)) == %F then
        y = %F
    end
end
endfunction


function P=PossibilitiesPosition(board, x, y)
// this one works
// we fill the vector possibilites with 9 zeros
// 0 means empty, 1 means it already has a value, so we don't need to change it

possibilities = []      // a vector that stores the possible values for position(x,y)
for t=1 : 9            // sudoku has 9 values
    possibilities(t)=0
end

// Check row f the value (x,y) for possibilities
// we fill the possibilities further by puttin '1' where the value is not possible 
for i=1 : 9            // sudoku has 9 values
    if board(x,i) > 0 then
        possibilities(board(x,i))=1
    end
end

// Check column of the value (x,y) for possibilities
// we fill the possibilities further by puttin '1' where the value is not possible
for j=1 : 9            // sudoku has 9 values
    if board(j, y) > 0 then
        possibilities(board(j, y))=1
    end
end

// Check the 3x3 matrix of the value (x,y) for possibilities
// first we see which 3x3 matrix we need
k=0
m=0
   if x >= 1 & x <=3 then
       k=1
   else if x >= 4 & x <= 6 then
           k = 4
   else k = 7
       end
   end
   if y >= 1 & y <=3 then
       m=1
   else if y >= 4 & y <= 6 then
           m = 4
   else m = 7
       end
   end

   // then we fill the possibilities further by puttin '1' where the value is not possible
   for i=k : k+2
       for j=m : m+2
           if board(i,j) > 0 then
               possibilities(board(i,j))=1
           end
       end           
   end       
   P = possibilities

   // we want to see the real values of the possibilities. not just 1 and 0
   for i=1 : 9            // sudoku has 9 values
       if P(i)==0 then
           P(i) = i
       else P(i) = 0
       end
   end

endfunction





///////////////////////////////////////////////////////////////////////////
//////////////////////////   Solve Sudoku   ///////////////////////////////
///////////////////////////////////////////////////////////////////////////

function S=solve(board) // the real solving function, here must be a problem somewhere
x=1
y=1
possibilities = [] // an empty vector to put in the possible value later on

if check(board) == %T then // if it's a fully solved sudoku the function gives the solution
    S = board

else
    for i=1 : 9                   // sudoku has 9 values
        for j=1 : 9               // sudoku has 9 values
            if board(i,j)==0 then // if the value board(i,j) is empty so 0
                x=i               // we put the coordinates in x and y
                y=j               // break means stop the loop
                break
            end
        end
    end
    possibilities = PossibilitiesPosition(board,x,y) //we check the possibilities

    for p=1 : 9                             // sudoku has 9 values
        if possibilities(p) > 0 then        // if this is a possibility
            board(x,y) = possibilities(p)   // we put in that value
            solve(board)                    // and we repeat until check(board) gives true
        end
    end
    board(x,y)=0                            // if we went trough al the possibilities
end                                         // and there is still no solution we have to put that value back to 0
                                            // this is called backtracking
endfunction


//////////////////////////////////////////////////////////////////////////////

Error code:

// Very Easy sudoku from brainbashers.com

M = [0 2 0 0 0 0 0 4 0
 7 0 4 0 0 0 8 0 2
 0 5 8 4 0 7 1 3 0
 0 0 1 2 8 4 9 0 0
 0 0 0 7 0 5 0 0 0
 0 0 7 9 3 6 5 0 0
 0 8 9 5 0 2 4 6 0
 4 0 2 0 0 0 3 0 9
 0 1 0 0 0 0 0 8 0]

solve(M)

!--error 4 Undefined variable: S at line 31 of function solve called by :
at line 24 of function solve called by :
at line 24 of function solve called by :
at line 24 of function solve called by :
at line 24 of function solve called by :
at line 24 of function solve called by :
at line 24 of function solve called by :
at line 24 of function solve called by :
at line 24 of function solve called by :
at line 24 of function solve called by :
at line 24 of function solve called by :
at line 24 of function solve called by :
at line 24 of function solve called by :
solve(M) at line 184 of exec file called by :
B-8525585618758424927.sce', 1 while executing a callback


Solution

  • The main issue is this line:

    solve(board) 
    

    which should be

    S = solve(board)
    

    A recursive function must provide two things: a way to delegate a modified task to another instance of itself, and a way to return the result to the instance that called it. You didn't have the second thing.

    Another, lesser issue, is your search for x,y:

    for i=1 : 9                   // sudoku has 9 values
        for j=1 : 9               // sudoku has 9 values
            if board(i,j)==0 then // if the value board(i,j) is empty so 0
                x=i               // we put the coordinates in x and y
                y=j               // break means stop the loop
                break
            end
        end
    end
    

    The break command only stops the loop from which it was called. So, it breaks your loop over j, but then the loop over i continues. A quick fix:

    x=0    // instead of 1
    y=0    // instead of 1
    
    // other stuff you have there
    
    for i=1 : 9                   // sudoku has 9 values
        for j=1 : 9               // sudoku has 9 values
            if board(i,j)==0 then // if the value board(i,j) is empty so 0
                x=i               // we put the coordinates in x and y
                y=j               // break means stop the loop
                break
            end
        end
        if x>0 then
            break
        end
    end
    

    Also, you probably wanted disp(solve(M)) at the end; otherwise the end result of computation is neither shown nor kept in any variable.

    With these corrections, your code does work, outputting this solution:

    1.    2.    6.    8.    9.    3.    7.    4.    5.  
    7.    3.    4.    6.    5.    1.    8.    9.    2.  
    9.    5.    8.    4.    2.    7.    1.    3.    6.  
    5.    6.    1.    2.    8.    4.    9.    7.    3.  
    8.    9.    3.    7.    1.    5.    6.    2.    4.  
    2.    4.    7.    9.    3.    6.    5.    1.    8.  
    3.    8.    9.    5.    7.    2.    4.    6.    1.  
    4.    7.    2.    1.    6.    8.    3.    5.    9.  
    6.    1.    5.    3.    4.    9.    2.    8.    7.  
    

    Things to consider:

    1. The double loop over i,j should be another function, one that receives a matrix and returns the first (x,y) coordinates where the entry is zero. Then this function would just have return [i,j] inside of the double loop, stopping the whole double loop:

    for i=1 : 9                   // sudoku has 9 values
        for j=1 : 9               // sudoku has 9 values
            if board(i,j)==0 then // if the value board(i,j) is empty so 0
                return [i,j]
            end
        end
    end
    // do something if the matrix is full 
    
    1. The backtracking is not implemented correctly. The command board(x,y)=0 has no effect, since the value of local variable board is simply forgotten when the function ends. Your code would go into infinite recursion if given an unsolvable puzzle.