Mercurial > hg > python
comparison nono.py @ 73:63e87db2bc31 simple
update to modern syntax using ruff on lochinver
| author | Henry Thompson <ht@markup.co.uk> |
|---|---|
| date | Sat, 09 Aug 2025 15:56:58 -0400 |
| parents | 15e540c190d5 |
| children | 0245bc07f16c |
comparison
equal
deleted
inserted
replaced
| 72:15e540c190d5 | 73:63e87db2bc31 |
|---|---|
| 12 # New fill: complete the run and discard it, kill the other end and queue it | 12 # New fill: complete the run and discard it, kill the other end and queue it |
| 13 # dead: advance margin and add fill to any internal sequences of fills (always?), queue the new fill(s) | 13 # dead: advance margin and add fill to any internal sequences of fills (always?), queue the new fill(s) |
| 14 # Change in the middle | 14 # Change in the middle |
| 15 # New dead: If deterministic, split the run in two and requeue the cell (now in two runs) | 15 # New dead: If deterministic, split the run in two and requeue the cell (now in two runs) |
| 16 # fill: If deterministic single gap at any end, kill, split, and requeue the cell (now in two runs) | 16 # fill: If deterministic single gap at any end, kill, split, and requeue the cell (now in two runs) |
| 17 #---------- | 17 # ---------- |
| 18 # Doesn't yet cover everything, e.g. killing gaps that are too small to be filled | 18 # Doesn't yet cover everything, e.g. killing gaps that are too small to be filled |
| 19 # Do we need to actually represent run-internal segments, e.g. skips and bars? | 19 # Do we need to actually represent run-internal segments, e.g. skips and bars? |
| 20 | 20 |
| 21 | 21 |
| 22 import sys | 22 import sys |
| 23 | 23 |
| 24 Red='[31m' | 24 Red = "[31m" |
| 25 eRed='[39m' | 25 eRed = "[39m" |
| 26 RedFmt=Red+'%s'+eRed | 26 RedFmt = Red + "%s" + eRed |
| 27 | |
| 27 | 28 |
| 28 class Run: | 29 class Run: |
| 29 '''What we're looking for, converted eventually into what | 30 '''What we're looking for, converted eventually into what |
| 30 we've found. | 31 we've found. |
| 31 "left" and "right" make sense for Rows, for Columns read "above" and "below"''' | 32 "left" and "right" make sense for Rows, for Columns read "above" and "below"''' |
| 32 def __init__(self,n,i,j): | 33 |
| 34 def __init__(self, n, i, j): | |
| 33 # A run of length n, starting within [i,j] | 35 # A run of length n, starting within [i,j] |
| 34 self.n=n | 36 self.n = n |
| 35 self.i=i | 37 self.i = i |
| 36 self.j=j | 38 self.j = j |
| 37 self.s=j-i | 39 self.s = j - i |
| 38 self.done=False | 40 self.done = False |
| 39 self.left=self.right=None | 41 self.left = self.right = None |
| 40 | 42 |
| 41 def leftEdge(self): | 43 def leftEdge(self): |
| 42 return self.i | 44 return self.i |
| 43 | 45 |
| 44 def rightEdge(self): | 46 def rightEdge(self): |
| 45 if self.done: | 47 if self.done: |
| 46 return self.i+self.n-1 | 48 return self.i + self.n - 1 |
| 47 return self.j+self.n-1 | 49 return self.j + self.n - 1 |
| 48 | 50 |
| 49 def __str__(self): | 51 def __str__(self): |
| 50 return str(self.n) | 52 return str(self.n) |
| 51 | 53 |
| 54 | |
| 52 class Space: | 55 class Space: |
| 53 def __init__(self,n,i,j): | 56 def __init__(self, n, i, j): |
| 54 # A space of length 1..n, starting within [i,j] | 57 # A space of length 1..n, starting within [i,j] |
| 55 # Once done, length == n | 58 # Once done, length == n |
| 56 # i and j don't change, but s, which is used by check0 | 59 # i and j don't change, but s, which is used by check0 |
| 57 # to decide where to look, is optimistic and may need to | 60 # to decide where to look, is optimistic and may need to |
| 58 # be restricted if there is an overlap with the next (forward or backward) | 61 # be restricted if there is an overlap with the next (forward or backward) |
| 59 # run (see self.right and self.left, if any, respectively) | 62 # run (see self.right and self.left, if any, respectively) |
| 60 assert n>0 | 63 assert n > 0 |
| 61 self.n=n | 64 self.n = n |
| 62 self.i=i | 65 self.i = i |
| 63 self.j=j | 66 self.j = j |
| 64 self.s=j-i | 67 self.s = j - i |
| 65 self.done=False | 68 self.done = False |
| 66 | 69 |
| 67 def __str__(self): | 70 def __str__(self): |
| 68 return '' | 71 return "" |
| 72 | |
| 69 | 73 |
| 70 class Vector(list): | 74 class Vector(list): |
| 71 # reads top-to-bottom or left-to-right | 75 # reads top-to-bottom or left-to-right |
| 72 def __init__(self,n,m): | 76 def __init__(self, n, m): |
| 73 list.__init__(self,list(range(n))) | 77 list.__init__(self, list(range(n))) |
| 74 self.n=n # size | 78 self.n = n # size |
| 75 self.m=m # parent NoNo | 79 self.m = m # parent NoNo |
| 76 self.margin0=0 # a run can start here, so if >0 then self[m0-1].val must be False | 80 self.margin0 = 0 # a run can start here, so if >0 then self[m0-1].val must be False |
| 77 self.marginN=n-1 # a run can end here, so if <n-1 then self[mN+1].val ditto | 81 self.marginN = n - 1 # a run can end here, so if <n-1 then self[mN+1].val ditto |
| 78 | 82 |
| 79 def initRuns(self,runs): | 83 def initRuns(self, runs): |
| 80 # Set runs to alternating list of Run and Skip | 84 # Set runs to alternating list of Run and Skip |
| 81 self.rn=len(runs) | 85 self.rn = len(runs) |
| 82 self.runs=[] | 86 self.runs = [] |
| 83 if self.rn==0: | 87 if self.rn == 0: |
| 84 # No runs means a vector of x | 88 # No runs means a vector of x |
| 85 for c in self: | 89 for c in self: |
| 86 c.setVal(False) | 90 c.setVal(False) |
| 87 else: | 91 else: |
| 88 need=sum(1+runs[k] for k in range(self.rn))-1 | 92 need = sum(1 + runs[k] for k in range(self.rn)) - 1 |
| 89 space=self.n-need | 93 space = self.n - need |
| 90 pos=0 | 94 pos = 0 |
| 91 while runs: | 95 while runs: |
| 92 self.runs.append(Run(r:=runs.pop(0),pos,pos+space)) | 96 self.runs.append(Run(r := runs.pop(0), pos, pos + space)) |
| 93 pos+=r | 97 pos += r |
| 94 if runs: | 98 if runs: |
| 95 self.runs.append(Space(space,pos,pos+space)) | 99 self.runs.append(Space(space, pos, pos + space)) |
| 96 pos+=1 | 100 pos += 1 |
| 97 # Adjacent pairs mutually restrict possible starting points | 101 # Adjacent pairs mutually restrict possible starting points |
| 98 for i in range(0,self.rn-1): | 102 for i in range(0, self.rn - 1): |
| 99 left=self.runs[2*i] | 103 left = self.runs[2 * i] |
| 100 right=self.runs[(2*i)+2] | 104 right = self.runs[(2 * i) + 2] |
| 101 left.right=right | 105 left.right = right |
| 102 right.left=left | 106 right.left = left |
| 103 self.initDisp() | 107 self.initDisp() |
| 104 | 108 |
| 105 def __str__(self): | 109 def __str__(self): |
| 106 return '%s|'%('|'.join(str(c) for c in self)) | 110 return "%s|" % ("|".join(str(c) for c in self)) |
| 107 | 111 |
| 108 def myPrintSize(self): | 112 def myPrintSize(self): |
| 109 return sum((len(str(run)) if isinstance(run,Run) else 1) for run in self.runs) | 113 return sum((len(str(run)) if isinstance(run, Run) else 1) for run in self.runs) |
| 110 | 114 |
| 111 def pass0(self): | 115 def pass0(self): |
| 112 # simple first pass down/across a row | 116 # simple first pass down/across a row |
| 113 for i in range(0,len(self.runs),2): | 117 for i in range(0, len(self.runs), 2): |
| 114 run=self.runs[i] | 118 run = self.runs[i] |
| 115 for p in range(run.i+run.s,run.i+run.n): | 119 for p in range(run.i + run.s, run.i + run.n): |
| 116 self[p].setVal(True) | 120 self[p].setVal(True) |
| 117 | 121 |
| 118 def check0(self): | 122 def check0(self): |
| 119 # Check 1st and last not-done runs for completeness | 123 # Check 1st and last not-done runs for completeness |
| 120 # Have to restrict lookahead/behind if there's overlap between runs... | 124 # Have to restrict lookahead/behind if there's overlap between runs... |
| 121 # Forwards | 125 # Forwards |
| 122 # ****Assumes margin0 is 0***** and marginN is n | 126 # ****Assumes margin0 is 0***** and marginN is n |
| 123 for i in range(0,len(self.runs),2): | 127 for i in range(0, len(self.runs), 2): |
| 124 run=self.runs[i] | 128 run = self.runs[i] |
| 125 if not run.done: | 129 if not run.done: |
| 126 # look for first True cell | 130 # look for first True cell |
| 127 for p in range(run.i,min(run.i+run.s+1, | 131 for p in range( |
| 128 run.right.leftEdge()-run.n if (run.right and run.i>run.n) else 100)): | 132 run.i, |
| 133 min( | |
| 134 run.i + run.s + 1, | |
| 135 run.right.leftEdge() - run.n if (run.right and run.i > run.n) else 100, | |
| 136 ), | |
| 137 ): | |
| 129 if self[p].val: | 138 if self[p].val: |
| 130 if p>0 and self[p-1].val==False: | 139 if p > 0 and self[p - 1].val == False: |
| 131 # We're pinned, force start here from now on | 140 # We're pinned, force start here from now on |
| 132 self.i=p | 141 self.i = p |
| 133 self.s=p+1 | 142 self.s = p + 1 |
| 134 self.right=None #Maybe? | 143 self.right = None # Maybe? |
| 135 l=self.trueRun(p,run.n) | 144 l = self.trueRun(p, run.n) |
| 136 if l==run.n: | 145 if l == run.n: |
| 137 if p!=0: | 146 if p != 0: |
| 138 self[p-1].setVal(False) | 147 self[p - 1].setVal(False) |
| 139 e=p+l | 148 e = p + l |
| 140 if e!=self.n: | 149 if e != self.n: |
| 141 self[e].setVal(False) | 150 self[e].setVal(False) |
| 142 break | 151 break |
| 143 break | 152 break |
| 144 # and backwards | 153 # and backwards |
| 145 m=len(self.runs)-1 | 154 m = len(self.runs) - 1 |
| 146 # if isinstance(self,Column) and self.x==3: | 155 # if isinstance(self,Column) and self.x==3: |
| 147 # breakpoint() | 156 # breakpoint() |
| 148 for i in range(0,m+1,2): | 157 for i in range(0, m + 1, 2): |
| 149 run=self.runs[m-i] | 158 run = self.runs[m - i] |
| 150 if not run.done: | 159 if not run.done: |
| 151 # look for first True cell | 160 # look for first True cell |
| 152 for p in range(run.i+run.s+(run.n-1), | 161 for p in range( |
| 153 max(run.i-1,run.left.rightEdge()+run.n if (run.left and run.i<self.n-run.n) else 0),-1): | 162 run.i + run.s + (run.n - 1), |
| 163 max( | |
| 164 run.i - 1, | |
| 165 run.left.rightEdge() + run.n | |
| 166 if (run.left and run.i < self.n - run.n) | |
| 167 else 0, | |
| 168 ), | |
| 169 -1, | |
| 170 ): | |
| 154 if self[p].val: | 171 if self[p].val: |
| 155 if p<self.n-1 and self[p+1]==False: | 172 if p < self.n - 1 and self[p + 1] == False: |
| 156 self.i=p | 173 self.i = p |
| 157 self.s=p+1 | 174 self.s = p + 1 |
| 158 self.left=None # Maybe? | 175 self.left = None # Maybe? |
| 159 l=self.trueRun(p,run.n,-1) | 176 l = self.trueRun(p, run.n, -1) |
| 160 if l==run.n: | 177 if l == run.n: |
| 161 e=p-l | 178 e = p - l |
| 162 if e!=0: | 179 if e != 0: |
| 163 self[e].setVal(False) | 180 self[e].setVal(False) |
| 164 if p+1!=self.n: | 181 if p + 1 != self.n: |
| 165 self[p+1].setVal(False) | 182 self[p + 1].setVal(False) |
| 166 break | 183 break |
| 167 break | 184 break |
| 168 | 185 |
| 169 def trueRun(self,p,n,delta=1): | 186 def trueRun(self, p, n, delta=1): |
| 170 res=0 | 187 res = 0 |
| 171 for i in range(p,p+(delta*n),delta): | 188 for i in range(p, p + (delta * n), delta): |
| 172 if self[i].val: | 189 if self[i].val: |
| 173 res+=1 | 190 res += 1 |
| 174 else: | 191 else: |
| 175 break | 192 break |
| 176 return res | 193 return res |
| 177 | 194 |
| 195 | |
| 178 class Row(Vector): | 196 class Row(Vector): |
| 179 cLet='R' | 197 cLet = "R" |
| 180 def __init__(self,n,m,pos): | 198 |
| 181 Vector.__init__(self,n,m) | 199 def __init__(self, n, m, pos): |
| 182 self.y=pos | 200 Vector.__init__(self, n, m) |
| 201 self.y = pos | |
| 183 | 202 |
| 184 def __repr__(self): | 203 def __repr__(self): |
| 185 return "R@%s%s:%s"%(self.y,self.runs,list.__repr__(self)) | 204 return "R@%s%s:%s" % (self.y, self.runs, list.__repr__(self)) |
| 186 | 205 |
| 187 def initDisp(self): | 206 def initDisp(self): |
| 188 self.width=self.myPrintSize() | 207 self.width = self.myPrintSize() |
| 189 | 208 |
| 190 def __str__(self): | 209 def __str__(self): |
| 191 return ((self.fmt%(' '.join(str(r) for r in self.runs if isinstance(r,Run))))+ | 210 return ( |
| 192 Vector.__str__(self)) | 211 self.fmt % (" ".join(str(r) for r in self.runs if isinstance(r, Run))) |
| 193 | 212 ) + Vector.__str__(self) |
| 194 def updateHeader(self,*,maxWidth=None,r=None,pre=None): | 213 |
| 214 def updateHeader(self, *, maxWidth=None, r=None, pre=None): | |
| 195 if maxWidth is None: | 215 if maxWidth is None: |
| 196 # update | 216 # update |
| 197 spacer=(" " if self.runs else "") | 217 spacer = " " if self.runs else "" |
| 198 if pre: | 218 if pre: |
| 199 self.infix+=(RedFmt%r)+spacer | 219 self.infix += (RedFmt % r) + spacer |
| 200 else: | 220 else: |
| 201 # post | 221 # post |
| 202 self.suffix=spacer+RedFmt%r+self.suffix | 222 self.suffix = spacer + RedFmt % r + self.suffix |
| 203 self.fmt="%s%s%%s%s|"%(self.prespace,self.infix,self.suffix) | 223 self.fmt = "%s%s%%s%s|" % (self.prespace, self.infix, self.suffix) |
| 204 else: | 224 else: |
| 205 # init | 225 # init |
| 206 self.maxWidth=maxWidth | 226 self.maxWidth = maxWidth |
| 207 self.prespace=' '*(maxWidth-self.width) | 227 self.prespace = " " * (maxWidth - self.width) |
| 208 self.fmt="%s%%s|"%self.prespace | 228 self.fmt = "%s%%s|" % self.prespace |
| 209 self.infix="" | 229 self.infix = "" |
| 210 self.suffix="" | 230 self.suffix = "" |
| 231 | |
| 211 | 232 |
| 212 class Column(Vector): | 233 class Column(Vector): |
| 213 cLet='C' | 234 cLet = "C" |
| 214 def __init__(self,n,m,pos): | 235 |
| 215 Vector.__init__(self,n,m) | 236 def __init__(self, n, m, pos): |
| 216 self.x=pos | 237 Vector.__init__(self, n, m) |
| 238 self.x = pos | |
| 217 | 239 |
| 218 def __repr__(self): | 240 def __repr__(self): |
| 219 return "C@%s%s:%s"%(self.x,self.runs,list.__repr__(self)) | 241 return "C@%s%s:%s" % (self.x, self.runs, list.__repr__(self)) |
| 220 | 242 |
| 221 def initDisp(self): | 243 def initDisp(self): |
| 222 self.height=self.myPrintSize() | 244 self.height = self.myPrintSize() |
| 223 | 245 |
| 224 def updateHeader(self,*,maxHeight=None,r=None,pre=None): | 246 def updateHeader(self, *, maxHeight=None, r=None, pre=None): |
| 225 dprint('CuH',r,pre) | 247 dprint("CuH", r, pre) |
| 226 if maxHeight is None: | 248 if maxHeight is None: |
| 227 # update | 249 # update |
| 228 if pre: | 250 if pre: |
| 229 for rc in str(r): | 251 for rc in str(r): |
| 230 self.infix.append(RedFmt%rc) | 252 self.infix.append(RedFmt % rc) |
| 231 if self.runs: | 253 if self.runs: |
| 232 self.infix.append('-') | 254 self.infix.append("-") |
| 233 else: | 255 else: |
| 234 # post | 256 # post |
| 235 ins=["-"] if self.runs else [] | 257 ins = ["-"] if self.runs else [] |
| 236 for rc in str(r): | 258 for rc in str(r): |
| 237 ins.append(RedFmt%r) | 259 ins.append(RedFmt % r) |
| 238 self.suffix=ins+self.suffix | 260 self.suffix = ins + self.suffix |
| 239 dprint('CuH1: |%s|,%s,%s,%s'%(self.prespace,self.infix,self.suffix,self.runs)) | 261 dprint( |
| 240 self.header=([" "]*self.prespace)+\ | 262 "CuH1: |%s|,%s,%s,%s" % (self.prespace, self.infix, self.suffix, self.runs) |
| 241 self.infix+\ | 263 ) |
| 242 (['-'.join(str(c) for c in self.runs)] if self.runs else [])+\ | 264 self.header = ( |
| 243 self.suffix | 265 ([" "] * self.prespace) |
| 266 + self.infix | |
| 267 + (["-".join(str(c) for c in self.runs)] if self.runs else []) | |
| 268 + self.suffix | |
| 269 ) | |
| 244 else: | 270 else: |
| 245 # init | 271 # init |
| 246 self.maxHeight=maxHeight | 272 self.maxHeight = maxHeight |
| 247 self.infix=[] | 273 self.infix = [] |
| 248 self.suffix=[] | 274 self.suffix = [] |
| 249 self.prespace=maxHeight - self.height # pad to same 'height' | 275 self.prespace = maxHeight - self.height # pad to same 'height' |
| 250 self.fmt="%s%%s"%(' '*self.prespace) | 276 self.fmt = "%s%%s" % (" " * self.prespace) |
| 251 header=('-'.join(str(c) for c in self.runs if isinstance(c,Run))) | 277 header = "-".join(str(c) for c in self.runs if isinstance(c, Run)) |
| 252 self.header=self.fmt%header | 278 self.header = self.fmt % header |
| 253 dprint(self.header) | 279 dprint(self.header) |
| 254 | 280 |
| 281 | |
| 255 class Cell: | 282 class Cell: |
| 256 def __init__(self,row,y,column,x): | 283 def __init__(self, row, y, column, x): |
| 257 # At the intersection of row and column Vectors | 284 # At the intersection of row and column Vectors |
| 258 self.row=row | 285 self.row = row |
| 259 self.column=column | 286 self.column = column |
| 260 self.x=x | 287 self.x = x |
| 261 self.y=y | 288 self.y = y |
| 262 self.val=None # three valued: None(unknown), True(filled), False(empty) | 289 self.val = None # three valued: None(unknown), True(filled), False(empty) |
| 263 self.row[x]=self | 290 self.row[x] = self |
| 264 self.column[y]=self | 291 self.column[y] = self |
| 265 | 292 |
| 266 def __repr__(self): | 293 def __repr__(self): |
| 267 return "c@(%s,%s):%s"%(self.x,self.y,self.val) | 294 return "c@(%s,%s):%s" % (self.x, self.y, self.val) |
| 268 | 295 |
| 269 def __str__(self): | 296 def __str__(self): |
| 270 return ' ' if self.val is None else ('\u25A0' if self.val else 'x') | 297 return " " if self.val is None else ("\u25a0" if self.val else "x") |
| 271 | 298 |
| 272 def setVal(self,v): | 299 def setVal(self, v): |
| 273 # Returns true iff old value was None | 300 # Returns true iff old value was None |
| 274 assert v in (True, False) | 301 assert v in (True, False) |
| 275 if v == self.val: | 302 if v == self.val: |
| 276 return False | 303 return False |
| 277 if self.val is not None: | 304 if self.val is not None: |
| 278 eprint("Reset not allowed: %s -> %s at %s,%s"%(self.val, v, self.x,self.y),err=103) | 305 eprint( |
| 279 self.val=v | 306 "Reset not allowed: %s -> %s at %s,%s" % (self.val, v, self.x, self.y), |
| 307 err=103, | |
| 308 ) | |
| 309 self.val = v | |
| 280 return True | 310 return True |
| 281 | 311 |
| 312 | |
| 282 class Nono(list): | 313 class Nono(list): |
| 283 | |
| 284 # 0,0 is upper left, so increasing y goes _downwards_, to match the standard layout | 314 # 0,0 is upper left, so increasing y goes _downwards_, to match the standard layout |
| 285 def __getitem__(self,xy): | 315 def __getitem__(self, xy): |
| 286 return list.__getitem__(self,xy[1])[xy[0]] | 316 return list.__getitem__(self, xy[1])[xy[0]] |
| 287 | 317 |
| 288 def __setitem__(self,xy,v): | 318 def __setitem__(self, xy, v): |
| 289 list.__getitem__(self,xy[1])[xy[0]] = v | 319 list.__getitem__(self, xy[1])[xy[0]] = v |
| 290 | 320 |
| 291 def __init__(self,runsPerRow: list[int], | 321 def __init__( |
| 292 runsPerCol: list[int], | 322 self, runsPerRow: list[int], runsPerCol: list[int], debug: bool |
| 293 debug: bool) -> list[list[Cell]]: | 323 ) -> list[list[Cell]]: |
| 294 global SOLVER | 324 global SOLVER |
| 295 self.loop=0 | 325 self.loop = 0 |
| 296 self.dp='' # old depth hack | 326 self.dp = "" # old depth hack |
| 297 self.debug = debug | 327 self.debug = debug |
| 298 self.dstate=[] | 328 self.dstate = [] |
| 299 SOLVER=self | 329 SOLVER = self |
| 300 n=self.n=len(runsPerCol) | 330 n = self.n = len(runsPerCol) |
| 301 list.__init__(self,list(list(list(range(n)) for _ in range(n)))) | 331 if n != len(runsPerRow): |
| 302 if n!=len(runsPerRow): | 332 print("losing r:%s x c:%s" % (len(runsPerRow), n), sys.stderr) |
| 303 print("losing r:%s x c:%s"%(len(runsPerRow),n),sys.stderr) | |
| 304 exit(1) | 333 exit(1) |
| 305 self.rc=runsPerRow | 334 self.rc = runsPerRow |
| 306 self.cc=runsPerCol | 335 self.cc = runsPerCol |
| 307 # print col nums>9 vertically :-( | 336 # print col nums>9 vertically :-( |
| 308 self.columns=cc=[Column(n,self,i) for i in range(n)] | 337 self.columns = cc = [Column(n, self, i) for i in range(n)] |
| 309 self.rows=rr=[Row(n,self,i) for i in range(n)] | 338 self.rows = rr = [Row(n, self, i) for i in range(n)] |
| 310 for x in range(n): | 339 for x in range(n): |
| 311 for y in range(n): | 340 for y in range(n): |
| 312 self[x,y]=Cell(rr[y],y,cc[x],x) | 341 self[x, y] = Cell(rr[y], y, cc[x], x) |
| 313 # Need cells in place for the following | 342 # Need cells in place for the following |
| 314 for row,runs in zip(rr,runsPerRow): | 343 for row, runs in zip(rr, runsPerRow): |
| 315 row.initRuns(runs) | 344 row.initRuns(runs) |
| 316 for col,runs in zip(cc,runsPerCol): | 345 for col, runs in zip(cc, runsPerCol): |
| 317 col.initRuns(runs) | 346 col.initRuns(runs) |
| 318 self.maxCRheight=maxCRheight=max(col.height for col in cc) | 347 self.maxCRheight = maxCRheight = max(col.height for col in cc) |
| 319 for c in cc: | 348 for c in cc: |
| 320 c.updateHeader(maxHeight=maxCRheight) | 349 c.updateHeader(maxHeight=maxCRheight) |
| 321 maxRRwidth=max(row.width for row in rr) | 350 maxRRwidth = max(row.width for row in rr) |
| 322 for r in rr: | 351 for r in rr: |
| 323 r.updateHeader(maxWidth=maxRRwidth) | 352 r.updateHeader(maxWidth=maxRRwidth) |
| 324 self.rowfmt="%s|%%s|"%(' '*maxRRwidth) | 353 self.rowfmt = "%s|%%s|" % (" " * maxRRwidth) |
| 325 | 354 |
| 326 def __str__(self): | 355 def __str__(self): |
| 327 lines=[self.rowfmt%('|'.join([(self.columns[i]).header[j] for i in range(self.n)])) # 'rotate' | 356 lines = [ |
| 328 for j in range(self.maxCRheight)] | 357 self.rowfmt |
| 329 lines+=[str(r) for r in self.rows] | 358 % ("|".join([(self.columns[i]).header[j] for i in range(self.n)])) # 'rotate' |
| 359 for j in range(self.maxCRheight) | |
| 360 ] | |
| 361 lines += [str(r) for r in self.rows] | |
| 330 return "\n".join(lines) | 362 return "\n".join(lines) |
| 331 | 363 |
| 332 def pass0(self): # do columns of empty layout | 364 def pass0(self): # do columns of empty layout |
| 333 for c in self.columns: | 365 for c in self.columns: |
| 334 c.pass0() | 366 c.pass0() |
| 335 dprint('After Pass 0 for columns', self, sep = '\n') | 367 dprint("After Pass 0 for columns", self, sep="\n") |
| 336 for r in self.rows: | 368 for r in self.rows: |
| 337 r.pass0() | 369 r.pass0() |
| 338 dprint('After Pass 0 for rows', self, sep = '\n') | 370 dprint("After Pass 0 for rows", self, sep="\n") |
| 339 for c in self.columns: | 371 for c in self.columns: |
| 340 c.check0() | 372 c.check0() |
| 341 dprint('After Check 0 for columns', self, sep = '\n') | 373 dprint("After Check 0 for columns", self, sep="\n") |
| 342 dprint(self) | 374 dprint(self) |
| 343 for r in self.rows: | 375 for r in self.rows: |
| 344 r.check0() | 376 r.check0() |
| 345 dprint('After Check 0 for rows', self, sep = '\n') | 377 dprint("After Check 0 for rows", self, sep="\n") |
| 346 | 378 |
| 347 def solve(self): | 379 def solve(self): |
| 348 self.pass0() | 380 self.pass0() |
| 349 | 381 |
| 382 | |
| 350 def dprint(*args, **kwargs): | 383 def dprint(*args, **kwargs): |
| 351 '''Debug print''' | 384 """Debug print""" |
| 352 if SOLVER.debug: | 385 if SOLVER.debug: |
| 353 print(*args, **kwargs) | 386 print(*args, **kwargs) |
| 354 sys.stdout.flush() | 387 sys.stdout.flush() |
| 355 | 388 |
| 356 def eprint(*args,**kw): | 389 |
| 357 '''error print''' | 390 def eprint(*args, **kw): |
| 358 print(*args,file=sys.stderr) | 391 """error print""" |
| 392 print(*args, file=sys.stderr) | |
| 359 sys.stderr.flush() | 393 sys.stderr.flush() |
| 360 print(SOLVER) | 394 print(SOLVER) |
| 361 breakpoint() | 395 breakpoint() |
| 362 exit(kw['err']) | 396 exit(kw["err"]) |
| 363 | 397 |
| 364 if __name__ == '__main__': | 398 |
| 365 if sys.argv[1] == '-d': | 399 if __name__ == "__main__": |
| 400 if sys.argv[1] == "-d": | |
| 366 sys.argv.pop(1) | 401 sys.argv.pop(1) |
| 367 debug = True | 402 debug = True |
| 368 else: | 403 else: |
| 369 debug = False | 404 debug = False |
| 370 if len(sys.argv)>1: | 405 if len(sys.argv) > 1: |
| 371 f=open(sys.argv[1]) | 406 f = open(sys.argv[1]) |
| 372 else: | 407 else: |
| 373 f=sys.stdin | 408 f = sys.stdin |
| 374 | 409 |
| 375 l = f.readline().rstrip() | 410 l = f.readline().rstrip() |
| 376 vv=l.split('/') | 411 vv = l.split("/") |
| 377 n=int(len(vv)/2) | 412 n = int(len(vv) / 2) |
| 378 print('%sx%s puzzle'%(n,n),file=sys.stderr) | 413 print("%sx%s puzzle" % (n, n), file=sys.stderr) |
| 379 cols=[[int(i) for i in v.split('.')] for v in vv[:n]] | 414 cols = [[int(i) for i in v.split(".")] for v in vv[:n]] |
| 380 rows=[[int(i) for i in v.split('.')] for v in vv[n:]] | 415 rows = [[int(i) for i in v.split(".")] for v in vv[n:]] |
| 381 | 416 |
| 382 solver=Nono(rows, cols, debug) | 417 solver = Nono(rows, cols, debug) |
| 383 print(solver) | 418 print(solver) |
| 384 print() | 419 print() |
| 385 solver.solve() | 420 solver.solve() |
| 386 print('Done',solver, sep = '\n') | 421 print("Done", solver, sep="\n") |
| 387 | |
| 388 | |
| 389 |
