在这里详述 源码库/sudoku.py。 {{{#!python # -*- coding: utf8 -*- """ MoinMoin - sudoku This parser is used to show and resolve sudoku puzzles Improving is encouraged, but please send me a copy Email: znight@tom.com @copyright: 2009 by znight@tom.com @license: GNU GPL """ import random from MoinMoin import wikiutil Dependiencies=[] sudoku_id=0 def sudoku_settings(gen=28): return locals() class SudStack: _data=[] _cand=[] def __init__(self): self._data=[] self._cand=[] def push(self,x,y): self._data.append(x[:]) self._cand.append(y[:]) def pop(self): if len(self._data)>0: return self._data.pop(),self._cand.pop() return [],[] def clear(self): self._data=[] self._cand=[] def pos2seq(x,y): return x+y*9 def blk2seq(b,s): return (b//3*3+s//3)*9+b%3*3+s%3 def seq2pos(p): return p%9,p//9 def seq2blk(p): return p%9//3+p//9//3*3,p%9%3+p//9%3*3 def remove(s,c): r=s s&=~c return 0 if r==s else 1,s def count1(s): c=0 for i in range (0,9): if s&1: c+=1 s>>=1 return c def subset(s,c): return (s&c)==c def find1(s,k): c=0 for i in range(0,9): if s&1: c+=1 if c>k: break s>>=1 return i def getcand(dt,cand): for i in range(0,81): if dt[i]!=0: cand[i]=(1<<(dt[i]-1)) continue cc,cl=seq2pos(i) cb,bs=seq2blk(i) for j in range(0,9): d=dt[pos2seq(j,cl)] if d!=0: cand[i]&=~(1<<(d-1)) d=dt[pos2seq(cc,j)] if d!=0: cand[i]&=~(1<<(d-1)) d=dt[blk2seq(cb,j)] if d!=0: cand[i]&=~(1<<(d-1)) cx=1 while cx>0: cx=0 for i in range(0,81): cs=count1(cand[i]) if cs<2: continue cc,cl=seq2pos(i) cb,bs=seq2blk(i) k=0 for k in range(0,9): if not (cand[i]&(1<=9: cand[i]=(1<=0 and j2>=0: for k in range(0,9): if k!=cc and k!=j1 and k!=j2: xx,cand[pos2seq(k,cl)]=remove(cand[pos2seq(k,cl)],c) cx+=xx j1=-1 j2=-1 for j in range(0,9): if j!=cl and subset(c,cand[pos2seq(cc,j)]): j1=j; break j+=1 while j<9: if j!=cl and subset(c,cand[pos2seq(cc,j)]): j2=j; break j+=1 if j1>=0 and j2>=0: for k in range(0,9): if k!=cl and k!=j1 and k!=j2: xx,cand[pos2seq(cc,k)]=remove(cand[pos2seq(cc,k)],c) cx+=xx j1=-1 j2=-1 for j in range(0,9): if blk2seq(cb,j)!=i and subset(c,cand[blk2seq(cb,j)]): j1=j; break j+=1 while j<9: if blk2seq(cb,j)!=i and subset(c,cand[blk2seq(cb,j)]): j2=j; break j+=1 if j1>=0 and j2>=0: for k in range(0,9): if k!=bs and k!=j1 and k!=j2: xx,cand[blk2seq(cb,k)]=remove(cand[blk2seq(cb,k)],c) cx+=xx def check(dt,cd): #print """check""",cd x=0 for i in range(0,81): if dt[i]==0: x=1 continue cc,cl=seq2pos(i) cb,bs=seq2blk(i) for j in range(0,9): v=pos2seq(j,cl) d=dt[v] if v!=i and d==dt[i]: break v=pos2seq(cc,j) d=dt[v] if v!=i and d==dt[i]: break v=blk2seq(cb,j) d=dt[v] if v!=i and d==dt[i]: break else: j=9 if j<9: break else: i=81 #print "check result",i>=81,x if i>=81: if x: return 2 #print "test ok" return 0 return 1 def resolve(tab,gen=False): ss=SudStack() ss.clear() count_back=0 count_step=0 count_test=0 tcc=0 rtab=tab dt=[] cd=[] for i in range(0,81): dt.append(ord(tab[i])-48) cd.append((1<<9)-1) getcand(dt,cd) while 1: cc=1 mv=-1 mp=-1 i=0 while cc>0: cc=0 mv=-1 mp=-1 for i in range(0,81): l=count1(cd[i]) if l==0: break if l==1 and dt[i]==0: dt[i]=find1(cd[i],0)+1 cc+=1 elif l>=2 and (mv==-1 or l10000): """may break""" if mp>=0: cs=count1(cd[mp]) if cs>1: count_test+=1 sk=0 if gen: sk=random.randint(0,cs-1) c=find1(cd[mp],sk) cd[mp]&=~(1<1: break if tcc<=0: count_back+=1 dt,cd=ss.pop() if len(dt)==0: break else: if tcc<=0: count_back+=1 dt,cd=ss.pop() if len(dt)==0: break if tcc<=0: if count_step>10000: """more than 10000 steps""" else: """cann't resolve""" elif tcc==1: """resolved""" elif tcc>1: """more than one results""" else: """...results""" return tcc,rtab def genquest(nf): nd=81 tt=[0]*81 while nd>nf: xcd='0'*81 tcc,rtab=resolve(xcd,True) xcd=rtab for i in range(0,81): tt[i]=i for i in range(0,81-1): v=random.randint(0,80-i) t=tt[v] tt[v]=tt[81-i-1] tt[81-i-1]=t nd=81 for i in range(0,81): cc=xcd v=tt[i] cc=xcd[0:v]+'0'+xcd[v+1:] tcc,rtab=resolve(cc) if tcc==1: xcd=xcd[0:v]+'0'+xcd[v+1:] nd-=1 if (nd<=nf): break return xcd class Parser: extensions='sud' Dependencies=[] def __init__(self,raw,request,**kw): self.raw=raw self.request=request args=kw.get('format_args','') try: settings=wikiutil.invoke_extension_function(request,sudoku_settings,args) for key,value in settings.items(): setattr(self,key,value) except ValueError,err: msg=u"sudoku: %s"%err.args[0] setattr(self,"gen",0) def render(self,formatter): global sudoku_id sudoku_id+=1 #text=(formatter.preformatted(1)) #if not self.raw is str: return 'xxx' text='' k=0 tab='' self.gen=0 if self.gen==0: for i in range(0,9): for j in range(0,9): while k'9': c='0' tab+=c k+=1 else: tab=genquest(self.gen) tcc,rtab=resolve(tab) #text+=rtab+"
" #text+=tab+"
" msgshowanswer=self.request.getText("Show Answer"); msghideanswer=self.request.getText("Hide Answer"); text+="""""" text+=""+msgshowanswer+"" text+="" for i in range(0,9): text+="" for j in range(0,9): k=pos2seq(j,i) c=tab[k] if c<'1' or c>'9': c='' text+="" text+="" text+="
"+c+"
" #self.request.write(formatter.preformatted(0)) return text def format(self,formatter): self.request.write(self.render(formatter)) """ class x: y=1 def write(self,str): print str b=x() a=Parser("xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx",b) a.format(b) """ }}}