Python Sudoku solver

Sudoku puzzleI spent the last couple of days thinking about and writing a program in Python to solve Sudoku puzzles. I know it has been done many times before, but I wanted to try anyway. I have been really excited about programming lately. It makes me feel like a kid again, when my dad had a TRS-80 and I was writing BASIC programs on it.

This Sudoku solver uses only a very basic method. I will add more advanced methods later. This was more about an exercise in programming than creating a robust Sudoku solver. Here it is. To get a usable copy of the code, click the little icon to the left of the printer icon, then copy and paste the code from the pop-up window.

#       sudoku_solver_7.py
#		version 0.1
#
#       Copyright 2011 Daniel Veazey <danielveazey@gmail.com>
#
#       This program is free software; you can redistribute it and/or modify
#       it under the terms of the GNU General Public License as published by
#       the Free Software Foundation; either version 2 of the License, or
#       (at your option) any later version.
#
#       This program is distributed in the hope that it will be useful,
#       but WITHOUT ANY WARRANTY; without even the implied warranty of
#       MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
#       GNU General Public License for more details.
#
#       You should have received a copy of the GNU General Public License
#       along with this program; if not, write to the Free Software
#       Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
#       MA 02110-1301, USA.
#
#       
 
def quadfinder(find): # to figure out which quad to check for a position while solving
	global quad_position
	for quadcount in range(0, 9):
		if find in quad_position[quadcount]:
			return quadcount
 
print "Welcome to Daniel Veazey's Sudoku Solver 7."
print "http://www.danielveazey.com"
print "Please fill in the available numbers on the board,"
print "starting on the top row (Row 1), going left to right."
print "If a square is blank, put a 0 in its place."
print "Separate each position with a comma and a space."
print "Each position can be only one digit, 0 through 9."
print "Example:"
print "Row 1: 5, 6, 0, 0, 4, 1, 0, 0, 8"
print "Row 2: 1, 0, 0, 0, 0, 9, 0, 7, 0"
print "etc."
print
print "Let's get started."
print
print
 
## ask the user to populate the board by rows
row = [0, 1, 2, 3, 4, 5, 6, 7, 8]
for x in range(0, 9):
	row[x] = list(input("Row " + str(x+1) + ": "))
 
print
print
print "Original board:"
for x in range (0, 9):
	print row[x]
 
## define and populate the columns by referring to the rows
col = [0, 1, 2, 3, 4, 5, 6, 7, 8]
for x in range (0, 9):
	col[x] = [row[0][x], row[1][x], row[2][x], row[3][x], row[4][x], row[5][x], row[6][x], row[7][x], row[8][x]]
 
## define and populate quads by referring to slices of rows
quad = [0, 1, 2, 3, 4, 5, 6, 7, 8]
quad[0] = row[0][0:3] + row[1][0:3] + row[2][0:3]
quad[1] = row[0][3:6] + row[1][3:6] + row[2][3:6]
quad[2] = row[0][6:] + row[1][6:] + row[2][6:]
quad[3] = row[3][0:3] + row[4][0:3] + row[5][0:3]
quad[4] = row[3][3:6] + row[4][3:6] + row[5][3:6]
quad[5] = row[3][6:] + row[4][6:] + row[5][6:]
quad[6] = row[6][0:3] + row[7][0:3] + row[8][0:3]
quad[7] = row[6][3:6] + row[7][3:6] + row[8][3:6]
quad[8] = row[6][6:] + row[7][6:] + row[8][6:]
 
## populate list of single positions
position = list()
for z in range(0, 81):
	for x in range(0, 9):
		for y in range(0, 9):
			position.append(row[x][y])
 
## put list of possible answers in unsolved single positions
for x in range(0, 81):
	if position[x] == 0:
		position[x] = [1, 2, 3, 4, 5, 6, 7, 8, 9]
 
## define which positions are in which quads
quad_position = [0, 1, 2, 3, 4, 5, 6, 7, 8]
quad_position[0] = [0, 1, 2, 9, 10, 11, 18, 19, 20]
quad_position[1] = [3, 4, 5, 12, 13, 14, 21, 22, 23]
quad_position[2] = [6, 7, 8, 15, 16, 17, 24, 25, 26]
quad_position[3] = [27, 28, 29, 36, 37, 38, 45, 46, 47]
quad_position[4] = [30, 31, 32, 39, 40, 41, 48, 49, 50]
quad_position[5] = [33, 34, 35, 42, 43, 44, 51, 52, 53]
quad_position[6] = [54, 55, 56, 63, 64, 65, 72, 73, 74]
quad_position[7] = [57, 58, 59, 66, 67, 68, 75, 76, 77]
quad_position[8] = [60, 61, 62, 69, 70, 71, 78, 79, 80]
 
################# SOLVING ######################################
## this program uses only a very simple method to solve the puzzle,
## just checking to see if a possible answer for a position
## is already in its row, column or quad. if so, the possible answer
## is eliminated from the list of possible answers.
 
did_change = True
while did_change == True:
	did_change = False
	for x in range(0, 81):
		if type(position[x]) == list:
			y = 0
			while type(position[x]) == list and y < len(position[x]): # to only keep checking if there are more items in the list of possible answers
				# check to see if the possible answer is already in a position in the row, column or quad
				if position[x][y] in row[x/9] or position[x][y] in col[x%9] or position[x][y] in quad[quadfinder(x)]: # quadfinder tells us which quad to check
					del position[x][y] ## delete the possible answer if it's found elsewhere
					did_change = True ## to keep the loop going
					if len(position[x]) == 1: ## if list of possible answers is only one item long,
						position[x] = position[x][0] ## remove the nested list
						row[x/9][x%9] = position[x] ## and copy the answer to the rows,
						col[x%9][x/9] = position[x] ## columns,
						for quad_count in range(0, 9): ## and quads
							if x in quad_position[quad_count]: ## similar to function quadfinder(), but used on its own here
								for z in range(0, 9):
									if x == quad_position[quad_count][z]:
										quad[quad_count][z] = position[x]
				else: y = y + 1 # to check the next item in the list of possible answers
 
## additional methods will go here in the future
 
## find out if the puzzle was solved:
solved = True
for x in range(0, 81):
	if type(position[x]) == list:
		solved = False
 
if solved == False:
	print
	print
	print "Here is a list of positions with either"
	print "the correct answers or"
	print "a list of possible correct answers:"
	for x in range(0, 81):
		print str(x+1) + ': ' + str(position[x])
 
	## also print board by rows
	print
	print
	print "This is as far as I got using the simple method Scroll up"
	print "to see a list of possible answers for each position on the board."
	for x in range (0, 9):
		print row[x]
else:
	print
	print
	print "I SOLVED IT!!!"
	for x in range (0, 9):
		print row[x]

Plans for future versions

  • Add more advanced methods for solving puzzles
  • Add a timer to tell the user how long it took to solve the puzzle

Any more ideas? Leave a comment.

The bike saga continues

I now know that the combination to my bike lock does not contain both a 1 and a 4. I thought it did, but none of the 302 combinations from my previous program worked. But I haven’t given up hope. Continue reading