// NAME           :   Aidan Eichman
// GROUP          :   APCS
// SCHOOL         :   Kalamazoo AMSC
// DIVISION       :   Senior-5
// CONTEST        :   Round #3
// PROGRAM        :   Veitch
// DESCRIPTION    :   Given a hexadecimal string,
//                :   output the boolean expression
//                :   with the rules provided in
//                :   the guidelines
// DATE           :   February 2020


#include 
#include 
#include 
#include 
#include 
#include 

using namespace std;

static string answer;
static vector> matrix(4);

void initBitset(string& input) {
    for (size_t i = 0; i < input.size(); ++i) {
        stringstream stream;
        stream << input[i];
        
        size_t num;
        stream >> hex >> uppercase >> num;
        
        matrix[i] = bitset<4>(num);
    }
    
    return;
}

vector delimAND(string& exp) {
    vector subExpAND;
    
    while (exp.length() > 0) {
        size_t len = 1;
        if (exp[0] == '~') len++;
        subExpAND.push_back(exp.substr(0, len));
        exp.erase(0, len);
    }
    
    return subExpAND;
}

vector delimOR(string exp) {
    vector subExpOR;
    
    while (exp.length() > 0) {
        size_t idx = exp.find('+');
        if (idx == string::npos) idx = exp.length();
        subExpOR.push_back(exp.substr(0, idx));
        exp.erase(0, idx + 1);
    }
    
    return subExpOR;
}

bool setState(string& var, size_t i, size_t j) {
    bool NOT = false;
    if (var.size() > 1) NOT = true;
    
    char letter = NOT ? var[1] : var[0];
    switch (letter) {
        case 'A':
            return !NOT ^ (j == 0 || j == 1);
            break;
        case 'B':
            return NOT ^ (i == 0 || i == 1);
            break;
        case 'C':
            return NOT ^ (j == 1 || j == 2);
            break;
        case 'D':
            return NOT ^ (i == 1 || i == 2);
            break;
        default:
            cerr << "RIP";
            return false;
            break;
    }
}

bool evalExp(string exp) {
    vector subExp(delimAND(exp));
    vector> boolExp(4, bitset<4>(15));
    
    for (auto var : subExp) {
        for (int i = 0; i < boolExp.size(); ++i) {
            for (int j = 0; j < boolExp[i].size(); ++j) {
                boolExp[i][j] = boolExp[i][j] && setState(var, i, j);
            }
        }
    }
    
    for (int i = 0; i < matrix.size(); ++i) {
        if (boolExp[i].to_ulong() != (boolExp[i].to_ulong() & matrix[i].to_ulong())) {
            return false;
        }
    }
    
    return true;
}

void altBitset(string exp) {
    vector subExp(delimAND(exp));
    vector> boolExp(4, bitset<4>(15));
    
    for (auto var : subExp) {
        for (int i = 0; i < boolExp.size(); ++i) {
            for (int j = 0; j < boolExp[i].size(); ++j) {
                boolExp[i][j] = boolExp[i][j] && setState(var, i, j);
            }
        }
    }
    
    for (int i = 0; i < matrix.size(); ++i) {
        for (int j = 0; j < matrix[i].size(); ++j) {
            if (matrix[i][j] && boolExp[i][j]) matrix[i][j].flip();
        }
    }
    
    return;
}

void tryExp(string& exp) {
    if (evalExp(exp)) {
        if (answer.length() > 0) answer += "+";
        answer += exp;
        altBitset(exp);
    }
}

int main() {
    ifstream fin("3sr_testdata.txt");
    cout<<"Aidan Eichman\nAPCS\nACSL Round 3 Senior-5 Veitch\n\n\n";
    for (int i = 0; i < 5; ++i) {
        string input;
        fin >> input;
        
        answer = "";
        initBitset(input);
        
        string exp;
        
        // group 8
        exp = "B";
        tryExp(exp);
        exp = "D";
        tryExp(exp);
        exp = "~B";
        tryExp(exp);
        exp = "A";
        tryExp(exp);
        exp = "C";
        tryExp(exp);
        exp = "~A";
        tryExp(exp);
        exp = "~D";
        tryExp(exp);
        exp = "~C";
        tryExp(exp);
        
        // group 4 rows
        exp = "B~D";
        exp = "B~D";
        tryExp(exp);
        exp = "BD";
        exp = "BD";
        tryExp(exp);
        exp = "~BD";
        exp = "~BD";
        tryExp(exp);
        exp = "~B~D";
        exp = "~B~D";
        tryExp(exp);
        
        // group 4 columns
        exp = "A~C";
        tryExp(exp);
        exp = "AC";
        tryExp(exp);
        exp = "~AC";
        tryExp(exp);
        exp = "~A~C";
        tryExp(exp);
        
        // group 4 blocks
        exp = "AB";
        tryExp(exp);
        exp = "BC";
        tryExp(exp);
        exp = "~AB";
        tryExp(exp);
        exp = "AD";
        tryExp(exp);
        exp = "CD";
        tryExp(exp);
        exp = "~AD";
        tryExp(exp);
        exp = "A~B";
        tryExp(exp);
        exp = "~BC";
        tryExp(exp);
        exp = "~A~B";
        tryExp(exp);
        
        // group 4 end-rows
        exp = "A~D";
        tryExp(exp);
        exp = "C~D";
        tryExp(exp);
        exp = "~A~D";
        tryExp(exp);
        
        // group 4 end-columns
        exp = "B~C";
        tryExp(exp);
        exp = "~CD";
        tryExp(exp);
        exp = "~B~C";
        tryExp(exp);
        
        // group 4 corners
        exp = "~C~D";
        tryExp(exp);
        
        // group 2 rows
        exp = "AB~D";
        tryExp(exp);
        exp = "BC~D";
        tryExp(exp);
        exp = "~AB~D";
        tryExp(exp);
        
        exp = "ABD";
        tryExp(exp);
        exp = "BCD";
        tryExp(exp);
        exp = "~ABD";
        tryExp(exp);
        
        exp = "A~BD";
        tryExp(exp);
        exp = "~BCD";
        tryExp(exp);
        exp = "~A~BD";
        tryExp(exp);
        
        exp = "A~B~D";
        tryExp(exp);
        exp = "~BC~D";
        tryExp(exp);
        exp = "~A~B~D";
        tryExp(exp);
        
        // group 2 columns
        exp = "AB~C";
        tryExp(exp);
        exp = "ABC";
        tryExp(exp);
        exp = "~ABC";
        tryExp(exp);
        exp = "~AB~C";
        tryExp(exp);
        
        exp = "A~CD";
        tryExp(exp);
        exp = "ACD";
        tryExp(exp);
        exp = "~ACD";
        tryExp(exp);
        exp = "~A~CD";
        tryExp(exp);
        
        exp = "A~B~C";
        tryExp(exp);
        exp = "A~BC";
        tryExp(exp);
        exp = "~A~BC";
        tryExp(exp);
        exp = "~A~B~C";
        tryExp(exp);
        
        // group 2 end-rows
        exp = "B~C~D";
        tryExp(exp);
        exp = "B~CD";
        tryExp(exp);
        exp = "~B~CD";
        tryExp(exp);
        exp = "~B~C~D";
        tryExp(exp);
        
        
        // group 2 end-columns
        exp = "A~C~D";
        tryExp(exp);
        exp = "AC~D";
        tryExp(exp);
        exp = "~AC~D";
        tryExp(exp);
        exp = "~A~C~D";
        tryExp(exp);
        
        
        // group 1
        exp = "AB~C~D";
        tryExp(exp);
        exp = "ABC~D";
        tryExp(exp);
        exp = "~ABC~D";
        tryExp(exp);
        exp = "~AB~C~D";
        tryExp(exp);
        
        exp = "AB~CD";
        tryExp(exp);
        exp = "ABCD";
        tryExp(exp);
        exp = "~ABCD";
        tryExp(exp);
        exp = "~AB~CD";
        tryExp(exp);
        
        exp = "A~B~CD";
        tryExp(exp);
        exp = "A~BCD";
        tryExp(exp);
        exp = "~A~BCD";
        tryExp(exp);
        exp = "~A~B~CD";
        tryExp(exp);
        
        exp = "A~B~C~D";
        tryExp(exp);
        exp = "A~BC~D";
        tryExp(exp);
        exp = "~A~BC~D";
        tryExp(exp);
        exp = "~A~B~C~D";
        tryExp(exp);
        
        cout << answer << '\n';
    }
    
    return 0;
}