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_rows
and 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
and check_blocks
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_if_all_numbers
.
check_blocks
takes a board as input, divides it into blocks and checks if each block contains all numbers 1 2 ... n
using check_if_all_numbers
.
The 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[1])) # 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[1]): # 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
set
's instead? - Is the way I've divided the code into separate functions good?
- What about the indexing in
check_blocks
? - Any general tips regarding best practice etc.?
np.sort
...np.array_equal
stuff, have you considered just using Python's built-inset
operations to check set equality? It would be a lot shorter and simpler (and probably faster). \$\endgroup\$block_size
as input and use it to create two different vectors withindices
incheck_blocks
. However, I didn't do it, in order to keep this relatively simple. As I'm a beginner I thought it was better to learn how to do the simpler things well. Expanding it to cover more cases will be easy once I have the correct techniques. =) \$\endgroup\$