E=enumerate
def f(g):
q,s,S=[{(x,y):v for x,r in E(g)for y,v in E(r)}],[],0;Z='*'
for d in q:
D={}
for i in d:
if'/'<d[i]<':':
u={Z:0,'?':0}
for X,Y in(0,1),(1,0),(-1,0),(0,-1),(1,1),(-1,1),(1,-1),(-1,-1):
if(N:=d.get((i[0]+X,i[1]+Y)))in u:u[N]+=1
D[i]=u
if all(D[i][Z]==int(d[i])for i in D):S+=1
elif~-all(D[i][Z]>=int(d[i])<=D[i][Z]+D[i]['?']for i in D):
for i in d:z=(('?'==d[i])>((U:={**d,i:Z})in s))*[U];q+=z;s+=z
return S
def to_board(s):
return [[*i] for i in filter(None, s.split('\n'))]
s = """
1121
1??*
12?*
0122
1110
1???
1110
0000
1110
3???
??20
*310
****
****
****
****
0000
0000
0000
0000
1100
*100
2321
??*2
13*2
1221
1*10
1110
1121
2*??
2*31
2220
1*10
"""
s1 = """
1110
2*31
3*??
2*4?
112?
01??11*211
12??2323*1
1*33*2*210
12?2122321
13?3101**1
1***101221
1***
3*52
2*31
12??
02??
01??
00000111
000012*1
00001*21
22101110
**100111
?31123*1
?311**31
**113*20
"""
for i in s.split('\n\n'):
assert f(to_board(i)) == 1
for i in s1.split('\n\n'):
assert f(to_board(i)) != 1
print('tests passed')
RT1lbnVtZXJhdGUKZGVmIGYoZyk6CiBxLHMsUz1beyh4LHkpOnYgZm9yIHgsciBpbiBFKGcpZm9yIHksdiBpbiBFKHIpfV0sW10sMDtaPScqJwogZm9yIGQgaW4gcToKICBEPXt9CiAgZm9yIGkgaW4gZDoKICAgaWYnLyc8ZFtpXTwnOic6CiAgICB1PXtaOjAsJz8nOjB9CiAgICBmb3IgWCxZIGluKDAsMSksKDEsMCksKC0xLDApLCgwLC0xKSwoMSwxKSwoLTEsMSksKDEsLTEpLCgtMSwtMSk6CiAgICAgaWYoTjo9ZC5nZXQoKGlbMF0rWCxpWzFdK1kpKSlpbiB1OnVbTl0rPTEKICAgIERbaV09dQogIGlmIGFsbChEW2ldW1pdPT1pbnQoZFtpXSlmb3IgaSBpbiBEKTpTKz0xCiAgZWxpZn4tYWxsKERbaV1bWl0+PWludChkW2ldKTw9RFtpXVtaXStEW2ldWyc/J11mb3IgaSBpbiBEKToKICAgZm9yIGkgaW4gZDp6PSgoJz8nPT1kW2ldKT4oKFU6PXsqKmQsaTpafSlpbiBzKSkqW1VdO3ErPXo7cys9egogcmV0dXJuIFMKIApkZWYgdG9fYm9hcmQocyk6CglyZXR1cm4gW1sqaV0gZm9yIGkgaW4gZmlsdGVyKE5vbmUsIHMuc3BsaXQoJ1xuJykpXQoKcyA9ICIiIgoxMTIxCjE/PyoKMTI/KgowMTIyCgoxMTEwCjE/Pz8KMTExMAowMDAwCgoxMTEwCjM/Pz8KPz8yMAoqMzEwCgoqKioqCioqKioKKioqKgoqKioqCgowMDAwCjAwMDAKMDAwMAowMDAwCgoxMTAwCioxMDAKMjMyMQo/PyoyCjEzKjIKMTIyMQoxKjEwCjExMTAKCjExMjEKMio/PwoyKjMxCjIyMjAKMSoxMAoiIiIKCnMxID0gIiIiCjExMTAKMiozMQozKj8/CjIqND8KMTEyPwoKMDE/PzExKjIxMQoxMj8/MjMyMyoxCjEqMzMqMioyMTAKMTI/MjEyMjMyMQoxMz8zMTAxKioxCjEqKioxMDEyMjEKCjEqKioKMyo1MgoyKjMxCjEyPz8KMDI/PwowMT8/CgowMDAwMDExMQowMDAwMTIqMQowMDAwMSoyMQoyMjEwMTExMAoqKjEwMDExMQo/MzExMjMqMQo/MzExKiozMQoqKjExMyoyMAoiIiIKZm9yIGkgaW4gcy5zcGxpdCgnXG5cbicpOgoJYXNzZXJ0IGYodG9fYm9hcmQoaSkpID09IDEKCmZvciBpIGluIHMxLnNwbGl0KCdcblxuJyk6Cglhc3NlcnQgZih0b19ib2FyZChpKSkgIT0gMQoKcHJpbnQoJ3Rlc3RzIHBhc3NlZCcp