import numpy as np def survive(gtab,cp,w,T): p=len(cp); N=1<<(w-1); L=w+T+p+4 S=np.zeros((N,L),dtype=np.uint8); idx=np.arange(N) for j in range(w-1): S[:,j]=(idx>>j)&1 S[:,w-1]=1 g=np.array(gtab,dtype=np.uint8) # g[2*c + r], c = self, r = near neighbour e=np.zeros((N,T+p+1),dtype=np.uint8) for t in range(T+p+1): e[:,t]=S[:,0] near=np.concatenate([np.full((N,1),cp[t%p],dtype=np.uint8),S[:,:-1]],1) far=np.concatenate([S[:,1:],np.zeros((N,1),dtype=np.uint8)],1) S=far^g[2*S+near] alive=np.ones(N,bool); death=np.full(N,T) for t in range(T): if cp[t%p]==1: bad=alive&(e[:,t]!=e[:,t+p]); death[bad]=t; alive&=~bad return int(alive.sum()), int(death.max()) names={(0,0,0,0):"0",(0,0,0,1):"self AND near",(0,0,1,0):"self AND NOT near",(0,0,1,1):"self", (0,1,0,0):"NOT self AND near",(0,1,0,1):"near (Rule 90)",(0,1,1,0):"self XOR near",(0,1,1,1):"self OR near (Rule 30)", (1,0,0,0):"NOR",(1,0,0,1):"XNOR",(1,0,1,0):"NOT near",(1,0,1,1):"self OR NOT near", (1,1,0,0):"NOT self",(1,1,0,1):"NOT self OR near",(1,1,1,0):"NAND",(1,1,1,1):"1"} T=80 for gtab,name in names.items(): row=[] for cp in ((0,1),(0,0,1)): fooled=0; worst=0 for w in range(1,13): a,dmax=survive(gtab,cp,w,T); fooled+=a; worst=max(worst,dmax if a==0 else T) row.append(f"{''.join(map(str,cp))}: {'FOOLED by '+str(fooled)+' starts' if fooled else 'never fooled (latest catch: night '+str(worst)+')'}") print(f" g = {name:24s} | "+" | ".join(row))