As you will see, I am not very familiar with Python and NumPy but want to learn it.
The following code is a very basic Sudoku solver which works fine for simple examples. Although it runs, I still have the feeling it is not very Pythonic.
from numpy import *
import sys
def set(col,row,wert):
# Set the value in field and adjust the possibility tensor
pos[col,row,:] = 0 # the field itself
pos[:,row,wert] = 0 # the col
pos[col,:,wert] = 0 # the row
# The 3x3 block
col_start = floor(col / 3) * 3
row_start = floor(row / 3) * 3
pos[col_start:col_start + 3,row_start:row_start + 3,wert] = 0
# Write down the value
feld[col,row] = wert + 1
def read(name):
# Read in the stuff and create field
fid = open('in','r')
for col in range(9):
line = fid.readline()
for row in range(9):
if line[row] is not '0':
set(row,col,int(line[row]) - 1)
fid.closed
def write(name):
# Write the output into a file
fid = open("out","w")
for col in range(0,9):
for row in range(0,9):
fid.write(str(feld[row,col]))
fid.write('\n')
fid.closed
def check():
# Check the solution for errors
print("%i Missing" % (81 - count_nonzero(feld)))
neq = lambda x: count_nonzero(unique(x)) != count_nonzero(x)
for x in range(9):
if neq(feld[:,x]):
print("Error in row %i" % (x))
if neq(feld[x,:]):
print("Error in col %i" % (x))
col_start = floor(x / 3) * 3
row_start = (x % 3) * 3
if neq(feld[col_start:col_start + 3,row_start:row_start + 3]):
print("Error in block %i / %i" % (col_start/3,row_start/3))
def only_pos_left():
# This point is the only one that can be x
for x in range(9):
for y in range(9):
if sum(pos[x,:,y]) == 1:
set(x,nonzero(pos[x,:,y])[0][0],y)
if sum(pos[:,x,y]) == 1:
set(nonzero(pos[:,x,y])[0][0],x,y)
col_start = floor(x / 3) * 3
row_start = (x % 3) * 3
if sum(pos[col_start:col_start + 3,row_start:row_start + 3,y]) == 1:
index = nonzero(pos[col_start:col_start + 3,row_start:row_start + 3,y]);
set(col_start + index[0][0],row_start + index[1][0],y)
def only_pos_for_it():
# This point can only be x
for x in range(9):
for y in range(9):
if sum(pos[x,y,:]) == 1:
set(x,y,nonzero(pos[x,y,:])[0][0])
# main method
if __name__ == "__main__":
# Init some variables
feld = zeros((9,9),dtype=uint8) # field with the values were sure about
pos = ones((9,9,9),dtype=bool_) # values which are still possible
old_pos = 0
read(sys.argv[0])
# Let it run
while any(old_pos != pos):
old_pos = copy(pos)
only_pos_left()
only_pos_for_it()
write(sys.argv[1])
check()
Some comments on it:
- I know that
from NumPy import *
is bad practise but its just so much faster to write. - Am I using the lambdas in a correct manner? I want it to be flexible to add more advanced solving algorithms later on.
- Please tell me just anything you would change to make better use of the language (speed and readability wise).
I know that in terms of data structures this could be optimized to use something like this
class point:
def __init__(self)
self.val = uint8
self.pos = zeros(9,dtype=bool_)
but then I would lose all the nice indexing that NumPy offers.