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='' 24 Red = ""
25 eRed='' 25 eRed = ""
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