比这篇新的文章: Have a tru
比这篇旧的文章: 123

数独(Sudoku)游戏及其求解器

语言: Python, 标签: 游戏 数独 2008/06/14发布 6个月前更新
作者: HYRY, 点击1567次, 评论(8), 收藏者(2)

开关行号, 全选(Ctrl+C复制) | 一键复制:HTML, BBCode(Discuz!) , 源代码 | 查看:裸代码, 全屏
背景
主题: 字体:
Python语言: 数独(Sudoku)游戏及其求解器
001 # 输入您解不了的sudoku问题让电脑帮你找到答案
002 # 采用propagate&distribute算法对Sudoku求解
003 # 只寻找一个解,稍做修改可以寻找所有的解
004 # 提供120个由浅入深的sudoku问题
005
006 from Tkinter import *
007 from sets import Set
008 from copy import *
009
010 ROWS = [
011     Set((0, 1, 2, 3, 4, 5, 6, 7, 8)),
012     Set((9, 10, 11, 12, 13, 14, 15, 16, 17)),
013     Set((18, 19, 20, 21, 22, 23, 24, 25, 26)),
014     Set((27, 28, 29, 30, 31, 32, 33, 34, 35)),
015     Set((36, 37, 38, 39, 40, 41, 42, 43, 44)),
016     Set((45, 46, 47, 48, 49, 50, 51, 52, 53)),
017     Set((54, 55, 56, 57, 58, 59, 60, 61, 62)),
018     Set((63, 64, 65, 66, 67, 68, 69, 70, 71)),
019     Set((72, 73, 74, 75, 76, 77, 78, 79, 80))
020 ]
021
022 COLS = [
023     Set(( 0, 9, 18, 27, 36, 45, 54, 63, 72)),
024     Set(( 1, 10, 19, 28, 37, 46, 55, 64, 73)),
025     Set(( 2, 11, 20, 29, 38, 47, 56, 65, 74)),
026     Set(( 3, 12, 21, 30, 39, 48, 57, 66, 75)),
027     Set(( 4, 13, 22, 31, 40, 49, 58, 67, 76)),
028     Set(( 5, 14, 23, 32, 41, 50, 59, 68, 77)),
029     Set(( 6, 15, 24, 33, 42, 51, 60, 69, 78)),
030     Set(( 7, 16, 25, 34, 43, 52, 61, 70, 79)),
031     Set(( 8, 17, 26, 35, 44, 53, 62, 71, 80))
032 ]
033
034 BLOCKS = [
035     Set(( 0, 1, 2, 9, 10, 11, 18, 19, 20)),
036     Set(( 3, 4, 5, 12, 13, 14, 21, 22, 23)),
037     Set(( 6, 7, 8, 15, 16, 17, 24, 25, 26)),
038     Set((27, 28, 29, 36, 37, 38, 45, 46, 47)),
039     Set((30, 31, 32, 39, 40, 41, 48, 49, 50)),
040     Set((33, 34, 35, 42, 43, 44, 51, 52, 53)),
041     Set((54, 55, 56, 63, 64, 65, 72, 73, 74)),
042     Set((57, 58, 59, 66, 67, 68, 75, 76, 77)),
043     Set((60, 61, 62, 69, 70, 71, 78, 79, 80))
044 ]
045
046 def getLine(alist, position):
047     for s in alist:
048         if position in s: return s
049
050 def getBlocks(k):
051     blocks = getLine(ROWS, k) | getLine(COLS, k) | getLine(BLOCKS, k)
052     blocks.remove(k)
053     return blocks
054
055 def makeInitBoard():
056     board = {}
057     for i in range(81):
058         board[i] = Set( range(1,10) )
059     return board
060
061 def applyOneNumBlocks(board, oneNumBlocks):
062     todel = Set()
063     for k, v in oneNumBlocks.items():
064         board[k] = Set((v,))
065         blocks = getBlocks(k)
066         for block in blocks:
067             todel.add((block, v))
068     while len(todel) > 0:
069         k, v = todel.pop()
070         if v in board[k]:
071             board[k] = board[k].copy()
072             board[k].remove(v)
073             if len(board[k]) == 1:
074                 v = board[k]._data.keys()[0]
075                 blocks = getBlocks(k)
076                 for block in blocks:
077                     todel.add((block, v))
078     return board
079
080 def isSolvedBoard(board):
081     for v in board.values():
082         if len(v) != 1:
083             return False
084     return True
085
086 def isImpossibleBoard(board):
087     for v in board.values():
088         if len(v) == 0:
089             return True
090     return False
091
092 def divideBoard(board):
093     m = 10
094     index = -1
095     for k, v in board.items():
096         if len(v)>1 and m > len(v):
097             m, index = len(v), k
098
099     board1 = copy(board)
100     board1[index] = board1[index].copy()
101     v = board1[index].pop()
102     if len(board1[index]) == 1:
103         v1 = board1[index]._data.keys()[0]
104         oneNumBlocks1 = {index:v1}
105     else:
106         oneNumBlocks1 = {}
107
108     board[index] = Set((v,))
109     oneNumBlocks = {index:v}
110     return board, board1, oneNumBlocks, oneNumBlocks1
111
112 def solveBoard(board, oneNumBlocks):
113     applyOneNumBlocks(board, oneNumBlocks)
114     if isImpossibleBoard(board):
115         return None
116     if isSolvedBoard(board):
117         return board
118     board1, board2, numbers1, numbers2 = divideBoard(board)
119     r = solveBoard(board1, numbers1)
120     if r: return r
121     r = solveBoard(board2, numbers2)
122     if r: return r
123
124 def solve( numbers ):
125         d = {}
126         for i , c in enumerate(numbers):
127             if c >="1" and c<="9":
128                 d[i] = int(c)
129         result = solveBoard( makeInitBoard(), d)
130         if not result: return None
131         s = ""
132         for i in range(81):
133             s += str(list(result[i])[0])
134         return s
135
136 def GetColor(index):
137     for i, block in enumerate(BLOCKS):
138         if index in block:
139             if i % 2 == 0:
140                 return "#ffffff"
141             else:
142                 return "#cccccc"
143
144 def ChangeFocus(entrys, entry, pos):
145     for k, v in entrys.iteritems():
146         if v == entry:
147             k = k + pos
148             if k < 0: k += 81
149             if k > 80: k -= 81
150             entrys[k].focus()
151
152 def LoadSudoku(entrys, data, solve=False):
153     def setdata():
154         for i, c in enumerate(data):
155             e = entrys[i]
156             e.config(state="normal")
157             if not solve:
158                 e.config(foreground="#000000")
159             else:
160                 if e.get() != "":
161                     e.config(foreground="#cc0000")
162             e.delete(0, END)
163             if c != "0":
164                 e.insert(0, c)
165                 e.config(state="readonly", readonlybackground=GetColor(i))
166                 if not solve: e.config(foreground="#007777")
167     return setdata
168
169 def SolveIt(entrys):
170     s = ""
171     for i in range(81):
172         c = entrys[i].get()
173         if c == "": c="0"
174         s += c
175     s = solve(s)
176     if s: LoadSudoku(entrys, s, True)()
177
178 def OneDigital(entrys, event):
179     jump = {38:-9, 40:9, 37:-1, 39:1}
180     if event.keycode in jump:
181         ChangeFocus(entrys, event.widget, jump[event.keycode])
182     if event.char == " ":
183         event.widget.delete(0, END)
184         return "break"
185     if event.char<"0" or event.char>"9":
186         return "break"
187     if len(event.widget.get()) > 0:
188         event.widget.delete(0, END)
189         event.widget.insert(0, event.char)
190         return "break"
191
192 def main():
193     root = Tk()
194     root.title("Sudoku Solver")
195     entrys = {}
196     for row in range(9):
197         f = Frame(root)
198         f.pack(side = TOP )
199         for col in range(9):
200             index = row * 9 + col
201             e = Entry(f)
202             e.config(width=2, bg=GetColor(index), font=("Helvetica", 30),
203                     justify=CENTER, highlightcolor="#cc0000", highlightthickness="2")
204             e.bind("<Key>", lambda event:OneDigital(entrys, event))
205             e.pack(side = LEFT)
206             entrys[index] = e
207
208     menubar = Menu(root)
209     sudokumenu = Menu(menubar, tearoff=0)
210     for i, line in enumerate(SudokuData.split("\n")):
211         if i % 10 == 0:
212             submenu = Menu(sudokumenu, tearoff=0)
213             sudokumenu.add_cascade(label = "%s - %s" % (i, i+10), menu=submenu)
214         submenu.add_command(label = str(i), command=LoadSudoku(entrys, line))
215         line = line.strip()
216     menubar.add_cascade(label="Sudoku", menu=sudokumenu)
217     menubar.add_command(label="Solve", command=lambda:SolveIt(entrys))
218     menubar.add_command(label="Clear", command=LoadSudoku(entrys, "0"*81))
219     root.config(menu=menubar)
220     mainloop()
221
222 SudokuData = """640013900100026400029045700002000830860037019700209000001300690936408020005000000
223 349560820060398000500421006050080010600150007020070040800205009000836070036000400
224 640013900100026400329045700002000830860037019700209000001300690930408020005000000
225 390000040615000239070309050003020900006903000001060803060107380147030592030000070
226 020005863560203090030007251009750000006004709070028600605800070800001006307060040
227 120056000050700103709103450034060801007801000090030567305078902070900040002000000
228 070005020240000958005429000004100736703000201681003500000596300307000015060700040
229 001080425000510060000906781069372000307000100020008670910000236836001000700009008
230 901200034524001068000040201170400003006010470840000010000150006050800127610007009
231 000009001007080429010004600078950213020040060653012980002100040196020500500800000
232 004035020903020705052900000040100050508090106000502907090018030200450608305009001
233 921040035403602001680001000030400050100080006060007090000200063300804509250060417
234 000470050007050061521008007973005400004090500006300279700500194180040600040069000
235 004003085800605090093040100200100809006504021170080500032050600010030052600709004
236 003507080605980400010000059300206075050070060160305002720000030006029507040708600
237 000002034382954060000070082736009205820030609109020308000090000060147800010200000
238 605091000100605907020070006401000075360050091250000608700040080509107002000560709
239 059600170670100004123000500902700000580030017000001409005000731200008045091004820
240 600092004140000093900405200260043050000209000010650082806304005520000036700560008
241 000076140000018703000005682045000017070843060960000320694500000502780000083960000
242 032700509040596207070000060050902800106000005204670091010000003908300004300840150
243 000004871703500200000000000350809060020460000400102398230000780807000920690007134
244 700306400260000970800507100934080000570010084000060539001409002057000091002108006
245 006049700082010600790080145649050270007060050030072096020000810070028000000000507
246 150204063200010004704095200803000006025000340900000105006420800400050002590806017
247 509060408016542000004070050700600504300010002408007003080030200000426870100080609
248 000001234546000700100784000817060000020835060000070489000326005003000671694500000
249 901036480020980000608452009200000591015008004040060807000009015190003708002000000
250 070000020800562007000798000085030470037201850092050160000379000700185004010000030
251 004035020903020705050900000040100050508090106000502907090018030200450608305009001
252 740500000020378006000009057400700000900000003000003002150900000200147090000002014
253 000600900000000203006293510000001000001538704523406890050060000600382400847000000
254 100000005005090100603205704000482000700000008000173000301806207007030500800000003
255 000402057000095010300760008600004002100807004500200003700029001010570000280103000
256 007600240046000090920085000800002900003000400004900006000730024050000860032006700
257 600000739050093004030700000000000001975040200000070006000900140008002000200015098
258 060104050008305600200000001800407006006000300700901004500000002007206900040508070
259 000064500000800000702003900508000060300000007090000201001600308000005000004290000
260 000004005070009060402001000000000206100802003905000000000200701060500080300100000
261 005708200400000006070060080520904031000000000860107054090030060700000005002406100
262 500000028004010506000900000283000009000000000600000743000002000401070300960000005
263 900006700001040060480005000000700021605108903310004000000900052060030100008600007
264 000205000050000060682000753005306900900000006001907500128000674090000020000401000
265 500402000007000200000600809002007960800020005063500100701005000006000500000801003
266 850004002400020900000800070006000001040080030200000500034007000087090006600100047
267 000012030658930000000780090700250400015340967080000005540001070139020050800000000
268 600502008050800010004007300203000041000090000760005903006200100080001060100706004
269 100430090020900010900020807000109306000000000506207000708090005090005040050062009
270 201900000600058041000003050010000070024305180070000020060500000790240005000007402
271 035600078800900600000478000054300001160080057300001290000845000003006009040009580
272 020406308600090000908000000700004900062905740009700001000000102000050006106802070
273 006005400809007000520000000407203090030489070010506204000000043000800507001700600
274 003016400940000602050000031000370010000208000030054000120000050507000043004590200
275 050679312000000048000000000047020501005080700301060890000000000260000000789451030
276 006500100400002009000030008070100500080000060003090040200040000900700003005008200
277 001600009700000050300480000070000085032090460410000090000053001090000008800004300
278 030000020908000105040080060000406000005000300000107000020090030306000801010000070
279 253070000070000500008506700090600040000302000010008060006809300004000020000000615
280 008560000000070090300009054500007003810000000002600000000000080041000302006200070
281 000080000270000054095000810009806400020403060006905100017000620460000038000090000
282 009000030300009002052031070004250000290000051000013200080340510500100006010000800
283 000004071800210000007090300000000426200000007659000000005060100000049005410300000
284 100700090000010006800006070903080100000000000008020507040600005300050000020004008
285 390000400000090070000800503000080100504000709001030000207005000080060000003000024
286 009005000470002000083604010015000080000307000020000740040501870000700052000200100
287 904002000050070400010000600200809000700000008000507003008000090006030040000100305
288 010008407950000000008010000082000000700406008000000620000050700000000082503200010
289 000002048000000290001900000100095300003000400008310006000008700015000000230500000
290 080000700000206900006038000090080040400000005060010020000720100007601000003000050
291 030921005150830000000000000590000004370000081600000053000000000000019026900574010
292 000050000102490300000021600000000020030000507590004000000900006900503804008006000
293 000030100020064007000200003070000289003000600291000030800003000400950060002040000
294 000000000500607003076040810800003002005080900600900001081070420200806007000000000
295 000300100060090730000000806000108400070000080002906000405000000037080020009003000
296 200900000070060059000400061701002004000040000800100906120003000530020070000009002
297 000051400000700020008000003010000008500040009700000060400000700020006000003980000
298 000080005001900000700000016000100609305000104608003000560000002000005400900020000
299 008000000000307050020000903000090062204000801650070000409000010010508000000000200
300 000100205000075000504000080050017000970000038000980010065000801000490000203001000
301 002009070000000390005830040100000000070902010000000008020086700037000000010500600
302 000800000007000050609002000530007010000020000010900064000300208040000700000001000
303 001000000500040000020318000086200004070000050400003860000486090000090002000000700
304 003007400007200000000603205001000809900060003806000100105402000000008600002300500
305 000800703170003060030006800003009020900000006020500300006300010040600058809005000
306 000700200009203000700000010030000068000090000410000020050000003000507900006002000
307 000030270000040010090000403040003005900402006800500040108000060050070000029080000
308 261500000007000010080201000003100020020050080050003600000704030030000800000002754
309 800000004020000070009106500006208900090030040002407800007905600080000020600000009
310 410020000000608700500340020842000000090000010000000598070083005008704000000050079
311 050600970006800002800004006040100005080307020100008040400700001700005800028006090
312 000000000500080007097401020030000010000659000920000040010203000600070008000000000
313 000000000600090008018502030040000020000761000130000050020304000700080009000000000
314 000000000700010009029603040050000030000872000240000060030405000800090001000000000
315 000000000500080007090401020030000010000659000920000040010203000600070008000000000
316 000000000500080007097401020030000010000659000920000040010203050600070008000000000
317 000000000500080007090401020030000010100659000920000040010203000600070008000000000
318 000000000500080007090401020030000010000659000020000040010203000600070008000000000
319 000000000005406100080000090004010500070090020006080300020000070000503600000000000
320 050604000300070002000000000060000050000193000040000080000000000900020007010508040
321 020809000100040003000000000080000020000571000090000060000000000700030004050206090
322 020000070000508004000000000400030008070090020600010005000000000500604001030000090
323 060000010000309004000000000400050009010080060200070003000000000300204007050000080
324 800007030020060040500009010040010000300008907000000000000000000900000508060020000
325 070000010000208003000000000300050008010040070600090002000000000200603009050000040
326 070000020005804000000000000008030500020090070004010600000000000001506400090000030
327 010000070900604005000000000500090004080010030200070006000000000600205000030000080
328 600010005090020040300080007020000080100705006000000000000000000700306000040000090
329 070000020000401005000000000000000000400305008060000090500060001020090070300080004
330 000000000005406100080000090004010500070090020006080300020100070000503600000000000
331 020100070000508004000000000400030008070090020600010005000000000500604001030000090
332 000000000500080007097401020030000010000659000020000040010203000600070008000000000
333 000000000005406100080001090004010500070090020006080300020100070000503600000000000
334 000000000500080007097401020030000010000659000920000040018203000600070008000000000
335 000000000500080007090401020030000010000659000920000040010203050600070008000000000
336 000000000500080007090401020030000010000659000020000040010203050600070008000000000
337 050604090300070002000000000060000050000193000040000080000000000900020007010508040
338 000000000005406100080000090004010500070090020006080300020000070009503600000000000
339 020000070900508004000000000400030008070090020600010005000000000500604001030000090
340 100000080090702005000000000050060002800090010030040007000000000070305004600000090
341 020000080500907001000000000100040007080050020300060009000000000900301006040000050"""
342
343 if __name__ == "__main__":
344     main()
打分:

所有评论,共8条:( 我也来说两句)

1
半瓶墨水 6个月前 回复
0
0
好多数字哈,不知道能不能压缩一下
2
HYRY 6个月前 回复
0
0
测试了一下,用这两句可以压缩
import zlib, binascii
SudokuData = binascii.b2a_base64(zlib.compress(SudokuData, 9))
解压用
SudokuData = zlib.decompress(binascii.a2b_base64(SudokuData))
不过如果数据库空间不是那么紧张的话,还是直接看数字舒服一点。  
3
大花裤衩 6个月前 回复
0
0
呵呵,开个玩笑,数据库空间还多着呢,尽管用。
  
4
半瓶墨水 6个月前 回复
0
0
ft,一不小心马甲泄露了
  
5
Ai.Freedom 6个月前 回复
0
0
一开始以为有sudoku题目的生成算法..
6
vilinov 2个月前 回复
0
0
没看懂………………
貌似是递归…………………………

还是推理比较强大
7
半瓶墨水 20天前 回复
0
0
@HYRY 呵呵写的很不错啊,终于有时间读完一遍
@vilinov 这家伙很懒没写注释,我来写  
解数独的方法为:
1. 先遍历一遍,找出所有“只有一个候选数字”的格子
2. 填满这些数字,重复第一步
3. 如果没有“只有一个候选数字”的格子,那就找最少候选的那个格子
  先尝试这个格子的其中一个候选,再尝试剩余的候选数字
8
半瓶墨水 20天前 回复
0
0
@7 有一点点不准确的地方:填入数字的同时,就找出了因为填数字而新产生的“只有一个候选数字”的格子了
参见applyOneNumbers函数

发表评论

注册登录后再发表评论