Sudoku resolver in Python

Last updated on Fri, 2007-12-14 12:45. Originally submitted by fabio on 2007-12-08 15:15.

A simple Sudoku resolver written in Python.

Sorry for the Italian code comments. Please add a comment below if you don't get parts of the algorithm.

# -*- coding: cp1252 -*-

# esercizio di pdp07 SUDOKU


import copy

#list of all numbers

num = ['1','2','3','4','5','6','7','8','9']
        

class sset(set):
	def rem(self, x):
		if x in self: self.remove(x)


	#adds elements of list
	def addlist(self,l):
		for a in l:
			self.add(a)

	def compl(self):
		s1=sset(num)
		for k in self:
			s1.remove(k)
		return s1

# define no repetitions
def alldiff(l):
        s = set(l)
        return len(l)==len(s)


#defines the squares from the upperleft angle
def sqg(a,b):
	a1 = a/3*3    
	b1 = b/3*3 
	l = [[i,j] for i in range(a1,a1+3) for j in range(b1,b1+3)]
	return l



class sudo:

	def __init__(self):
		self.boa = [['#' for i in range(0,9)] for j in range(0,9)]
		self.indices = (0,0)
		self.pos = [[sset(num) for i in range(0,9)] for j in range(0,9)]
		self.free = 81
	
	def __iter__(self):
		return(self)

	def setchange(self, sudo2):
		self.pos = sudo2.getpos()
		self.boa = sudo2.getboa()
		self.free = sudo2.getfree()

	def getpos(self):
		return self.pos

	def getboa(self):
		return self.boa

	def getfree(self):
		return self.free

	def add(self, i, j, d):
		if((self.boa[i][j]=='#') and (d in self.pos[i][j])):
			self.boa[i][j] = d
			self.remx(j, d)
			self.remy(i, d)
			self.pos[i][j]=sset([])
			self.remsqr(i, j, d)
			self.free = self.free - 1
		else:
			# print "eccezione add"
			raise ValueError


	def remx(self, j, d):
		for i in range(0, 9):
			self.pos[i][j].rem(d)
                

	def remy(self, i, d):
		for j in range(0, 9):
			self.pos[i][j].rem(d)

	def remsqr(self, i, j, d):
		for l in sqg(i,j):
  			self.pos[l[0]][l[1]].rem(d)

	def dcopy(self):
		b1=sudo()
		b1.boa = copy.deepcopy(self.boa)
		b1.indices = (0,0)
		return b1

	def minpos(self):
		m = 0
		n = 0
		for i in range(0,9):
			for j in range(0,9):
				#print "boa: " + repr(self.boa[i][j])
				if ((self.boa[i][j]=='#') and ((len(self.pos[i][j])< len(self.pos[m][n]) or (self.boa[m][n]!='#')))):
					m = i
					n = j
					
		return (m,n)

	def move(self):
		if (self.getfree() == 0):
			print "risolto"
			return 
		(m, n) = self.minpos()
		#print repr(m) + " " + repr(n)
		if(len(self.pos[m][n])==0):
			#print "eccezione"
			raise ValueError
		else:
			#print "lunghezza min pos" + repr(len(self.pos[m][n]))
			if(len(self.pos[m][n])==1):
				#print "pop: " + repr(self.pos[m][n].pop())
				r = self.pos[m][n].pop()
				self.pos[m][n].add(r)
				self.add(m, n, r)
				self.move()
			else:
				for d in self.pos[m][n]:
					#print repr(d)
					s = copy.deepcopy(self)
					s.add(m, n, d)
					#print "move prima if:" + repr(s)
					if(s.solve()==1):
						#print "fatto s.solve() s e :" + repr(s)
						self.setchange(s)
						return
				raise ValueError

	def solve(self):
		try:
			self.move()
			return 1
		except ValueError:
			return 0

	def __repr__(self):
		val = reduce(lambda a,b: a+b, 
			  [repr(self.boa[k])+"\n" for k in range(9)])
		posz = ""
		for i in range(0,9):
			for j in range(0,9):
				a = self.pos[i][j]
				posz += "(" + repr(j) + "," + repr(i) + ")"  + repr(self.pos[i][j]) + "\n"
		return "val:\n" + val + "possibilita:\n" + posz



#print repr(table)
print "Sudoku\n"
print "Per inserire un nuovo sudoku da console, digita: 1>"
print "Per risolvere un sudoku da default, digita:      2>"
print "Per terminare digita                             0\n>"

c=raw_input("Cosa vuoi fare?> ")
while (c!="0"):
	if c=="1":
		read="y"
		table=sudo()
		while (read!="n"):
			try:
				val = raw_input("Dimmi un numero da inserire> ")
				x = int(raw_input("Posizione X> "))
				y = int(raw_input("Posizione Y> "))
				table.add(y, x, val)
				read = raw_input("Continuare? [y/n]>")
			except ValueError:
				print "Riprova, numero gia presente o posizione occupata!"
		print repr(table)
		table.solve()
		print repr(table)
	else:
		if c=="2":
			try:
				table2=sudo()
				print repr(table2)
				table2.add(0,3,'9')
				table2.add(0,4,'8')
				table2.add(0,5,'3')
				table2.add(0,8,'7')
				table2.add(1,1,'8')
				table2.add(1,6,'4')
				table2.add(1,7,'1')
				table2.add(2,0,'5')
				table2.add(2,1,'6')
				table2.add(2,2,'7')
				table2.add(2,6,'8')
				table2.add(3,6,'9')
				table2.add(3,7,'3')
				table2.add(4,0,'7')
				table2.add(4,3,'5')
				table2.add(4,4,'2')
				table2.add(4,5,'9')
				table2.add(4,8,'1')
				table2.add(5,1,'9')
				table2.add(5,2,'4')
				table2.add(6,2,'1')
				table2.add(6,6,'2')
				table2.add(6,7,'8')
				table2.add(6,8,'6')
				table2.add(7,1,'5')
				table2.add(7,2,'9')
				table2.add(7,7,'7')
				table2.add(8,0,'8')
				table2.add(8,3,'7')
				table2.add(8,4,'4')
				table2.add(8,5,'1')
			except ValueError:
				print "ERRORE, numero gia presente o posizione occupata!"
			print repr(table2)
			table2.solve()
			print repr(table2)


	print "Per inserire un nuovo sudoku da console, digita: 1>"
	print "Per risolvere un sudoku da default, digita:      2>"
	print "Per terminare digita                             0\n>"
	c=raw_input("Cosa vuoi fare?> ")

nice one

Submitted by Lena Dahlman (not verified) on Thu, 2009-01-29 16:24.

Nice one Fabio? By the way, the texts are too small to read. I'll try this one. Hope it works.

Let me know if you have

Submitted by fabio on Thu, 2009-01-29 17:09.

Let me know if you have problems with the code. I can help you.

cool

Submitted by pierce (not verified) on Tue, 2007-12-18 10:50.

Well, tested this code.. pretty cool man!

Post new comment

The content of this field is kept private and will not be shown publicly.
If you have a personal or company website insert its address in the form http://www.example.com/ .
  • Web page addresses and e-mail addresses turn into links automatically.
  • Allowed HTML tags: <a> <em> <strong> <cite> <code> <ul> <ol> <li> <dl> <dt> <dd> <pre> <del> <img> <h2> <h3> <h4> <b> <video> <sub> <sup>
  • Lines and paragraphs break automatically.
  • Images can be added to this post.
  • You may use [inline:xx] tags to display uploaded files or images inline.
  • You may insert videos with [video:URL]
  • Each email address will be obfuscated in a human readable fashion or (if JavaScript is enabled) replaced with a spamproof clickable link.

More information about formatting options