Mercurial > hg > python
changeset 13:70993b538ddb
works on 5a
author | Henry S. Thompson <ht@inf.ed.ac.uk> |
---|---|
date | Fri, 20 Mar 2020 19:15:42 +0000 |
parents | ede2551ae7d9 |
children | 1e961cf10f88 |
files | nono.py |
diffstat | 1 files changed, 80 insertions(+), 25 deletions(-) [+] |
line wrap: on
line diff
--- a/nono.py Sun Mar 15 19:08:44 2020 +0000 +++ b/nono.py Fri Mar 20 19:15:42 2020 +0000 @@ -25,6 +25,7 @@ def __init__(self,n,m,runs): list.__init__(self,list(range(n))) self.n=n + self.m=m self.margin0=0 # a run can start here, so if >0 then self[m0-1].val must be False self.marginN=n-1 # a run can end here, so if <n-1 then self[mN+1].val ditto self.runs=self.origRuns=runs @@ -70,21 +71,22 @@ for sub in self.seedList(1,j+1,pos0+v+r,posN,runLen-(r+1)): yield [-v,r]+sub - def step(self): + def step(self,pos): if self.runs==[]: return 0 scratch=[0 if c.val is None else c.val for c in self] wins=0 changed=0 for k,runs in enumerate(self.allRuns): - dprint('=====pass %s======'%k) + dprint('=====pass %s.%s.%s.%s======'%(self.m.loop,self.cLet,pos,k)) if self.onepass(self.margin0,self.marginN+1,scratch,runs.copy()): wins+=1 dprint(wins, scratch) + dprint('r40',self.m.rows[4]) maybeSeq=None inSeq=None for i in range(self.n): - if scratch[i]==wins: + if scratch[i]>=wins: # If blobby in _every_ pass, then must be a blob if inSeq is None: inSeq=i if maybeSeq is None else maybeSeq @@ -111,6 +113,7 @@ dprint('s4',inSeq,i) if inSeq is not None: self.checkNew(i) + dprint('r41',self.m.rows[4]) return changed def onepass(self,i0,iBound,scratch,stack): @@ -183,22 +186,44 @@ return True print("Shouldn't happen? - fell through",stack,i,iBound) + def checkX(self,pos,crosspos): + # New x at pos, are there others that can be xed out now? + # Overkill as is? + dprint('cx',self.cLet+str(crosspos),pos) + dprint('cxr1',self.m.rows[4]) + if self.runs: + start0=0 if self.margin0==0 else self.margin0+1 + if self.marginal(range(start0,pos+1),self.runs[0]): + dprint('cx1a') + else: + dprint('cx1b') +# if len(self.runs)>1: + startN=self.marginN if (self.marginN==self.n-1) else self.marginN-1 + if self.marginal(range(startN,pos,-1),self.runs[-1]): + dprint('cx2a') + else: + dprint('cx2b') + dprint('cxr2',self.m.rows[4]) + def checkNew(self,pos): # New blob at pos, can we complete anything? # Assuming @@ FTTB that it's never possible to definitively complete a # non-marginal run, which is wrong if the length is unique and it's bounded... - start0=0 if self.margin0==0 else self.margin0+1 - startN=self.marginN if (self.marginN==self.n-1) else self.marginN-1 + start0=self.margin0 #0 if self.margin0==0 else self.margin0+1 + startN=self.marginN # self.marginN if (self.marginN==self.n-1) else self.marginN-1 + dprint('cn',start0,pos,startN) changed=False # First, find our boundaries: s=pos # start index of our run - while s>start0 and self[s-1].val is True: - s-=1 + if s>start0: + while s>start0 and self[s-1].val is True: + s-=1 f=pos # finish index of our run - while f<startN and self[f+1].val is True: - f+=1 + if f<startN: + while f<startN and self[f+1].val is True: + f+=1 l=(f-s)+1 # our length - print('%s:%s,%s,%s,%s:<%s>'%(str(self.__class__.__name__)[0],s,f,l,self.runs,self)) + dprint('%s:%s,%s,%s,%s:<%s>'%(self.cLet,s,f,l,self.runs,self)) c=self.runs.count(l) if c==0: # not big enough yet @@ -210,12 +235,13 @@ changed=True dprint('n1') # mark our margins - for i in range(start0,s): + for i in range(start0,s): # not sure this is still needed since + # added gap-filling in self.marginal if self[i].val is None: - self[i].setVal(False) + self.newX(i,False) if f<startN: if self[f+1].val is None: - self[f+1].setVal(False) + self.newX(f+1,True) self.found0(f) # pull in the start margin at least to f+2 else: dprint('x1a') @@ -225,13 +251,13 @@ if self.marginal(range(startN,f,-1),l): changed=True dprint('n2') - # mark our margins + # mark our margins: still needed? see above for i in range(startN,f,-1): if self[i].val is None: - self[i].setVal(False) + self.newX(i,False) if s>start0: if self[s-1].val is None: - self[s-1].setVal(False) + self.newX(s-1,True) self.foundN(s) # pull in the finish margin at least to s-2 else: dprint('x2a') @@ -241,24 +267,33 @@ self.resetAllRuns() def marginal(self,rng,l): - print('m',rng.start,rng.stop,rng.step) + dprint('m',rng.start,rng.stop,rng.step) g=0 # length of a gap for i in rng: if self[i].val is True: + # Shouldn't be possible? dprint('mx0') return False if self[i].val is False: - g=0 + if g>0: + # Block a too-small gap + for i in (i-g,i): + self.newX(i,True) + g=0 else: # None g+=1 if g==l: dprint('mx1') return False + if g>0: + # Block a too-small gap + for j in (i-g,i): + self.newX(j,True) return True def found0(self,i): - print('found0 called on %s at %s'%(self,i)) + dprint('found0 called on %s at %s'%(self,i)) i=self.margin0 while self[i].val is False: i+=1 @@ -269,7 +304,7 @@ self.updateHeader(r=r,pre=True) def foundN(self,i): - print('foundN called on %s at %s'%(self,i)) + dprint('foundN called on %s at %s'%(self,i)) i=self.marginN while self[i].val is False: i-=1 @@ -281,6 +316,7 @@ class Row(Vector): + cLet='R' def __init__(self,n,m,runs,pos): Vector.__init__(self,n,m,runs) self.y=pos @@ -293,11 +329,12 @@ def updateHeader(self,*,maxWidth=None,r=None,pre=None): if maxWidth is None: # update + spacer=(" " if self.runs else "") if pre: - self.infix+=(RedFmt%r)+(" " if self.runs else "") + self.infix+=(RedFmt%r)+spacer else: # post - self.suffix=" "+RedFmt%r+self.suffix + self.suffix=spacer+RedFmt%r+self.suffix self.fmt="%s%s%%s%s|"%(self.prespace,self.infix,self.suffix) else: # init @@ -312,7 +349,14 @@ if crossCheck: self[x].column.checkNew(self.y) + def newX(self,x,crossCheck=False): + dprint('nx %s%s@%s'%('R',self.y,x)) + self[x].setVal(False) + if crossCheck: + self[x].column.checkX(self.y,x) + class Column(Vector): + cLet='C' def __init__(self,n,m,runs,pos): Vector.__init__(self,n,m,runs) self.x=pos @@ -353,6 +397,12 @@ if crossCheck: self[y].row.checkNew(self.x) + def newX(self,y,crossCheck=False): + dprint('nx %s%s@%s'%('C',self.x,y)) + self[y].setVal(False) + if crossCheck: + self[y].row.checkX(self.x,y) + class Cell: def __init__(self,row,y,column,x): # At the intersection of row and column Vectors @@ -382,10 +432,12 @@ if self.val is not None: print("Warning: %s -> %s at %s,%s"%(self.val,v,self.x,self.y),file=sys.stderr) self.val=v + class Nono(dict): # 0,0 is upper left, so increasing y goes _downwards_, to match the standard layout def __init__(self,runsPerRow,runsPerCol): + self.loop=0 n=self.n=len(runsPerCol) if n!=len(runsPerRow): print("losing r:%s x c:%s"%(len(runsPerRow),n),sys.stderr) @@ -415,18 +467,21 @@ def solve(self): someChanged=1 while someChanged>0: + self.loop+=1 someChanged=0 + dprint("***Solve C %s***"%self.loop) for c in self.columns: - someChanged+=c.step() + someChanged+=c.step(c.x) print(someChanged) print(self) + dprint("***Solve R %s***"%self.loop) for r in self.rows: - someChanged+=r.step() + someChanged+=r.step(r.y) print(someChanged) print(self) def dprint(*args): - print(*args) + pass # print(*args) if __name__ == '__main__': if len(sys.argv)>1: