//pin defines

#define TURN_OUTPUT  5

#define TURN_INPUT   6

#define SECRET_SAUCE 25        //seeds the random function, change this every time you play a game

//makes it easier to read the code if we enumerate MY_TURN and OPPONENT_TURN

#define MY_TURN           0            

#define OPPONENT_TURN 1

//tokens for the playfield to tell who took a spot

#define MY_MOVE   1

#define OPP_MOVE  -1

//timeout error

#define ERROR_FLAG 0

char i;

char j;

char oppI;

char oppJ;

int turn;

int field[3][3];

int errorCatchI;

int errorCatchJ;

void setup()

{

  //initialize pins and modules  

  Serial.begin(9600);

  Serial.setTimeout(1000);                //sets how long Serial.readBytes will last before it triggers a timeout

  pinMode(TURN_OUTPUT, OUTPUT);  

  pinMode(TURN_INPUT, INPUT);

  //clear field

  for(i=0; i< 3; i++)

        for(j = 0; j<3; field[i][j++] = 0);

  //decide who goes first

  establishContact();

}

void loop()

{

  if(turn == MY_TURN && !digitalRead(TURN_INPUT))

  {

        //find open space

        for(i = 0; i <= 2; i++)

        {

          for(j= 0; field[i][j] != 0 && j < 2; j++);

          if(!field[i][j])break;

        }

   

        //check to make sure all open spaces aren't taken or that we haven't gone outside the playfield

        if(field[i][j] || i > 2 || j > 2)

        {

          Serial.println();

          Serial.print("Game Over");

          while(1); //end game stop here on infinite loop

        }

        //set move on field

        field[i][j] = MY_MOVE;

        //send move to opponent

        Serial.write(i);

        Serial.write(j);

   

        //set to the opponets turn

        turn = OPPONENT_TURN;

        digitalWrite(TURN_OUTPUT, turn);

  }

  else if(turn == OPPONENT_TURN && digitalRead(TURN_INPUT))

  {

        //get opponents move, I used readBytes() instead of read() because it handles timeouts without extra code

         errorCatchI = Serial.readBytes( &oppI, 1);

         errorCatchJ = Serial.readBytes( &oppJ, 1);

         

         //check to see that we didn't get a timeout error

         if(errorCatchI == ERROR_FLAG || errorCatchJ == ERROR_FLAG)

         {

           Serial.println();

           Serial.print("I wiated for one whole second and you didn't send me anything!");

           while(1); //stop here on error

         }

         

         //check to make sure the space is open and they havent gone outside the playfield

        if(field[oppI][oppJ] || oppI > 2 || oppJ > 2)

        {

          Serial.println();

          Serial.println("Spot is outside the playfield or already taken!");

          Serial.println("The game may have ended.");

          Serial.println(oppI);

          Serial.println(oppJ);

          while(1); //end game, infinite loop

        }

   

        //set their move on the field

        field[oppI][oppJ] = OPP_MOVE;

   

        //set to my turn

        turn = MY_TURN;

        digitalWrite(TURN_OUTPUT, turn);

  }

  else

  {

        //you get here if you have changed your turn pin but your opponent hasn't

        //or vise-versa

  }

}

void establishContact(void)

{

  int myScore,

          oppScore;

  //generate a random number to see who goes first    

  randomSeed(SECRET_SAUCE);          

  myScore = random(0,255);

  //send my random number every 100ms until I recieve some data over the UART

  while (Serial.available() <= 0) {

        Serial.print(myScore);        //send my Score

        delay(100);

  }

  oppScore = Serial.read();

  //decide if it's my turn

  if(myScore > oppScore)

        turn = MY_TURN;

  else

        turn = OPPONENT_TURN;

  digitalWrite(TURN_OUTPUT, turn);

}