// An apgluxe-style attempt to replicate simeks's searcher described in https://conwaylife.com/forums/viewtopic.php?p=48948#p48948
// It generates glider collisions, quickly filters them using lifelib, and then use segments of the apgsearch soup searcher to determine whether the pattern is a single object, and checks whether it is already synthesizable within 4 gliders.
// By adjusting the cnt variable (and its dependent parameters), it is easy to make it generate any arbitrary number of gliders.
#include <iostream>
#include <vector>
#include <string>
#include <cstring>
#include <random>
#include <ctime>
int run_search(int it, int num, int log, int cnt, std::mt19937 mt){
    // the main search
    // list of gliders
    // there are 16 orientations of a glider, which are all collected in this list
    // the gliders variable is a std::vector<std::vector<int>>, which is a list that stores lists of integers.
    // those integers represent where to add cells
    // index 0-3: southeast gliders; index 4-7: southwest gliders; index 8-11: northeast gliders; index 12-15: northwest gliders
    //std::vector<std::vector<int> > gliders;
    int gliders[16][5][2] = {{{0, 1}, {1, 2}, {2, 0}, {2, 1}, {2, 2}}, {{0, 0}, {1, 1}, {1, 2}, {2, 0}, {2, 1}}, {{0, 2}, {1, 0}, {1, 2}, {2, 1}, {2, 2}}, {{0, 0}, {0, 2}, {1, 1}, {1, 2}, {2, 1}},
        {{0, 0}, {0, 1}, {0, 2}, {1, 2}, {2, 1}}, {{0, 0}, {0, 1}, {1, 1}, {1, 2}, {2, 0}}, {{0, 1}, {0, 2}, {1, 0}, {1, 2}, {2, 2}}, {{0, 1}, {1, 1}, {1, 2}, {2, 0}, {2, 2}},
        {{0, 1}, {1, 0}, {2, 0}, {2, 1}, {2, 2}}, {{0, 2}, {1, 0}, {1, 1}, {2, 1}, {2, 2}}, {{0, 0}, {1, 0}, {1, 2}, {2, 0}, {2, 1}}, {{0, 0}, {0, 2}, {1, 0}, {1, 1}, {2, 1}},
        {{0, 0}, {0, 1}, {0, 2}, {1, 0}, {2, 1}}, {{0, 1}, {0, 2}, {1, 0}, {1, 1}, {2, 2}}, {{0, 0}, {0, 1}, {1, 0}, {1, 2}, {2, 0}}, {{0, 1}, {1, 0}, {1, 1}, {2, 0}, {2, 2}}};
    for(int t=0; t<it; t++){
        //apg::lifetree<uint32_t, 1> lt(1000);
        for (int i=0; i<num; i++){
            bool pat[150][150] = {{false}};
            //generate glider positions
            //int coordinates[4][2] = {{0}};
            //std::vector<int> cases;
            for (int i=0; i<4; i++){
                int dx = mt() % 83, dy = mt() % 34, phase = mt() % 4, orient = mt() % 4;
                // use the orient variable to determine the location (x, y) of the glider and the direction (orient) of the glider;
                // case 0: northwest box
                // case 1: northeast box
                // case 2: southwest box
                // case 3: northwest box
                int x, y;
                /*switch (orient){
                    case 0: x=std::floor(dx/2)+dy; y=33+dx-x;
                    case 1: x=149-std::floor(dx/2)-dy; y=33+dx-x;
                    case 2: x=std::floor(dx/2)+dy; y=116-dx+x;
                    case 3: x=149-std::floor(dx/2)-dy; y=116-dx+x;
                }*/
                //cases.push_back(orient);
                if (orient == 0){
                    x = std::floor(dx/2) + dy; y=33+dx-x;
                } else if (orient == 1){
                    x = 149 - std::floor(dx/2) - dy; y=33+dx-(149-x);
                } else if (orient == 2){
                    x = std::floor(dx/2) + dy; y=116-dx+x;
                } else if (orient == 3){
                    x = 149 - std::floor(dx/2) - dy; y=116-dx+(149-x);
                }
                //coordinates[i][0] = x;
                //coordinates[i][1] = y;
                /*std::cout << "Case: " << orient << std::endl;
                std::cout << "DX: " << dx << std::endl;
                std::cout << "DY: " << dy << std::endl;*/
                if (x < 0){
                    std::cerr << "Serious error: the derived x value is " << x << ", which is negative.";
                } else if (y < 0){
                    std::cerr << "Serious error: the derived y value is " << y << ", which is negative.";
                }
                for (int i=0; i<5; i++){
                    pat[x+gliders[orient*4+phase][i][0]][y+gliders[orient*4+phase][i][1]] = true;
                    //pat[j][k] = true;
                }
            }
            //generate rle
            std::string rle;
            for(int i=0; i<150; i++) {
                if(i) rle += '$';
                int cnt = 0, cv = 2;
                for(int j=0; j<150; j++) {
                    if(pat[i][j] != cv) {
                        if(cv != 2) {
                            if(cnt != 1) rle += std::to_string(cnt);
                            rle += cv?'o':'b';
                        }
                        cnt = 1; cv = pat[i][j];
                    } else cnt++;
                }
                if(cv) rle += (std::to_string(cnt)+(cv?'o':'b'));
            }
            while(rle.back() == '$') rle.pop_back();
            std::string srle;
            int cnt = 0;
            for(char c:rle) {
                if(c == '$') {
                    if(srle.length()) cnt++;
                } else {
                    if(cnt) srle += (std::to_string(cnt)+'$');
                    cnt = 0;
                    srle += c;
                }
            }
            srle += '!';
            std::cout << "x = 0, y = 0, rule = B3/S23\n" << srle << std::endl;
            //std::cout << srle << std::endl;
            //look for periodicity at period 8
            //totest: apg::pattern, apg::bitworld, lifeapi.h
            //apg::upattern: 15847 soups/second
            //apg::upattern with dynamic stabilization: 15748 soups/second (about at fast as upattern gets)
            //apg::pattern: 5871 soups/second
            //todo: use golgrid
            //preprocess pattern
        }
    }
}
int main(int argc, char *argv[]){
    //read the arguments
    int cnt = 4;
    int it = 0; int num = 0; bool log = false;
    for(int i=0; i<argc; i++){
        //std::cout << argv[i] << std::endl;
        if (strcmp(argv[i], "-n") == 0){
            num = atoi(argv[i+1]);
        } else if (strcmp(argv[i], "-i") == 0){
            it = atoi(argv[i+1]);
        } else if (strcmp(argv[i], "-L") == 0){
            log = atoi(argv[i+1]);
        }
    }
    //gliders.insert(gliders.end(), gliders_south.begin(), gliders_south.end());
    //gliders.insert(gliders.end(), gliders_north.begin(), gliders_north.end());
    std::mt19937 mt;
    mt.seed(std::time(nullptr));
    //int cmbs[6][2] = {{0, 1}, {0, 2}, {0, 3}, {1, 2}, {1, 3}, {2, 3}};
    run_search(it, num, log, cnt, mt);
}
