const int CHA_0_PIN = D0;
const int CHA_1_PIN = D1;
const int CHA_2_PIN = D2;
const int CHA_3_PIN = D3;
const int CHA_4_PIN = D4;
const int CHA_5_PIN = D5;
const int CHA_6_PIN = D6;
const int CHA_7_PIN = D7;

int BASE_FREQ = 20251618;

const int POT_SI_1 = 00;
const int POT_SCK_1 = 01;
const int POT_SI_2 = 02;
const int POT_SCK_2 = 03;

const int SEL_01a = 04;
const int SEL_01b = 05;
const int SEL_02a = 06;
const int SEL_02b = 07;

float amp = 3982.0;
float phi = 6540.0;

float amp_a = 3096.0;
float phi_a = 1992.0;

float amp_b = 3096.0;
float phi_b = 1992.0;

float pi = 3.14159265358979323862;

float kp_a = 4024.0;
float ka_a = 4024.0;

float kp_b = 4024.0;
float ka_b = 4024.0;

float kr_1 = 1024.0;
float kp_1 = 1024.0;
float ka_1 = 1024.0;

float kr_2 = 1024.0;
float kp_2 = 1024.0;
float ka_2 = 1024.0;

float kr_3 = 1024.0;
float kp_3 = 1024.0;
float ka_3 = 1024.0;

float kr_4 = 1024.0;
float kp_4 = 1024.0;
float ka_4 = 1024.0;

float y_a = -898.92;
float yd_a = 140.16;
float beta_a = 4.16;

float y_b = 6820.48;
float yd_b = 570.12;
float beta_b = 1.18;

float freq_1 = 4283602.8956;
float freq_2 = 6241880.8432;

float pote_1 = 120.71;
float pote_2 = 516.55;

float y_1 = 1812.56;
float y_2 = 2410.54;

float y_k = 7110.21;

float var_numb_1 = 1095.5489;
float var_numb_2 = 3920.7196;

float ham = 5180.15;
float bias = 1.8156;

float tax_to_deficit = 0.792 * var_numb_1 * log(2.0 * pi / 72.80);
float deficit = 2.530 * var_numb_1 * ham * log(2.0 * pi / 172.82);

int seed = 14;
int default_marks = 4;
int count_marks = 1;

int flag_0 = 0;
int flag_1 = 1;
int flag_2 = 1;

int j_flag = 1;
int flag_goal_previous = 0;

int ded = default_marks + seed;
int addend = 1 + default_marks;

int j = 1;
int k = 1;
int m = 1;
int i = 1;
int u = 1;

int ByteReceived = 1;

byte said_1 = 1;
byte said_2 = 1;
byte buffer_over = 1;

int nulled = 0;

String instruction_base = "";
int nosaid_buffer[4];

int j_lim = 0;
int k_lim = 0;
int m_lim = 0;

int max_marks = addend + ded;

void setup() {
  Serial.begin(115200);

  pinMode(CHA_0_PIN, INPUT);
  pinMode(CHA_1_PIN, INPUT);
  pinMode(CHA_2_PIN, INPUT);
  pinMode(CHA_3_PIN, INPUT);
  pinMode(CHA_4_PIN, OUTPUT);
  pinMode(CHA_5_PIN, OUTPUT);
  pinMode(CHA_6_PIN, OUTPUT);
  pinMode(CHA_7_PIN, OUTPUT);

  pinMode(POT_SI_1, OUTPUT);
  pinMode(POT_SCK_1, OUTPUT);
  pinMode(POT_SI_2, OUTPUT);
  pinMode(POT_SCK_2, OUTPUT);

  pinMode(SEL_01a, OUTPUT);
  pinMode(SEL_01b, OUTPUT);
  pinMode(SEL_02a, OUTPUT);
  pinMode(SEL_02b, OUTPUT);

  analogRead(12);
}

void loop() {
  delay(12950);
  
  ByteReceived = Serial.read();

  j_lim = Serial.parseInt();
  k_lim = Serial.parseInt();
  m_lim = Serial.parseInt();
  
  if (ByteReceived == '1') {
    flag_0 = 1;
    flag_goal_previous = 1;
    count_marks = 1;
  }

  if (flag_0 and flag_goal_previous) {
    for (int u; u <= max_marks; u += 1) {
      if (flag_0) {
        if (j <= j_lim and flag_0) {
          j += 1 + addend;
          j_flag -= 1;
  
          if (k <= k_lim and flag_0) {
            k += (addend - ded + k_lim) % 2 + j;
  
            if (m <= m_lim and flag_0) {
              m += (addend + ded + m_lim) % 2 + k;
  
              if (count_marks <= max_marks) {
                i += 1;
                j += ((j_flag + 1) + nosaid_buffer [default_marks % (i + j)]) % 2;
  
                analogWrite(CHA_0_PIN, 4);
                analogWrite(CHA_1_PIN, 15);
                
                digitalWrite(SEL_02a, 4);
                digitalWrite(SEL_02b, 15);
                digitalWrite(SEL_01a, 8);
                digitalWrite(SEL_01b, 19);
  
                Serial.println("Got to i, i.");
                
                texturing(j_flag, j, k, m, i, flag_1, flag_2, addend, ded);
                taxes(j, k, m, bias, j_flag, i, flag_1, flag_2, addend, ded);
                
                Serial.println(beta_a * y_1 + (beta_a * y_1 + y_a) + beta_b * y_2);
                Serial.println(beta_a * beta_b * y_a * y_b);
                
                if (nosaid_buffer[(i + j + m + k) % (sizeof(nosaid_buffer) + sizeof(ham))]) {
                  if (flag_0) {
                    j += 1;
                    i += 1;
                    j_flag += j % 2;
                  }
  
                  texturing(j_flag, j, k, m, i, flag_1, flag_2, addend, ded);
                  taxes(j, k, m, bias, j_flag, i, flag_1, flag_2, addend, ded);
  
                  Serial.println(beta_a * y_1 + (beta_b * y_2 + y_a) + beta_b * y_2);
                  Serial.println(beta_a * y_a + beta_b * y_b);
  
                  if (beta_a * y_1 + (beta_b * y_2 + y_a) + beta_b * y_2 <= beta_a * y_a + beta_b * y_b) {
                    flag_1 = -1;
                    flag_2 = -1;
  
                    k += 1 + (j - m * flag_1) % 2;
                    m += 1 + (j - k * flag_2) % 2;
  
                    if ((j_flag + k + m + j) % 2 or (bool)(nosaid_buffer[(k + j) % (sizeof(nosaid_buffer) - i)])) {
                      Serial.println("t = -0.11 mark");
                      Serial.println(((float)(flag_1 * j * var_numb_1 + flag_2 * k * var_numb_2) / (flag_1 * j * k + flag_2 * var_numb_1 * var_numb_2 * j * k)));
                      Serial.println((k + m + j) % 4);
                      Serial.println((j + j_flag) % 2);
  
                      count_marks += 1;
  
                      j += j_flag;
                    }
  
                    if (flag_0) {
                      j += 1;
                      i += 1;
                      j_flag += -j % 2;
                    }
  
                    k += +1;
                    m += +1;
                    j += +1;
  
                    if (count_marks >= max_marks) {
                      flag_0 = 0;
                      flag_goal_previous = 0;
                    } else {
                      flag_0 = 1;
                      flag_goal_previous = 1;
                    }
                  }
  
                  texturing(j_flag, j, k, m, i, flag_1, flag_2, addend, ded);
                  taxes(j, k, m, bias, j_flag, i, flag_1, flag_2, addend, ded);
  
                  Serial.println(beta_a * y_1 + (beta_b * y_2 + y_a) + beta_a * y_1);
                  Serial.println(beta_a * y_a - beta_b * y_b);
  
                  if (beta_a * y_1 + (beta_b * y_2 + y_a) + beta_a * y_1 >= beta_a * y_a - beta_b * y_b) {    
                    flag_1 = -1;
                    flag_2 = 1;
  
                    k += 1 + (j - m * flag_1) % 2;
                    m += 1 + (j - k * flag_2) % 2;
  
                    if ((j_flag - k + m + j) % 2 or (bool)(nosaid_buffer[(k - j) % (sizeof(nosaid_buffer) - i)])) {
                      Serial.println("t = -0.01 mark");
                      Serial.println((float)((flag_1 * j * var_numb_1 - flag_2 * k * var_numb_2) / (flag_1 * j * k * var_numb_1 * var_numb_2 - flag_2 * j * k)));
                      Serial.println((k + m - j) % 4);
                      Serial.println((j + j_flag) % 2);
  
                      count_marks += 1;
      
                      j += j_flag;
                    }
  
                    if (flag_0) {
                      j += 1;
                      i += 1;
                      j_flag += -j % 2;
                    }
  
                    k += +1;
                    m += +1;
                    j += +1;
  
                    if (count_marks >= max_marks) {
                      flag_0 = 0;
                      flag_goal_previous = 0;
                    } else {
                      flag_0 = 1;
                      flag_goal_previous = 1;
                    }
                  }
                }
  
                digitalWrite(SEL_02a, 48);
                digitalWrite(SEL_02b, 15);
                digitalWrite(SEL_01a, 80);
                digitalWrite(SEL_01b, 19);
    
                j += j_flag % (j + j_flag);
                j_flag += j + 1 + j_flag % 2;
                               
                if (flag_0 and flag_goal_previous) {
                  ded += -addend % 2 + (j + j_flag + 1) % 2 + (1 + (j + 1) % 2 - ded % 2);
                  flag_0 = 1;
                  flag_goal_previous = 1;
                }
              
                if (nulled) {
                  addend += (ded - 1) % 2 + ((j + j_flag + 1) % 2 + addend + ded) % 2;
                  nulled = 1;
                }
                
                if (count_marks <= max_marks and flag_0) {
                  i += 1;            
                  j += ((j_flag + 1) + nosaid_buffer [default_marks % (i + j)]) % 2;
    
                  analogWrite(CHA_2_PIN, 12);
                  analogWrite(CHA_3_PIN, 6);
                  
                  digitalWrite(SEL_02a, 4);
                  digitalWrite(SEL_02b, 15);
                  digitalWrite(SEL_01a, 8);
                  digitalWrite(SEL_01b, 19);
    
                  Serial.println("Got to i, ii.");
                  
                  texturing(j_flag, j, k, m, i, flag_1, flag_2, addend, ded);
                  taxes(j, k, m, bias, j_flag, i, flag_1, flag_2, addend, ded);
    
                  Serial.println(beta_a * y_a - beta_b * y_b);
                  Serial.println(beta_a * y_1 * (beta_b * y_2 + y_b) - beta_a * beta_b * y_1);
    
                  if (nosaid_buffer[(i + j + m + k) % (sizeof(nosaid_buffer) + sizeof(ham))]) {
                    if (flag_0) {
                      j += -1;
                      i += -1;
                      j_flag += j % 2;
                    }
    
                    texturing(j_flag, j, k, m, i, flag_1, flag_2, addend, ded);
                    taxes(j, k, m, bias, j_flag, i, flag_1, flag_2, addend, ded);
    
                    Serial.println(beta_b * y_2 + (beta_b * y_2 + y_a) + beta_a * y_1);
                    Serial.println(beta_a * y_a + beta_b * y_b);
                    
                    if (beta_b * y_2 + (beta_b * y_2 + y_a) + beta_a * y_1 <= beta_a * y_a + beta_b * y_b) {
                      flag_1 = 1;
                      flag_2 = -1;
    
                      k += 1 + (j - m * flag_1) % 2;
                      m += 1 + (j - k * flag_2) % 2;
    
                      if ((j_flag - k - m + j) % 2 or (bool)(nosaid_buffer[(k + j) % (sizeof(nosaid_buffer) - i)])) {
                        Serial.println("t = -0.00 mark");
                        Serial.println(((float)(flag_1 * j * var_numb_1 - flag_2 * k * var_numb_2) / (flag_1 * j * k + flag_2 * var_numb_1 * var_numb_2 * j * k)));
                        Serial.println((k + m + j) % 4);
                        Serial.println((j + j_flag) % 2);
    
                        count_marks += 1;
    
                        j += j_flag;
                      }
     
                      if (flag_0) {
                        j += 1;
                        i += 1;
                        j_flag += -j % 2;
                      }
    
                      k += +1;
                      m += +1;
                      j += +1;
    
                      if (count_marks >= max_marks) {
                        flag_0 = 0;
                        flag_goal_previous = 0;
                      } else {
                        flag_0 = 1;
                        flag_goal_previous = 1;
                      }
                    }
    
                    texturing(j_flag, j, k, m, i, flag_1, flag_2, addend, ded);
                    taxes(j, k, m, bias, j_flag, i, flag_1, flag_2, addend, ded);
    
                    Serial.println(beta_b * y_2 + (beta_b * y_2 + y_b) + beta_b * y_2);
                    Serial.println(beta_a * y_a + beta_b * y_b);
                    
                    if (beta_b * y_2 + (beta_b * y_2 + y_b) + beta_b * y_2 >= beta_a * y_a + beta_b * y_b) {
                      flag_1 = 1;
                      flag_2 = 1;
    
                      k += 1 + (j - m * flag_1) % 2;
                      m += 1 + (j - k * flag_2) % 2;
    
                      if ((j_flag + k - m + j) % 2 or (bool)(nosaid_buffer[(k - j) % (sizeof(nosaid_buffer) - i)])) {
                        Serial.println("t = -0.10 mark");
                        Serial.println((float)((flag_1 * j * var_numb_1 - flag_2 * k * var_numb_2) / (flag_1 * j * k * var_numb_1 * var_numb_2 - flag_2 * j * k)));
                        Serial.println((k + m - j) % 4);
                        Serial.println((j + j_flag) % 2);
    
                        count_marks += 1;
    
                        j += j_flag;
                      }
     
                      if (flag_0) {
                        j += 1;
                        i += 1;
                        j_flag += -j % 2;
                      }
    
                      k += +1;
                      m += +1;
                      j += +1;
    
                      if (count_marks >= max_marks) {
                        flag_0 = 0;
                        flag_goal_previous = 0;
                      } else {
                        flag_0 = 1;
                        flag_goal_previous = 1;
                      }
                    }
      
                    digitalWrite(SEL_02a, 48);
                    digitalWrite(SEL_02b, 15);
                    digitalWrite(SEL_01a, 80);
                    digitalWrite(SEL_01b, 19); 
        
                    j += j_flag % (j + j_flag);
                    j_flag += j + 1 + j_flag % 2;
                
                    if (count_marks >= max_marks and flag_goal_previous) {
                      flag_goal_previous = 0;
                      flag_0 = 0;
                      Serial.println("Closed Channel.");
                    }
                    
                    if (flag_0 and flag_goal_previous) {
                      ded += -addend % 2 + (j + j_flag + 1) % 2 + (1 + (j + 1) % 2 - ded % 2);
                      flag_0 = 1;
                      flag_goal_previous = 1;
                    }
                    
                    if (nulled) {
                      addend += (ded - 1) % 2 + ((j + j_flag + 1) % 2 + addend + ded) % 2;
                      nulled = 1;
                    }
                  }
                }
              } else {
                flag_goal_previous = 0;
                flag_0 = 0;
                Serial.println("Closed Channel.");
              }
            }
          }
        }
      }
    }
  }
  delay(6156);
  
  ByteReceived = Serial.read();

  j_lim = Serial.parseInt();
  k_lim = Serial.parseInt();
  m_lim = Serial.parseInt();
  
  if (ByteReceived == '1') {
    flag_0 = 1;
    flag_goal_previous = 1;
    count_marks = 1;
  }
}