Mercurial > hg > python
changeset 57:057b52746850 simple
use Run and Space classes in Vector.runs
author | Henry Thompson <ht@markup.co.uk> |
---|---|
date | Thu, 01 Jun 2023 18:21:56 +0100 |
parents | 40273cb7c7fc |
children | a3aaf6c085f4 |
files | nono.py |
diffstat | 1 files changed, 91 insertions(+), 42 deletions(-) [+] |
line wrap: on
line diff
--- a/nono.py Mon May 29 23:14:59 2023 +0100 +++ b/nono.py Thu Jun 01 18:21:56 2023 +0100 @@ -13,28 +13,69 @@ for vals in zip(*args): yield from vals +class Run: + def __init__(self,n,i,j): + # A run of length n, starting within [i,j] + self.n=n + self.i=i + self.j=j + self.done=False + + def __str__(self): + return str(self.n) + +class Space: + def __init__(self,n,i,j): + # A space of length 1..n, starting within [i,j] + # Once done, length == n + assert n>0 + self.n=n + self.i=i + self.j=j + self.done=False + + def __str__(self): + return '-' + class Vector(list): # reads top-to-bottom or left-to-right - def __init__(self,n,m,runs): + def __init__(self,n,m): list.__init__(self,list(range(n))) self.n=n # size self.m=m # parent NoNo 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 + + def initRuns(self,runs): + # Set runs to alternating list of Run and Skip self.rn=len(runs) - self.initialComplete=[] - self.finalComplete=[] - #self.resetAllRuns() + self.runs=[] + if self.rn==0: + # No runs means a vector of x + for c in self: + c.setVal(False) + else: + need=sum(1+runs[k] for k in range(self.rn))-1 + space=self.n-need + pos=0 + while runs: + self.runs.append(Run(r:=runs.pop(0),pos,pos+space)) + pos+=r + if runs: + self.runs.append(Space(space,pos,pos+space)) + pos+=1 + self.initDisp() def __repr__(self): - return "V@%s%s:%s"%(self.x,self.origRuns,list.__repr__(self)) + return "V@%s%s:%s"%(self.x,self.runs,list.__repr__(self)) def __str__(self): return '%s|'%('|'.join(str(c) for c in self)) def myPrintSize(self): - return sum(len(str(run)) for run in self.runs)+len(self.runs)-1 + return sum(len(str(run)) for run in self.runs) + +#=========v-old-v============ def resetAllRuns(self): # compute the set of all possible layouts for runs @@ -324,12 +365,27 @@ self.marginN-=r+1 self.updateHeader(r=r,pre=False) +#=============new simple============ + def pass0(self): + need=sum(1+self.runs[k] for k in range(self.rn))-1 + space=self.n-need + p=0 + for run in self.runs: + if run>space: + for p in range(p+space,p+run): + self[p].setVal(True) + p+=1 + else: + p+=run + p+=1 class Row(Vector): cLet='R' - def __init__(self,n,m,runs,pos): - Vector.__init__(self,n,m,runs) + def __init__(self,n,m,pos): + Vector.__init__(self,n,m) self.y=pos + + def initDisp(self): self.width=self.myPrintSize() def __str__(self): @@ -371,24 +427,12 @@ class Column(Vector): cLet='C' - def __init__(self,n,m,runs,pos): - Vector.__init__(self,n,m,runs) + def __init__(self,n,m,pos): + Vector.__init__(self,n,m) self.x=pos - self.height=self.myPrintSize() -#=============new simple============ - def pass0(self): - need=sum(1+self.runs[k] for k in range(self.rn))-1 - space=self.n-need - p=0 - for run in self.runs: - if run>space: - for p in range(p+space,p+run): - self[p].setVal(True) - p+=1 - else: - p+=run - p+=1 + def initDisp(self): + self.height=self.myPrintSize() def updateHeader(self,*,maxHeight=None,r=None,pre=None): dprint('CuH',r,pre) @@ -454,18 +498,14 @@ return ' ' if self.val is None else ('\u25A0' if self.val else 'x') def setVal(self,v): - if v is True: - if self.val is False: - wprint("Warning: x -> * at %s,%s"%(self.x,self.y)) - elif self.val is True: - # No-op - return - self.val=v - else: - if self.val is not None: - wprint("Warning: %s -> %s at %s,%s"%(self.val,v,self.x,self.y)) - self.val=v - + # Returns true iff old value was None + assert v in (True, False) + if v == self.val: + return False + if self.val is not None: + eprint("Reset not allowed: %s -> %s at %s,%s"%(self.val, v, self.x,self.y),err=103) + self.val=v + return True class Nono(dict): # 0,0 is upper left, so increasing y goes _downwards_, to match the standard layout @@ -482,18 +522,24 @@ self.rc=runsPerRow self.cc=runsPerCol # print col nums>9 vertically :-( - self.columns=cc=[Column(n,self,runsPerCol[i],i) for i in range(n)] + self.columns=cc=[Column(n,self,i) for i in range(n)] + self.rows=rr=[Row(n,self,i) for i in range(n)] + for x in range(n): + for y in range(n): + self[(x,y)]=Cell(rr[y],y,cc[x],x) + # Need cells in place for the following + for row,runs in zip(rr,runsPerRow): + row.initRuns(runs) + for col,runs in zip(cc,runsPerCol): + col.initRuns(runs) self.maxCRheight=maxCRheight=max(col.height for col in cc) for c in cc: c.updateHeader(maxHeight=maxCRheight) - self.rows=rr=[Row(n,self,runsPerRow[i],i) for i in range(n)] maxRRwidth=max(row.width for row in rr) for r in rr: r.updateHeader(maxWidth=maxRRwidth) self.rowfmt="%s|%%s|"%(' '*maxRRwidth) - for x in range(n): - for y in range(n): - self[(x,y)]=Cell(rr[y],y,cc[x],x) + def __str__(self): lines=[self.rowfmt%('|'.join([(self.columns[i]).header[j] for i in range(self.n)])) # 'rotate' @@ -505,6 +551,8 @@ def pass0(self): # do columns of empty layout for c in self.columns: c.pass0() + for r in self.rows: + r.pass0() def solve(self): self.pass0() @@ -561,5 +609,6 @@ rows=[[int(i) for i in v.split('.')] for v in vv[n:]] solver=Nono(rows,cols) + breakpoint() solver.solve()