#include <LiquidCrystal_I2C.h>

// LiquidCrystal_I2C lcd(I2C_ADDR, LCD_COLUMNS, LCD_LINES);
LiquidCrystal_I2C lcd(0x27, 16, 2);

enum {start_up, start, calibration, player_white, player_black};
byte key = start_up;
const int MUX_ADDR [4] = {A1, A2, A3, 5};
const int MUX_SELECT[4] = {13, 11, 10, 9};
// const int MUX_S0 = 0;   // Multiplexer control pin S0
// const int MUX_S1 = 1;   // Multiplexer control pin S1
// const int MUX_S2 = 2;   // Multiplexer control pin S2
// const int MUX_S3 = 3;   // Multiplexer control pin S3
const int MUX_OUTPUT[4] = {12, 4, 3, 2};
const int MUX_CHANNEL[16][4] = {
  {0, 0, 0, 0},
  {1, 0, 0, 0},
  {0, 1, 0, 0},
  {1, 1, 0, 0},
  {0, 0, 1, 0},
  {1, 0, 1, 0},
  {0, 1, 1, 0},
  {1, 1, 1, 0},
  {0, 0, 0, 1},
  {1, 0, 0, 1},
  {0, 1, 0, 1},
  {1, 1, 0, 1},
  {0, 0, 1, 1},
  {1, 0, 1, 1},
  {0, 1, 1, 1},
  {1, 1, 1, 1}
};
bool state =0;
char reed_column[2] = {'z','z'};
int reed_row[2] = {-1,-1};
int reed_sensor_record [8][8];
int reed_sensor_status[8][8];
int reed_sensor_status_memory[8][8];
int button_white={7};
int button_black={8};

unsigned long timer = 0;
enum{WHITE, BLACK};
int second = 60;
int minute = 9;
int second_white = second;
int second_black = second;
int minute_white = minute;
int minute_black = minute;

bool new_turn_countdown = true;


void setup() {
  // put your setup code here, to run once:
  Serial.begin(9600);
  for(int i=0; i<4; i++){
    pinMode(MUX_ADDR[i], OUTPUT);
    digitalWrite(MUX_ADDR[i], LOW);
    pinMode(MUX_SELECT[i], OUTPUT);
    digitalWrite(MUX_SELECT[i], HIGH);
    pinMode(MUX_OUTPUT[i], INPUT_PULLUP);
  }
  pinMode(button_white, INPUT_PULLUP);
  pinMode(button_black, INPUT_PULLUP);
  

  for(int i=0; i<2; i++){
    for(int j=0; j<8; j++){
      reed_sensor_record[i][j] = 1;
      reed_sensor_status[i][j] = 1;
    }
  }
  for(int i=2; i<6; i++){
    for(int j=0; j<8; j++){
      reed_sensor_record[i][j] = 0;
      reed_sensor_status[i][j] = 0;
    }
  }
  for(int i=6; i<8; i++){
    for(int j=0; j<8; j++){
      reed_sensor_record[i][j] = 1;
      reed_sensor_status[i][j] = 1;
    }
  }

  timer = millis();
  lcd.init();
  lcd.backlight();

  lcd_display();
  Serial.println("Hello, Arduino");
}

void loop() {
  game();
  // if(digitalRead(button_white) != HIGH){
  //   int t1 = millis();
  //   call();
  //   int t2 = millis();
  //   Serial.println(t2-t1);
  //   delay(100);
  // }
}

void call(){
  recordHashmap();
  Serial.println("map recorded");

  printHashmap();
  Serial.println("map printed");
  // this speeds up the simulation
}

bool button(byte type){
  if(type==WHITE && digitalRead(button_white)!=HIGH){
    return true;
  }
  if(type==BLACK && digitalRead(button_black)!=HIGH){
    return true;
  }
  return false;
}
void game(){
  switch(key){
    case start:
      if(button(WHITE)){
        if(initialCheck()){
          key = player_white;
        }
        else{
          lcd_display();
        }
      }
      break;
    case player_white:
      if(millis()-timer>995){
        // delay(1000);
        countdown();
        lcd_display();
      }
      if(button(WHITE)){
        new_turn_countdown=true;
        call();
        key = player_black;
      }
      break;

    case player_black:
      if(millis()-timer>995){
        // delay(1000);
        countdown();
        lcd_display();
      }
      if(button(BLACK)){
        new_turn_countdown=true;
        call();
        key = player_white;
      }
      break;

  }
}


void recordHashmap(){
  int column = 0;
  int row = 0;

  for(int mux=0; mux<4; mux++){
    digitalWrite(MUX_SELECT[mux], LOW);
    delay(100);
    for(int channel=0; channel<16; channel++){
      for(int i=0; i<4; i++){
        digitalWrite(MUX_ADDR[i], MUX_CHANNEL[channel][i]);
      }
      delay(20);
      // Serial.print("Channel: ");
      // Serial.print(channel);
      // Serial.print(" Row: ");
      // Serial.print(row);
      // Serial.print(" Column: ");
      // Serial.print(column);
      // Serial.print(" Value: ");
      int res = digitalRead(MUX_OUTPUT[mux]);
      // Serial.println(res);
      reed_sensor_record[row][column] = res;
      column++;
      if(column >= 8){
        row++;
        column = 0;
      }
    }

    for(int j=0; j<4; j++){
      digitalWrite(MUX_SELECT[j], HIGH);
    }
  }

  for(byte i=0; i<8; i++){
    for(byte j=0; j<8; j++){
      if(reed_sensor_record[i][j] != reed_sensor_status[i][j]){
        if(reed_sensor_record[i][j] == 0){
          reed_row[0] = 8-i;
          reed_column[0] = 'a' + j;
        }
        else{
          reed_row[1] = 8-i;
          reed_column[1] = 'a' + j;
        }
      }
    }
  }
  for(byte i=0; i<8; i++){
    for(byte j=0; j<8; j++){
      reed_sensor_status[i][j] = reed_sensor_record[i][j];
    }
  }


}



void printHashmap(){
  for(int i=0; i<8; i++){
    for(int j=0; j<8; j++){
      Serial.print(reed_sensor_record[i][j]);
      Serial.print(" ");
    }
    Serial.println("");
  }
  Serial.print("Departed from: ");
  Serial.print(reed_row[0]);
  Serial.println(reed_column[0]);

  Serial.print("Arrived at: ");
  Serial.print(reed_row[1]);
  Serial.println(reed_column[1]);
}


bool initialCheck(){
  recordHashmap();
  if(reed_row[0]==-1 && reed_row[1]==-1){
    return true;
  }
  for(int i=0; i<2; i++){
    for(int j=0; j<8; j++){
      reed_sensor_record[i][j] = 1;
      reed_sensor_status[i][j] = 1;
    }
  }
  for(int i=2; i<6; i++){
    for(int j=0; j<8; j++){
      reed_sensor_record[i][j] = 0;
      reed_sensor_status[i][j] = 0;
    }
  }
  for(int i=6; i<8; i++){
    for(int j=0; j<8; j++){
      reed_sensor_record[i][j] = 1;
      reed_sensor_status[i][j] = 1;
    }
  }
  reed_row[0] = -1; 
  reed_row[1] = -1;
  return false;
}


void countdown(){
  if (new_turn_countdown == true ) {
    new_turn_countdown = false;
    if (key == player_white) {
      second = second_white;
      minute = minute_white;
    }
    else if (key == player_black) {
      second = second_black;
      minute = minute_black;
    }
  }

  //countdown
  timer = millis();
  second-=1;
  if(second<1){
    second=60;
    minute-=1;
  }

  //  Record the white player time
  if (key == player_white) {
    second_white = second;
    minute_white = minute;
  }

  //  Record the black player time
  else if (key == player_black) {
    second_black = second;
    minute_black = minute;
  }
  
}


void lcd_display(){
  switch(key){
    case start_up:
      lcd.setCursor(0, 0);
      lcd.print("   AUTOMATIC    ");
      lcd.setCursor(0, 1);
      lcd.print("   CHESSBOARD   ");
      delay(4000);
      lcd.setCursor(0,0);
      lcd.print("   PRESS WHITE  ");
      lcd.setCursor(0, 1);
      lcd.print(" BUTTON TO START");
      key = start;
      break;

    case start:
      lcd.setCursor(0,0);
      lcd.print("   ARRANGE THE  ");
      lcd.setCursor(0, 1);
      lcd.print(" BOARD CORRECTLY");
      break;

    case player_white:
      lcd.setCursor(0,0);
      lcd.print("  WHITE  BLACK  ");
      lcd.setCursor(0, 1);
      lcd.print("   "+String(minute_white)+ ":" + String(second_white) + "   " + String(minute_black)+ ":" + String(second_black) + "  ");
      break;
    
    case player_black:
      lcd.setCursor(0,0);
      lcd.print("  WHITE  BLACK  ");
      lcd.setCursor(0, 1);
      lcd.print("   "+String(minute_white)+ ":" + String(second_white) + "   " + String(minute_black)+ ":" + String(second_black) + "  ");
      break;


  }



}
$abcdeabcde151015202530354045505560fghijfghij
$abcdeabcde151015202530354045505560fghijfghij
$abcdeabcde151015202530354045505560fghijfghij
$abcdeabcde151015202530354045505560fghijfghij
Loading
cd74hc4067
Loading
cd74hc4067
Loading
cd74hc4067
Loading
cd74hc4067