Mercurial > hg > python
comparison nono.py @ 11:1b9daa849b0f
A bit further: red col working, finding middle of row 1, formatting off, outer loop in place, but fails overall after 3rd pass achieves nothing
author | Henry S. Thompson <ht@inf.ed.ac.uk> |
---|---|
date | Sun, 15 Mar 2020 17:05:49 +0000 |
parents | 0a24625b33fa |
children | ede2551ae7d9 |
comparison
equal
deleted
inserted
replaced
10:0a24625b33fa | 11:1b9daa849b0f |
---|---|
43 | 43 |
44 def resetAllRuns(self): | 44 def resetAllRuns(self): |
45 # compute the set of all possible layouts for runs | 45 # compute the set of all possible layouts for runs |
46 self.rn=len(self.runs) | 46 self.rn=len(self.runs) |
47 rtot=sum(self.runs) | 47 rtot=sum(self.runs) |
48 self.allRuns=list(self.seedList(0,0,0, | 48 self.allRuns=list(self.seedList(0,0,self.margin0,self.marginN+1, |
49 sum(1+self.runs[k] for k in range(self.rn))-1)) | 49 sum(1+self.runs[k] for k in range(self.rn))-1)) |
50 self.nar=len(self.allRuns) | 50 self.nar=len(self.allRuns) |
51 | 51 |
52 def seedList(self,i,j,pos,runLen): | 52 def seedList(self,i,j,pos0,posN,runLen): |
53 """ | 53 """ |
54 :param i: starting skip before next run | 54 :param i: starting skip before next run |
55 :type i: 0 if pos==0 else 1 | 55 :type i: 0 if pos==0 else 1 |
56 :param j: next run number | 56 :param j: next run number |
57 :type j: int | 57 :type j: int |
58 :param pos: left margin | 58 :param pos0: left margin |
59 :type pos: int | 59 :type pos0: int |
60 :param posN: right margin | |
61 :type posN: int | |
60 """ | 62 """ |
61 bound=self.n-(pos+runLen)+1 | 63 bound=posN-(pos0+runLen)+1 |
62 #dprint('s',i,j,pos,runLen,bound) | 64 dprint('s',i,j,pos0,posN,runLen,bound) |
63 if j==self.rn: | 65 if j==self.rn: |
64 yield [] | 66 yield [] |
65 return | 67 return |
66 r=self.runs[j] | 68 r=self.runs[j] |
67 for v in range(i,bound): | 69 for v in range(i,bound): |
68 for sub in self.seedList(1,j+1,pos+v+r,runLen-(r+1)): | 70 for sub in self.seedList(1,j+1,pos0+v+r,posN,runLen-(r+1)): |
69 yield [-v,r]+sub | 71 yield [-v,r]+sub |
70 | 72 |
71 def step(self): | 73 def step(self): |
74 if self.runs==[]: | |
75 return 0 | |
72 scratch=[0 if c.val is None else c.val for c in self] | 76 scratch=[0 if c.val is None else c.val for c in self] |
73 wins=0 | 77 wins=0 |
78 changed=0 | |
74 for k,runs in enumerate(self.allRuns): | 79 for k,runs in enumerate(self.allRuns): |
75 dprint('=====pass %s======'%k) | 80 dprint('=====pass %s======'%k) |
76 if self.onepass(self.margin0,self.marginN+1,scratch,runs.copy()): | 81 if self.onepass(self.margin0,self.marginN+1,scratch,runs.copy()): |
77 wins+=1 | 82 wins+=1 |
78 dprint(wins, scratch) | 83 dprint(wins, scratch) |
85 inSeq=i if maybeSeq is None else maybeSeq | 90 inSeq=i if maybeSeq is None else maybeSeq |
86 dprint('s1',inSeq) | 91 dprint('s1',inSeq) |
87 maybeSeq=None | 92 maybeSeq=None |
88 if self[i].val is None: | 93 if self[i].val is None: |
89 self.newBlob(i,True) # Check cross-vector | 94 self.newBlob(i,True) # Check cross-vector |
95 changed=1 | |
90 elif self[i].val is True: | 96 elif self[i].val is True: |
91 # already there | 97 # already there |
92 pass | 98 pass |
93 else: | 99 else: |
94 print("Shouldn't happen: attempt to blob where x already present! %s at %s"%(self,i),file=sys.stderr) | 100 print("Shouldn't happen: attempt to blob where x already present! %s at %s"%(self,i),file=sys.stderr) |
103 dprint('s3',i) | 109 dprint('s3',i) |
104 maybeSeq=i | 110 maybeSeq=i |
105 dprint('s4',inSeq,i) | 111 dprint('s4',inSeq,i) |
106 if inSeq is not None: | 112 if inSeq is not None: |
107 self.checkNew(i) | 113 self.checkNew(i) |
114 return changed | |
108 | 115 |
109 def onepass(self,i0,iBound,scratch,stack): | 116 def onepass(self,i0,iBound,scratch,stack): |
110 """note that stack is not a simple run, but one with _negative_ numbers between | 117 """note that stack is not a simple run, but one with _negative_ numbers between |
111 and possibly before the positive ones, indicating obligatory skips | 118 and possibly before the positive ones, indicating obligatory skips |
112 """ | 119 """ |
113 i=i0 # starting index into self/scratch/maybe | 120 i=i0 # starting index into self/scratch/maybe |
114 maybe=[0]*(iBound-i0) | 121 maybe=[0]*self.n |
115 dprint('r: %s'%stack) | 122 dprint('r: %s'%stack,i0,iBound) |
116 req=sum((-r if r<0 else r) for r in stack) | 123 req=sum((-r if r<0 else r) for r in stack) |
117 while stack and i<iBound: | 124 while stack and i<iBound: |
118 r=rr=stack.pop(0) | 125 r=rr=stack.pop(0) |
119 dprint('pop:',r) | 126 dprint('pop:',r) |
120 if r<1: | 127 if r<1: |
206 self[i].setVal(False) | 213 self[i].setVal(False) |
207 if f<self.marginN-1: | 214 if f<self.marginN-1: |
208 if self[f+1].val is None: | 215 if self[f+1].val is None: |
209 self[f+1].setVal(False) | 216 self[f+1].setVal(False) |
210 self.found0(f) # pull in the start margin at least to f+2 | 217 self.found0(f) # pull in the start margin at least to f+2 |
211 if f<self.marginN-2 and self[f+2].val is True: | |
212 dprint('n1a') | |
213 self.checkNew(f+2) # I think@@ | |
214 else: | 218 else: |
215 dprint('x1a') | 219 dprint('x1a') |
216 else: | 220 if not changed: |
217 dprint('x1b') | 221 if self.runs[-1]==l: |
218 if self.runs[-1]==l: | 222 # is it safely _right_ marginal, i.e. no blobs or big enough gaps _after_ us? |
219 # is it safely _right_ marginal, i.e. no blobs or big enough gaps _after_ us? | 223 if self.marginal(range(self.marginN-1,f,-1),l): |
220 if self.marginal(range(self.marginN-1,f,-1),l): | 224 changed=True |
221 changed=True | 225 dprint('n2') |
222 dprint('n2') | 226 # mark our margins |
223 # mark our margins | 227 for i in range(self.marginN-1,f,-1): |
224 for i in range(self.marginN-1,f,-1): | 228 if self[i].val is None: |
225 if self[i].val is None: | 229 self[i].setVal(False) |
226 self[i].setVal(False) | 230 if s>self.margin0+1: |
227 if s>self.margin0+1: | 231 if self[s-1].val is None: |
228 if self[s-1].val is None: | 232 self[s-1].setVal(False) |
229 self[s-1].setVal(False) | 233 self.foundN(s) # pull in the finish margin at least to s-2 |
230 self.foundN(s) # pull in the finish margin at least to s-2 | 234 else: |
231 if s>self.margin0+2 and self[s-2].val is True: | 235 dprint('x2a') |
232 dprint('n2a') | |
233 self.checkNew(s-2) # I think@@ | |
234 else: | 236 else: |
235 dprint('x2a') | 237 dprint('x2b') |
236 else: | |
237 dprint('x2b') | |
238 if changed: | 238 if changed: |
239 self.resetAllRuns() | 239 self.resetAllRuns() |
240 | 240 |
241 def marginal(self,rng,l): | 241 def marginal(self,rng,l): |
242 print('m',rng.start,rng.stop,rng.step) | |
242 g=0 # length of a gap | 243 g=0 # length of a gap |
243 for i in rng: | 244 for i in rng: |
244 if self[i].val is True: | 245 if self[i].val is True: |
245 dprint('mx0') | 246 dprint('mx0') |
246 return False | 247 return False |
261 i+=1 | 262 i+=1 |
262 if self[i].val is True: | 263 if self[i].val is True: |
263 r=self.runs.pop(0) | 264 r=self.runs.pop(0) |
264 self.initialComplete.append(r) | 265 self.initialComplete.append(r) |
265 self.margin0+=r+1 | 266 self.margin0+=r+1 |
266 self.updateHeader(r=r) | 267 self.updateHeader(r=r,pre=True) |
267 | 268 |
268 def foundN(self,i): | 269 def foundN(self,i): |
269 print('foundN called on %s at %s'%(self,i)) | 270 print('foundN called on %s at %s'%(self,i)) |
270 i=self.marginN | 271 i=self.marginN |
271 while self[i].val is False: | 272 while self[i].val is False: |
272 i-=1 | 273 i-=1 |
273 if self[i].val is True: | 274 if self[i].val is True: |
274 r=self.runs.pop() | 275 r=self.runs.pop() |
275 self.finalComplete=[r]+self.finalComplete | 276 self.finalComplete=[r]+self.finalComplete |
276 self.marginN-=r+1 | 277 self.marginN-=r+1 |
277 self.updateHeader(r=r) | 278 self.updateHeader(r=r,pre=False) |
278 | 279 |
279 | 280 |
280 class Row(Vector): | 281 class Row(Vector): |
281 def __init__(self,n,m,runs,pos): | 282 def __init__(self,n,m,runs,pos): |
282 Vector.__init__(self,n,m,runs) | 283 Vector.__init__(self,n,m,runs) |
314 Vector.__init__(self,n,m,runs) | 315 Vector.__init__(self,n,m,runs) |
315 self.x=pos | 316 self.x=pos |
316 self.height=self.myPrintSize() | 317 self.height=self.myPrintSize() |
317 | 318 |
318 def updateHeader(self,*,maxHeight=None,r=None,pre=None): | 319 def updateHeader(self,*,maxHeight=None,r=None,pre=None): |
320 dprint('CuH',r,pre) | |
319 if maxHeight is None: | 321 if maxHeight is None: |
320 # update | 322 # update |
321 if pre: | 323 if pre: |
322 self.infix+=(RedFmt%r)+" " | 324 for rc in str(r): |
325 self.infix.append(RedFmt%rc) | |
326 self.infix.append("-") | |
323 else: | 327 else: |
324 # post | 328 # post |
325 self.suffix=" "+RedFmt%r+self.suffix | 329 ins=["-"] |
326 self.fmt="%s%s%%s%s"%(self.prespace,self.infix,self.suffix) | 330 for rc in str(r): |
331 ins.append(RedFmt%r) | |
332 self.suffix=ins+self.suffix | |
333 dprint('CuH1: |%s|,%s,%s,%s'%(self.prespace,self.infix,self.suffix,self.runs)) | |
334 self.header=(["-"]*self.prespace)+\ | |
335 self.infix+\ | |
336 ['-'.join(str(c) for c in self.runs)]+\ | |
337 self.suffix | |
327 else: | 338 else: |
328 # init | 339 # init |
329 self.maxHeight=maxHeight | 340 self.maxHeight=maxHeight |
330 self.infix="" | 341 self.infix=[] |
331 self.suffix="" | 342 self.suffix=[] |
343 self.prespace=maxHeight - self.height # pad to same 'height' | |
344 self.fmt="%s%%s"%(' '*self.prespace) | |
332 header=('-'.join(str(c) for c in self.runs)) | 345 header=('-'.join(str(c) for c in self.runs)) |
333 self.prespace=' '*(maxHeight - self.height) # pad to same 'height' | |
334 self.fmt="%s%%s"%self.prespace | |
335 self.header=self.fmt%header | 346 self.header=self.fmt%header |
347 dprint(self.header) | |
336 | 348 |
337 def newBlob(self,y,crossCheck=False): | 349 def newBlob(self,y,crossCheck=False): |
338 self[y].setVal(True) | 350 self[y].setVal(True) |
339 if crossCheck: | 351 if crossCheck: |
340 self[y].row.checkNew(self.x) | 352 self[y].row.checkNew(self.x) |
396 lines=[self.rowfmt%('|'.join([(self.columns[i]).header[j] for i in range(self.n)])) # 'rotate' | 408 lines=[self.rowfmt%('|'.join([(self.columns[i]).header[j] for i in range(self.n)])) # 'rotate' |
397 for j in range(self.maxCRheight)] | 409 for j in range(self.maxCRheight)] |
398 lines+=[str(r) for r in self.rows] | 410 lines+=[str(r) for r in self.rows] |
399 return "\n".join(lines) | 411 return "\n".join(lines) |
400 | 412 |
413 def solve(self): | |
414 someChanged=1 | |
415 while someChanged>0: | |
416 someChanged=0 | |
417 for c in self.columns: | |
418 someChanged+=c.step() | |
419 print(someChanged) | |
420 print(self) | |
421 for r in self.rows: | |
422 someChanged+=r.step() | |
423 print(someChanged) | |
424 print(self) | |
425 | |
401 def dprint(*args): | 426 def dprint(*args): |
402 print(*args) | 427 print(*args) |
403 | 428 |
404 if __name__ == '__main__': | 429 if __name__ == '__main__': |
405 if len(sys.argv)>1: | 430 if len(sys.argv)>1: |
420 cols.append(vv) | 445 cols.append(vv) |
421 | 446 |
422 rows=[[int(s) for s in l.split()] for l in f] | 447 rows=[[int(s) for s in l.split()] for l in f] |
423 | 448 |
424 solver=Nono(rows,cols) | 449 solver=Nono(rows,cols) |
425 print(solver) | 450 solver.solve() |
426 for c in solver.columns: | |
427 c.step() | |
428 print() | |
429 print(solver) | |
430 for r in solver.rows: | |
431 r.step() | |
432 print() | |
433 print(solver) |