-4

I made a program that solves 4x4 sudoku using backtracking algorithm (the grid is split into 2 parts which are also split into 2 parts with 4 cells) , it has 3 functions, first prints the grid, second checks if a number can be placed into a cell, and main function (first 2 functions work as they are intended to).The program isn't working properly, I checked it on pythontutor and found out that it returns lists even though it shouldn't, for example a number is placed into the list, then a function calls itself and if some of the numbers can't be placed then the function returns, but it seems that it also returns the list.Here's the code.I know that this program has flaws and it isn't very efficient (I also know what to change), but it won't work because of the same reason.

def sudoku(array):
for x in range(2):  #loop that iterates through 2 lists
    for y in range(2):  #loop that iterates through 2 lists inside lists from above
        for z in range(4):  #loop that iterates through each cell

            if array[x][y][z] == 0: #if a cell is empty then we can write numbers in it
                for t in range(1, 5): #loop used for writing numbers into the cells  
                    array[x][y][z] = t #line that writes numbers into the cells
                    rec = check(x, y, z, t, array) #check if a number can be placed
                    if rec == False:  #if it can then
                        g = sudoku(array)   #call the function
                        if g == True:   #if g returns true then a solution is found, stop the program
                            return True 
                        elif g == False and t == 4:  #if g returns false and no number can be written into the next cell, and all numbers were written into the current cell, then return
                            return False
                    elif rec == True and t == 4: #if a number cant be placed into the cell and none of the numbers are valid, then return
                        return False
print_grid(array) #when all loops finish then a solution is found, print the grid
return True     #return
array = [[[0, 4, 0, 0], [0, 1, 3, 0]], [[0, 2, 4, 0], [0, 0, 1, 0]]]
Lunix
  • 1
  • 1
  • 5
    What do you mean "it returns lists"? I don't see the function retuning lists. I also don't see the function being called. Show us how you call it and how you came to the conclusion that it returns a list. – tobias_k Jan 25 '16 at 10:07
  • That's the problem, there isn't a line that returns a list (and it shouldn't be returned).Function calls itself on the line g = sudoku(array).In the first image you can see 3 stacks and number 4 is in the list, but in the second image, 3rd stack is gone because none of the numbers can be written into the cell, but as you can see number 4 is still in the list (it shouldn't be there). http://i.imgur.com/qH9C9fz.png http://i.imgur.com/HnyOzWY.png – Lunix Jan 25 '16 at 10:17
  • 1
    it only means that you forgot to remove that number. You work with one array all the time - if you don't remove something then it stays in array. – furas Jan 25 '16 at 10:27
  • What furas said. And on a related note, I can't see any actual backtracking in your algorithm: since you're using the one `array` to hold your board state you need to explicitly remove stuff from it when you decide that a particular trial solution can't succeed. Alternatively, pass a copy of `array` when you recurse. – PM 2Ring Jan 25 '16 at 10:32
  • BTW, `array` isn't a great variable name, since there's a [standard module with that name](https://docs.python.org/3/library/array.html) which provides array objects. – PM 2Ring Jan 25 '16 at 10:33
  • Why should I remove a number?I write a number, if it is correct then I call the function (with that number inside the list), if I return from functions then everything they changed will be lost (or am I wrong?) and the next number will rewrite the old one.Also why can't one list be used? – Lunix Jan 25 '16 at 10:50
  • Is the code posted the actual code? There should be an indentation in the code after `def sudoku(array)` or the code following it won't be in the function. – oystein-hr Jan 25 '16 at 10:51
  • I didn't indent it because it wasn't necessary. – Lunix Jan 25 '16 at 10:53
  • I changed the program and now it removes numbers that can't be placed into the board, and the program now works.Can anyone explain why? – Lunix Jan 25 '16 at 11:03
  • 1
    What do you mean it wasn't necessary to indent? This is python code? https://docs.python.org/2/tutorial/controlflow.html#defining-functions – oystein-hr Jan 25 '16 at 11:21
  • 1
    "if I return from functions then everything they changed will be lost (or am I wrong?)". Yes, that's wrong. When your function calls itself the _same_ `array` is passed to the new call, so all modifications to `array` are only affecting the one object and thus all of those modifications are cumulative. – PM 2Ring Jan 25 '16 at 11:40
  • 1
    Welcome to Stack Overflow, cool Sudoku solver! You probably got down-voted because people were having trouble testing your code and understanding what you thought was wrong. Indentation is very important in Python. Unlike in other languages, Python relies on indentation to know where a function definition ends. – anjsimmo Jan 25 '16 at 12:21

1 Answers1

0

Notice in the image you posted, that all 3 of the frames point to the same list.

Same List

In Python, lists are 'mutable'. It means, that you can modify the list, and that all the variables that reference that list will point to the changed list.

If you want to preserve the original list so that you can easily backtrack, then you will need to perform a 'deep copy' of the entire list:

def deep_copy(array):
    array_copy = [[[0, 0, 0, 0], [0, 0, 0, 0]], [[0, 0, 0, 0], [0, 0, 0, 0]]]
    for x in range(2):
        for y in range(2):
            for z in range(4):
                array_copy[x][y][z] = array[x][y][z]
    return array_copy

We give other functions (or in this case, our own function) a copy of the list rather than the original, so that any changes only affect the copy:

array_copy = deep_copy(array)
g = sudoku(array_copy)

Deep Copy

anjsimmo
  • 704
  • 5
  • 18