Skip to content

Instantly share code, notes, and snippets.

Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save DroneBetter/4f5d775e7c37f062ce750d4a8fefc84a to your computer and use it in GitHub Desktop.
Save DroneBetter/4f5d775e7c37f062ce750d4a8fefc84a to your computer and use it in GitHub Desktop.
Modification of gzip_swar_life.py supporting arbitrary isotropic non-totalistic cellular automata
import os,sys
from time import time,sleep
from functools import reduce
from dronery import dbg,redumulate,expumulate,shortduce,ORsum,maph,filterh,lap,tap,taph,saph,tarmap,tarmaph,charmap,factorise,primate,revange,loduct,tilter,permutation,decompose,recompose,id,rle,Fraction,__add__,__or__,compose,minh,maxh,reshape,denest,transpose,stratrix,bitverse,sap,rgetitem,sortduct
#print('\n'.join(map(lambda n: ''.join(map(lambda x: 'o' if x else ' ',(lambda x: map(lambda i: x>>3*i+1&1,range(x.bit_length()//3+1)))(n))),redumulate(lambda x,i: (lambda x: reduce(int.__or__,map(lambda j: (lambda x: x>>1&x&x<<1)(~x^i*j),(2,3,4,5,6))))(x>>4|x|x<<4)&i<<1,redumulate(lambda x,i: x|1<<3*i,range(2,64),9),2))));exit()
from itertools import product,starmap,accumulate,groupby,chain,islice,pairwise
try:
from itertools import batched
except:
def batched(l,n):
it=iter(l)
while batch:=tuple(islice(it,n)): yield(batch)
from math import isqrt,sqrt,gcd,lcm
digits={"0","1","2","3","4","5","6","7","8","9"}
"""
Modification of https://gist.github.com/DavidBuchanan314/acae2aab38953759aacc114b417ed0b9 supporting arbitrary OT and INT rules and topological manifolds
manifold=(x type, y type), type 0 is bounded, 1 is cylindrical, 2 is Möbius
States are stored as integers, moving along the bits will scroll in the x axis according to the width and increment the y value each time
The convention for outer-totalistic rules (such that each cell's state depends on its previous value and the sum of its neighbouring eight cells) is to store 4 bits per cell, with the last bit determining its value
It is added with copies of itself shifted leftwards and rightwards by 4 bits so each cell becomes the sum of its horizontal neighbours, then again by 4*WIDTH bits to sum with its vertical ones and their horizontal ones also
After this, for each sum that is a birth or survival condition the summed state is bitwise XORed with a constant that is the NOT of the desired sum for each cell, so those that become 1111 satisfy the sum
This is 'folded' by bitwise ANDing with itself shifted left by 2 bits, then again by 1, then with a constant that is 1 for each cell's last bit
Enact this for all outer totals (keeping in mind that survivals are 1 greater than in notation due to including themselves), bitwise OR those that are exclusively birth, exclusively survival and both, respectively, into three integers
Bitwise OR (the exclusively birth one AND NOT the original state), (the exclusively survival one AND the original state) and the both one together, to get the next state
For isotropic non-totalistic rules (similar to OT ones but depending on the configuration of the neighbours under symmetry as well as their sum), my initial idea was to store them as bits in the centres of their own 3*3 regions in the integer (instead of 4*1), so each can become a copy of its neighbourhood, and then XOR with the NOTs of the desired ones (and so forth) like originally
However, I realised each can instead be an 8*1 region in its outer neighbourhood excluding itself (now enabled by default in byteINT)
Here is one cell in the centre of its neighbourhood
| |
| o|
| |
First, we OR together itself shifted by (1,0), (0,1) and (-1,-1)
| o|
| |o
| o |
Then we OR this with (itself shifted by (3,0) AND a constant that is 01100000 for each bit) and itself shifted by (-11,0)
o | o| o
o | |o
o | o | o
The indexes of the state of the central cell within each neighbour are thus
3 | 0| 5
2 | |7
4 | 1 | 6
The transitions are again ANDed with the original state or its NOT (depending on whether they're birth or survival)
This allows their encoding as videos without using gzip to convert cells of 4 bits to bytes
"""
manifold=(0,0) #0: edges, 1: cylinddrical, 2: Möbius
FPS=10 #Reduce if your media player is buffering.
totalTransitions=({"c"}, #using c for 0 and 8 because otherwise no distinction from empty set
{"c","e"},
{"c","e","k","a","i","n"},
{"c","e","k","a","i","n","y","q","j","r"},
{"c","e","k","a","i","n","y","q","j","r","t","w","z"},
{"c","e","k","a","i","n","y","q","j","r"},
{"c","e","k","a","i","n"},
{"c","e"},
{"c"}) #if squares had more edges and vertices, it would approach a normal distribution, I think
transitionLetters=("c","e","k","a","i","n","y","q","j","r","t","w","z")
transitionTotals=tap(len,totalTransitions)
transitionIndexes=tuple(redumulate(int.__add__,transitionTotals[:-1],0)) #(could be islice(dronery.polynomial.infdiv(transitionTotals,(1,-1)),0,9) :-)
regularTransitions=tuple(charmap(lambda i,t: tap(str(i).__add__,transitionLetters[:t]),enumerate(transitionTotals)))
reducerTransitions=("0c","1c","2c","3c","2n","4c","1e","2a","2k","3n","3i","4n","3q","3y","4y","5e","2e","3a","3j","4a","4w","5a","3k","4q","4k","5j","5k","6e","3e","4r","4j","5n","5i","6a","5q","5y","6k","7e","2i","3r","4i","4t","5r","4z","6i","4e","5c","6c","7c","6n","8c") #from eightfold_reducer import reducer;reducer(3) will return them in this order
reducerPermutation=permutation(0x11c62736cec85cd1c29f0e06b5affb6285d47a8fbedbcbb077f39e)#permutation(tap(reducerTransitions.index,regularTransitions))
transitions=tarmap(str.__add__,product(("B","S"),reducerTransitions))
unreducedTransitions=(0,1,6,7,1,2,7,10,6,7,16,17,8,9,18,19,51,52,57,58,52,53,58,61,57,58,67,68,59,60,69,70,6,8,16,18,7,9,17,19,38,39,28,29,39,40,29,32,57,59,67,69,58,60,68,70,89,90,79,80,90,91,80,83,1,2,8,9,4,3,12,11,7,10,18,19,12,11,20,21,52,53,59,60,55,54,63,62,58,61,69,70,63,62,71,72,8,13,22,24,12,14,23,25,39,41,30,31,43,42,34,33,59,64,73,75,63,65,74,76,90,92,81,82,94,93,85,84,6,8,38,39,8,13,39,41,16,18,28,29,22,24,30,31,57,59,89,90,59,64,90,92,67,69,79,80,73,75,81,82,16,22,28,30,18,24,29,31,28,30,45,46,30,35,46,47,67,73,79,81,69,75,80,82,79,81,96,97,81,86,97,98,7,9,39,40,12,14,43,42,17,19,29,32,23,25,34,33,58,60,90,91,63,65,94,93,68,70,80,83,74,76,85,84,18,24,30,35,20,26,34,36,29,31,46,47,34,36,49,48,69,75,81,86,71,77,85,87,80,82,97,98,85,87,100,99,1,4,8,12,2,3,9,11,8,12,22,23,13,14,24,25,52,55,59,63,53,54,60,62,59,63,73,74,64,65,75,76,7,12,18,20,10,11,19,21,39,43,30,34,41,42,31,33,58,63,69,71,61,62,70,72,90,94,81,85,92,93,82,84,2,3,13,14,3,5,14,15,9,11,24,25,14,15,26,27,53,54,64,65,54,56,65,66,60,62,75,76,65,66,77,78,9,14,24,26,11,15,25,27,40,42,35,36,42,44,36,37,60,65,75,77,62,66,76,78,91,93,86,87,93,95,87,88,7,12,39,43,9,14,40,42,18,20,30,34,24,26,35,36,58,63,90,94,60,65,91,93,69,71,81,85,75,77,86,87,17,23,29,34,19,25,32,33,29,34,46,49,31,36,47,48,68,74,80,85,70,76,83,84,80,85,97,100,82,87,98,99,10,11,41,42,11,15,42,44,19,21,31,33,25,27,36,37,61,62,92,93,62,66,93,95,70,72,82,84,76,78,87,88,19,25,31,36,21,27,33,37,32,33,47,48,33,37,48,50,70,76,82,87,72,78,84,88,83,84,98,99,84,88,99,101) #indices in transitions list of each neighbourhood
reducedTransitions=tap(unreducedTransitions.index,range(102))
def setRule(string):
global rulestring,OT,byteINT,ruleTotalTransitions,rule,transitionInt,totalSums,minuses,rulestring,RLErulestring,dualRule,b1c,b1e,b2c,b2a,b3i,edges,corners,nearCorners,gutterPreservation,cellWidth,cellHeight,cellBits
rulestring=string.lower().replace("/",'').replace("b",'').split("s")
byteINT=True
ruleTotalTransitions=[[set() for _ in range(9)] for _ in range(2)]
for i,r in enumerate(rulestring):
accumulator=''
for t in reversed(r):
if t in {"0","1","2","3","4","5","6","7","8"}:
ruleTotalTransitions[i][int(t)]=(totalTransitions[int(t)] if accumulator=='' else totalTransitions[int(t)]-set(accumulator) if "-" in accumulator else set(accumulator))
accumulator=''
else:
accumulator+=t
rule={("S" if i else "B")+str(j)+t for i,s in enumerate(ruleTotalTransitions) for j,ss in enumerate(s) for t in ss}
#rule^=set(transitions)
pairs=(('c','e'),('i','t'),('n','r'),('y','j'),('q','w'))
#rule=set(map(lambda t: (lambda s,n,t: ('b' if s=='s' else 's')+str(8-int(n))+((lambda c: (lambda p: p[1^p.index(t)])(pairs[c.index(True)]) if any(c) else t)(lap(lambda p: p.__contains__(t),pairs)) if n=='4' else t))(*t),rule))
totalSums=tuple(tuple(sum((("s" if i else "b")+str(j)+t in rule) for t in s) for j,s in enumerate(totalTransitions)) for i in range(2))
minuses=tuple(tuple(--0--len(t)>>1<j<len(t) for j,t in zip(i,totalTransitions)) for i in totalSums)
(rulestring,RLErulestring)=(b+s.join(''.join(''.join(str(j)*(y!=0)+("-"*m+''.join(t for k,t in enumerate(u) if (("s" if i else "b")+str(j)+str(t) in rule)^m))*(y!=len(u))) for j,(y,u,m) in enumerate(zip(w,totalTransitions,x))) for i,(w,x) in enumerate(zip(totalSums,minuses))) for b,s in zip(("b","B"),("s","/S")))
#print(rulestring);exit() #these three commented parts for inverting rule
OT=not(any(any((i in j) for j in rulestring) for i in totalTransitions[4]))
dualRule=[lap(rule.__contains__,transitions[51*i:51*(i+1)]) for i in range(2)] #the rule that is dual
rule=lap(rule.__contains__,transitions)
transitionInt=ORsum(starmap(lambda i,t: t<<i,enumerate(rule)))
checkTransition=(lambda transition: rule[transitions.index(transition)])
if manifold[0]==0 or manifold[1]==0:
(b1c,b1e,b2c,b2a,b3i)=map(checkTransition,("B1c","B1e","B2c","B2a","B3i"))
edges=(b1c or b1e or b2c or b2a or b3i)
if not any(manifold):
corners=b1c
nearCorners=(b1e or b2a) #not b1c because that will be detected by edges and corners
else:
corners=False
nearCorners=edges
else:
corners=nearCorners=edges=False
gutterPreservation=(edges and not any(map(checkTransition,("B2c","B2i","B4c","B4i","B6i"))))
rule=lap(rule.__getitem__,unreducedTransitions)
cellWidth=(4 if OT else 8 if byteINT else 3)
cellHeight=(1 if OT or byteINT else 3)
cellBits=cellWidth*cellHeight
loadRule=setRule
dual=lambda f,r: ORsum(starmap(lambda i,t: t<<unreducedTransitions[f(reducedTransitions[i])],enumerate(decompose(r,102))))
reversal=lambda r: dual((~(~0<<9)).__xor__,~r)
strobing=lambda r: (~(~0<<102)^r,dual((~(~0<<9)).__xor__,r))
checker=lambda r: (dual((~(~0<<9)//3).__xor__,r),dual((~(~0<<10)//3).__xor__,~r))
rulestringer=lambda transitionInt: (lambda transitionInt: 'B'+'/S'.join(map(lambda s: ''.join(starmap(lambda i,t: (lambda r: (lambda s: bool(u)*str(i)+(m and bool(s))*'-'+s)(''.join(sorted(starmap(lambda i,s: s*transitionLetters[i],enumerate(map((1).__xor__,r) if (m:=(u:=sum(r))>t[1]>>1) else r))))))(tap(lambda r: transitionInt>>51*s+r&1,range(t[0],t[0]+t[1]))),enumerate(zip(transitionIndexes,transitionTotals)))),range(2))))(recompose(reducerPermutation((t:=tuple(decompose(transitionInt,102)))[:51])+reducerPermutation(t[51:])))
contains=lambda r,t: r>>reducerTransitions.index((t:=t+'c'*(len(t)==2))[1:])+51*(t[0].lower()=='s')&1
def dualities(inputString):
global transitionInt
setRule(inputString)
if rulestringer(transitionInt)!=inputString:
print('your rule is '+rulestringer(transitionInt))
ruleReversal=reversal(transitionInt)
if (selfInverse:=ruleReversal==transitionInt):
print('it is self-inverse')
else:
print('the reversal is '+rulestringer(ruleReversal))
strule=strobing(transitionInt)
chule=checker(transitionInt)
print('the strobing dual is '+rulestringer(strule[0])+(not selfInverse)*(' and '+rulestringer(strule[1])+' alternating in time'))
print('the checkerboard dual is '+rulestringer(chule[0])+(not selfInverse)*(' and '+rulestringer(chule[1])+' alternating in space'))
#dualities(input('>>> '));exit()
'''count=0
for b,s in product(range(1<<9),repeat=2):
setRule('b'+'s'.join(map(lambda t: ''.join(map(lambda i: (t>>i&1)*str(i),range(9))),(b,s))))
if checker(transitionInt)==2*(transitionInt,): count+=1;print('b'+'s'.join(map(lambda t: ''.join(map(lambda i: (t>>i&1)*str(i),range(9))),(b,s))))
if not(s or b&7): print(b>>3)
print('count',count)
exit()'''
#print(tuple(tuple(i for i in range(9) if OTtransitions[0][i]^o and OTtransitions[1][i-1]^a) for o in range(2) for a in range(1+(not o))));exit()
shift=(lambda n,b: n<<-b if b<0 else n>>b)
bits=lambda n,k: (1<<n*k)//~(~0<<k) #more correctly, ORsum(1<<k*i for i in range(n))=~(~<<n*k)//~(~0<<k)
def setBoard(w,h,manifoldModes=True):
global boardWidth,boardHeight,WIDTH,HEIGHT,STATE_BYTE_LENGTH,innerCOLSHIFT,COLSHIFT,WRAPSHIFT,BIAS,WRAP_MASK,lastColumn,firstColumn,MASK_1,emptyColumns
boardWidth=w;boardHeight=h
WIDTH=boardWidth+2;HEIGHT=boardHeight+2
STATE_BYTE_LENGTH=(boardWidth*boardHeight>>OT if OT or byteINT else --0--9*boardWidth*boardHeight//8)
innerCOLSHIFT=cellWidth*boardWidth
COLSHIFT=cellBits*WIDTH
WRAPSHIFT=COLSHIFT*boardHeight
BIAS=((WIDTH+1)*cellWidth if OT or byteINT else (WIDTH*cellBits+1)*4)
unitNeighbourhood=0xf if OT else 0xff if byteINT else bits(3,3*WIDTH)*0b111
WRAP_MASK=bits(WIDTH,cellWidth)*unitNeighbourhood<<COLSHIFT
lastColumn=bits(HEIGHT,COLSHIFT)*unitNeighbourhood
firstColumn=shift(lastColumn,(cellWidth if OT or byteINT else 3*(1-WIDTH))-((OT or byteINT) and COLSHIFT))
BLIT_MASK_1=( int.from_bytes((WIDTH*HEIGHT>>OT)*(b"\x11" if OT else b"\x01"),"little")
if OT or byteINT else
bits(WIDTH,cellWidth)*bits(HEIGHT,cellWidth*cellHeight*WIDTH)<<(1+3*WIDTH)*(not(OT or byteINT)))
MASK_1=~(~0<<COLSHIFT*(HEIGHT-1)|firstColumn|lastColumn)&~0<<COLSHIFT&BLIT_MASK_1
emptyColumns=bits(WIDTH,8)*bits(HEIGHT,COLSHIFT)*0b1100000
global OTtransitions,INTtransitions,irr,andnts,ands
if OT:
OTtransitions=tuple(tuple((str(i) in s) for i in range(9)) for s in rulestring.replace("b",'').split("s"))
(irr,andnts,ands)=(tuple(MASK_1*(0xf^i) for i in range(10) if (i<9 and OTtransitions[0][i])^o and OTtransitions[1][i-1]^a) for o in range(2) for a in range(1+(not o))) #(tuple(MASK_1*(15^i) for i,(b,s) in enumerate(OTtransitions[0],OTtransitions[1][-1:]+OTtransitions[1][:7]) if b^o and s^a) for o in range(2) for a in range(1+(not o)))
elif byteINT:
(irr,andnts,ands)=(tuple({MASK_1*ORsum((~i>>j&1)<<(5,0,3,7,-1,2,6,1,4)[j] for j in tuple(range(4))+tuple(range(5,9))) for k,(b,s) in enumerate(zip(*dualRule)) if b^o and s^a for i,r in enumerate(unreducedTransitions) if r%51==k and (s if r//51 else b)}) for o in range(2) for a in range(1+(not o)))
else:
INTtransitions=tuple(MASK_1*ORsum((~i&1<<3*j)<<3*(WIDTH-1)*j for j in range(3))>>WIDTH*3+1 for i,r in enumerate(rule) if r)
if manifoldModes:
def reversalParameters(axis=0,inputWidth=WIDTH): #axis=0 for none, 1 for x, 2 for y
if axis:
inputWidth=(WIDTH if axis==2 else HEIGHT)
masks=[[[m,1<<i,False],[m,0,True]] for i,m in enumerate(andMasks(inputWidth))] #mask, shift right, order (True is shift after)
exceeding=(1<<(inputWidth-1).bit_length())-inputWidth
if exceeding:
endShifts=[-exceeding>>1,exceeding>>1]
#print(inputWidth,endShifts)
for i,m in enumerate(masks):
#print(m[0][1])
shifter=(lambda i,m: min(m[0][1],m[0][1]-(2<<i),key=abs))
if -endShifts[0]<=shifter(i,m):
m[0][1]+=endShifts[0]
m[1][0]>>=-endShifts[0]
break
else:
m[0][0]>>=m[0][1]-endShifts[0]
m[0][1]-=endShifts[0]
m[0][2]=True
m[1][0]>>=-endShifts[0]
common=(m[0][1]^m[0][1]-(2<<i)>0 and shifter(i,m))
if common:
endShifts[0]=-common
if endShifts[0]<m[0][1]:
m[0][1]=0
else:
break
masks[-1][0][0]>>=endShifts[1]
masks[-1][0][1]+=endShifts[1]
'''for i,m in enumerate(masks):
for a in m:
if not i: #or a[1]>0
a[0]&=(1<<(inputWidth-a[1] if a[1]<0 and not a[2] else inputWidth))-1''' #small optimisation but turns out not to work for all values not three quarters of a power of 2
for i,m in enumerate(masks):
m[1][1]=m[0][1]-2*(1<<i)
bytewise=(lambda m: [ORsum((m[0]&1<<i)<<(cellWidth-1)*i for i in range(1<<(inputWidth-1).bit_length()))<<(not(OT or byteINT) and 3*WIDTH+1),cellWidth*m[1],m[2]])
if axis:
masks=[[( [(l:=ORsum((n&1<<(cellWidth*i if OT or byteINT else 3*(WIDTH+i)+1))<<cellWidth*(cellHeight*WIDTH-1)*i for i in range(1<<(HEIGHT-1).bit_length())))|l<<cellWidth*(WIDTH-1),s*cellHeight*WIDTH,o]
if axis==1 else
[n|n<<COLSHIFT*(HEIGHT-1),s,o]) for n,s,o in map(bytewise,m)] for m in masks]
#print("\n".join(hex(n[0]) for m in masks for n in m))
'''if axis:
for m in masks:
for i,n in enumerate(m):
printBoard(n[0],False,("+" if i else "-"))'''
conditionalSwap=(lambda x,b,t,f,br: '('*br+x+(t+')'*br+f if b else f+')'*br+t))
indent=(lambda i,t: " "*(i>len(t) and i-len(t))+t)
marge=[max(len(str((abs if i else hex)(n[i]))) for m in masks for n in m) for i in range(2)]
return("def reverseBits"+("Y" if axis==2 else "X" if axis else '')+"(x):\n "+"\n ".join("x="+'|'.join(conditionalSwap('x',(n[2] and n[1]),"&"+indent(marge[0],str(hex(n[0]))),((">>" if n[1]>0 else "<<")+indent(marge[1],str(abs(n[1]))) if n[1] else ' '*(2+marge[1])),(n[1] and n[2])) for n in m) for m in masks)+"\n return(x)")
global reverseBits,reverseBitsX,reverseBitsY
for i in range(3):
#print(reversalParameters(i))
exec(reversalParameters(i))
niemiec=True #whimsical
boardRow=lambda board,i: board>>(cellWidth*WIDTH*i if OT or byteINT else 3*WIDTH*(i*3+1)+1)&~(~0<<cellWidth*WIDTH)
boardStr=(lambda board,inner=True,b='b',o='o',j='\n': j.join((lambda i: ''.join(o if i>>cellWidth*j&1 else b for j in range(inner,i.bit_length()//cellWidth+2-inner)))(boardRow(board,i)) for i in range(inner,HEIGHT-inner)))
phaseStr=(lambda boards,inner=True,o='o',_='_',O='O',j='\n': j.join((lambda i: ''.join((lambda i: (((o,_,O)[i-1] if False else (O if i==(1<<len(boards))-1 else o) if i&1 else _)) if i else ' '*len(o))(ORsum(starmap(lambda i,s: (s>>cellWidth*j&1)<<i,enumerate(i)))) for j in range(inner,WIDTH-inner)))(tap(lambda b: boardRow(b,i),boards)) for i in range(inner,HEIGHT-inner)))
blocks=(lambda board,inner=True: '\n'.join(map(lambda p: ''.join(map(lambda a,b: ' ▄▀█'[a<<1|b],*(p if len(p)==2 else p+((0,)*len(p),)))),batched(map(lambda i: (lambda i: map(lambda j: i>>cellWidth*j&1,range(inner,WIDTH-inner)))(boardRow(board,i)),range(inner,HEIGHT+1-inner)),2))))
def printBoard(board,inner=True,symbol="=",phases=False,end='\n'):
print(symbol*(boardWidth if inner else WIDTH)+"\n"+(phaseStr(board,inner,*(('▓▓','░░'),('▒▒','░░'))[0],'██') if phases else blocks(board,inner)),end=end) #boardStr(board,inner,' ','o','\n'))
RLE=(lambda board,inner=True,includeRule=False: ("x ="+str(boardWidth)+", y = "+str(boardHeight)+", rule = "+RLErulestring+"\n")*includeRule+''.join((lambda l,q: l*2 if niemiec and q==2 else l if q==1 else str(q)+l)(l,len(list(q))) for l,q in groupby(boardStr(board,inner,'b','o','$')))+"!")
cellsAtCoordinates=(lambda cells: ORsum(1<<cellWidth*(x+cellHeight*y*WIDTH) for x,y in cells)<<BIAS)
def proceed(RLE,i):
while RLE[i] in set("x y, =rule"):
i+=1
return(i)
def RLEsize(RLE): #for headerless ones
width=height=0
arm=0
output=0
endOfTheLine=False #"end of the line"
stringer='' #like finger
for r in RLE.replace(' ',''):
if r in digits:
stringer+=r
else:
stringer=(int(stringer) if stringer else 1)
if r=="$":
height+=stringer
arm=0
endOfTheLine=False
else:
if r=="!":
break
if r and r!='\n':
arm+=stringer
if arm>width: width=arm
stringer=''
return((width,height+1))
def loadRLE(RLE):
if RLE[0]=='x':
i=1
size=[]
for di in range(2):
stringer=''
i=proceed(RLE,i)
for i,r in enumerate(RLE[i:],start=i):
if r in digits:
stringer+=r
else:
break
size.append(int(stringer))
global boardWidth,boardHeight,WIDTH,HEIGHT,STATE_BYTE_LENGTH,innerCOLSHIFT,COLSHIFT,WRAPSHIFT,BIAS,WRAP_MASK,lastColumn,firstColumn,MASK_1,emptyColumns #please tell me if you can find a better way than this of having inner functions set globals
setBoard(*size)
i=proceed(RLE,i)
global rulestring,OT,byteINT,ruleTotalTransitions,rule,totalSums,minuses,rulestring,RLErulestring,dualRule,b1c,b1e,b2c,b2a,b3i,edges,corners,nearCorners,gutterPreservation,cellWidth,cellHeight,cellBits
setRule(RLE[i:(i:=RLE.index('\n'))]) #distinct from \n
else:
i=0
arm=0
output=0
endOfTheLine=False #"end of the line"
stringer='' #like finger
#print(RLE[i:])
for r in RLE[i:].replace(' ',''):
if r in digits:
stringer+=r
else:
stringer=(int(stringer) if stringer else 1)
if r=="$":
arm=(arm//boardWidth-endOfTheLine+stringer)*boardWidth
#arm+=(stringer-endOfTheLine)*boardWidth-arm%boardWidth #hmm (not sure which I like more)
endOfTheLine=False
else:
if r=="o":
output|=ORsum(1<<s%boardWidth*cellWidth for s in range(arm,arm+stringer))<<arm//boardWidth*COLSHIFT+BIAS
elif r=="!":
break
if r and r!='\n':
arm+=stringer
endOfTheLine=not(arm%boardWidth)
stringer=''
return(output)
#andMasks=(lambda inputWidth: tap(lambda i: reduce(lambda n,j: n|n<<(1<<j),range(i+1,bitWidth),(1<<(1<<i))-1),range(bitWidth:=(inputWidth-1).bit_length()))) #equivalently,
andMasks=(lambda inputWidth: tap(lambda i: ~(~0<<(1<<bitWidth))//(1<<(1<<i)|1),range(bitWidth:=(inputWidth-1).bit_length()))) #thank you Donald Knuth (https://www-cs-faculty.stanford.edu/~knuth/fasc1a.ps.gz :-)
colmask=lambda x: lastColumn<<cellWidth*(x+1)
rowmask=lambda y: WRAP_MASK<<COLSHIFT*y
def marginalise(state,marginalisation=1): #very suspicious (marginalisation 2 causes it to only grow, 1 causes it to recede also, 0 doesn't call it)
if state:
global boardWidth,boardHeight,WIDTH,HEIGHT,STATE_BYTE_LENGTH,innerCOLSHIFT,COLSHIFT,WRAPSHIFT,BIAS,WRAP_MASK,lastColumn,firstColumn,MASK_1,emptyColumns,OTtransitions,INTtransitions,irr,andnts,ands
for minX in range(boardWidth):
if colmask(minX)&state:
break
for maxX in revange(boardWidth):
if colmask(maxX)&state:
break
for minY in range(boardHeight):
if rowmask(minY)&state:
break
for maxY in revange(boardHeight):
if rowmask(maxY)&state:
break
state=RLE(state)
if marginalisation==2:
minX=min(minX,1);maxX=max(maxX,boardWidth+~1);minY=min(minY,1);maxY=max(maxY,boardHeight+~1)
setBoard(maxX+4+~minX,maxY+4+~minY,False) #no manifolds when marginalising
global shiftX,shiftY
shiftX=minX-1;shiftY=minY-1
return(shift(loadRLE(state),shiftX*cellWidth+shiftY*COLSHIFT))
else:
raise(ValueError("empty :-("))
yuv4mpeg=False#(OT and input("Would you like YUV4MPEG mode?").lower() in {"y","yes"})
deflate_verbatim=(lambda data: len(data).to_bytes(2,"little")+(len(data)^0xffff).to_bytes(2,"little")+data)
if yuv4mpeg:
GZIP_HEADER = b"\x1f\x8b\x08\x00\x00\x00\x00\x00\x00\x03"
YUV_HEADER = f"YUV4MPEG2 W{WIDTH} H{HEIGHT} F{FPS}:1 Cmono\n".encode()
#This tree could be encoded more concisely, but I'm lazy
MAGIC_HUFFMAN_TREE = bytes.fromhex(f"6ce30990244992244908fc{'f'*60}00000020{'2'*14}0000")
sys.stdout.buffer.write(GZIP_HEADER)
sys.stdout.buffer.write(b"\x00" + deflate_verbatim(YUV_HEADER) + b"\x00")
def loadapg(apgcode,p=False):
if apgcode[:2] in {"xp","xq"}: #could be "xs" except still lifes are not very interesting to analyse
global objectType
objectType=('p','q').index(apgcode[1])
period=''
i=2
while apgcode[i] in digits:
period+=apgcode[i]
i+=1
period=int(period)
inelegant=[[] for _ in range(5)] #cannot be [[]]*5 because then they are the same
z=0
sleepy=False
for i in apgcode[i+1:]:
if sleepy:
n="0123456789abcdefghijklmnopqrstuvwxyz".index(i)+4
for j in range(5):
inelegant[5*z+j]+=[0]*n
sleepy=False
else:
if i=='z':
inelegant+=[[] for _ in range(5)]
z+=1
else:
try:
cells="0123456789abcdefghijklmnopqrstuv".index(i)
for j in range(5):
inelegant[5*z+j].append(cells>>j&1)
except:
if i=='y':
sleepy=True
else:
for j in range(5):
inelegant[5*z+j]+=[0]*(2+(i=='x'))
'''print('\n'.join(map(lambda l: ''.join(map(lambda c: 'o' if c else ' ',l)),inelegant)))
print(inelegant)'''
global boardWidth,boardHeight,WIDTH,HEIGHT,STATE_BYTE_LENGTH,innerCOLSHIFT,COLSHIFT,WRAPSHIFT,BIAS,WRAP_MASK,lastColumn,firstColumn,MASK_1,emptyColumns,OTtransitions,INTtransitions,irr,andnts,ands
setBoard(max((i for j in inelegant for i,k in enumerate(j) if k),default=0)+1,max(i for i,j in enumerate(inelegant) if any(j))+1)
if p:
global state
state=loadRLE('$'.join(map(lambda l: ''.join(map(lambda c: 'o' if c else 'b',l)),inelegant))+'!')
return(period if p else state)
else:
raise(ValueError('not xp or xq'))
'''critterMask=1
(stro,crit,ters)=tap(lambda n: eval('lambda state: '+('|'.join(map(lambda i: (lambda s: (lambda d: '('+d[:(f:=d.find('s'))]+('(s:='+s+')' if d.count('s')>1 else '('+s+')')+d[f+1:]+')' if 's' in d else d or '0')((lambda n: '|'.join(filter(id,map(lambda i: (n>>i&1)*('s'+bool(i)*('<<'+str((i&1)+COLSHIFT*(i>>1&1)))),range(4)))))(n>>(i<<2))))((~i&1)*'~'+'state&'+(~i>>1&1)*'~'+'state>>1&'+(~i>>2&1)*'~'+'state>>'+str(COLSHIFT)+'&'+(~i>>3&1)*'~'+'state>>'+str(COLSHIFT+1)+'&'+str(critterMask)),range(1<<4))) or '0')), #extremely unoptimised
(0xfed3b56179a2c480, #(0b1111_1110_1101_0011_1011_0101_0110_0001_0111_1001_1010_0010_1100_0100_1000_0000,
0x08432a97165bcdef, # 0b0000_1000_0100_0011_0010_1010_1001_0111_0001_0110_0101_1011_1100_1101_1110_1111,
0x01234a9e865dcb7f))# 0b0000_0001_0010_0011_0100_1010_1001_1110_1000_0110_0101_1101_1100_1011_0111_1111))
#exit()'''
def iterateCellular(state,marginalisation=0):
global WIDTH,HEIGHT,innerCOLSHIFT,COLSHIFT,WRAPSHIFT,WRAP_MASK,lastColumn,firstColumn,MASK_1,emptyColumns,INTtransitions,irr,andnts,ands
if marginalisation:
global shiftX,shiftY
state=marginalise(state,marginalisation)
if manifold[0]:
state|=(reverseBitsX if manifold[0]==2 else id)(state>>innerCOLSHIFT&lastColumn|state<<innerCOLSHIFT&firstColumn)
if manifold[1]:
state|=(reverseBitsY if manifold[1]==2 else id)(state>>WRAPSHIFT|(state&WRAP_MASK)<<WRAPSHIFT)
if OT or byteINT:
summed=( ((s:=(state>>4)+state+(state<<4))>>COLSHIFT)+s+(s<<COLSHIFT)
if OT else
(s:=state>>1|state>>COLSHIFT|state<<COLSHIFT+1)<<11|s|s>>3&emptyColumns)
masks=[ORsum(((s:=(s:=summed^r)&s>>1)&s>>2 if OT else (s:=(s:=(s:=summed^r)&s>>1)&s>>2)&s>>4) for r in o) for o in (irr,andnts,ands)]
return((state&masks[2]|masks[0]|masks[1]&~state)&MASK_1)
else:
return(ORsum((s:=(s:=((s:=state>>2|state|state<<2)>>6*WIDTH|s|s<<6*WIDTH)^r)>>1&s&s<<1)>>3*WIDTH&s&s<<3*WIDTH for r in INTtransitions)&MASK_1)
def analyse(apgcode,metric=(0,),interface=False,stateInstead=False): #0: volatility, 1: heat, 2: polyomino?, 3: minimum population, 4: gutter, -1: correct margins only
def polyomino(state):
omino=0
newmino=1<<(state.bit_length()-1)
while newmino!=omino:
omino=newmino
newmino=(omino|(omino<<COLSHIFT+cellWidth|omino<<COLSHIFT-cellWidth|omino>>COLSHIFT-cellWidth|omino>>COLSHIFT+cellWidth if polyferz else omino<<COLSHIFT|omino<<cellWidth|omino>>cellWidth|omino>>COLSHIFT))&state
return(omino==state)
global state,objectType,period
period=loadapg(apgcode,True)
global boardWidth,boardHeight,WIDTH,HEIGHT,STATE_BYTE_LENGTH,innerCOLSHIFT,COLSHIFT,WRAPSHIFT,BIAS,WRAP_MASK,lastColumn,firstColumn,MASK_1,emptyColumns,OTtransitions,INTtransitions,irr,andnts,ands,shifts
originalSize=(boardWidth,boardHeight)
shifts=((1,1) if objectType else (0,0)) #would be (0,0) except it is very suspicious
global shiftX,shiftY
for i in range(period+1):
#printBoard(state)
state=iterateCellular(state,2-objectType)
if objectType:
shifts=tap(int.__add__,shifts,(shiftX,shiftY))
if metric==-1:
if objectType:
state=RLE(state)
setBoard(boardWidth+abs(shifts[0]),boardHeight+abs(shifts[1]))
state=shift(loadRLE(state),(lambda f: -f(-shifts[0])*cellWidth-f(-shifts[1])*COLSHIFT)(lambda x: x>0 and x))
return(period,state)
memory=state
accumulator=0
energies=[]
differences=0
minpop=state.bit_count()
poly=0
measureStricts=True
if measureStricts:
factors=(lambda p: (1,)+factorise(p))(period)[:-1] #numbers are not proper divisors of themselves, however 1 detects stators :-)
#fates=[state for _ in factors] #factorStates :-) #this will not work (must sample full period, not only representatives)
unabidings=[0 for _ in factors]
pasts=[] #instead of fates
for i in range(period):
if measureStricts: pasts.append(state) #storing at indexes of primitive roots of unity would take list A000010(n)=O((1-6/pi**2)*n) elements long
#printBoard(state)
#if i: #(would enclose for loop)
for j,f in enumerate(factors):
if i>=f:
unabidings[j]|=state^pasts[i-f]
'''if not i%f:
unabidings[j]|=state^fates[j] #reduced OR of XORs of all from first to last contains XOR of last with first :-)'''
previous=state
accumulator|=state
state=iterateCellular(state,0)
if 3 in metric:
minpop=min(minpop,state.bit_count())
if 2 in metric:
poly+=polyomino(state)
if 0 in metric or 1 in metric or 4 in metric:
difference=state^previous
differences|=difference
if 1 in metric:
energies.append(difference.bit_count())
if 2 in metric:
if poly: printBoard(state)
if 1 in metric:
heat=sum(energies)/period
if 0 in metric:
rotor=differences.bit_count()
strictor=reduce(int.__and__,unabidings).bit_count() #only well-defined here for oscillators (spaceships in the mode with subpixels) #"strictor, come down for dinner" "not now, mother"
footprint=accumulator.bit_count()
volatility=rotor/footprint
strict=strictor/footprint
global gutter
if 4 in metric:
gutter=False
columns=tap(lambda x: (colmask(x)&accumulator).bit_count(),range(boardWidth))
rows=tap(lambda y: (rowmask(y)&accumulator).bit_count(),range(boardHeight))
for mask,d in ((colmask,columns),(rowmask,rows)):
mini=maxi=-1
for x,c in enumerate(d):
if c:
if mini==-1: mini=x
maxi=x
for x,c in enumerate(d[mini+1:maxi],start=mini+1):
if not c and (mask(x-1)&differences or mask(x+1)&differences): gutter=True
if interface and (4 not in metric or gutter):
print('h',heat,'f',footprint,'r',rotor,'v',volatility,'s',strict)
return(gutter if 4 in metric else minpop if 3 in metric else poly if 2 in metric else heat if 1 in metric else (volatility,strict))
if __name__=='__main__':
polyferz=False #unfortunately they do not exist
#dualities(input('rule '));exit() #for getting a rule's duals
mode=5 #0,1,2,3 (simulate RLE, sort census, exhaustively search bounded plane, make picture (or OT map) :-)
OTmap=0 #also for printing known spaceships in a given rule
setRule('b3s23' if mode==3 and OTmap or mode>3 else input("Which rule would you like? ") or 'b3s23')
setBoard(8,8)
#logarithmic replicator rule emulator rulestring
#setRule('B2a3eny4at/S01c2ci3i4e5e');setBoard(3,3);print(hex(ORsum(starmap(lambda i,p: ('','bo','obo','3o').index(RLE(iterateCellular(loadRLE('$'.join(map(('bbb','bob','obo','ooo').__getitem__,p))))).split('$')[1])<<2*i,enumerate(product(range(4),repeat=3))))));exit()
if mode==5: #2x2's
#transitions: (0,1,2e,2c,3,4)
ruleTransitionSet=set()
ruleTable=[]
l=[]
f=lambda r: lambda s: r>>2+((s^s>>1)&(s^s>>2)&1)&1 if (wt:=s.bit_count())==2 else r>>wt+(wt>2)&1
rulestringer2x2=lambda r,space=0: ''.join(map(lambda i: ((' ','0'),(' ','1'),(' ','2e'),(' ','2c'),(' ','3'),(' ','4'))[i][r>>i&1],range(6)) if space else map(('0','1','2e','2c','3','4').__getitem__,filter(lambda i: r>>i&1,range(6)))).replace('2e2c','2'+' '*space).replace('e ','e').replace(' 2c','2c').replace(' ',' ')
reversal=lambda r: ~(r<<5|(r&0b10)<<3|r&0b1100|r>>3&0b10|r>>5&1)&0b111111
convert2to3=lambda r0,r1: recompose(tap(lambda t: f(r1)(recompose(tap(lambda t: f(r0)(recompose(t)),reshape(denest(tap(compose(transpose,tuple),reshape(denest(tuple(pairwise(map(compose(pairwise,tuple),reshape(decompose(t,9),(3,3)))))),(2,2,2,2)))),(4,4))))),reducedTransitions))
for r in chain.from_iterable(sorted(sap(lambda r: tuple(sorted((r,reversal(r)))),range(1,~(~0<<6)) if (excludeSelfForcers:=False) else range(1<<6)),key=lambda r: r[0])):#chain.from_iterable(map(lambda r: (r:=bitverse(r,5),~(~0<<6)^r),range(1<<5))):#range(1<<6):
rulestring=rulestringer2x2(r)
transitions2x2=convert2to3(r,r)
ruleTransitionSet.add(transitions2x2)
ruleTable.append([r,rulestringer2x2(r,1)]+rulestringer(transitions2x2).split('/')) #recompose(map(f,range(1<<4)))
l.append(transitions2x2)
#print(stratrix(tarmap(lambda i,r: tarmap(lambda j,u: int(rulestringer(r^u)==rulestringer(l[i^j])),enumerate(l)),enumerate(l))))
#print(stratrix(((0,)+tuple(range(len(l))),)+tarmap(lambda i,r: (i,)+tarmap(lambda j,u: int(rulestringer(r^u)==rulestringer(l[i^j])),enumerate(l)),enumerate(l))))
#print(tap(taph(rulestringer2x2),((0,63),(4,59),(8,55),(12,51),(18,45),(22,41),(26,37),(30,33))))
#print(stratrix(tap(lambda r: tuple(decompose(r,6)),(chain.from_iterable(((0,63),(4,59),(8,55),(12,51),(18,45),(22,41),(26,37),(30,33)))))))
#print(stratrix(ruleTable,dims=2))
def equivalences(l,f=lambda i,j: not(i^j),relation=0,sym='='):
equiv=[]
for i,j in product(range(102),repeat=2):
if i!=j and all(map(lambda r: f(r>>i&1,r>>j&1),l)): equiv.append([i,j])
if relation:
i=0
while i<len(equiv):
for j in range(i):
for k in range(2):
if equiv[i][k] in equiv[j]:
if equiv[i][~k&1] not in equiv[j]:
equiv[j].append(equiv[i][~k&1])
del equiv[i];i=-1
if i==-1: break
if i==-1: break
i+=1
print(equiv)
print('\n'.join(map(compose(maph(transitions.__getitem__),(' '+sym+' ').join),equiv)))
maxlen=max(map(compose(rgetitem(2),len),ruleTable))
#print('\n|-\n'.join(starmap(lambda i,r: '|'+'rowspan=2|r||'*(~i&1)+' '*(len(str(r[0]))==1)+str(r[0])+'||'+r[1].replace(' ',' ')+'||'+' '*(maxlen-len(r[2]))+r[2]+'/'+r[3],enumerate(ruleTable))))
#print(len(set(l)))
#equivalences(l,lambda i,j: not i or j,sym='=>')
#equivalences(l,lambda i,j: i^j,sym='^') #does not even work with excludeSelfForcers
#c=tap(lambda r0: tap(lambda r1: convert2to3(r0,r1),range(1<<6)),range(1<<6)) #very inefficient but only needed to run once
from compositions_2to3 import c
convert2to3=lambda r0,r1: c[r0][r1]
l=tuple(chain.from_iterable(c))
#print(l)
#equivalences(l)
#print(tap(taph(rulestringer),l))
#print(tap(l.count,sorted(s:=set(l))),len(s))
normalise=lambda r0,r1: (~(~0<<6)^r0,~(~0<<6)^reversal(r1)) if r0&1 else (r0,r1)
#binsort=lambda r: tuple(chain.from_iterable(sorted(map(sorted,reshape(r,(2,2)))))) #=lambda r: min(map(lambda n: tuple(chain.from_iterable(tap(lambda t: t[::(-1)**(n>>1)],reshape(r,(2,2)))[::(-1)**(n&1)])),range(4)))
equivalenceClass=lambda r0,r1: tarmap(normalise,((r0,r1),(r1,r0),(reversal(r0),reversal(r1)),(reversal(r1),reversal(r0))))
s=sorted(set(starmap(lambda r0,r1: equivalenceClass(*min(equivalenceClass(r0,r1))),product(map((2).__mul__,range(1,1<<5)),range(1,~(~0<<6))))))
maxlen=max(map(compose(lambda r: c[r[0]][r[1]],rulestringer,lambda s: s.index('/')),chain.from_iterable(s)))
table=lambda s: '\n|-\n'.join(map(lambda t: (lambda r: '|rowspan=3|r|| ||rowspan=2|c||'+r[0]+'\n|-\n|rowspan=3|r||'+r[1]+'\n|-\n|rowspan=2|c||'+r[2]+'\n|-\n| ||'+r[3])(tarmap(lambda r0,r1: (rulestringer2x2(r0,1)+'||'+rulestringer2x2(r1,1)).replace(' ',' ')+'||'+(maxlen-(s:=rulestringer(c[r0][r1])).index('/'))*' '+s,t)),s))
#print(table(filter(lambda r: any(map(lambda r: not contains(convert2to3(*r),'B0'),r)),s)))
print(table(filter(lambda r: all(map(lambda r: contains(convert2to3(*r),'B0') and not contains(convert2to3(*r),'S8'),r)),s)))
print(len(s))
strobing=lambda r: contains(r:=convert2to3(*r),'B0') and not contains(r,'S8')
print(len(tuple(filter(lambda r: any(map(lambda r: not contains(r:=convert2to3(*r),'B0'),r)),s))))
print(len(tuple(filter(lambda r: not all(map(strobing,r)) and all(map(lambda r: contains(r:=convert2to3(*r),'B0') or not contains(r,'B1c') and any(map(lambda c: contains(r,c),('B1e','B2a','B2c','B3i'))) and any(map(lambda c: contains(r,c),('B1e','B2a','B2e','B3a'))),r)),s))))
print(stratrix(tap(taph(rulestringer),undisproven:=tap(compose(filterh(lambda r: not contains(r:=convert2to3(*r),'B0')),tarmaph(convert2to3)),filter(lambda r: not all(map(strobing,r)) and all(map(lambda r: contains(r:=convert2to3(*r),'B0') or not contains(r,'B1c') and any(map(lambda c: contains(r,c),('B1e','B2a','B2c','B3i'))) and any(map(lambda c: contains(r,c),('B1e','B2a','B2e','B3a'))) and not all(map(lambda c: contains(r,c),('S0','S1c','S1e','S2c','S2e','S2k','S2a','S3a','S3i','S3n','S3j','S4a'))) and not all(map(lambda c: contains(r,c),('B1e','B2a'))),r)),s))),dims=2))
print(tap(compose(lambda n: 'BS'[n//51]+reducerTransitions[n%51]),reduce(set.__and__,chain.from_iterable(tap(compose(filterh(lambda r: not contains(r,'B1e')),taph(lambda r: set(filter((r:=tuple(decompose(~(~0<<102)^r))).__getitem__,range(len(r)))))),undisproven)))))
print(len(undisproven))
print(len(tuple(filter(lambda r: all(map(strobing,r)),s))))
elif mode==4: #reformat
with open(os.path.join(sys.path[0],'c2-P098.json'),newline='') as db: #https://conwaylife.com/forums/viewtopic.php?p=171031#p171152
for i,s in enumerate(db):
print('\n'.join(s.replace('.',' ').split('| --- |')))
if i>20: break
elif mode==3:
from PIL import Image
rms=lambda c: sqrt(sum(tap((2.).__rpow__,c))/len(c)) #root-mean-square, not Richard Martin Stallman
triangleWave=lambda o,period=1: (lambda p: tap(rms(p).__rtruediv__,p))(tap(lambda c: (lambda o: 3*o if o<1/3 else o<2/3 and 2-3*o)((o/period+c/3)%1),range(3)))
if OTmap:
speed=(3,1,1) #speed given as (p,x,y) (with x>=y), or False/0 for all speeds
if speed[2]>speed[1]: speed=(speed[0],)+speed[2:0:-1]
rule=input('rule? (blank for map) ')
speedRequirement=bool(speed and not rule) #if on, spaceships of desired speed blue, otherwise they are green and others are hidden
printRLEs=rule!='' or speedRequirement and 0 #overrides the OT map; 1: particular rule, 2: self-complementary
particular=ORsum(starmap(lambda i,s: ORsum(map(lambda t: (str(t) in s)<<t,range(9)))<<9*i,enumerate(rule.lower().split('s'))))
particularSpeeds=set()
count=0
prule=lambda r,sur=True: 'B'+'/S'.join(map(lambda n: ''.join(map(lambda i: str(i)*(n>>i&1),range(9))),(r&~(~0<<9),r>>9)[:1+sur]))
speedStr=lambda p,x,y: ('('+str(x)+','+str(y)+')' if y else (x!=1)*str(x))+'c/'+str(p)
mask=~(~0<<9)
'''spaceships=(0b111101101_111001000_000001100_000001000, #xq4_153 glider
0b110001100_101011000_000001100_000001000, #xq4_6frc LWSS
0b110011001_110001000_000011000_000001000, #xq3_2di2472z131
0b111111001_111110100_000000000_000000100, #xq1_69 moon
0b111111100_111110100_000000000_000000100, #xq1_609 split moon
0b111000100_110000100_000000100_000001000, #xq3_c86302ia4g27g648gxg846g72g4ai20368czxc2104ey2chm0mhcy2e4012czy417qqi0ei8h4h8ie0iqq71
0b000000110_111001000_000000110_000001000, #xq8_y1842ve4z8sqp821zw1
0b111100000_111101000_111100000_111101000, #xq16_sususvsususzfvvvvvvvvvfzw3171713
0b110100010_111110100_000100000_000110100, #xq1_0g8kallak8gzg47b5445b74g
0b110100010_111110100_000100000_001110100, #xq1_18mcsak8gzg2d67a521
0b111100010_111100100_010100000_000100100, #xq1_g1kssk1gz025bb52
0b110110010_111110100_010100000_010110100, #xq1_4qttq4z932239
0b110100010_111110100_010100000_001110100, #xq1_4qttq4zh5665h
0b110100010_111110100_010100000_011110100, #xq1_4qttq4z13a2114
0b101100011_110110100_001100000_000110100, #xq1_27mut2o4oz4e67b421
0b111100010_111110100_001100000_001110100, #xq1_4ts8y08st4z125blaalb521zy111
0b101100010_101110100_001100000_101110100, #xq1_8kqlli8gzi7579774g
0b101100010_111110100_001100000_011110100, #xq1_10u4reu5q4ozg2d77a5201
0b111100010_110110100_001100000_000110100, #xq1_0g8ka55ak8gzg4779559774g
0b111100010_111110100_011100000_011110100, #xq1_10ucsak8gzg0f67a521
0b110010010_110100100_000010010_000100100, #xq1_y1gy14tc2sgg8gz080g13aeli0cril669rkjz13vgbi3thh5nt862djd4q6dicz8162rjkta82825l09rp5na90gzx1ui56696y140lcn8b343zy0v0dicy29062t3diczi0c5na90gy2i0c5na90gz40ogn8b343y140ogn8b343z1w2v1q4oy290g2v1q4ozy0v4ihg8gy02g1lqna90gz80g2d5mt9a180gk08cegn8b343z02t5b70u54hktai0q7qifhq4oz2b3431bqm62re4lhibek5121zy02711210gvp2t56b43zy8201
0b110010010_110100100_000010010_010100100, #xq1_x81sk1gw8y48wg1ks18zw801ilmb9jeoc8w8coej9bmli108z14bml96s794sho6cc6ohs497s69lmb41zy24geqn4lliwill4nqeg4zy41221038mm8301221
0b110010010_111100100_000010010_001100100, #xq1_40lcq4oz20alv5kg8gz80alvk5121z40l6b43
0b111110010_111110100_000010010_000010100, #xq1_g2f2gwg2f2gz025ak44ka52zy111
0b111110010_111110100_000010010_000110100, #xq1_g4a55ak8z4cb89gmo9z1y12
0b111110010_111110100_000010000_001110100, #xq1_04qllq4z93222239
0b111010010_111110100_010010000_000110100, #xq1_082ll28z18333381
0b111010011_111100100_001010000_000100100, #xq1_ivccicz01
0b101010010_111010100_001010000_001010100, #xq1_09ck1gz8corfb32
0b101010010_111010100_001010000_001010100, #xq1_09ck1gz8corfb32
0b111010010_111110100_001010000_001010100, #xq1_0g4appa4gz2g676676g2
0b111110010_111100100_000110000_000100100, #xq1_cicdc0izx1
0b110110010_111010100_000110000_000010100, #xq1_80afs0gzw90gfg96z105f3
0b110110010_111110100_000110000_010010100, #xq1_4qppq4z932239
0b110110010_111110100_000110000_010010100, #xq1_4qppq4z932239
0b110110010_111010100_000110000_001010100, #xq1_8sg8cotg4z259952
0b110110010_101110100_000110000_000110100, #xq1_02tdq4z4112114
0b101110010_110110100_000110000_000110100, #xq1_9063mit2o4ozx2633421
0b111101010_111010100_000001010_000010100, #xq1_w2bc4isgz080gpwim1s24oz136w15mk4121z040oabkhk1icz01y1id1z0906kka2b1icz0gow18ra90gz1502611iq0fg96zwgkd8ie21zx1
0b111001010_111010100_000001000_001010100, #xq1_y1g4a99a4gwg4a99a4gzw4qiai11192222229111iaiq4z26c140m3siq4y04qis3m041c62zy382eh6iwi6he28zy44114y04114
0b111101010_111110100_000001000_000110100, #xq1_4m38o48gz0gwg0fg696z26c1121
0b111001010_111000100_001001000_001000100, #xq1_0i0curoz26qq324oz2b2iuqpz020136
0b111001010_111100100_001001000_000100100, #xq1_g4qakffkaq4gzw2y22
0b111001010_111010100_001001010_001010100, #xq1_8oaus77suao8zigd041140dgiz41c62w26c14
0b111101010_111110100_001001000_000110100, #xq1_14ss41z14aa41
0b111001010_111110100_011001000_001000100, #xq1_20suroz20136
0b111101010_110100100_000101000_000100100, #xq1_4com68s2hh2s86moc4zx9ovh5665hvo9zx2x2w2x2
0b111101010_111110100_000101000_001100100, #xq1_26crrc62zw2w2
0b111101010_111110100_000101000_000010100, #xq1_1j66j1
0b110101010_101000100_010101010_001000100, #xq1_y74dkeb80gkgozw80goy12g1ltk91b36mgz0h3dba28ctsqa828q8i3n7d1z0gkg575igqocd1051pssm6z04nkjx1513xirq201zw4nkjy1906fpmm6zx4nkjgggggggggpdcz906fpdd11111hlhlmvptsmgz80gocrr333b35lh5hiqocd1z20136m6m6bb3jm6w1513zwhomqa826n7d1zx2013
0b110101010_111000100_010101010_011000100, #xq1_wogkg08bekd4zgm63b19ktl1g2z1d7nj28aoaaea08zw6m63bbc8w69f9zwcd7nmohy069f9z03reecg2y269f9zy01ddpoooooorrjuc0izx69f9uos02g0mmpgzwgmstp82a3aaea02zw1dcoqgi5nlg18zy0315102qe5m4
0b111101010_111000100_110101010_001000100, #xq1_40ostsmgz2b2iocd1z020136rroz0i0cujm6z26qqopdcz1w1513
0b111101010_111000100_001101000_001000100, #xq1_woruc0izciuizw6muc0izx1
0b111101010_111100100_001101000_000100100, #xq1_0cooor6c8z3rccfcgob3m4zy131
0b111101010_111000100_111101000_001000100, #xq1_i6svvs6izw9339
0b111101010_111000100_111101000_001000100, #xq1_i6svvs6izw9339
0b110011010_111100100_000011010_011100100, #xq1_g0kdoao4ozw2b2jd1y78qgkg8gz0h0lrmqmqmqmqmro0105m56r21zw8qgkg8gy120amqmqmt4oz105m56r21y11glhicx1z020amtkcksk5020ad6l796z0h0ldoalv44hicwhzx2b1512a0adbdbdczwh0lrdbdbjwg0kdoao4ozw80amslcq9o8oo23235pzy01502g1lava0amqmt4ozy480alv54hlgigh8gzy180aok512a0ad6l6bi1zw8qgkg5m3a25l0lrmqmqpzh0lavaa0amqmqm6y08qgkg8gz80alvll0ldoaokjgghg5656bi1z40lava282b1503alul1kckcq9gz20alvll0lrdbdbdafq02b15121zh0lava28q8pmgz80alvlg5m3a343z40l6b80amqmqmqmqmqmqe96zy11glhicy28q8pmgzy020ad6l796w105m3a343zy31
0b110011010_111100100_000011010_111100100, #xq1_g0kdoao4oy98qgkg8gzw2b2jd1x2gslsicw105m56r21z0h0lreaeaeaemg020amqmqmqmt4ozw8q8pmgy1201glhicy11z105m3a343y120ad6l796zyd1
0b110011010_110010100_000011000_000010100, #xq1_g4aic370e6s4gz4c3vgw18328zw2w2
0b110011010_101010100_000011000_001010100, #xq1_80qgo1s41wgz011035jsgu4e82zy41105b8hs41zy114sh8ggi8530sogzwi3cu011x2uo452zx2543ce0so69a41
0b111011010_111010100_000011010_011010100, #xq1_gos0ec3iyci3ce0sogz0g2e0s8r3iy8i3r8s0e2gzw25i7kh033ao0gwg0oa330hk7i52zy08q3488843r8118r3488843q8zy04b97ot0fd348843df0to79b4
0b110111010_110110100_000011000_000110100, #xq1_14sho0gz28ll82
0b101011010_111000100_001011000_011000100, #xq1_g4s8euknfcmmcfnkue8s4gzw20731b02w20b13702
0b101011010_110100100_001011010_010100100, #xq1_wg0oggo0gxio3ee3oiy2io3ee3oixg0oggo0gzx283foqdbvbd7o0qg7tbfrrfbt7gq0o7dbvbdqof382zy114h7s6vxvlm6eb025520be6mlvxv6s7h41zy1hkrrfb0rg61mvy8vm16gr0bfrrkhzw81sjmd7o0gfdj7tbo2g0oggo0g2obt7jdfg0o7dmjs18zx129nn9vw11wvadrpeg33geprdavw11wv9nn921zy5vjee3o6pu0h1w11w1h0up6o3eejvzy5var375ujo2gy4g2oju573ravzxg2o8s0761m0b0m1d3c1oggo1c3d1m0b0m1670s8o2gzg1k17hcpodg40m1m04b6ut4vv4tu6b40m1m04gdopch71k1gz025jfeivviefj52y01221771221y025jfeivviefj52zy011033011yk11033011
0b101011010_101100100_001011000_001100100, #xq1_80aoklsicz40lav44aauu96zg0kbvjj88svbjz80adnks5p1121zw1w201
0b111011010_101100100_001011010_101100100, #xq1_y1cislsgq8z69equ6288uv168c0izg8r9erl0h21501z1215102
0b111011010_111100100_001011000_011100100, #xq1_g8gkgqot4y1g080kgq8z1ib6l6565gkggjk7dbdbda08z0pqu62xp5uv1w1woru731z0ci3b2xcdbfc80kgggmj7m4zciebdrtr501w697l6detizx102051y5102
0b111011010_110010100_000011000_000010100, #xq1_040oabcc9kicz01wgy08qr3zi0c5566i596
0b111011010_101010100_001011000_001010100, #xq1_xcoa080kqk432oom4zcvid0jb54755po8866q8z6vm90vy2gm9xgz3f4bgcda2uqq911hmm51zx3150102522c41162
0b101011010_111100100_101011010_011100100, #xq1_283eue382y0283eue382z4gdopkpoooooooopkpodg4zw14bb702jeej207bb41zy611
0b111011010_111000100_011011000_001000100, #xq1_08ogssoeecffceeossgo8z1050e75hy2h57e0501
0b111011010_111100100_011011000_000100100, #xq1_8qgk05sqkg8gz2b150k7b5121
0b111011010_111010100_011011000_001010100, #xq1_0oek58c0izjvvw1z17ta85c0izy01
0b111011010_110110100_011011010_010110100, #xq1_g0ohs41ya14sho0gz02830admuu6uummuu6uumda0382zwg1fc5h6vgf4bb4fgv6h5cf1gzx2552w2594kk4952w2552zy81221
0b111011010_110110100_111011010_000110100, #xq1_y680gwg0ogg4688k8uss44a4veeih688o8k8uss942cggg8gz80gkt828k8ushh9a1jnv7b80gkt8a0i0c8ok8usuvjwg1wid1wiruk1icxg0ogg4g8gsoo2o4oz201w2tu6w137e03suvu5201w2tuusuvv6w13701uvvn1gosuvv711210j1r8fn7332235p0m4tocxgosuv84ousc1ciczy2vvjy4vvjy4vvvvvvvvsgg8g0o7f12173dh7jbgosuf3x807osuv84306235osuvvvvvc1114qstoczy2vvpy4vvpy4vvvvvvvv7112103sug8gsomhspq137fuox20s37fv24o0c8ok37fvvvvv6ggg4b7n36z80gw8nfcwgose0o7fvfk80gw8nff7fvvcwgos0gfvvtg137fvvsgg8g0pgr2utsoo88okj0d4n36x137fv243f76g696z2015n28252f7hhiagptvsq2015n2a09062352f7fvpw1gw9mgw9rf5g96x1031141217338343zy6201w103114c2252f7744a4vee9hc223252f77i48611121
0b110111010_110010100_000111000_000010100, #xq1_0i0c85kuozxg108qr3z9062k5f3
0b110111010_101010100_000111000_001010100, #xq1_y8gmsl04zxg08wogk05beaqskk609z0ounldebr2e7l04w63a02z3rea08zx1
0b110111010_111010100_000111010_101010100, #xq1_y3g4a99a4gwg4a99a4gwg4a99a4gzwg84i222911922222291192222229119222i48gz82odt0pes4gygg4sep0tdo28zy020b1301u9t2y82t9u1031b02zy282e4f353f4e28y082e4f353f4e28zy41y31y41y31
0b110111010_101010100_010111000_001010100, #xq1_y040lsmgy1gz906kcss2i335lft43z80aer30g1ltn6zw1y2201
0b110111010_111010100_010111010_011010100, #xq1_wgy0gwgx4gt8sg8hs41yg14sh8gs8tg4xgwgy0gz28e4uokou2y4113vngo0g0ogq08y080qgo0g0ognv311y42uokou4e82zy21vrosg8hs41w80n1jfne3bo1hy2h1ob3enfj1n08w14sh8gsorv1zy2254317hvda03u70oa32x122a2kkkk2a221x23ao07u30advh713452zyd4bjjb4y5124421y54bjjb4
0b110111010_111010100_110111000_011010100, #xq1_y24qppq4zx8oss30svuskggz41n3tbvwvn7e1b02zy02xv77v8t3n14zw8ogscmfvx2z010501w4114
0b101111010_101010100_001111000_001010100, #xq1_gy040lsu8gz403aqueow201u080gz010513y190gf0fg96zy9v090gz080aos0gx90gf0fg96zi0c5577hgg4g8701zy120a371
0b101111010_100010100_101111010_000010100, #xq1_w40lsu8gzw20aoqg4b80gz40lstttsttv71z080aeeeeeeeuozxh0l7n29l513zx80aeu421zy11
0b111100101_111110100_000000100_000110100, #xq1_15kcgl50ck51zwg4ilabk4z098m98zw98mkba2zx1w1
0b111100101_110100100_000100100_000100100, #xq1_y1g8kqdcccc7cizwg08hlcjcjcu1zwh8amc3781w10g8kqdcccc7ciz6lifg3adhp54444hlcjcjcu1z0125bmcph47u0pait3c37801gzy2125b31w125b3333e34
0b110100101_110100100_000100100_010100100, #xq1_2so6o7cccccdqk8gz210vmptakoxhfil6zw8vkc1ui8q217foelaczxg13b521y0gocna53zx43e3333333b521
0b111100101_111100100_000100100_001100100, #xq1_0g8kqdocogzcl9uhwpat72zw125b31w1
0b111100101_111100100_000100100_011100100, #xq1_wokqdocizgmq4v0hz125b134
0b110100101_111010100_000100100_001010100, #xq1_02so5ak8gzwvkbi01ul6z4obte4alak8r0oz1w1w103060d103
0b111100101_111110100_000100100_000110100, #xq1_w9amah8z08ac154z11
0b110100101_111100100_010100100_010100100, #xq1_g02sncssctakozgfqdepepela6zw1y021
0b111100101_111100100_010100100_011100100, #xq1_02sotakozic7cna6zx1
0b111100101_111110100_010100100_010010100, #xq1_0g8228gcppcg8228gz04kbi11111111ibk4z2hadah2y02hadah2
0b111100101_111110100_010100100_001110100, #xq1_2sotakoz210306
0b111100101_110100100_001100100_000100100, #xq1_okatcc7ciz06ale7666s69zxg9l4xo0gz0obitjn3jb134zw12511712
0b111100101_111100100_001100100_001100100, #xq1_8sdqkoz8sofka6zw21
0b111100101_110010100_001100100_000010100, #xq1_y2880cppcg55gc99cg55gc99cg55gcppc088zy1gg1lk1h48ye84h1kl1ggzy02s0u10j7644gw88w88w88wg4467j01u0s2zx4kb49ce8hw4kbk9hcj66jch9kbk4wh8ec94bk4z84ala59y542324y042324y595ala48z021112yu21112
0b111100101_111010100_001100100_001010100, #xq1_x8hamah80qskizgk5had29831ab022zw4511
0b111100101_111000100_011100100_011000100, #xq1_w8g0octacy2gk8gzgogvjn6767br3333jn51oz015lihgocddcccsuao1z027lh91b530gx21z8sm666efdceulmgggoqkozgoqqpotacw4lp1119bi0cz01521gf6vjvjm66eflczy51521x1
0b111100101_111000100_111100100_001000100, #xq1_08stacy4gz4eeeld1111119tkgjggoqkozw9tscsctacw4lp1119bi0czwgoqpoonm77776666flcz013a840lihggggggkl9gzw4eb3jn7nn77br337lh80gz4eb3j3na6w18tcssssuao1zw9tssuueeum6na6x21zy021036na6
0b111100101_100010100_111100100_000010100, #xq1_x8hamah8w8hamah8zw9h6pq5a2oo2a5qp6h9z125hsvvg7offo7gvvsh521z0h2f7b1k2gwg2k1b7f2hzw1441mk3gqqg3km1441zy51441
0b111010101_111100100_000010100_001100100, #xq1_0gklmml4c2rm84zg0of8gnlkgy18acca8z01230t0aho7d1791v11v11zxg0fg8x45t44s90fgz08aqbbp5dk4s4jgcr3as642zw29831642w12560cb521
0b111010101_111100100_000010100_001100100, #xq1_0gklmml4c2rm84zg0of8gnlkgy18acca8z01230t0aho7d1791v11v11zxg0fg8x45t44s90fgz08aqbbp5dk4s4jgcr3as642zw29831642w12560cb521
0b111010101_111110100_000010000_000010100, #xq1_48l66l84zx22
0b111110000_111100100_000010000_000100100, #xq1_cidc0izw1
0b111010101_111010100_001010100_011000100, #xq1_06lsogzobqj1zcl731
0b101010101_110100100_001010100_100100100, #xq1_y142tro62k06qk8gyuggy3g44gy2g44gy3ggyug8kq60k26ort24z84qmgkk7i3cmgd8anck8gs4o0g8kqt306qk8gy5g8kc0oicgmc3ha0n0ck8v8228v8kc0n0ah3cmgcio0ck8gy5g8kq603tqk8g0o4sg8kcna8dgmc3i7kkgmq48zx1089e5h1p4g0o8v50s23sd590dfrvmu10g8kc06qk8gwvrf04237e6v6e75f50doaaod05f57e6v6e73240frvwg8kq60ck8g01umvrfd095ds32s05v8o0g4p1h5e9801zy2153lsm05v8o17131v10u1w10u1947491ergmngoognmgmq48yo84qmgmngoognmgre1947491u01w1u01v13171o8v50msl351zy41xv01j7oc194744744gwvy221131x131w1yu1w131x13112y2vwg447447491co7j10vx1zy342dr8acvcaj1x42dr8acvca8rd24yzyl42dr8acvca8rd24x1jacvca8rd24
0b111010101_110100100_001010100_010100100, #xq1_08s5acwgk8g0oy18s5acw8gzwgf9kd1v851kj1thh5pvdm87v1q3wg0kow8gz27vcnu6senb52103w1521y1v99t4smprhril6z01w9tiapyd1wv999t4hjqulkozy221yg10gf4fu3pd8dka6zyt1w1w1
0b101010101_100100100_101010100_000100100, #xq1_ygg8ytgyzyfca5s8wg8kgzwg8kqt4888u0ca5s8832pvqo0g8kgy1g8wca5s8y56lie4xca5s8xokaogxg8kgy1g8y7gy1ca5s88ulg57mhec8dd0vpgz0g9l4e44lear4c703q9hl3vrjghtkjpo8e5qj1be76hus88888u0h2ad46s024lr8co048amhog08hlc3hwg3ap72wg8kg0ml2u4k444vl4eeve4eeveeve44vvl4z3q9d6fj4444l4e4x12510ik51bppvg80bfc8d7ejght1em263010211170304222f0609544v0c0ib99v0o15mijua39ehhht0f34w6ak722fl1ksdhe62mm0vj1zg0954444444l4e4y4125b2117095444k4f55g5s8ywh08454k4f55g5t81yc6ak72w1251z10ik4444444l4e4y4g8kq8ggs0ik44454ukk1k72ywh024k454ukk1kn2gygca5s8wg8kgzobimcup4444l4e4xg8kg095kgqjjv120qu62msep1hnged8co0g08gggs0o04888u0c0ik44v0609qiiv03gkd9pfaoiehhhn0uo4y2ca5s88ulg57mhec8dd0vpgz01il4e44lear46s0obihlovrp1hn5pj32ekbpgqeschf722222f0h8am4c7084lr263042adh3102hl6ohw1oajs8w12510dl8f454444444vl4eeve4eeveeve44vvl4zw125bn4222f06ak722o8jvb301251y112w6ak72y5cl9e4x6ak72x35a31x1251y112y71y56ak722fl1ksdhe62mm0vj1zyg12yt1yzyj6ak72w1251
0b101010101_110100100_101010100_100100100, #xq1_8s5acwgz4vel4igq7c4dakoz27ka6w9t4higaczy24ogn7i79qo4dakozy2973rpjp5n79qoik08gzy34up32jlsgg817dv1q3zy313suagsdka6w27ka6zy1icv0r328a9gw8gzy18sjao22aviia17m5aczy321y08av999bhtqk8gzya13auui8240lpzye973r13a840ozye8su7b3i3lczyb8av99994tcka6zy38s5acw8s57a2iniapzy34ov1c119b9512b521zy31030vv94tqk8gxgk8gzy5ivc114ku4590gpv0d1zy48g1ef5fikg8ce7m3a53zy4if7ni7iaffip8lczxgk8gw8sj757apw21zwhvolh44eioip8lczw8vhao1053w21zy021
0b111010101_111000100_011010100_001000100, #xq1_w8gs6fe4s4ef6sg8y28gs6fe4s4ef6sg8zy5vy1gosoggosogy1vzxgogw870egj410v0110v014jge078wgogz24713317ie2qev3m078w870m3veq2ei71331742zy522w11y011y011w22
0b111010101_100100100_011010100_000100100, #xq1_48mr2a6v6a2rm84y2gy5g0oc88osogy4gwgy7gy4goso84zy2144s90r1buu66utpjgmok6c0oc5e3k1gfr0mut44su773d4o88osen6kol7d0c6kk6nfh90r1m2a6v6a2rm84zy3125bc05831bglom6oh1f7eq17430sddsq850t0tn3rq26hmfgwgfr065210vy011xvw9s441zybh1vn1agj41034712882fvk0r1r0r1db42e9ui2upb63n0c6fma90v048osuck971cb521zyc12560qf7q88oso8acch7vh1v11y224bmo1cb521034amfv35henb521zyf125bc06521032174301441yj123011
0b111010101_110100100_011010100_010100100, #xq1_g8kgqpscvoe0sg8kgz1d0v69mcuudi3bodnupgz35a31hn532e1jkr3731zy1125bnhfd379zy46ak72
0b111010101_111100100_011010100_010100100, #xq1_wg8kgy1ca5s8z6l2jb095hhtkpvgz3qs4strv731r3t7v2z6a19h5m7feseutf72z35ame845445hk7ogzy01y21251
0b111010101_111000100_111010100_001000100, #xq1_0gosl6z973vts4daczxvvvd11i0cz4ogvff9dlcz137fbo01zy01
0b111110101_111000100_000110100_001000100, #xq1_8sl6zwiq906zx153
0b110110101_100100100_000110100_000100100, #xq1_08s5acy2gzxv9kd1119t4gjgggggk8gz272mlcy0in41p11119t9ajz04u2o2222240lkoxgogcb25mgz013a8i222222s8dlb70e332b521z272rl9gy010872qk8gz0go7kh5480gk8g0on41lkozw15210g0273s5764e9lqsggk8gzy14eil6wv9999ag2codkh9q3zy3v4arem5acy1gk521zy14e9lcwv99a840ocom5aczy31y0viiip8lcs64ma53zy0gk8g0272qfd8tiapzx13s5hk4201y021zw2s8rli1zw1g02a9gzx872rl9gzy0go7kh5480gy08gzy1152108s8bum2n9ajzy4gy0v999j2l67c4dakozy24eil6wviia240363dka6zy4v4aredka6y115k8gzy24e9lcwviiiia1863m5hibozxgk8g0108so7ksc4eilb711521zw13s5hk420152103t4gl53z08s8rli1y0g02s8b521zwgoa2988888872mlqs0eoo8qk8gzw4f838888840l53x1316q8kd1z08s8dl6y09t4gjgggginiapzy0vi5mgggin41p11111521zw27ka6y21
0b110110101_110100100_000110100_010100100, #xq1_y7g8kggsqls8zy6ja9t81wcaqgo4y2g8zg8kq8gggm5ivy2g3ajmebiscknul72z1dk8qjpun5po8pi222f06ak76tdlt81zx12x301251y812
0b110110101_101100100_000110100_001100100, #xq1_w42droaaord24zx2abqpdu3g6qk8gzy0216d45noc1p4zy4g4knl468rd24zw4p1cod0qv2y0vz0ggvg44g0ff0g82qba2z84qmglohnrl5111112zx1y31
0b110110101_111100100_000110100_001100100, #xq1_wgwg0oclqsggk8gz4ogfirgna6w18t9ajzgf4phdacy4vir8os5acz4ogc7oboy4v4cbcvgbozgf4q6e5k8gx8s8b53x21zw43170fplcs64ma53zy521
0b111110101_111110100_000010100_000010100, #xq1_x84h1koggok1h48zxial9gy0g9laiz84hc522864468225ch48z0272y8272
0b111110101_111110100_000100100_010110100, #xq1_2s8o2k70cz872385s06
0b111110101_111110100_000110100_001110100, #xq1_30e8s8z30r8s8z301
0b110110101_101100100_010110100_001100100, #xq1_042tfoqqoft24zg9ltu1w1utl9gzw15f4114f51
0b110110101_111100100_010110100_011100100, #xq1_8sou0v4ki0cz273q33233b53wgzw431thhhhhphtsobozy02103b53y021
0b110110101_111010100_010110000_010010100, #xq1_012uqqu21zik763367ki
0b110110101_111100100_110110100_001100100, #xq1_x8s5acz8souu1tacz273ffgna53zx27ka6
0b101110101_100100100_001110100_000100100, #xq1_x8s5acwgzwgwv9kd1wv44ki0czgognai1w4e4lvv1qmgz018tpa3888s8nkstiapz0hlvv0roookg3x21z08avv0mmmmmlcz04lvv0ddddddtb8gz02avv0roooookgjm5acz0hlvv0m6666mib34ma53z08avv0dcccccuq0sggk8gz04lvvgbox131uijbklpzx1ge5k8g0272qffol6zy2gf92b8g0f222403zy113a53
0b101110101_110100100_001110100_010100100, #xq1_y0gy6ca5s8zwj0kt911111h194lr8s8z6l2usm4e4444l4e4e40ae4zcl8vsngoggjg4t9y06ld8s8zw12511111p14nigggm5ivzy81y26ak72
0b111110101_111100100_001110100_001100100, #xq1_048o88o8if2oo2fi8o88o84z45t930h1xvvx1h039t54z125bc179ks2bb2sk971cb521
0b111110101_111010100_001010100_001010100, #xq1_w8s52qea9z125ap6sg811z04511
0b111110101_110100100_011110100_000100100, #xq1_ya8s5acwgk8gzy28gy1gwv9kd1v851ozy027pa38888872qpo8s8rl480gk8gzxgogna53wiv1ccecececececlh9q3z08s8dka6y115ki0cy14e4li1z4u2opookg80gw9vg6666667mb521z13a840l4iegnai22403ziv1c11j1dcv0d1z0hl491b9js3qljgg80gz9vg6667a2403w4u2opoooooqk8gz04e4dakoy29bi0cy018t9ajzx272qk8gwiv1ccscscscscscb25mgzy0go7kh54445pgm664e4ma8403b521zy11521y0210u5ac0u5906zya4e9lc113a53zyc1
0b111110101_110100100_011110100_010100100, #xq1_xgy18ggg81qeaaeq18ggg8y048o88o84z24bd1m2qma430ue0kvvw220v022u29831tth3op2ei9o88o4mcg8zw48mr2a62c4p7d0avvk0gwvxvwgwvva0lv4gg9qb8eo1hzy411x1441vv0ip850c7c0dgj41vv5gh43014410321zyb24bmo1cb521034amp3gdn84zyt11
0b111001101_100010100_000001100_000010100, #xq1_04lmkki0czw8aq3z4ld55906
0b111101101_110010100_000001100_000010100, #xq1_04p1s88zg8v0vg01u44gzw103070o4vzy242f0712
0b111001101_111110100_001001000_001110100, #xq1_gk5uu5kgzx22
0b111001101_101010100_011001100_101010100, #xq1_y2o0rouosqogzwc0oeusoqvtourvjca8z30r3fbb90vavtoruf63lhzwg0snvecvdf6310o0ervjca8zw1o0r34w1y0g084554dl4zwc0oeu1y1c0dciz30r3frvy2o0ro4zxc0d1iy3609ggggokgzw60snvoosqogxc0oeu4qa8zwc0obb90vavtfesog1n7301z30r3frvucftvesft7pba2zy11d0cdvesdf7301zy4301w1
0b111001101_111010100_011001000_011010100, #xq1_wgoqsouor0oz1utruotvqosueo0cz0vvcvcvcvcvcvdcz0vfmv6fun6fut70cz1037me7v6m06zy51
0b111001101_111010100_111001000_001010100, #xq1_4kgttgk4y64kgttgk4z042fvvtshp4y04phstvvf24zy1137nadfeefdan731
0b111101101_111110100_000101000_100110100, #xq1_2sns06z103
0b111101101_111110100_000101000_010110100, #xq1_2sncgm0gz87t61d01
0b110101101_101100100_010101100_101100100, #xq1_y3gko6okgy08asksa8w45uqelkgyagy145uqelkggg8ylgko8okgy0gko8okgyl8gggklequ54y1gyagklequ54w8asksa8y0gko6okgzw45uqlnpj1r1jpmefnlqbns88sdu9vdgjpdrblrblrbdjbt36imlcckqv5pmjbufh9y2gklequ54y18ask6e2drbokgwgkobrd2e6ksa8y145uqelkgy29hfubjmp5vqkcclmi63tbjdbrlbrlbrdpjgdv9uds88snbqlnfempj1r1jpnlqu54z45uql7f5fs76tev7j7vo0gpcr7cvudaro9cbqdlbevahnt4c6rldq5rmalrbrl6kstlbrlbrdpjgdv9uds8ggocmblqu541fj4y04jf145uqlbmcogg8sdu9vdgjpdrblrbltsk6lrbrlamr5qdlr6c4tnhavebldqbc9oraduvc7rcpg0ov7j7vet67sf5f7lqu54z0gfvtqmbrrtitms4rcog0vv0g1k3gufakrvisc5trm7cvu01iors46ufafutm1781su38bsk6e2dncfedqbopsba3f7lq6rrblquuqlbrr6ql7f3abspobqdefcnd2e6ksb83us1871mtufafu64sroi10uvc7mrt5csivrkafug3k1g0vv0gocr4smtitrrbmqtvfgzw2983us18buf7eusc5ds88sn045vq1760tg33gs0330tg33gt0330su330uv11wvvxvvw11vg11gu0145ucs561r1760t0220t0671r165scu5410ug11gv11wvvxvvw11vu033us0330tg33gt0330sg33gt0671qv540ns88sd5csue7fub81su3892zy64jh63dd36hj410330671288210330128821033012882176033014410330671288210330128821w2983166134gg4316613892w128821033012882176033014410330671288210330128821033012882176033014jh63dd36hj4
0b110101101_111100100_010101100_011100100, #xq1_y5g0ox2sncssq840oz04oeoooookv1vnj7qdlg3fvtk0ox8gsgg80gz1urtup7s7ssrtup6t7t6qop33335vtos776qo1z43ulrsvpv9p6tbc3tndb2gsue6u575g9vfbi0cz0103y197s7767qdlouvn51oy21zyb217111201
0b110101101_111010100_010101100_011010100, #xq1_w24v0mo74qogy0gwgy0goq47om0v42z24vwhfu6v216bt330aa033tb612v6ufhwv42z0gf0g024vmjesgj4y24jgsejmv420g0fgzw227gj4w1154y64511w4jg722
0b110101101_110100100_110101100_010100100, #xq1_yagyvo048qssssssssssssscsscsssssss7sizxgxo0gmgpam77777j7vfvvjv7bfvvvfvvvvfnvvvvvvfv35nqrff71aj7lrj1bfvuvo1ljr9mffffjqtscsss7si88888e8kgz03gkdrhrva67n7jtqauqnmnnm2nuviu70bjmeeecrff7rvvuvvsquvtuuuuusuvvutvvvvvvuvvvvsgaptuuusuvvvvf3l55575uckknka8zg095644745ghgikcfri2b77jnffffffedfffeohquvvutvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvpvsquvvjv712w301z10ikc44s4k1h1956ur98qssptuuuuuuemuuue3hbfvvfnvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvjv7bfvvpvsg8wo0gz0o15mrhrvacstspnbafbtdttd8tfv9fs0qpdeee6ruusrvvfvv7bfvnfffff7fvvfnvvvvvvfvvvv71ajnfff7fvvvvuolkkkskf655t5a2zx1x301d1jadssssspsvuvvpvsquvvvuvvvvutvvvvvvuvoktbruusgapslrpgquvfv3glpriduuuupbn76777s7922222e251zya1yv3042b777777777777767767777777s79
0b110101101_110100100_110101100_110100100, #xq1_x8aknkkkkc9agsggg80gzwg018b8gsulnlft8d6qo1z1ur6eedkg3wg2q322bi0cz0vmvpiopnaeaad5lt3q2240oz0vdvjvvrvsvksptsnq82a9gz0vrv7vvfvvvnvfvvnf8388403z0vmvf7ffn8r88qikv1c11i0cz0vdjqpom711152e223951oz217119a84vskklpv9pjdczx8aknkkklqba7u465906zy0103y121
0b110101101_101100100_110101100_001100100, #xq1_0gwgoqsjsqoggoqsjsqogwgz22vtqdeputm1661mtupedqtv22zwvvvfg9srqtvvtqrs9gfvvvzwvvvvm3bbt3bb3tbb3mvvvvz014jh73cc278w872cc37hj41zy811
0b110101101_101010100_110101100_001010100, #xq1_y448u0no6g4oo8oo8oo4g6on0u84zy424h6djlgcuuvssvuucgljd6h42zy148u0cgl8ppubjjtrrtjjbupp8lgc0u84zy2iper56fvvnj2dq66qd2jnvvf65repizy09avlimuvvvvvvvnjppjnvvvvvvvumilva9zy4hfjnvvvvvvvvvvvvvvvvvvnjfhzy0gocmmqtvvvvvfv7fvvf7vfvvvvvtqmmcogzwh2fdqtvvvfvvvuehqnmmnqheuvvvfvvvtqdf2hz12vy0v1034udt5ros6rr6sor5tdu4301vy0v21z04jgsejmviscvu0nqhl4gg4lhqn0uvcsivmjesgj4zy011u301vu011ujb33tt33bju110uv103u11zy1298u0110u89206811860298u0110u892zy51441y311y31441
0b101101101_110100100_001101100_010100100, #xq1_wgg0o4114o0csg8228gsc0o4114o0ggz02s86r4tlcjemvp8ee8pvmejclt4r68s2zwv4kfgfk4vwv10vv01vwv4kfgfk4vzwvx1880v88vs4nn4sv88v0881xvzwvx1u43t17fk4vv4kf71t34u1xvzwv4phcn5tfsc071oo170csft5nchp4vzwv0vggv10j7q2ogffgo2q7j01vggv0vzwv0v0216vc2f0f0gg0f0f2cv6120v0vzwv0vw2a7oshiwvvwihso7a2wv0vz2a7o7a2y01u0u4334u0u1y02a7o7a2zy6153c351wv0vzyd153c351
0b101101101_101100100_001101100_101100100, #xq1_wgg0o4114ogccgo2i8wggw8i2ogccgo4114o0ggz02s86rsdtcv88wvgg0v2112v0ggvw88vctdsr68s2zwvxhjtu53kve1ig0f0gg0f0gi1evk35utjhxvz2a7osigu31g5o1f0hjuf2hh2fujh0f1o5g13ugiso7a2zx4puq567467kc8ff8ck77kc8ff8ck764765qup4zw1532351ym1532351
0b101101101_111100100_001101100_011100100, #xq1_y3gwgkleq6e2e6qelkggko8qckscktmameq6ei6u265ss562u6ie6qemamtkcskcq8okggkleq6e2e6qelkgwgzy0goqandpjgbu265scktb6132uu4410v220v144uu441vu0110uv144uu441v022v0144uu2316btkcs562ubgjpdnaqogz045u134hno8cbfbroi10uv11wgfvgxvgwvxvvxvvy0vvxvvxvwgvxgvfgw11vu01iorbfbc8onh431u54zgkoj1uu26jdarfphgfvo1hvug33vbhmlsqv781q0770pscj72ss27jcsp0770q187vqslmhbv33guvh1ovfghpfradj62uu1jokgz087vcg8srvrsk6uq3n3absp0770cetfaqnun2cbksqvmnbrr8pp8rrbnmvqskbc2nunqaftec0770psba3n3qu6ksrvrs8gcv78zw1441fg22gfvg0os7gocr7di63fd16613963d7uo1ce3rv681186vr3ec1ou7d36931661df36id7rcog7so0gvfg22gf1441zy422w11y011w22y711y811y811y722w11y011w22
0b101101101_111100100_001101100_111100100, #xq1_y0gkluqu54xgy4gx45uqulkgz8as37hioradjbt36imlcclmi63tbjdaroih73sa8zwvg0osnuntl6ksrvl8rr8lvrsk6ltnunso0gvz02983u1551r0df2qv681186vq2fd0r1551u3892zy21441y511y51441
0b111101101_111010100_001101100_001010100, #xq1_wgocd2uu2dcogz9av3dm1vv1md3va9zx22w22w22
0b101101101_111100100_101101100_011100100, #xq1_y2g0oy9is7ccccsq840ozwg0o0sf93j33333j3337refkvssssut3q2240ozxvdb2hfq322226cdcqn5444591hprl62q21zxvrdkg8v3r33bjwgon666666elh201z8hub07u9e5fn9f2uonr4reueeeeelh80gz43e3tqb1b63mblc8b8g1fsl444ighjrlc8b8gzy043e333335vgrooooosreu5v777fnob88403zy8103y497s6667b2403
0b111101101_110100100_011101100_010100100, #xq1_y1g8228g0o4114ouuo4114o0g8228gz04phcn8qao7ssgjvs4nn4svjgss7oaq8nchp4zwvwv0v98v0g491s8778s194g0v89v0vwvzwv4kfgfop0nvum05ouuo50muvn0pofgfk4vzwvxv0vvbg3fsvo4114ovsf3gbvv0vxvzwv02a7o77o7a2vvkkvvkkvv2a7o77o7a20vzwvg44gvkkvu6037qiffiq7306uvkkvg44gvzwv0v21603v10uu030ss030uu01v30612v0vzwv0v04phcn5tvrgck77kcgrvt5nchp40v0vz4kfgfk4vw1wvv1w88w1vvw1wv4kfgfk4zx1088v0g8227t061oo160t7228g0v8801zy210j76pso7a20vv02a7osp67j01zy5v21h4ogck77kcgo4h12vzy3153cuk3j9y29j3kuc351zy64kfgfk4y04kfgfk4zy91y61
0b111101101_110100100_111101100_000100100, #xq1_xgg0o4114ouuo4114o0ggz08isombkd5suvvus5dkbmosi8zwvvvoovss0j77j0ssvoovvvzwvvvvvvvvbgssgbvvvvvvvvzwvvvvvvv5ohffho5vvvvvvvzwvvvvvf3gb0ss0bg3fvvvvvzwvvvvv1uvs4nn4svu1vvvvvzwvvvjgs2vggvvggv2sgjvvvzwvvvgi1u120vv021u1igvvvzwvvvf1oo0nvvvvn0oo1fvvvzwvv70csv3gbvvbg3vsc07vvz4kf70sig01v0vv0v10gis07fk4zxv2160cs7o77o7sc0612vzxvx2a7o7ss7o7a2xvz0ggvw8i2ofgffgfo2i8wvggzw216fq1re523325er1qf612zy02a7o7a2y02a7o7a2
0b111101101_111100100_111101100_011100100, #xq1_o048qssssccccccc7siz0cdjup0gm6c888e8t5bcns2z6095mrspdrescscv12gldvzx6mpgg66no6qnpu27krvz0609gggg6mv0jb194454mvzx6mpgg6mpfpf666666vg9z0609gggg66vgctopi2aimvzx6mpgg6meh6lep74uidvz609qmt3prd73333fo40arvzg3bcnpggm6311171bqt3e34z1021533333333333e34
0b110100011_110110100_000100010_000110100, #xq1_0g8g4q5embkecgogz34b4r4wg9gq253me4zo4q4r4w1i1b8kode4z01214bkedq5e6131
0b110100011_111110100_000100000_001110100, #xq1_wg8kalla88allak8gziteletiy2iteletiz013631y413631
0b110100011_110100100_010100010_010100100, #xq1_8so6nscsakoy1gzgvha907pnhhjbj336dqk80gz4f7orfnufhn7b43xgpffm96z8so7cqpon6s666666b521z273sbkl19ru6uudiczxvcicwvhai01zxvciqgcrlihg8gz2vehm6b52ufhn7b43z0vcicy0vciczgvs2qok8gvs2qok8gz010vcin3cmbj33521zxvcicwv3kjzgogfkaa04nvouudicz4f7odm77rpeooopook8gz8so7msrut2qok8gw136tsq4oz2v3k51p6r33jlihgocmb5121z4f7oredflb71111121zy01
0b110100011_101100100_010100000_001100100, #xq1_w8qn6mna8888oo8888anm6nq8z23vsnbqqtvfg1221gfvtqqbnsv32z025bbrmaaa98888889aaamrbb52zy04bnnbpl5lddl5lpbnnb4zy48nfog11gofn8zy614bnnb41
0b110100011_111110100_010100000_001110100, #xq1_0g8k2tuembmcogz3438nfedqd631
0b110100011_111110100_010100000_011110100, #xq1_4ermeu6u5q4ozx13633521
0b110100011_110100100_110100010_010100100, #xq1_goq7mm7q2amma2q7mm7qogzwvvtmq88soos88qmtvvzwvvvt038mffm830tvvvz025bb52x11x25bb52
0b110100011_101100100_110100000_001100100, #xq1_w8qn6mnaooanm6nq8z23vsnbaabnnbaabnsv32z04bnnb41vuuv14bnnb4zy325bb52
0b110100011_111110100_110100000_010110100, #xq1_4ermueuudiczx10jdicz8smrutvuciczw1y11
0b110100011_111110100_110100000_101110100, #xq1_0g4allqk8z1uvfmqd72z27d72
0b101100011_110110100_001100000_000110100, #xq1_27mut2o4oz4e67b421
0b101100011_101110100_001100010_001110100, #xq1_w8kqllak8gzwiblbalala9k8gz8pu7ul9gdg9lu7up8zw2bul9gdg9lub2zy1136d631
0b101100011_111110100_001100000_100110100, #xq1_0g8kallak8gz9unu9w9unu9zw1y21
0b110010011_110010100_000010010_000010100, #xq1_xg84a99ak8zx8f3iik8gnjhz08oq51x1w4ct2zxhu6c4y1g8f362z4ct2y18ki5ipq4z08on362w4nh948bizx2tc4w8k91cg5u9z263no8sa126e172zy01
0b111010011_111010100_000010010_001010100, #xq1_wg2f2gy2g2f2gz23bkgdmllllllmdgkb32zx8n64la22al46n8zy111y211
0b111010011_110110100_000010000_000110100, #xq1_8coej2w2jeoc8zx12599521
0b111010011_111110100_000010000_001110100, #xq1_08ka55ik8w8ki55ak8z26lla7amb55bma7all62zx15e41111114e51
0b111010011_111100100_001010000_000100100, #xq1_ivccicz01
0b111010011_111100100_001010000_000100100, #xq1_ivccicz01
0b111010011_110010100_001010010_000010100, #xq1_y38ce76kgzgogs801vc244cfhzw1249jb4xgkb32zy0hfci2q96n8zgk673o4jb4licfhzgfm1ik4ibj9421z0147cc741
0b101010011_111010100_001010000_001010100, #xq1_8oqur362zw18l62zit7bc4z026e731
0b111010011_110110100_001010000_110110100, #xq1_4evok6skcciczx13w1
0b111010011_111110100_001010000_011110100, #xq1_4qq4x2tdigz137lkkouf51zy0131
0b111010011_111010100_001010000_011010100, #xq1_2bmau5uozwv0v0vv96z4d657a71
0b111010011_111010100_111010000_000010100, #xq1_4evu61q48gzx1u1idiivcz8suvo1m9421zw1w1
0b111010011_111010100_111010000_001010100, #xq1_08oqur362z26evf51
0b111010011_111110100_111010000_011010100, #xq1_4qp9ak8z137fvf4
0b111010011_110110100_111010000_000110100, #xq1_4u8cevu4z125aa421
0b111010011_111110100_111010000_001110100, #xq1_2tdigz4fvuu9zx1
0b110110011_100100100_000110000_000100100, #xq1_w2tdq4z01vdodv1z131x131
0b110110011_110100100_000110000_000100100, #xq1_27ksciczwgv0m66696z4e23343
0b110110011_101100100_000110010_001100100, #xq1_cicskn2gz0g18at131z343b8vzo4qslm272z01x31
0b100110011_110010100_000110000_000010100, #xq1_0ifcek0gz8s52qj311z4bjjb4
0b110110011_111010100_000110000_001010100, #xq1_0g0oq7u2t24oz1311v871xv96zgoggv2sgxvicz0103bsf8n843
0b110110011_101110100_000110000_000110100, #xq1_4e4raedic
0b110110011_110110100_000110000_100110100, #xq1_2buaem96
0b110110011_110110100_000110000_000110100, #xq1_0g23uoc8z9nmb4
0b110110011_110110100_000110000_000110100, #xq1_0g23uoc8z9nmb4
0b111110011_111110100_000010010_001110100, #xq1_wg4allq4y24qlla4gz8pml9gwh5a88a5hwg9lmp8zw26loh654a55a456hol62zy11y81
0b110110011_110010100_000110000_000010100, #xq1_gogafsgwgzgpg69ppffg96z0105f3
0b110110011_111010100_010110000_001010100, #xq1_0272ee6u1icz4e477b701
0b101110011_101100100_001110010_001100100, #xq1_0g2nkssicz131taqfv1dcicz27kbauu4lh8gzwgf9prk5121zwgf9ppm96z8sgf9pt2qo4ozw2t5n7ia81gz8s8rllvv8b343zw4e23343
0b101110011_110010100_001110010_000010100, #xq1_w4qppa48gy8g84appq4z4ql1g56hla9k8gy0g8k9alh65g1lq4z130at4pq4wg8i3223i8gw4qp4ta031zy1g954a549a5445a945a459gzy14f373nppq4w4qppn373f4zy71031w1301
0b111110011_111010100_001110010_001010100, #xq1_go0ana0ogy2go0ana0ogz4bl89k952c2442c259k98lb4zx25ai4ka3ll3ak4ia52zy39ckknnkkc9zy425aiia52
0b101110011_110110100_001110000_000110100, #xq1_02buu1q4oz4d779421
0b111110011_110010100_001110010_000010100, #xq1_gogajm25q48gz0h0la403s25k0jm25q48gz1j1cccccfg9b1icgb4216p4ak8gz131ak80g0kb807o48gc8la90gfg96z272lai01jchakg3ci54g8n843zy0v09m942d46s25q201z8s8521y3id2poo48gz8s8j3333333334q20s3421zxidi8k80goga521gz4e4ihgg961ci983jfg96z4e49h11id108n843zx9m9il2hd8k8gzgogali0c68li10u1icz0105q4g8g1eg8701zx9m94k1i1z272lai0130t28k6c4ak8gzy0v09m834216p9ki10u1icz8s8521y1272k6c4a521z8s8j33333333j3k9hc2k8gzx2t28k8g0131al40o7843z8s85210gf0p6gg4b421z8s8j33342qg96zx2t24o0n84ogajm25q48gz0g0kb412108co5a40e58n825q48gz131al90632521x8s85q20s3421z272pooooooooooooo48b1i1z272k8gy48s8la430t24ozy0v0id2o48gy02t1ge121z8s8la90go0n8252co5ihg8gzxidi45g9gy08co59n843zy0v09m924d68j33421z8s8521y3he12s0gz8s8j3333333334p1ccfg96zx2t28k8g0oghu1icz0g0kb4216o5ak50p6hh4ak8gz131al9063ka90gfg96o8kb807o48gz272pooooo4b807o48gwidi8kb421z272k8gwv0in25k0jcha5201z4e4a5k0jcha4031121zx131121
0b111110011_110110100_001110010_000110100, #xq1_0g0ocgm362dicz131s4a40361ccs24oz8s8j2l9gm3632521zx1u1q4861q4g8gz0gog74a51odi98343zw10361doc8m96
0b101001011_111100100_001001010_011100100, #xq1_y1gocuroxgy2goz8cgesmg010us6vdcw4m3f6m0gxgosmgz4d2vomsub073trk72vof338nr5ckl1obhtoczy0hv6d114qvor225e1v1t2r4rful1iv8v3r8gwgozy12tnh1307oucmgwv0v0u1t2voesmgw15s4jfm6zy18nthgo0s3f6d1wv0v0fgn8v3e7d1wgk74pudczy0hvcmgg4bv3r88kegvgn8r4ruflg9v2vor21w13z4m8v3d7fq0sonr5s8v3uoo2trk65lg3qhn36z261e7d10g0f7cvm6w4doucd01x137d1zy1136fr3x1y213
0b101001011_111100100_001001010_111100100, #xq1_wgxorucog0mso0gy0cogz0cdv6su0dcui0avt2t1ogrbnpjq8zcih54mql0lvrcv1u0v0vavndv1z6mv0fggg6mvpfv0v0v0g0mmfm9z348q2mla0avt3fon0v0vlvervogz03rf63ngr3nk0lvr4r810ddupc51zy21d731w631y231
0b111001011_111010100_001001000_001010100, #xq1_y3oruc0ogzy0cogkabo1q62z0ogbjf9965h5q072kc4bq8z6mvc62w3rf60342322322c4bq8z01yhor4z0cogy1ogy7g0mpgz3rfhbigg66f3o612ei2mqi1162zx6mvccjls5q07211162zy01wpqug4qb2zy4631
0b101001011_101100100_101001010_101100100, #xq1_y5gocurozwg0ogsomac8b24oz0hladjenblcicvdcy2goczgkbmnutbs3vlg3sfmbo8a3hn3r8gz8nutbt2r4rvl14rvelhin0fulh21z4revlv0v0vv4evelh870uqk75pz2tnvav0n8v3lks3f6mg0f7cudczhervlv0n8v3mg015s8v3rgosroz8ntvav0v0nfq0sfmm0g0p7qn8eicz4revlv0v0t2ucd10317kjg7jdcz2tnvav0v0t2ukv1egv6b80amp7urozhervlv0v0u1tor21gv6ro01uta3icz8ntvav0v0rsl8eai0sva0amp6vdcz4revlv0m9u3ndgevelehvav0m9r8gz2tnvav0dit7fnanonfnao4l14cpudczhervlv0r4ruflgjnbt3srn54ck413z8ntvav0r4tor210u1t2r4tocudcz4ruflfgrkbe88cgf0v0r4tor217uroz2bkfhsjnblcicxgvgm9t0uqkn36z08fjmggo1vcd114qq0suta34f1toczw9mr8825vgn520137etm1fhtk8fbjzgo0vfpsqk759gxg0ovm60fvfpsqpz8q5n42105ckihgo1t2r4t8s0v0mpmgz8fjl4go013gvgm45cotqr130v0djd1z4d2tfnq8i3p7d1xgpmgxv0r7r3zw8fjmggpmf6d10uflfht4o0v0mfm6zx1urox2upl40o7vqo1wv0dudcz4m8v3mgwg2r4tk8f8b24owv0rsroz08nnva0alfgtir130gpvdcwv0mpmgzgkbv3lk1lat3tua25vfkh2s0v0djd1z018nva0amp6v6d11j0f6d1wv0r7r3zw4rvl0lav0r4f1unbrgoxv0mfm6zw2tva0alv0m9f6mg0pvm6wv0dudczwhevl0lav0t2f87udd01xv0rsrozxvvi8a343v3r88cgfmr8g0v0mpmgzw1unbls2s0v0d9akn36wv0v0djd1zw2tv7qo1w1urow261u0v0v0r7r3zw2tfnao4o0s3mgg8a3430v0v0mfm6zw4rvelh210v0tkihfmbogf0v0dudczw8nva0amp6v6mg0pgn36xv0rsrozw4rvl0lav0din0fb5tocxv0mpmgzw2tva0alv0r4n3r8gsfr3wv0djd1zwhevl0lav0u1n43f6m0gxv0r7r3z8cgv7a82bkr7rtk46onbd4o0v0mfm6z0heful1kdidudr225fvpki10v0dudcz08nv7a825f0t2ucmggk75pwv0rsroz1307urox2upd10v0uqpxv0mpmgzwgkbe88o8i3k51ogfnao4o0v0djd1z0g0vmbogc3v3l4037dvcd1wv0r7r3zhlad7fq026cvdcwgosroxv0mfm6zgv6d1x4m8f8bp5p0t2uku0v0dudcz8q5vhqsod11icw4d2upd01gvgrsrozwgfvkh21vdcy2gvb3gfvfkhicz0gkbe88q5vgn520su7rtrk74l1ovm6z0gfmbo88kfhdk412ao9blq6pvcd01z2upnchevelhihg8g0v0r4tor217urozhervlv0u1uro010v0v0u1tomqkn36z8ntvav0u1tomac8bkt2upd01jd1z4revlv0m9u3ndgevelehu7d11hpsmgz2tnvav0dit7fnanonfnaoht49hsjd1zhervlv0r4ruflgjf3trk7ifo3smgz8ntvav0v0u1tor228p7qo23srn59gz4revlv0v0r4t8u2k8v3mg0kbt2uqpz2tnvav0v0t2rhn43073e882bkn36zhervlv0v0dir1tk8e4f1u0velh8gz8ntvav0fgv7a8173rgo0sfqvor21z4revlv0fgv6b8o4l18f6m0gpmgz2tnvav0v0vu5hpmfbjwvv935pzhervlv0v0vv937rtk8f8b2hvdcz8fjdetqmp6vdc1unblsin0fb5sicz09ejnblehendguhn36w26cvm6z04d2tervelhih75py41zy2103apguqpzy7136
0b101001011_111100100_101001010_111100100, #xq1_y48qrkacbqoggggggggggggggggoqbcakrq8zxgo0clr7e7rlrnuntlfuflpj1u5nltnunrlr7e7rlc0ogz463fe268jgc5uu4aa4uu5llueeukk5uu4aa4uu5cgj862ef364zyh23177132
0b111001011_111100100_011001000_001100100, #xq1_xgosuroz2bkvhm52esmgz8q5vhdk8e7d1zx137fr3
0b111001011_111010100_011001000_001010100, #xq1_0goc08cge4ja8gg8aj4egc80cogzxgfir2j1157337511j2rifgzy09ca134ja8gg8aj431ac9z8c6vv6c80115733751108c6vv6c8
0b111001011_111010100_011001000_011010100, #xq1_wgocuroz8q6aalau2s0gzxvujvjvjvdcz4molkblvhf13zw26cvm6zy21
0b111001011_111100100_111001000_001100100, #xq1_oruso0gz0631rq51zorusu2d4z0631
0b111001011_111010100_111001000_001010100, #xq1_4couuv5445vuuoc4zx9l4kjjk4l9zw4c3t8448t3c4
0b110101011_110100100_000101010_000100100, #xq1_y08c6row8c6rowgzgk6jrooop3338o893jdcy0goz0hvha40os66666dc119e882jpm6z15cpr336y3136row15cpccmggow8c6rozw26s66666rooooo2324o0so6qpooq31tp7q324ozwirp333336y126qpw10jqkg8aes54ni6qpz4dpcm66roy1gk63mggg4dpc113y2136z8c7cqpoop333jrlh4ckjw26cr3z0136mg0os66mg0os66d1zy1136y0136
0b111101011_110100100_000101010_010100100, #xq1_08c6roz13u3e88c6roocw8c6roz2bpjoooopm66b51km3mggozwgpmggggpy1gpfpppm6z4dpc11119mmmda826cmg01z8c7cnh136d113w136d1z0136d1
0b111101011_111100100_000101000_001100100, #xq1_or6c8zgmjuj1z1dpc51z3rcogz6m6s62zcdjpb2z031
0b111101011_111010100_000101000_000010100, #xq1_046on2442no64z0gpq4aiia4qpgz11y611
0b110101011_100100100_110101000_000100100, #xq1_0gocy0gy18c6roooooooooocz15svvvfvtosggpf23icy38cbjz4dpn76cm666b5svvrhr3333j338o843zw4ni6qpy0gk7vvvvrhdf3226cr3zy0136y2136y013
0b101101011_110100100_001101000_000100100, #xq1_08ogccgo448um0rf422s86moc4z0gg1v88vs4w1y02uv4kfgo8zw1vuhg3vs4y12uvh88vv0ggz136d1oo173oe6037c1jgsc0631z08ogcc73vs4xgg2uv136moc4zx1306er1c7301360d7301
0b111101011_111100100_001101000_001100100, #xq1_0coooor6c8z3rccc7soorj6kgzy03rpgw3rpgz0or666s733rpc51zw63333rc62
0b111101011_111100100_011101000_000100100, #xq1_wg0msooooooor6c8xcogz0cdjhhtcoggmpoooj33fj01dcogzw311dc62w311cc73333333ec62z0coorj6kggsoojjucccsccc7jm4z3rcoorjhggmph11cccfcgob31zx631111111d631x31
0b110011011_110010100_000011000_010010100, #xq1_xggka2cbv0umo4k8z02tck063f8w1gu6c19pq4z8o7130731y126e072fggzxvjs211is3vgu6o4224l4k8z8oq3gh0e62w10317kgg1e5vgzw103162y61jgcs0e62zyg1
0b110011011_101010100_000011000_101010100, #xq1_xciksks4cck432oom4zxogb6q8wjk8866q8zw3f4bgc8w1dt4ggc8zxo4ntlsgi575d1ddkgzy01y1h0niln5n162z0ciksks46gjhq3qrm51z0ogb6q8012rui66q8z3f4bgc8w6ma8ggc8z0o4ntlsgorkg01ddkgzw1y531w1
0b101011011_110010100_001011010_010010100, #xq1_yoggka2cbv6e0scumo4k8zyc8ki9hqco8si1cg8i3fggy110u64h1p24oggok2i48gzyb2613010317o5oa3073c4u1x2t9o6f07kgbhe3613073c4zyb8k4omu0sc51y44c370e6p8y2103aoo0scg88gz0g84i2koggo42p1h46u01yt1031tc922i48gwg8448gz4c3703163ehbgk70f6o9t2yt4qihcu1e90m3t7d361e6p8zy38oq3ghwgg0oo162yr4c3ghy01307kggzy510316po0hg3c4yt8o7121hic37031zy8130103162yv4c3703162
0b101011011_110010100_001011010_110010100, #xq1_y3g84iccb2zy3124ubtkgwg0sogzy2o4299jio2d51w6ma8ggc8zwgm9q1ce89i66q8xorkg01ddkgzwhttlhy012111162y031w1z69gggghg764ggc8zx3efkkj3td51zy069ggp0gzwgsnviiccbrq8z69ggggo0e62w31zworbq8y0o48o8864ggggc8wogzx695o3719kmm51x1diworb2zy21249pckhkbao0gmm51w31zy3o42ndb2y131zy412433d4
0b101011011_101010100_001011000_001010100, #xq1_04qis8ocqh9ik8y28ki9hqco8siq4zwvdsfa30103162y026130103afsdvzwvm50qt2yc2tq05mvz26130731tc4y84ct13703162z08k4odr6c2s8occeddecco8s2c6rdo4k8zwvp1sbnb1301u684486u1031bnbs1pvz1301w8p6e073c4y04c370e6p8w1031
0b111011011_111010100_001011000_011010100, #xq1_ciksc4ks4ccb2z6mvcjbq8wjb5c07mkgz6nujfrs574c16ma21162zctfpur7ks46gcda8ggc8zcdv6pqb2wpqk60sd51z69576457466q8
0b111011011_110010100_011011000_010010100, #xq1_y1o48o88oosg764ggc8z0gm9q1cj017tu2260sd51z6nbbf3j2mg9vvz348ocnv67rrvvzx17nbbfemvvzy1121rokvvwgzy5jb576ed9zy5pqk433d4zy66ma8ggc8zy6jk8optd4zy3g0m7bvvw31zy1orkltsqvvz0g847drvppmmvvz0pqkkshjgr35vvzw3r5n1diwpfvggo0ec8zy01078565576e2oo833d4zyc1
0b111011011_111010100_011011010_001010100, #xq1_xg84oom4y0ciks4ccb2zw348tmao0gms55c0oue731zwgs8ls55j744erl42s130ec8z69g5rq801211304a46654o833d4zx1w31
0b111011011_111010100_011011000_101010100, #xq1_cikssriy0gxgxogzwjuv111ccbo1f73ufsprb2zcibefnj1y631zy11
0b111011011_111010100_011011010_011010100, #xq1_69qemvseosg7ec8z6svfgairrtf731zw69577r9
0b111011011_111010100_011011000_111010100, #xq1_g84iccb2z124ubtk0gxogz069577rfsprb2zy431
0b111011011_111010100_111011000_001010100, #xq1_0o48oosg7ec8z6utpvvvf731z31f731
0b111011011_111010100_111011000_011010100, #xq1_0o48oosg7ec8z6utpvqtf731z31f731
)
spaceship=lambda b,s: any(map(lambda h: not(h&~b&mask or h>>9&~s&mask or b&~h>>18&mask or s&~h>>27&mask),spaceships))'''
grey=1
rainbow=0
rules=lap(lambda _: set() if rainbow else 0,range(1<<18))
with open(os.path.join(sys.path[0],('R1-C2-NM-gliders.db.txt','new-gliders.db.txt','May13-gliders.db')[2]),newline='') as db: #https://github.com/jedlimlx/HROT-Glider-DB/blob/master/R1-C2-NM-gliders.db.txt, https://conwaylife.com/forums/viewtopic.php?f=11&t=1074&p=146424#p146424
m=0
for ors in db:
s=ors
attribution=[]
for _ in range(2):
attribution.append(s[:s.index(':')])
s=s[s.index(':')+1:]
minr=s[:(c:=s.index(':'))]
s=s[c+1:]
maxr=s[:s.index(':')]
sh=s
details=[]
for _ in range(6):
details.append(sh[:sh.index(':')])
sh=sh[sh.index(':')+1:]
p,x,y=details[1:4]
if '/' in p: p=p[:p.index('/')]
p=int(p)
x,y=abs(int(x)),abs(int(y));x,y=max(x,y),min(x,y)
unsimp=(p,x,y)
g=gcd(p,x,y);p//=g;x//=g;y//=g
if not speedRequirement or (p,x,y)==speed:
minr,maxr=map(lambda r: (lambda b,s: b|s<<9)(*map(lambda t: ORsum(tap(lambda i: (str(i) in t)<<i,range(9))),r.split('/'))),(minr,maxr))
diff=minr^maxr
indexes=tilter(lambda i: diff>>i&1,range(18))
for rule in map(ORsum,product(*map(lambda i: (0,1<<i),indexes))):
#if printRLEs==2 and (not (rule|minr)&1 and (rule|minr)==~(~0<<18)^bitverse(18,rule|minr)): #do suspicious recording here
val={(p,x,y)} if rainbow else 1<<(not speedRequirement and (p,x,y)==speed) #p>2*(x+y)
rules[rule|minr]|=val
if minr&1 and ~minr&1<<17:
rules[bitverse(18,~(~0<<18)^(rule|minr))]|=val
if rule|minr==bitverse(18,~(~0<<18)^(rule|minr)):
rules[~(~0<<18)^(rule|minr)]|=val
if printRLEs and (speedRequirement and (p,x,y)==speed or (m==-1 or diff.bit_count()>=m if printRLEs==2 else not(minr&~particular or particular&~maxr))):# or not (minr^0b1100)&0b1111:#or y==0 and 2*x>p and x!=p and 3*x!=2*p and ~minr&1:
if printRLEs==2 and m!=-1: m=max(m,diff.bit_count())
print(', '.join(filter(id,attribution)))
if not speedRequirement: print(speedStr(p,x,y))
if g!=1: print('period '+str(p*g))
print(((lambda a,b: '/S'.join(map(lambda a,b: ''.join(map(lambda t: t if t in b else '('+t+')',a)).replace(')(',''),a.split('/S'),b.split('/S'))))(prule(maxr,True),prule(minr,True))+' '+str(1<<diff.bit_count()))+'\nx = '+details[4]+', y = '+details[5]+', rule = '+prule(minr if speedRequirement else particular,True)+'\n'+sh,end='')
setBoard(*RLEsize(sh))
printBoard(loadRLE(sh))
particularSpeeds.add(unsimp)
count+=1
input()
if printRLEs: print(speedStr(*speed) if speed else prule(particular),count,', '.join(starmap(lambda p,x,y: '('+str(x)+','+str(y)+')c/'+str(p) if y else (x!=1)*str(x)+'c/'+str(p),sorted(particularSpeeds,key=lambda t: (Fraction(t[2],t[1]),Fraction(t[0],t[1]+t[2]),gcd(*t))))));exit()
spaceship=lambda b,s: rules[b|s<<9] or b==~(~0<<9)^bitverse(9,s) and ~b&1 and rules[~(~0<<18)^(b|s<<9)]
disproven=lambda b,s,sub=False: not(b&1 and s&1<<8) and ((not(~b&0b1110 or s&0b11100000) or not(~b&0b111110000 or s&0b11111) or not(~b&0b011110000 or s&0b11110) or not((b^0b0010)&0b1110 or (s^0b1100000)&0b11100000) or ~b&1<<1 and s&1<<7 or b&1<<1 and ~b&1<<2 and not ~s&0b11<<6 or (((~b&0b10 or ~b&0b1100 and not s&0b1111 or not b&0b1100 and not s&1 or not s&0b11111) and (s&1<<7 or not ~b&0b111110000 or not ~b&0b111100000 and s&0b1100000 or b&1<<8 and not ~s&0b1100000) or s&1<<6 and not b&0b110 or not ~s&0b11<<6 and not b&0b100 or not ~b&0b1110 and not s&0b111<<5)) if b&1 else not b&0b1110 or not ~s&0b1111 or b&0b10 or not(~b&0b1100) and s&1 or not (s^0b11110)&0b11111 or ((b&0b10 or not ~b&0b1100 and s&1 or not ~s&0b1111110 or not ~b&0b11000 and not ~s&0b111110 or not ~b&0b111000 and not ~s&0b11110 or ~b&0b100 and not ~s&0b11111100 or not ~s&0b11111 or b&0b11<<2 and not ~s&0b1111)) or False and not ~b&0b11100 and s&0b10)\
or (speedRequirement and 2*(speed[1]+speed[2])>speed[0] and (not(~b&0b110 and bitverse(9,s)&0b110) and not(~s&0b110000 and bitverse(9,b)&0b110000) or 4*speed[1]+3*speed[2]>2*speed[0] and (bool(~b&0b110)+bool(bitverse(9,s)&0b110)+(~s&0b110000)+(bitverse(9,b)&0b110000)<4) if b&1 else not(b&0b110) and not(s&0b110000))))\
or not sub and ((b&1 or ~s&1<<8) and disproven(*map(lambda n: bitverse(9,~(~0<<9)^n),(s,b)),True) or b==~(~0<<9)^bitverse(9,s) and disproven(~(~0<<9)^b,~(~0<<9)^s,True))
#print(sum(starmap(compose(disproven,bool),product(range(1<<9),repeat=2))));exit()
'''unknown=[]
for b,s in product(range(1<<9),repeat=2):
if not(spaceship(b,s) or disproven(b,s) or b&1):# and b==~(~0<<9)^bitverse(9,s):
unknown.append((b,s))
for r in range(8): print('B'+'/S'.join(map(lambda n: ''.join(map(lambda i: str(i)*(n>>i&1),range(9))),__import__('random').choice(unknown))))
exit()'''
#print('\n|-\n'.join(map(lambda y: '|'+'||'.join(map(lambda x: 'style="background:#'+('c0c0c0','80ff80','ffa0a0')[bool(disproven(*(c:=(c:=(x^x>>1)<<1|(y^y>>1)<<5,~(~0<<9)^bitverse(9,c)))))<<1|bool(spaceship(*c))]+';"|{{cata|census/'+'|'.join(starmap(lambda b,s: b+s.join(map(lambda n: ''.join(map(lambda i: str(i)*(n>>i&1),range(9))),c)),(('b','s'),('B','/S'))))+'}}',(3,7,8,12))),range(16))))
#print(rle(sorted(tarmap(lambda b,s: (lambda b,s: 3*(0xff,) if b==0b1000 and s==0b1100 else (0xff,spaceship(b,s) and 0xff,0) if disproven(b,s) else (0,0xff,0) if spaceship(b,s) else 3*(b&1 and ~s&1<<8 and 0x33,))(*((bitverse(9,mask^s),bitverse(9,mask^b)) if b&1 and s&1<<8 else (b,s))), starmap(lambda x,y: tap(lambda n: n or n^n>>1,(bitverse(9,x),y)) if not grey else tap(lambda n: bitverse(9,n^n>>1),(x,y)) if x<1<<8 else (bitverse(9,x^x>>1),y^y>>1) if y<1<<8 else ((x&~(1<<8))^(x&~(1<<8))<<1|1,y^y>>1),product(range(1<<9),repeat=2)) if True else chain(product(map(lambda n: bitverse(9,n^n>>1),range(1<<8)),map(lambda n: bitverse(9,n^n>>1),range(1<<9))),product(map(lambda n: bitverse(9,n^n>>1),range(1<<8,1<<9)),map(lambda n: n^n>>1,range(1<<9))))))));exit()
if rainbow: speeds=sorted(reduce(set.__or__,map(saph(lambda s: Fraction(s[1]+s[2],s[0])),rules)))#;print(len(reduce(set.__or__,rules)),len(speeds));exit()
img=Image.frombytes('RGB',2*(1<<9,),bytes(charmap(lambda b,s: (lambda b,s: 3*(0xff,) if False and b==0b1000 and s==0b1100 else (3*(0x33,) if disproven(b,s) else tap(compose((32.).__mul__,int,minh(255)),reduce(taph(__add__),starmap(lambda p,x,y: triangleWave((x+y)/(p*speeds[-1]) if True else speeds.index(Fraction(x+y,p))/len(speeds)),rules[b|s<<9]))) if rules[b|s<<9] else 3*(0,)) if rainbow else (0xff,spaceship(b,s) and 0xff,0) if disproven(b,s) else (0,spaceship(b,s)&1 and 0xff,spaceship(b,s)&2 and 0xff) if spaceship(b,s) else 3*((False and b&1) and ~s&1<<8 and 0x33,))(*((bitverse(9,mask^s),bitverse(9,mask^b)) if b&1 and s&1<<8 else (b,s))), starmap(lambda x,y: tap(lambda n: n or n^n>>1,(bitverse(9,x),y)) if not grey else tap(lambda n: bitverse(9,n^n>>1),(x,y)) if x<1<<8 else (bitverse(9,x^x>>1),y^y>>1) if y<1<<8 else ((x&~(1<<8))^(x&~(1<<8))<<1|1,y^y>>1),product(range(1<<9),repeat=2)) if True else chain(product(map(lambda n: bitverse(9,n^n>>1),range(1<<8)),map(lambda n: bitverse(9,n^n>>1),range(1<<9))),product(map(lambda n: bitverse(9,n^n>>1),range(1<<8,1<<9)),map(lambda n: n^n>>1,range(1<<9))))))).transpose(5)
else:
inputcode=input('apgcode ')
if (suspicious:=inputcode[:3]=='x ='):
inRLE=[inputcode]
while not inRLE or '!' not in inRLE[-1]: inRLE.append(input())
state=loadRLE('\n'.join(inRLE))
objectType=0
period=int(input('what is the period, perchance '))
shifts=(0,0)
for i in range(period+1):
state=iterateCellular(state,2-objectType)
if objectType:
shifts=tap(int.__add__,shifts,(shiftX,shiftY))
else:
(period,state)=analyse(inputcode,-1)
states=tuple(expumulate(iterateCellular,period-1)(state))
subpixels=(period if objectType else 1) #I was going to do lcm(lcm(period,shifts[0]),lcm(period,shifts[1])) but then remembered they are factors
upscale=8**(not objectType)
overlays=tuple(tarmap(lambda o,s: (lambda i: i>=0 and s>>i&1)(((y+o*shifts[1]*subpixels//period)//subpixels*cellWidth*WIDTH if OT or byteINT else 3*WIDTH*(y*3+1)+1)+(x+o*shifts[0]*subpixels//period)//subpixels*cellWidth),enumerate(states)) for y in range(subpixels*HEIGHT) for x in range(subpixels*WIDTH))
print(stators:=sum(map(all,overlays)),'stators',rotors:=sum(map(any,overlays))-stators,'rotors',strict:=stators+rotors-sum(map(lambda c: any(c) and any(map(lambda f: all(map(lambda i: c[i*f:(i+1)*f]==c[(i+1)*f:(i+2)*f],range(period//f-1))),factorise(period)[:-1])),overlays)),'strict')
cells=tuple(tap(lambda c: min(int(rms(c)*255),255),zip(*starmap(lambda o,s: triangleWave(o,period) if s else (0,0,0),enumerate(overlays[x+y*subpixels*WIDTH])))) for y in range(subpixels*HEIGHT) for x in range(subpixels*WIDTH))
#cells=tuple(tap(lambda c: min(int(rms(c)*255),255),zip(*starmap(lambda o,s: triangleWave(o,period) if (lambda n,i: i>=0 and n>>i&1)(s,((y+o*shifts[1]*subpixels//period)//subpixels*cellWidth*WIDTH if OT or byteINT else 3*WIDTH*(y*3+1)+1)+(x+o*shifts[0]*subpixels//period)//subpixels*cellWidth) else (0,0,0),enumerate(states)))) for y in range(subpixels*HEIGHT) for x in range(subpixels*WIDTH))
#from colorsys import hsv_to_rgb
#img=Image.frombytes('RGB',(100,360),bytes(int(0.5+255*u) for hue in range(360) for sat in range(100) for u in hsv_to_rgb(hue/360, sat/100, 1))) #demo from https://stackoverflow.com/a/48280414
img=Image.frombytes('RGB',(subpixels*WIDTH,subpixels*HEIGHT),bytes(chain.from_iterable(cells))).resize((upscale*subpixels*WIDTH,upscale*subpixels*HEIGHT),resample=Image.BOX)
img.save((lambda s: 'xp'+str(period)+'_suspicious_'+rulestring if suspicious else s[:s.index('_')]+'_toolong_'+rulestring if len(s)>256-4 else s)(inputcode)+'.png')
img.show()
elif mode==2:
try:
from eightfold_reducer import reducer
except:
raise(ImportError("no eightfold reducer (get it at https://github.com/DroneBetter/ChessPieceVision/blob/main/eightfold%20reducer.py and put it in my folder :-)"))
setBoard(*((int(input("board width ")),)*2))
bounded=(not (edges or corners or nearCorners) or input("include patterns that exceed the bounds? "+"(rule is gutter-preserving) "*gutterPreservation).lower() in {'y','yes'})
r=reducer(boardWidth,True,True,cellWidth,cellHeight,OT,byteINT)
#print(len(set(r[:])))
sliceNum=int(input("there are "+str(len(r))+" states, how many slices would you like? "))
slicer=(lambda n: (lambda i,f: (f-i,slice(i,f,1)))(*map(lambda i: len(r)*i//sliceNum,(n,n+1))))
(l,sliceAttempted)=slicer(int(sliceNum!=1 and input("which would you like to search? ")))
n=1<<(14+2*OT)#min(l>>10,4096)
finals=set()
t=time()
for i,s in enumerate(r[sliceAttempted]):
if not i%n and i:
print((lambda t: str(i)+'/'+str(l)+' ('+str(100*i//l)+'%) in '+str(int(t*1000)/1000)+'s, '+str(int(n//t))+' soups/s, '+str(int((len(r)-i)*t)//n)+'s remaining')(time()-t))
t=time()
past=[]
state=s
#print('it begins')
#printBoard(state)
while state not in past:
past.append(state)
state=iterateCellular(state)
#printBoard(state)
finals.add((lambda p: (p,min(map(r.symmetry,past[-p:]))))(len(past)-past.index(state)))
print(len(finals))
m=max(p for p,s in finals)
for p,s in finals:
if p>2 or m==2:
printBoard(s)
print(p)
elif mode:
import os,csv
interface=(input('interface? ')=='y')
name=''
while not name: name=input("name ")
if name[-7:]=='_sorted': name='sorted_'+name[:-7] #in case I forget which way around it is (surprisingly often)
if interface:
def reversedLines(file,blocksize=4096): #from https://stackoverflow.com/a/10933932
part=''
file.seek(0,os.SEEK_END)
here=file.tell()
while 0<here:
delta=min(blocksize,here)
here-=delta
file.seek(here,os.SEEK_SET)
block=file.read(delta)
for c in reversed(block):
if c=='\n' and part:
yield(part[::-1])
part=''
else: part+=c
if part: yield(part[::-1])
with open(os.path.join(sys.path[0],name+".csv"),newline='') as census:
revsus=reversedLines(census)
oscillators=[]
while True:
oscillators.append((next(revsus).strip('\n'))[1:-2].split('","'))
apgcode=oscillators[-1][0]
wibble=True
if wibble:
p=int(apgcode[2:apgcode.index('_')])
printBoard(tuple(redumulate(lambda s,_: iterateCellular(s),range(p-1),reduce(lambda s,_: iterateCellular(s,2),range(p),loadapg(apgcode)))),phases=True)
else:
printBoard(loadapg(apgcode))
print(*oscillators[-1][:2])
analyse(apgcode,(0,1,2,3,4),True)
input()
else:
volatilityThreshold=0.8
cond=(lambda v: not v if metric==4 else v>(28 if name=='xp5' else 20) if metric==3 else v==False if metric==2 else v[0]<volatilityThreshold)
#analyse("xp30_w33z8kqrqk8zzzx33")#("xp8_gk2gb3z11")
metric=0 #0: volatility, 1: heat, 2: polyomino?, 3: minpop, 4: gutter-preserving?
with open(os.path.join(sys.path[0],name+".csv"),newline='') as census:
next(census)
nice=[(lambda p,o: (p[1:-1],int(o[1:-2])))(*c.split(',')) for c in census]
metrics=[analyse(n[0],(metric,)) for n in nice]
nicests=sorted(zip(metrics,nice))
with open(os.path.join(sys.path[0],"sorted_"+name+".csv"),'w',newline='') as census:
wr=csv.writer(census,quoting=csv.QUOTE_ALL)
wr.writerows((*n,v) for v,n in nicests)
for v,n in nicests[::(-1)**(metric!=3)]:
if v==None or cond(v):
break
printBoard(loadapg(n[0]),symbol='')
print(*n,v)
suspicious=1 #very suspicious
if suspicious:
print('All known {{period|'+str(period)+'}} oscillators with [[volatility]] of at least '+str(volatilityThreshold)+'.\n{|class="wikitable sortable" style="margin-left:auto; margin-right:auto; clear:both; text-align:center"\n! Rank !! Name !! Image !! Rotor Size !! Volatility'+' !! Strict volatility'*(len(factorise(period))>2)) #very suspicious
round=(lambda n,d=3: (lambda n: n+'0'*(d+2-len(n)))(str(int(n*10**d)/10**d)))
for i,(v,n) in enumerate(nicests[::-1],start=1): #start=1 is a constant source of pain to me however we wouldn't want to upset the ordinal pedants
if v==None or cond(v):
break
if suspicious: print('|-\n|'+str(i)+'||{{LinkCatagolue|code='+n[0]+'|style=raw|patternname=unnamed}}||[[File:'+n[0]+'.png|96px]]||96||'+round(v[0])+'||'+round(v[1]))
else: print(RLE(loadapg(n[0]))[:-1]+'3$')#print(*n,v)
if suspicious: print('|}')
else:
testGlider=True
#state=(lambda r: loadRLE(r+'\n'+input()) if r else loadRLE("$$b3o$bobo$2b2o3b2o$7b2o2$b2o$obo$bo!" if rulestring=="b3ai4s23" else "$$3o$2bo$bo!") if testGlider else int.from_bytes(os.urandom(STATE_BYTE_LENGTH),"little") & MASK_1)(input('RLE '))
inRLE=[]
while not inRLE or '!' not in inRLE[-1]: inRLE.append(input())
state=loadRLE('\n'.join(inRLE))
while True:
state=iterateCellular(state,manifold==(0,0) and False)
if yuv4mpeg:
#output a (gzip-compressed!) YUV4MPEG frame
sys.stdout.buffer.write(deflate_verbatim(b"FRAME\n"))
sys.stdout.buffer.write(MAGIC_HUFFMAN_TREE)
sys.stdout.buffer.write((state>>BIAS-3).to_bytes(WIDTH*HEIGHT>>1,"little"))
sys.stdout.buffer.write(b"\x04")
else:
print(RLE(state))
printBoard(state)
sleep(1/FPS)
#print(state.bit_count())
if state.bit_count()==290:
print(RLE(state));exit()
@DroneBetter
Copy link
Author

DroneBetter commented Sep 21, 2022

Made for use in my tablebase program's oscillator search/visualisation mode (which currently works by only storing states as lists of booleans and storing a list of each cell's neighbourhood to account for manifolds instead of computing on-the-fly), but can be used by others also if you'd like. gzip_swar_life has toroidal vertical scrolling and horizontal skewed scrolling (from the fact that bitwise operators scroll around, so each cell on the right edge perceives the one on the left edge a row down as being orthogonally adjacent to it rightwards), this makes it a correct torus in both axes by immersing within a mask scrolled left and right as well as up and down. But tablebase vision supports topological manifolds with axes like Möbius strips (ie. Klein bottles where one axis is toroidal and the other Möbius, and real projective planes where both are Möbius). To achieve this in a bitwise implementation, you must reverse the order of bits. You can reverse a 2**n-bit number in 5*n operations, and for non-power-of-2-bit widths, you can generate the functions for the first power of 2 after the width, and bitshift left by half the difference between them at the beginning, and right at the end, however it can be optimised further by bitwise arithmetic. It also enacts these operations only once on the scrolling bitmasks in each axis, by copying the reversal AND-masks to both sides.
I will make a bitwise simulator for isotropic non-totalistic cellular automata, eventually.
Edit: I have finished that (in this program for convenience), it works by having each cell in the centre of a 3*3 square of bits instead of the rightmost cell of four consecutive ones, and bitwise-ORing it with displaced versions of itself (instead of summing) such that the bits around each cell are its neighbourhood, then bitwise-XORing with the bitwise NOT of the mask for each MAP transition and folding by bitwise ANDs up and down as well as left and right, it will take longer and I don't know how I'd make it work with YUV4MPEG (as the original one was intended to do efficiently (being that 4 bits is half a byte, as well as the number capable of storing nine possibilities (neighbourhood sum range 0 to 8 inclusive))), but it should be many times faster than my original boolean list implementation in any case.
Edit once more: Now featuring INT simulation in eight cells per byte (see explanation here), RLE header loading and preliminary testing mode (enabled by default in non-video mode) for simulation on an infinite plane (extremely suspiciously, by exporting it to an RLE, changing the board size to have a one-cell margin and reimporting it), will be used in implementing an idea of mine eventually
Edit again: Can now import and analyse apgcodes, currently only sorts by volatility (not intended to be fast but to be able to peruse Catagolue on my behalf so I can spend less of my life doing so), turn off demoMode and put it in the same folder as a census backup containing only oscillators of the specified period (explained in this wiki article) named census.csv and then wait (currently you can download all of a period but trying all from b3s23/all-soups (as you may be inclined to do if you become mad with power) seems to make the file cut off midway through), it will show you some but also creates sorted_census.csv (in ascending order of volatility for more comedic effect)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment