Created
May 22, 2011 01:58
-
-
Save pdsouza29/985097 to your computer and use it in GitHub Desktop.
2009 Sudoku Solver
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# Preetam D'Souza | |
# 4.24.09 | |
# Period 7 | |
###[ Constraint Solvers: Sudoku ]### | |
SIZE = 9 # 9x9 | |
# Check method cycles through each key in the dictionary, and makes | |
# sure that each value (neighbor) does not have the same value as the key | |
def check(neighbors, colors): | |
for k in neighbors.keys(): | |
for v in neighbors[k]: | |
if colors[k] == colors[v]: # check if neighbors have same color | |
return False | |
return True # no neighbors have same color | |
# This Brute Force recursion method searches all possible territory | |
# coloring states by using a depth-first search through the | |
# state tree. | |
def brute(neighbors, colorlist, colors, depth): | |
if depth==len(neighbors): # list fully generated | |
if check(neighbors,colorlist): # good solution | |
print "OKAY: %s" % colorlist | |
#else: # solution fails | |
# print "NOT OKAY: %s" % colorlist | |
if depth>=len(neighbors): return # base case | |
for color in colors: # for each available color | |
n = neighbors.keys()[depth] # the last neighbor | |
colorlist[n] = color # try this color | |
brute(neighbors,colorlist,colors,depth+1) #depth-first recursion | |
# This search method uses forward checking with a degree and minimum color choice | |
# heuristic. There is also backtracking implemented into the recursive algorithm. | |
def search(neighbors, colorlist, colors, choices, sorted, depth): | |
if depth==len(neighbors): # list fully generated | |
print "OKAY: %s\n" % colorlist | |
for x in colorlist: | |
m[x[0]][x[1]] = colorlist[x] | |
return | |
sorted = sort(choices,sorted) | |
#print "Sorted list: %s\nChoices: %s\n" % (sorted,choices) | |
n = sorted[0] # neighbor with least color choices & most connections | |
for color in choices[n][0]: # for each available color for n | |
colorlist[n] = color # try this color | |
tmp = [] | |
for x in neighbors[n]: # alter neighbors | |
if x not in choices: continue | |
choices[x][1] -= 1 # neighbors have one less uncolored neighbor | |
if x in sorted and color in choices[x][0]: # remove color from neighbors | |
tmp.append(x) | |
choices[x][0].remove(color) | |
sorted.remove(n) # this territory has been used | |
search(neighbors,colorlist,colors,choices,sorted,depth+1) #depth-first recursion | |
sorted.append(n) #backtrack | |
for k in tmp: | |
choices[k][0].append(color) | |
for x in neighbors[n]: # backtrace | |
if x not in choices: continue | |
choices[x][1] += 1 | |
# Selection sort algorithm | |
def sort(choices,neighbors): | |
max = -1 | |
for i in xrange(0,len(neighbors)): | |
m = i | |
for j in xrange(i+1,len(neighbors)): | |
jcolors = len(choices[neighbors[j]][0]) # remaining choices for neighbors[j] | |
mcolors = len(choices[neighbors[m]][0]) # remaining choices for neighbors[max] | |
if jcolors < mcolors: | |
m = j | |
elif jcolors == mcolors and choices[neighbors[j]][1] > choices[neighbors[m]][1]: | |
m = j | |
neighbors[i], neighbors[m] = neighbors[m], neighbors[i] | |
return neighbors | |
# display sudoku matrix | |
def display(matrix): | |
for i in xrange(SIZE): | |
print '\n' | |
for j in xrange(SIZE): | |
if matrix[i][j] == '-1': | |
print '_'.rjust(5), | |
else: | |
print matrix[i][j].rjust(5), | |
print '\n\n' | |
# File I/O | |
infile = open('evil.txt') | |
filelist = infile.read() | |
print "filelist=%s" % filelist | |
lines = filelist.split('\n') | |
lines = lines[:-2] | |
print "file by lines %s\n\n" % lines | |
m = [[-1]*SIZE for i in xrange(SIZE)] | |
for i in xrange(len(lines)): | |
line = lines[i].split(',') | |
for j in xrange(len(line)): | |
if '\r' in line[j]: line[j] = line[j][:-1] | |
m[i][j] = line[j] | |
print "Matrix: %s" % m | |
display(m) | |
# dictionary creation | |
dict = {} | |
for i in xrange(SIZE): | |
for j in xrange(SIZE): | |
if m[i][j] != '-1': continue # blank space | |
k = (i,j) | |
if k not in dict: dict[k] = [] | |
for dx in xrange(SIZE): | |
vr = (i,dx) # each item in row i | |
vc = (dx,j) # each item in col j | |
if vr not in dict: dict[vr] = [] | |
if vc not in dict: dict[vc] = [] | |
if vr != k and vr not in dict[k]: dict[k].append(vr) | |
if vc != k and vc not in dict[k]: dict[k].append(vc) | |
if vr != k and k not in dict[vr]: dict[vr].append(k) | |
if vc != k and k not in dict[vc]: dict[vc].append(k) | |
# add neighbors in each 3x3 square region | |
t = (1,1) | |
for i in xrange(3): | |
r = (t[0]+3*i,t[1]) | |
for j in xrange(3): | |
r = (r[0],t[1]+3*j) | |
square = [(r[0]-1,r[1]-1),(r[0]-1,r[1]),(r[0]-1,r[1]+1), | |
(r[0] ,r[1]-1),(r[0] ,r[1]),(r[0] ,r[1]+1), | |
(r[0]+1,r[1]-1),(r[0]+1,r[1]),(r[0]+1,r[1]+1)] | |
for k in square: | |
for v in square: | |
if v == k : continue | |
if v not in dict[k]: dict[k].append(v) | |
if k not in dict[v]: dict[v].append(k) | |
# get rid of fixed places | |
for key in dict.keys(): | |
if m[key[0]][key[1]] != '-1': | |
del dict[key] | |
print "Dictionary: %s\n\n" % dict | |
colors = "1 2 3 4 5 6 7 8 9".split(' ') | |
# create the choices dictionary | |
colorlist = {} | |
choices = {} | |
for x in dict.keys(): | |
if m[x[0]][x[1]] != '-1': | |
continue | |
tmp = colors*1 | |
for n in dict[x]: | |
if m[n[0]][n[1]] in tmp: | |
tmp.remove(m[n[0]][n[1]]) | |
choices[x] = [tmp*1,len(dict[x])] # [remaining choices, # of neighbors] | |
print "Color Choices and Uncolored Neighbors Dictionary: %s\n\n" % choices | |
sorted = sort(choices,dict.keys()) | |
print "Sorted Neighbor List: %s\n" % sorted | |
# SEARCH | |
search(dict,colorlist,colors,choices,sorted,0) | |
# output solution | |
display(m) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment