The code below takes a filled out Sudoku board of size NxN, with sub-blocks of nxn, and checks if the solution is correct.
main_function takes a board as input. This function calls
check_blocks. The first of the two is used to check both the rows and columns of the board. The second one is used to check the nxn sub-blocks.
check_if_all_numbers takes a vector of numbers as input and checks if the vector contains all numbers
1 2 ... n. This function is called by both
check_rows takes a board as input, loops over each of the rows and checks whether it contains all numbers
1 2 ... n using
check_blocks takes a board as input, divides it into blocks and checks if each block contains all numbers
1 2 ... n using
main_function will stop once it finds an incorrect row, columns or block. For a correct board, the output from the function will look like this:
Function main_function() is called Checking rows: All rows are correct Checking columns: All columns are correct Checking blocks: All blocks are correct
These are the function definitions:
import numpy as np def main_function(board): print('Function main_function() is called\n') # If the input is of type "list", convert it to a numpy array # Otherwise keep it as it is if type(board) == list: board = np.asarray(board) print('Checking rows:') rows_are_correct = check_rows(board) if not rows_are_correct: print('There are incorrect rows on the board') return else: print('All rows are correct') print('Checking columns:') # Transpose board and do the same operations as with the columns transposed_board = board.transpose() cols_are_correct = check_rows(transposed_board) if not cols_are_correct: print('There are incorrect columns on the board') return else: print('All columns are correct') # Check if all nxn blocks are correct print('Checking blocks:') blocks_are_correct = check_blocks(board) if not blocks_are_correct: print('There are incorrect blocks on the board') return else: print('All blocks are correct') def check_blocks(board): size_of_blocks = int(np.sqrt(board.shape)) # Number of cols/rows in each sub-block indices = np.arange(0,size_of_blocks) # Create a vector [0,1,..n] that represents # the row and columns indices of each block is_permutation = True # Initialize is_permutation to True for x in range(0,size_of_blocks): # Double loop over rows and columns for y in range(0,size_of_blocks): rid = indices + y*size_of_blocks # row index[0,1,..,n] then [0,1]+1*n... cid = indices + x*size_of_blocks # column index sub_block = board[np.ix_(rid,cid)] # Subtract sub-blocks using np.ix_ flat_block = sub_block.flatten() # flatten the block and pass is_permutation = check_if_all_numbers(flat_block) # and pass it to check_if_all_numbers if not is_permutation: return is_permutation return is_permutation def check_if_all_numbers(numbers): all_numbers = np.arange(1,numbers.size+1) # List of numbers 1-N sorted_numbers = np.sort(numbers) # Sort numbers is_permutation = np.array_equal(sorted_numbers, all_numbers) # Check if all numbers are present return is_permutation def check_rows(board): # Initialize is_permutation to True is_permutation = True for n in range(0,board.shape): # Loop over the rows/columns is_permutation = check_if_all_numbers(board[n]) # Check if all numbers are present if not is_permutation: return is_permutation return is_permutation
This is saved as "sudoku_checker.py". I have the following lines in the bottom of the file.
board = [[1,2,3,4],[4,3,1,2],[2,1,4,3],[3,4,2,1]] main_function(board) board = [[9,4,2,7,6,1,8,5,3],[3,8,7,5,9,2,6,4,1],[6,1,5,8,3,4,2,9,7], \ [2,6,3,1,4,7,5,8,9],[8,7,1,9,2,5,3,6,4],[4,5,9,3,8,6,1,7,2], \ [7,9,6,2,1,8,4,3,5],[5,2,8,4,7,3,9,1,6],[1,3,4,6,5,9,7,2,8]] main_function(board)
I'm using Spyder, with Python 2.7. The program is called by simply clicking "Run". To be honest, I don't know how to call if from the command prompt.
How can I improve this code. I'm a beginner in Python and I'm looking for any improvements.
- I've used a lot of Numpy in the code. Would it be better to do this in plain Python, or is Numpy a good choice? If so, how? I tried this at first but failed, and went for Numpy instead.
- Should I have used plain Python and
- Is the way I've divided the code into separate functions good?
- What about the indexing in
- Any general tips regarding best practice etc.?