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()