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: