changeset 6:a56d5285575b

drafted Vector.checkNew, still need found0 and foundN
author Henry S. Thompson <ht@inf.ed.ac.uk>
date Tue, 10 Mar 2020 19:56:07 +0000
parents bd1db1ed4c25
children 13f600be3a1b
files nono.py
diffstat 1 files changed, 86 insertions(+), 10 deletions(-) [+]
line wrap: on
line diff
--- a/nono.py	Mon Mar 09 17:39:38 2020 +0000
+++ b/nono.py	Tue Mar 10 19:56:07 2020 +0000
@@ -25,7 +25,20 @@
   def __init__(self,n,m,runs):
     list.__init__(self,list(range(n)))
     self.n=n
-    self.runs=runs
+    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
+    self.initialComplete=[]
+    self.finalComplete=[]
+    self.resetAllRuns()
+
+  def __repr__(self):
+    return "V@%s%s:%s"%(self.x,self.origRuns,list.__repr__(self))
+
+  def __str__(self):
+    return '%s|'%('|'.join(str(c) for c in self))
+
+  def resetAllRuns(self):
     # compute the set of all possible layouts for runs
     self.rn=len(self.runs)
     rtot=sum(self.runs)
@@ -52,12 +65,6 @@
       for sub in self.seedList(1,j+1,pos+v+r,runLen-(r+1)):
         yield [-v,r]+sub
 
-  def __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 step(self):
     scratch=[0 if c.val is None else c.val for c in self]
     for k,runs in enumerate(self.allRuns):
@@ -185,6 +192,72 @@
       for k in range(iBound):
         scratch[k]+=maybe[k]
 
+  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...
+    changed=False
+    # First, find our boundaries:
+    s=pos # start index of our run
+    while s>self.marginO and self[s-1].val is True:
+      s-=1
+    f=pos # finish index of our run
+    while f<self.marginN and self[f+1].val is True:
+      f+=1
+    l=(f-s)+1 # our length
+    c=self.runs.count(l)
+    if c==0:
+      # not big enough yet
+      dprint('n0')
+      return
+    j=self.runs.index(l)
+    if j==0:
+      # is it safely left marginal, i.e. no blobs or big enough gaps before us?
+      if marginal(range(self.margin0,s)):
+        changed=True
+        # mark our margins
+        for i in range(margin0+1,s):
+          if self[i].val is None:
+            self[i].setVal(False)
+        if f<marginN-1:
+          if self[f+1].val is None:
+            self[f+1].setVal(False)
+            if f<marginN-2 and self[f+2].val is True:
+              dprint('n1')
+              self.checkNew(f+2) # I think@@
+        self.found0(f) # pull in the start margin at least to f+2
+      elif j==self.rn-1:
+        # is it safely _right_ marginal, i.e. no blobs or big enough gaps _after_ us?
+        if self.marginal(range(self.marginN-1,r,-1),l):
+          changed=True
+          # mark our margins
+          for i in range(marginN-1,f,-1):
+            if self[i].val is None:
+              self[i].setVal(False)
+          if s>margin0+1:
+            if self[s-1].val is None:
+              self[s-1].setVal(False)
+              if s>margin0+2 and self[s-2].val is True:
+                dprint('n2')
+                self.checkNew(s-2) # I think@@
+          self.foundN(s) # pull in the finish margin at least to s-2
+    if changed:
+      self.resetAllRuns()
+
+  def marginal(self,rng,l):
+    g=0 # length of a gap
+    for i in rng:
+      if self[i].val is True:
+        return False
+      if self[i].val is False:
+        g=0
+      else:
+        # None
+        g+=1
+        if g==l:
+          return False
+    return True
+
 class Row(Vector):
   def __init__(self,n,m,runs,pos,dprintWidth):
     Vector.__init__(self,n,m,runs)
@@ -228,15 +301,18 @@
   def setVal(self,v):
     if v is True:
       if self.val is False:
-        dprint("Warning: x -> * at %s,%s"%(self.x,self.y))
+        print("Warning: x -> * at %s,%s"%(self.x,self.y),file=sys.stderr)
       elif self.val is True:
         # No-op
         return
+      self.val=v
+      self.row.checkNew(self.x)
+      self.column.checkNew(self.y)
       # @@ check row/col completed
     else:
       if self.val is not None:
-        dprint("Warning: %s -> %s at %s,%s"%(self.val,v,self.x,self.y))
-    self.val=v
+        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