Arduino Application Development Procedure Part-5

Previously in Arduino Application Development Procedure Part-4, I provided commentary on my code for taking turns between players in Tic-Tac-Toe. In this stage, I will provide the finished code and some commentary if needed. Figuring out winning wasn’t as difficult as figuring out how to reset the game at the end. Again, I will be providing sections of code for readability and will provide a zipped folder of the finished code. Even though this final program works, in the end, I added a few more features but kept a majority of the code.

Section One: Global Variables

... //I am just shortening the initial code in this snippet, everything below flagTurn9P1 is new, nothing else changed
boolean flagTurn1P1 = 0; //variable for turn1 player1, will help with logic so I don't override past turns
boolean flagTurn2P2 = 0; //you can only ever have 9 turns max in a game of tic-tac-toe, need to keep track of who took a turn and where it took place; aslo specific turns exist for specific players in paper tic-tac-toe, so I named them appropriately
boolean flagTurn3P1 = 0;
boolean flagTurn4P2 = 0;
boolean flagTurn5P1 = 0;
boolean flagTurn6P2 = 0;
boolean flagTurn7P1 = 0;
boolean flagTurn8P2 = 0;
boolean flagTurn9P1 = 0;
//new lines below:
boolean p1Win = 0; //flag for checking if p1 wins
boolean p2Win = 0; //flag for checking if p2 wins
boolean gameDraw = 0; //flag for checking if there is a draw
int movePossibleWinsCt = 0; //count for possible wins
int randSeq = 0; //variable for selecting which sequence plays if a player wins
int seqCt = 0; //variable for making the sequence only repeat a few times

Section Two: Main Loop

Nothing changed in the setup code, I still kept Serial.begin(9600) included because it was important to debugging.

//changed the first if statement to include p1Win, p2Win, and game draw flags for resetting purposes
if (ttt1[0][0] == 0 && ttt1[0][1] == 0 && ttt1[0][2] == 0 && ttt1[1][0] == 0 && ttt1[1][1] == 0 && ttt1[1][2] == 0 && ttt1[2][0] ==  0 && ttt1[2][1] == 0 && ttt1[2][2] == 0 && lightCount == 0 && playerSw == 0 && p1Win == 0 && p2Win == 0 && gameDraw == 0) {
    updateMatrix(); //update the appropriate 3x3 matrix by reading the input for buttons for all positions, see updateMatrix function below
    randSeq = random(1, 5); //generate a new random number as long as ttt1 is empty
    startSeq();
  } else { //as soon as one of the values changes the game has begun
    if (lightCount == 0) { //run the update light FCN once because player one will have made a move, check if no lights are lit yet to run the first function, see updateFirstMove below
      updateFirstMove();
    } else if (lightCount == 1 && flagTurn2P2 != 1 && playerSw == 1) { //check if the light count is 1, make sure the flag for Player 2 for this turn is not set yet and make sure the right player is playing; 1RED ON
      buttonPressAndMatrixUp(playerSw, lightCount); //check if buttons are pressed, update appropriate matrices, uses current player and lightCount as arguments, see function below
      randSeq = random(1, 5); //generate a new random number if light count = 1, do this before one person can win each time
    } else if (lightCount == 2 && flagTurn3P1 != 1 && playerSw == 0) { //each turn has a pattern, check current light count, make sure appropriate turn flag is not set yet, and make sure right player is playing; 1RED 1BLUE ON 2TOT
      buttonPressAndMatrixUp(playerSw, lightCount);
      randSeq = random(1, 5);
    } else if (lightCount == 3 && flagTurn4P2 != 1 && playerSw == 1) { //2RED 1BLUE 3TOT
      buttonPressAndMatrixUp(playerSw, lightCount);
      randSeq = random(1, 5);
    } else if (lightCount == 4 && flagTurn5P1 != 1 && playerSw == 0) { //2RED 2BLUE 4TOT
      buttonPressAndMatrixUp(playerSw, lightCount);
      randSeq = random(1, 5);
    } else if (lightCount == 5 && flagTurn6P2 != 1 && playerSw == 1) { //this is when player 1 may have made a move to win; 3RED 2BLUE 5TOT
      //NEW CODE BELOW
      p1Win = checkP1Win(); //after count updated to 5, it is possible a player may have one, update p1Win flag
      if (p1Win == 0) { //if they haven't, continue the regular sequence
        buttonPressAndMatrixUp(playerSw, lightCount);
      } else if (p1Win == 1) { //check if the first player won
        turnAllLEDOff(); //turn all the LEDs off (blue and red)
        playerSw = 0; //set the right player (last turn switches the player)
        if (randSeq == 1) { //check which random number 1-4 randSeq last equaled 
          while (seqCt < 3) { //only repeat the sequence three times
            winSeq1(playerSw); //each win sequence takes the player who won to change light colors, I just made up four different sequences, see below function for reference
            seqCt++; //increase the seq count by 1
          }
          if (seqCt == 3) { //after the sequence finishes (seqCt will equal 3), check if any button is left pressed via checkPressedEnd function
            while (checkPressedEnd()) { //as long as something is still pressed, the following functions are called
              checkMatrixAndReset(ttt1, 0); //checks ttt1 to see if there are still values that equal 1
              checkMatrixAndReset(ttt2, 1); //checks ttt2
            }
            resetGame(); //function that only works if every light is off and no matrix positions equal 1
          }
        } else if (randSeq == 2) { //each random sequence gets the same code repeated above, even draw conditions seen below get the same code
          while (seqCt < 3) {
            winSeq2(playerSw);
            seqCt++;
          }
          if (seqCt == 3) {
            while (checkPressedEnd()) {
              checkMatrixAndReset(ttt1, 0);
              checkMatrixAndReset(ttt2, 1);
            }
            resetGame();
          }
        } else if (randSeq == 3) {
          while (seqCt < 3) {
            winSeq3(playerSw);
            seqCt++;
          }
          if (seqCt == 3) {
            while (checkPressedEnd()) {
              checkMatrixAndReset(ttt1, 0);
              checkMatrixAndReset(ttt2, 1);
            }
            resetGame();
          }
        } else if (randSeq == 4) {
          while (seqCt < 3) {
            winSeq4(playerSw);
            seqCt++;
          }
          if (seqCt == 3) {
            while (checkPressedEnd()) {
              checkMatrixAndReset(ttt1, 0);
              checkMatrixAndReset(ttt2, 1);
            }
            resetGame();
          }
        }
      }
    } else if (lightCount == 6 && flagTurn7P1 != 1 && playerSw == 0) { //3RED 3BLUE 6TOT
      p2Win = checkP2Win(); //check if the next player wins
      if (p2Win == 0) { //if not, keep doing regular sequence
        buttonPressAndMatrixUp(playerSw, lightCount);
      } else if (p2Win == 1) { //if win, do something
        turnAllLEDOff();
        playerSw = 1;
        if (randSeq == 1) {
          while (seqCt < 3) {
            winSeq1(playerSw);
            seqCt++;
          }
          if (seqCt == 3) {
            while (checkPressedEnd()) {
              checkMatrixAndReset(ttt1, 0);
              checkMatrixAndReset(ttt2, 1);
            }
            resetGame();
          }
        } else if (randSeq == 2) {
          while (seqCt < 3) {
            winSeq2(playerSw);
            seqCt++;
          }
          if (seqCt == 3) {
            while (checkPressedEnd()) {
              checkMatrixAndReset(ttt1, 0);
              checkMatrixAndReset(ttt2, 1);
            }
            resetGame();
          }
        } else if (randSeq == 3) {
          while (seqCt < 3) {
            winSeq3(playerSw);
            seqCt++;
          }
          if (seqCt == 3) {
            while (checkPressedEnd()) {
              checkMatrixAndReset(ttt1, 0);
              checkMatrixAndReset(ttt2, 1);
            }
            resetGame();
          }
        } else if (randSeq == 4) {
          while (seqCt < 3) {
            winSeq4(playerSw);
            seqCt++;
          }
          if (seqCt == 3) {
            while (checkPressedEnd()) {
              checkMatrixAndReset(ttt1, 0);
              checkMatrixAndReset(ttt2, 1);
            }
            resetGame();
          }
        }
      }
    } else if (lightCount == 7 && flagTurn8P2 != 1 && playerSw == 1) { //4RED 3BLUE 7TOT
      p1Win = checkP1Win(); //again check if next player won
      movePossibleWinsCt = checkPlayerCanMoveToWin(lightCount, playerSw); //also check if any moves can be played next turn that results in a win
      if (p1Win == 0 && movePossibleWinsCt > 0) { //if there are moves to win by either player and p1 hasn't won, continue the sequence
        buttonPressAndMatrixUp(playerSw, lightCount);
      } else if (p1Win == 1) { //if the player1 wins, do something
        turnAllLEDOff();
        playerSw = 0;
        if (randSeq == 1) {
          while (seqCt < 3) {
            winSeq1(playerSw);
            seqCt++;
          }
          if (seqCt == 3) {
            while (checkPressedEnd()) {
              checkMatrixAndReset(ttt1, 0);
              checkMatrixAndReset(ttt2, 1);
            }
            resetGame();
          }
        } else if (randSeq == 2) {
          while (seqCt < 3) {
            winSeq2(playerSw);
            seqCt++;
          }
          if (seqCt == 3) {
            while (checkPressedEnd()) {
              checkMatrixAndReset(ttt1, 0);
              checkMatrixAndReset(ttt2, 1);
            }
            resetGame();
          }
        } else if (randSeq == 3) {
          while (seqCt < 3) {
            winSeq3(playerSw);
            seqCt++;
          }
          if (seqCt == 3) {
            while (checkPressedEnd()) {
              checkMatrixAndReset(ttt1, 0);
              checkMatrixAndReset(ttt2, 1);
            }
            resetGame();
          }
        } else if (randSeq == 4) {
          while (seqCt < 3) {
            winSeq4(playerSw);
            seqCt++;
          }
          if (seqCt == 3) {
            while (checkPressedEnd()) {
              checkMatrixAndReset(ttt1, 0);
              checkMatrixAndReset(ttt2, 1);
            }
            resetGame();
          }
        }
      } else if (movePossibleWinsCt == 0) { //if there are no possible wins, do something for a draw, 7 moves it is possible to determine if there are moves left
        gameDraw = 1; //update gameDraw flag to 1, will do something with this in the "reset" phase
        turnAllLEDOff(); //turn all the LEDs off
        while (seqCt < 3) {
          drawSeq(); //special sequence of lights for a draw
          seqCt++;
        }
        if (seqCt == 3) {
            while (checkPressedEnd()) {
              checkMatrixAndReset(ttt1, 0);
              checkMatrixAndReset(ttt2, 1);
            }
            resetGame();
          }
      }
    } else if (lightCount == 8 && flagTurn9P1 != 1 && playerSw == 0) { //4RED 4BLUE 8TOT
      p2Win = checkP2Win(); //check if next player won
      movePossibleWinsCt = 0; //reset movePossibleWinsCt back to 0 (may have changed above)
      movePossibleWinsCt = checkPlayerCanMoveToWin(lightCount, playerSw); //check if possible after 8 lights if one can win
      if (p2Win == 0 && movePossibleWinsCt > 0) { //if p2 still hasn't won and it is possible for p1 to win, continue sequence
        buttonPressAndMatrixUp(playerSw, lightCount);
      } else if (p2Win == 1) { //do something if p2 wins
        turnAllLEDOff();
        playerSw = 1;
        if (randSeq == 1) {
          while (seqCt < 3) {
            winSeq1(playerSw);
            seqCt++;
          }
          if (seqCt == 3) {
            while (checkPressedEnd()) {
              checkMatrixAndReset(ttt1, 0);
              checkMatrixAndReset(ttt2, 1);
            }
            resetGame();
          }
        } else if (randSeq == 2) {
          while (seqCt < 3) {
            winSeq2(playerSw);
            seqCt++;
          }
          if (seqCt == 3) {
            while (checkPressedEnd()) {
              checkMatrixAndReset(ttt1, 0);
              checkMatrixAndReset(ttt2, 1);
            }
            resetGame();
          }
        } else if (randSeq == 3) {
          while (seqCt < 3) {
            winSeq3(playerSw);
            seqCt++;
          }
          if (seqCt == 3) {
            while (checkPressedEnd()) {
              checkMatrixAndReset(ttt1, 0);
              checkMatrixAndReset(ttt2, 1);
            }
            resetGame();
          }
        } else if (randSeq == 4) {
          while (seqCt < 3) {
            winSeq4(playerSw);
            seqCt++;
          }
          if (seqCt == 3) {
            while (checkPressedEnd()) {
              checkMatrixAndReset(ttt1, 0);
              checkMatrixAndReset(ttt2, 1);
            }
            resetGame();
          }
        }
      } else if (movePossibleWinsCt == 0) { //if no possible moves to win, do somehting for a draw
        gameDraw = 1;
        turnAllLEDOff();
        while (seqCt < 3) {
          drawSeq();
          seqCt++;
        }
        if (seqCt == 3) {
            while (checkPressedEnd()) {
              checkMatrixAndReset(ttt1, 0);
              checkMatrixAndReset(ttt2, 1);
            }
            resetGame();
          }
      }
    } else if (lightCount == 9) { //last possible light count to check
      p1Win = checkP1Win(); //again, someone might make a mistake by chance, check if p1Wins
      if (p1Win == 0) { //if p1 doesn't win by mistake, set movePossibleWinsCt to 0
        movePossibleWinsCt = 0;
      } else if (p1Win == 1) { //do something if p1 wins which is most likely to happen
        turnAllLEDOff();
        playerSw = 0;
        if (randSeq == 1) {
          while (seqCt < 3) {
            winSeq1(playerSw);
            seqCt++;
          }
          if (seqCt == 3) {
            while (checkPressedEnd()) {
              checkMatrixAndReset(ttt1, 0);
              checkMatrixAndReset(ttt2, 1);
            }
            resetGame();
          }
        } else if (randSeq == 2) {
          while (seqCt < 3) {
            winSeq2(playerSw);
            seqCt++;
          }
          if (seqCt == 3) {
            while (checkPressedEnd()) {
              checkMatrixAndReset(ttt1, 0);
              checkMatrixAndReset(ttt2, 1);
            }
            resetGame();
          }
        } else if (randSeq == 3) {
          while (seqCt < 3) {
            winSeq3(playerSw);
            seqCt++;
          }
          if (seqCt == 3) {
            while (checkPressedEnd()) {
              checkMatrixAndReset(ttt1, 0);
              checkMatrixAndReset(ttt2, 1);
            }
            resetGame();
          }
        } else if (randSeq == 4) {
          while (seqCt < 3) {
            winSeq4(playerSw);
            seqCt++;
          }
          if (seqCt == 3) {
            while (checkPressedEnd()) {
              checkMatrixAndReset(ttt1, 0);
              checkMatrixAndReset(ttt2, 1);
            }
            resetGame();
          }
        }
      } else if (movePossibleWinsCt == 0) { //again, it is possible to draw if someone made a mistake
        gameDraw = 1;
        turnAllLEDOff();
        while (seqCt < 3) {
          drawSeq();
          seqCt++;
        }
        if (seqCt == 3) {
            while (checkPressedEnd()) {
              checkMatrixAndReset(ttt1, 0);
              checkMatrixAndReset(ttt2, 1);
            }
            resetGame();
          }
      }
    }
  }
}

My only comment on this lengthy section is I could have made it much shorter by using better functions. However, sometimes turning certain repeated code into functions is a difficult process in testing and debugging. I would run into unusual problems where certain variables would not get updated and some loops broke without me knowing what broke them. The hardest bug to fix is one that you don’t know what is causing it.

Section Three: Additional Functions

Everything after the “turnLightUp()” function was new, so I just copied the code I have below.

//simple function that returns true or false (1 or 0) if p1 wins, doesn't accept any input parameters
boolean checkP1Win() {
  //setup variables for rows and columns and local variable for setting if winning
  int r1 = 0;
  int r2 = 1;
  int r3 = 2;
  int c1 = 0;
  int c2 = 1;
  int c3 = 2;
  boolean p1WinFlag = 0;
  //the if statement below literally just checks all the valid ways you can win at TIC-TAC-TOE; 3 lights are required and the || (or symbol) separates each three light check; parenthesis between the || are REQUIRED
  if ((ttt1[r1][c1] == 1 && ttt1[r1][c2] == 1 && ttt1[r1][c3] == 1) || (ttt1[r2][c1] == 1 && ttt1[r2][c2] == 1 && ttt1[r2][c3] == 1) || (ttt1[r3][c1] == 1 && ttt1[r3][c2] == 1 && ttt1[r3][c3] == 1) || (ttt1[r1][c1] == 1 && ttt1[r2][c1] == 1 && ttt1[r3][c1] == 1) || (ttt1[r1][c2] == 1 && ttt1[r2][c2] == 1 && ttt1[r3][c2] == 1) || (ttt1[r1][c3] == 1 && ttt1[r2][c3] == 1 && ttt1[r3][c3] == 1) || (ttt1[r1][c1] == 1 && ttt1[r2][c2] == 1 && ttt1[r3][c3] == 1) || (ttt1[r1][c3] == 1 && ttt1[r2][c2] == 1 && ttt1[r3][c1] == 1)) {
    p1WinFlag = 1; //update the p1WinFlag to 1
    return p1WinFlag; //return the value of p1WinFlag (will need a variable in the main loop to set it equal to
  } else { //if none of the valid win conditions are met, return the default value of p1WinFlag : 0
    return p1WinFlag;
  }
}
//this function is the same as the previous one, it just checks ttt2 because it belongs to player 2
boolean checkP2Win() {
  int r1 = 0;
  int r2 = 1;
  int r3 = 2;
  int c1 = 0;
  int c2 = 1;
  int c3 = 2;
  boolean p2WinFlag = 0;
  if ((ttt2[r1][c1] == 1 && ttt2[r1][c2] == 1 && ttt2[r1][c3] == 1) || (ttt2[r2][c1] == 1 && ttt2[r2][c2] == 1 && ttt2[r2][c3] == 1) || (ttt2[r3][c1] == 1 && ttt2[r3][c2] == 1 && ttt2[r3][c3] == 1) || (ttt2[r1][c1] == 1 && ttt2[r2][c1] == 1 && ttt2[r3][c1] == 1) || (ttt2[r1][c2] == 1 && ttt2[r2][c2] == 1 && ttt2[r3][c2] == 1) || (ttt2[r1][c3] == 1 && ttt2[r2][c3] == 1 && ttt2[r3][c3] == 1) || (ttt2[r1][c1] == 1 && ttt2[r2][c2] == 1 && ttt2[r3][c3] == 1) || (ttt2[r1][c3] == 1 && ttt2[r2][c2] == 1 && ttt2[r3][c1] == 1)) {
    p2WinFlag = 1;
    return p2WinFlag;
  } else {
    return p2WinFlag;
  }
}
//following function simulates valid "plays" between players to see if there are possible ways to win still (this allows a Draw condition); accepts light count and player
/*
   Note: I had tried to check if players could make any move based on if there were already two lights in any valid sequence and one "empty" spot, this did not work because
   it would always return true because there are always lights that are not for the next turn (not at 9 obviously). I scrapped that idea and thought: "Hey why not temporarily
   fill up the matrix of each player to see if one of them can win? That would be easier."
*/
int checkPlayerCanMoveToWin(int lc, bool pl) {
  boolean tempWinP1 = 0; //set a flag for a temporary Win Status for player 1
  boolean tempWinP2 = 0; //set a flag for temporary win status for player 2
  int countWins = 0; //this variable counts the number of times any player can potentially win, will return what this value is; in main loop, if this is greater than 0 then there isn't a draw, if it is equal, then it is a draw because no player can win
  for (int i = 0; i < rows; i++) { //loop through the matrices again using row and column "for()" method
    for (int j = 0; j < columns; j++) {
      if (ttt1[i][j] == 1 || ttt2[i][j] == 1) { //again need to fill empty positions in either matrix, don't overwrite existing ones and don't put a 1 where a different matrix already equals 1

      } else if (ttt1[i][j] == 0 && ttt2[i][j] == 0) { //redundant check to make sure both spots in matrix 1 and 2 equal 0
        if (lc == 7 && pl == 1) { //after 7 lights it is possible to determine a "draw" state; 6 lights has too many ways and is indeterminate, make sure right player is referenced
          ttt1[i][j] = 1; //temporarily set matrix 1 position equal to 1
          ttt2[i][j] = 1; //player2 can also potentially still win, set matrix 2 position equal to 1
          tempWinP1 = checkP1Win(); //update tempWinP1 by using function checkP1Win after ttt1 has been updated
          tempWinP2 = checkP2Win(); //do the same thing with tempWinP2
          if (tempWinP1 == 1 || tempWinP2 == 1) { //if either tempWin flag equals 1, increase the count by 1
            countWins++;
          } else { //otherwise, don't update the countAmount
            countWins = countWins;
          }
          ttt1[i][j] = 0; //reset the position back to 0, don't want to mess up the regular turn sequence
          ttt2[i][j] = 0; //same thing for player 2
          tempWinP1 = 0; //reset the flag for p1
          tempWinP2 = 0; //same thing for p2
        } else if (lc == 8 && pl == 0) { //check if the light count is 8 (only one player can make a move which is player 1)
          ttt1[i][j] = 1; //temporarily set ttt1 position to 1
          tempWinP1 = checkP1Win(); //check if P1 can win
          if (tempWinP1 == 1) { //if they can, increase count by 1
            countWins++;
          } else { //if they can't, keep it the same
            countWins = countWins;
          }
          ttt1[i][j] = 0; //reset ttt1 position back to 0
          tempWinP1 = 0; //reset flag back to 0
        }
      }
    }
  }
  return countWins; //return the amount that countWin has either incremented by or stayed the same
  countWins = 0; //reset countWin in the function to start from scratch the next time the function is used
}
//turn all LEDs off for light sequences
void turnAllLEDOff() {
  digitalWrite(RR1C1, LOW);
  digitalWrite(RR1C2, LOW);
  digitalWrite(RR1C3, LOW);
  digitalWrite(RR2C1, LOW);
  digitalWrite(RR2C2, LOW);
  digitalWrite(RR2C3, LOW);
  digitalWrite(RR3C1, LOW);
  digitalWrite(RR3C2, LOW);
  digitalWrite(RR3C3, LOW);
  digitalWrite(BR1C1, LOW);
  digitalWrite(BR1C2, LOW);
  digitalWrite(BR1C3, LOW);
  digitalWrite(BR2C1, LOW);
  digitalWrite(BR2C2, LOW);
  digitalWrite(BR2C3, LOW);
  digitalWrite(BR3C1, LOW);
  digitalWrite(BR3C2, LOW);
  digitalWrite(BR3C3, LOW);
}
//light sequence one, change light colors based on player that won
void winSeq1(bool pl) {
  if (pl == 0) {
    digitalWrite(RR1C1, HIGH);
    delay(100);
    digitalWrite(RR2C2, HIGH);
    delay(100);
    digitalWrite(RR3C3, HIGH);
    delay(100);
    digitalWrite(RR3C2, HIGH);
    digitalWrite(RR2C3, HIGH);
    delay(100);
    digitalWrite(RR3C2, LOW);
    digitalWrite(RR2C3, LOW);
    delay(100);
    digitalWrite(RR3C1, HIGH);
    digitalWrite(RR1C3, HIGH);
    delay(500);
    digitalWrite(RR1C1, LOW);
    digitalWrite(RR1C3, LOW);
    digitalWrite(RR2C2, LOW);
    digitalWrite(RR3C1, LOW);
    digitalWrite(RR3C3, LOW);
    delay(500);
    digitalWrite(RR1C1, HIGH);
    digitalWrite(RR1C3, HIGH);
    digitalWrite(RR2C2, HIGH);
    digitalWrite(RR3C1, HIGH);
    digitalWrite(RR3C3, HIGH);
    delay(500);
    digitalWrite(RR1C1, LOW);
    digitalWrite(RR1C3, LOW);
    digitalWrite(RR2C2, LOW);
    digitalWrite(RR3C1, LOW);
    digitalWrite(RR3C3, LOW);
    delay(500);
    digitalWrite(RR1C1, HIGH);
    digitalWrite(RR1C3, HIGH);
    digitalWrite(RR2C2, HIGH);
    digitalWrite(RR3C1, HIGH);
    digitalWrite(RR3C3, HIGH);
    delay(500);
    digitalWrite(RR1C1, LOW);
    digitalWrite(RR1C3, LOW);
    digitalWrite(RR2C2, LOW);
    digitalWrite(RR3C1, LOW);
    digitalWrite(RR3C3, LOW);
    delay(1000);
  } else if (pl == 1) {
    digitalWrite(BR1C1, HIGH);
    delay(200);
    digitalWrite(BR1C2, HIGH);
    digitalWrite(BR2C1, HIGH);
    delay(200);
    digitalWrite(BR1C3, HIGH);
    digitalWrite(BR3C1, HIGH);
    delay(200);
    digitalWrite(BR2C3, HIGH);
    digitalWrite(BR3C2, HIGH);
    delay(200);
    digitalWrite(BR3C3, HIGH);
    delay(500);
    digitalWrite(BR1C1, LOW);
    digitalWrite(BR1C2, LOW);
    digitalWrite(BR1C3, LOW);
    digitalWrite(BR2C1, LOW);
    digitalWrite(BR2C3, LOW);
    digitalWrite(BR3C1, LOW);
    digitalWrite(BR3C2, LOW);
    digitalWrite(BR3C3, LOW);
    delay(500);
    digitalWrite(BR1C1, HIGH);
    digitalWrite(BR1C2, HIGH);
    digitalWrite(BR1C3, HIGH);
    digitalWrite(BR2C1, HIGH);
    digitalWrite(BR2C3, HIGH);
    digitalWrite(BR3C1, HIGH);
    digitalWrite(BR3C2, HIGH);
    digitalWrite(BR3C3, HIGH);
    delay(500);
    digitalWrite(BR1C1, LOW);
    digitalWrite(BR1C2, LOW);
    digitalWrite(BR1C3, LOW);
    digitalWrite(BR2C1, LOW);
    digitalWrite(BR2C3, LOW);
    digitalWrite(BR3C1, LOW);
    digitalWrite(BR3C2, LOW);
    digitalWrite(BR3C3, LOW);
    delay(500);
    digitalWrite(BR1C1, HIGH);
    digitalWrite(BR1C2, HIGH);
    digitalWrite(BR1C3, HIGH);
    digitalWrite(BR2C1, HIGH);
    digitalWrite(BR2C3, HIGH);
    digitalWrite(BR3C1, HIGH);
    digitalWrite(BR3C2, HIGH);
    digitalWrite(BR3C3, HIGH);
    delay(500);
    digitalWrite(BR1C1, LOW);
    digitalWrite(BR1C2, LOW);
    digitalWrite(BR1C3, LOW);
    digitalWrite(BR2C1, LOW);
    digitalWrite(BR2C3, LOW);
    digitalWrite(BR3C1, LOW);
    digitalWrite(BR3C2, LOW);
    digitalWrite(BR3C3, LOW);
    delay(1000);
  }
}
//light sequence 2, change light colors based on player that won
void winSeq2(bool pl) {
  int randL = 0;
  int rep = 0;
  if (pl == 0) {
    while (rep < 20) {
      randL = random(1, 10);
      switch (randL) {
        case 1:
          digitalWrite(RR1C1, HIGH);
          delay(100);
          digitalWrite(RR1C1, LOW);
          delay(100);
          break;
        case 2:
          digitalWrite(RR1C2, HIGH);
          delay(100);
          digitalWrite(RR1C2, LOW);
          delay(100);
          break;
        case 3:
          digitalWrite(RR1C3, HIGH);
          delay(100);
          digitalWrite(RR1C3, LOW);
          delay(100);
          break;
        case 4:
          digitalWrite(RR2C1, HIGH);
          delay(100);
          digitalWrite(RR2C1, LOW);
          delay(100);
          break;
        case 5:
          digitalWrite(RR2C2, HIGH);
          delay(100);
          digitalWrite(RR2C2, LOW);
          delay(100);
          break;
        case 6:
          digitalWrite(RR2C3, HIGH);
          delay(100);
          digitalWrite(RR2C3, LOW);
          delay(100);
          break;
        case 7:
          digitalWrite(RR3C1, HIGH);
          delay(100);
          digitalWrite(RR3C1, LOW);
          delay(100);
          break;
        case 8:
          digitalWrite(RR3C2, HIGH);
          delay(100);
          digitalWrite(RR3C2, LOW);
          delay(100);
          break;
        case 9:
          digitalWrite(RR3C3, HIGH);
          delay(100);
          digitalWrite(RR3C3, LOW);
          delay(100);
          break;
        default:

          break;
      }
      rep++;
    }
    delay(500);
    digitalWrite(RR2C2, HIGH);
    delay(500);
    digitalWrite(RR2C2, LOW);
    delay(1000);
  } else if (pl == 1) {
    while (rep < 20) {
      randL = random(1, 10);
      switch (randL) {
        case 1:
          digitalWrite(BR1C1, HIGH);
          delay(100);
          digitalWrite(BR1C1, LOW);
          delay(100);
          break;
        case 2:
          digitalWrite(BR1C2, HIGH);
          delay(100);
          digitalWrite(BR1C2, LOW);
          delay(100);
          break;
        case 3:
          digitalWrite(BR1C3, HIGH);
          delay(100);
          digitalWrite(BR1C3, LOW);
          delay(100);
          break;
        case 4:
          digitalWrite(BR2C1, HIGH);
          delay(100);
          digitalWrite(BR2C1, LOW);
          delay(100);
          break;
        case 5:
          digitalWrite(BR2C2, HIGH);
          delay(100);
          digitalWrite(BR2C2, LOW);
          delay(100);
          break;
        case 6:
          digitalWrite(BR2C3, HIGH);
          delay(100);
          digitalWrite(BR2C3, LOW);
          delay(100);
          break;
        case 7:
          digitalWrite(BR3C1, HIGH);
          delay(100);
          digitalWrite(BR3C1, LOW);
          delay(100);
          break;
        case 8:
          digitalWrite(BR3C2, HIGH);
          delay(100);
          digitalWrite(BR3C2, LOW);
          delay(100);
          break;
        case 9:
          digitalWrite(BR3C3, HIGH);
          delay(100);
          digitalWrite(BR3C3, LOW);
          delay(100);
          break;
        default:

          break;
      }
      rep++;
    }
    delay(500);
    digitalWrite(BR2C2, HIGH);
    delay(500);
    digitalWrite(BR2C2, LOW);
    delay(1000);
  }
}
//light sequence 3, change light color based on player that won
void winSeq3(bool pl) {
  if (pl == 1) {
    digitalWrite(RR3C3, HIGH);
    digitalWrite(BR1C1, HIGH);
    delay(200);
    digitalWrite(BR2C1, HIGH);
    delay(200);
    digitalWrite(BR1C1, LOW);
    digitalWrite(BR2C2, HIGH);
    delay(200);
    digitalWrite(BR2C3, HIGH);
    digitalWrite(BR2C1, LOW);
    delay(200);
    digitalWrite(BR1C3, HIGH);
    digitalWrite(BR2C2, LOW);
    delay(200);
    digitalWrite(BR1C2, HIGH);
    digitalWrite(BR2C3, LOW);
    delay(200);
    digitalWrite(BR2C2, HIGH);
    digitalWrite(BR1C3, LOW);
    delay(200);
    digitalWrite(BR3C2, HIGH);
    digitalWrite(BR1C2, LOW);
    delay(200);
    digitalWrite(BR3C3, HIGH);
    digitalWrite(BR2C2, LOW);
    delay(200);
    digitalWrite(RR3C3, LOW);
    digitalWrite(BR3C1, HIGH);
    delay(200);
    digitalWrite(BR2C3, HIGH);
    delay(200);
    digitalWrite(BR1C3, HIGH);
    delay(200);
    digitalWrite(BR1C2, HIGH);
    digitalWrite(BR2C2, HIGH);
    delay(200);
    digitalWrite(BR2C1, HIGH);
    digitalWrite(BR1C1, HIGH);
    delay(200);
    digitalWrite(BR3C1, HIGH);
    delay(500);
    turnAllLEDOff();
    delay(1000);
  } else if (pl == 0) {
    digitalWrite(BR3C3, HIGH);
    digitalWrite(RR1C1, HIGH);
    delay(200);
    digitalWrite(RR2C1, HIGH);
    delay(200);
    digitalWrite(RR1C1, LOW);
    digitalWrite(RR2C2, HIGH);
    delay(200);
    digitalWrite(RR2C3, HIGH);
    digitalWrite(RR2C1, LOW);
    delay(200);
    digitalWrite(RR1C3, HIGH);
    digitalWrite(RR2C2, LOW);
    delay(200);
    digitalWrite(RR1C2, HIGH);
    digitalWrite(RR2C3, LOW);
    delay(200);
    digitalWrite(RR2C2, HIGH);
    digitalWrite(RR1C3, LOW);
    delay(200);
    digitalWrite(RR3C2, HIGH);
    digitalWrite(RR1C2, LOW);
    delay(200);
    digitalWrite(RR3C3, HIGH);
    digitalWrite(RR2C2, LOW);
    delay(200);
    digitalWrite(BR3C3, LOW);
    digitalWrite(RR3C1, HIGH);
    delay(200);
    digitalWrite(RR2C3, HIGH);
    delay(200);
    digitalWrite(RR1C3, HIGH);
    delay(200);
    digitalWrite(RR1C2, HIGH);
    digitalWrite(RR2C2, HIGH);
    delay(200);
    digitalWrite(RR2C1, HIGH);
    digitalWrite(RR1C1, HIGH);
    delay(200);
    digitalWrite(RR3C1, HIGH);
    delay(500);
    turnAllLEDOff();
    delay(1000);
  }
}
//light sequence 3, change color based on player that won
void winSeq4(bool pl) {
  if (pl == 1) {
    digitalWrite(BR1C3, HIGH);
    digitalWrite(BR2C2, HIGH);
    digitalWrite(BR3C1, HIGH);
    delay(300);
    digitalWrite(BR1C3, LOW);
    digitalWrite(BR2C2, LOW);
    digitalWrite(BR3C1, LOW);
    digitalWrite(BR1C1, HIGH);
    digitalWrite(BR2C1, HIGH);
    digitalWrite(BR1C2, HIGH);
    delay(300);
    digitalWrite(BR1C1, LOW);
    digitalWrite(BR2C1, LOW);
    digitalWrite(BR1C2, LOW);
    digitalWrite(BR2C3, HIGH);
    digitalWrite(BR3C2, HIGH);
    digitalWrite(BR3C3, HIGH);
    delay(300);
    digitalWrite(BR2C3, LOW);
    digitalWrite(BR3C2, LOW);
    digitalWrite(BR3C3, LOW);
    digitalWrite(BR1C1, HIGH);
    digitalWrite(BR2C2, HIGH);
    digitalWrite(BR3C3, HIGH);
    delay(300);
    digitalWrite(BR1C1, LOW);
    digitalWrite(BR2C2, LOW);
    digitalWrite(BR3C3, LOW);
    digitalWrite(BR1C3, HIGH);
    digitalWrite(BR1C2, HIGH);
    digitalWrite(BR2C3, HIGH);
    delay(300);
    digitalWrite(BR1C3, LOW);
    digitalWrite(BR1C2, LOW);
    digitalWrite(BR2C3, LOW);
    digitalWrite(BR2C1, HIGH);
    digitalWrite(BR3C1, HIGH);
    digitalWrite(BR3C2, HIGH);
    delay(300);
    digitalWrite(BR2C1, LOW);
    digitalWrite(BR3C1, LOW);
    digitalWrite(BR3C2, LOW);
    delay(1000);
  } else if (pl == 0) {
    digitalWrite(RR1C3, HIGH);
    digitalWrite(RR2C2, HIGH);
    digitalWrite(RR3C1, HIGH);
    delay(300);
    digitalWrite(RR1C3, LOW);
    digitalWrite(RR2C2, LOW);
    digitalWrite(RR3C1, LOW);
    digitalWrite(RR1C1, HIGH);
    digitalWrite(RR2C1, HIGH);
    digitalWrite(RR1C2, HIGH);
    delay(300);
    digitalWrite(RR1C1, LOW);
    digitalWrite(RR2C1, LOW);
    digitalWrite(RR1C2, LOW);
    digitalWrite(RR2C3, HIGH);
    digitalWrite(RR3C2, HIGH);
    digitalWrite(RR3C3, HIGH);
    delay(300);
    digitalWrite(RR2C3, LOW);
    digitalWrite(RR3C2, LOW);
    digitalWrite(RR3C3, LOW);
    digitalWrite(RR1C1, HIGH);
    digitalWrite(RR2C2, HIGH);
    digitalWrite(RR3C3, HIGH);
    delay(300);
    digitalWrite(RR1C1, LOW);
    digitalWrite(RR2C2, LOW);
    digitalWrite(RR3C3, LOW);
    digitalWrite(RR1C3, HIGH);
    digitalWrite(RR1C2, HIGH);
    digitalWrite(RR2C3, HIGH);
    delay(300);
    digitalWrite(RR1C3, LOW);
    digitalWrite(RR1C2, LOW);
    digitalWrite(RR2C3, LOW);
    digitalWrite(RR2C1, HIGH);
    digitalWrite(RR3C1, HIGH);
    digitalWrite(RR3C2, HIGH);
    delay(300);
    digitalWrite(RR2C1, LOW);
    digitalWrite(RR3C1, LOW);
    digitalWrite(RR3C2, LOW);
    delay(1000);
  }
}
//only one sequence for drawing, no specific player applies
void drawSeq() {
  digitalWrite(RR1C1, HIGH);
  delay(300);
  digitalWrite(RR1C2, HIGH);
  digitalWrite(RR2C1, HIGH);
  delay(300);
  digitalWrite(BR3C3, HIGH);
  delay(300);
  digitalWrite(BR3C2, HIGH);
  digitalWrite(BR2C3, HIGH);
  delay(300);
  digitalWrite(RR1C3, HIGH);
  delay(200);
  digitalWrite(RR2C2, HIGH);
  delay(200);
  digitalWrite(RR3C1, HIGH);
  delay(200);
  digitalWrite(RR1C3, LOW);
  digitalWrite(RR2C2, LOW);
  digitalWrite(RR3C1, LOW);
  digitalWrite(BR3C1, HIGH);
  delay(200);
  digitalWrite(BR2C2, HIGH);
  delay(200);
  digitalWrite(BR1C3, HIGH);
  delay(200);
  digitalWrite(BR1C3, LOW);
  digitalWrite(BR2C2, LOW);
  digitalWrite(BR3C1, LOW);
  digitalWrite(RR3C1, HIGH);
  delay(200);
  digitalWrite(RR2C2, HIGH);
  delay(200);
  digitalWrite(RR1C3, HIGH);
  delay(200);
  digitalWrite(BR1C3, HIGH);
  delay(200);
  digitalWrite(BR2C2, HIGH);
  delay(200);
  digitalWrite(BR3C1, HIGH);
  delay(2000);
  turnAllLEDOff();
  delay(1000);
}
//do something while waiting for input, small sequence that shows red X and blue O, repeats until someone plays (small delay to wait for)
void startSeq(){
  digitalWrite(RR1C1, HIGH);
  digitalWrite(RR2C2, HIGH);
  digitalWrite(RR3C3, HIGH);
  digitalWrite(RR1C3, HIGH);
  digitalWrite(RR3C1, HIGH);
  delay(250);
  turnAllLEDOff();
  delay(250);
  digitalWrite(BR1C1, HIGH);
  digitalWrite(BR1C2, HIGH);
  digitalWrite(BR1C3, HIGH);
  digitalWrite(BR2C1, HIGH);
  digitalWrite(BR2C3, HIGH);
  digitalWrite(BR3C1, HIGH);
  digitalWrite(BR3C2, HIGH);
  digitalWrite(BR3C3, HIGH);
  delay(250);
  turnAllLEDOff();
  delay(250);
}
//function that simply returns true or false if there are still buttons pressed after the game is finished (reads all inputs and checks if they are active)
boolean checkPressedEnd() {
  if (digitalRead(R1C1IN) == 1 || digitalRead(R1C2IN) == 1 || digitalRead(R1C3IN) == 1 || digitalRead(R2C1IN) == 1 || digitalRead(R2C2IN) == 1 || digitalRead(R2C3IN) == 1 || digitalRead(R3C1IN) == 1 || digitalRead(R3C2IN) == 1 || digitalRead(R3C3IN) == 1) {
    return true;
  } else {
    return false;
  }
}
//function that checks each position in the matrix specified by the first parameter and flashes the corresponding light until the button is pressed to set it back to zero, accepts player since player is tied to light color
void checkMatrixAndReset(bool mat[rows][columns], bool pl) {
  for (int r = 0; r < rows; r++) { //loop through rows and columns again of the specified matrix
    for (int c = 0; c < columns; c++) {
      if (r == 0 && c == 0 && mat[r][c] == 1) { //check each position and check if the position equals 1
        while (mat[r][c] == 1) { //if that position equals one, it will loop until it no longer is equal to 1
          if (pl == 0) { //check player by pl input
            digitalWrite(RR1C1, HIGH);
            delay(100);
            digitalWrite(RR1C1, LOW);
            delay(100); //blink the correct light on and off
            ttt1[r][c] = digitalRead(R1C1IN); //set the right matrix position equal to digitalRead of the corresponding position, as soon as it reads 0, it will end the while loop
          } else if (pl == 1) { //do the same thing for player 2 color
            digitalWrite(BR1C1, HIGH);
            delay(100);
            digitalWrite(BR1C1, LOW);
            delay(100);
            ttt2[r][c] = digitalRead(R1C1IN);
          }
        }
      } else if (r == 0 && c == 1 && mat[r][c] == 1) { //repeat the same thing for each position, it skips ones that are already 0
        while (mat[r][c] == 1) {
          if (pl == 0) {
            digitalWrite(RR1C2, HIGH);
            delay(100);
            digitalWrite(RR1C2, LOW);
            delay(100);
            ttt1[r][c] = digitalRead(R1C2IN);
          } else if (pl == 1) {
            digitalWrite(BR1C2, HIGH);
            delay(100);
            digitalWrite(BR1C2, LOW);
            delay(100);
            Serial.println(digitalRead(R1C2IN));
            ttt2[r][c] = digitalRead(R1C2IN);
          }
        }
      } else if (r == 0 && c == 2 && mat[r][c] == 1) {
        while (mat[r][c] == 1) {
          if (pl == 0) {
            digitalWrite(RR1C3, HIGH);
            delay(100);
            digitalWrite(RR1C3, LOW);
            delay(100);
            ttt1[r][c] = digitalRead(R1C3IN);
          } else if (pl == 1) {
            digitalWrite(BR1C3, HIGH);
            delay(100);
            digitalWrite(BR1C3, LOW);
            delay(100);
            ttt2[r][c] = digitalRead(R1C3IN);
          }
        }
      } else if (r == 1 && c == 0 && mat[r][c] == 1) {
        while (mat[r][c] == 1) {
          if (pl == 0) {
            digitalWrite(RR2C1, HIGH);
            delay(100);
            digitalWrite(RR2C1, LOW);
            delay(100);
            ttt1[r][c] = digitalRead(R2C1IN);
          } else if (pl == 1) {
            digitalWrite(BR2C1, HIGH);
            delay(100);
            digitalWrite(BR2C1, LOW);
            delay(100);
            ttt2[r][c] = digitalRead(R2C1IN);
          }
        }
      } else if (r == 1 && c == 1 && mat[r][c] == 1) {
        while (mat[r][c] == 1) {
          if (pl == 0) {
            digitalWrite(RR2C2, HIGH);
            delay(100);
            digitalWrite(RR2C2, LOW);
            delay(100);
            ttt1[r][c] = digitalRead(R2C2IN);
          } else if (pl == 1) {
            digitalWrite(BR2C2, HIGH);
            delay(100);
            digitalWrite(BR2C2, LOW);
            delay(100);
            ttt2[r][c] = digitalRead(R2C2IN);
          }
        }
      } else if (r == 1 && c == 2 && mat[r][c] == 1) {
        while (mat[r][c] == 1) {
          if (pl == 0) {
            digitalWrite(RR2C3, HIGH);
            delay(100);
            digitalWrite(RR2C3, LOW);
            delay(100);
            ttt1[r][c] = digitalRead(R2C3IN);
          } else if (pl == 1) {
            digitalWrite(BR2C3, HIGH);
            delay(100);
            digitalWrite(BR2C3, LOW);
            delay(100);
            ttt2[r][c] = digitalRead(R2C3IN);
          }
        }
      } else if (r == 2 && c == 0 && mat[r][c] == 1) {
        while (mat[r][c] == 1) {
          if (pl == 0) {
            digitalWrite(RR3C1, HIGH);
            delay(100);
            digitalWrite(RR3C1, LOW);
            delay(100);
            ttt1[r][c] = digitalRead(R3C1IN);
          } else if (pl == 1) {
            digitalWrite(BR3C1, HIGH);
            delay(100);
            digitalWrite(BR3C1, LOW);
            delay(100);
            ttt2[r][c] = digitalRead(R3C1IN);
          }
        }
      } else if (r == 2 && c == 1 && mat[r][c] == 1) {
        while (mat[r][c] == 1) {
          if (pl == 0) {
            digitalWrite(RR3C2, HIGH);
            delay(100);
            digitalWrite(RR3C2, LOW);
            delay(100);
            ttt1[r][c] = digitalRead(R3C2IN);
          } else if (pl == 1) {
            digitalWrite(BR3C2, HIGH);
            delay(100);
            digitalWrite(BR3C2, LOW);
            delay(100);
            ttt2[r][c] = digitalRead(R3C2IN);
          }
        }
      } else if (r == 2 && c == 2 && mat[r][c] == 1) {
        while (mat[r][c] == 1) {
          if (pl == 0) {
            digitalWrite(RR3C3, HIGH);
            delay(100);
            digitalWrite(RR3C3, LOW);
            delay(100);
            ttt1[r][c] = digitalRead(R3C3IN);
          } else if (pl == 1) {
            digitalWrite(BR3C3, HIGH);
            delay(100);
            digitalWrite(BR3C3, LOW);
            delay(100);
            ttt2[r][c] = digitalRead(R3C3IN);
          }
        }
      }
    }
  }
}
//final function to reset the entire game, it checks if all the matrix positions for both players are empty (0's)
void resetGame() {
  int r1 = 0;
  int r2 = 1;
  int r3 = 2;
  int c1 = 0;
  int c2 = 1;
  int c3 = 2;
  //if both matrices are filled with 0's, reset every global variable that controls the playing sequence back to their default values
  if (ttt1[r1][c1] == 0 && ttt1[r1][c2] == 0 && ttt1[r1][c3] == 0 && ttt1[r2][c1] == 0 && ttt1[r2][c2] == 0 && ttt1[r2][c3] == 0 && ttt1[r3][c1] == 0 && ttt1[r3][c2] == 0 && ttt1[r3][c3] == 0 && ttt2[r1][c1] == 0 && ttt2[r1][c2] == 0 && ttt2[r1][c3] == 0 && ttt2[r2][c1] == 0 && ttt2[r2][c2] == 0 && ttt2[r2][c3] == 0 && ttt2[r3][c1] == 0 && ttt2[r3][c2] == 0 && ttt2[r3][c3] == 0) {
    playerSw = 0;
    lightCount = 0;
    flagTurn1P1 = 0;
    flagTurn2P2 = 0;
    flagTurn3P1 = 0;
    flagTurn4P2 = 0;
    flagTurn5P1 = 0;
    flagTurn6P2 = 0;
    flagTurn7P1 = 0;
    flagTurn8P2 = 0;
    flagTurn9P1 = 0;
    p1Win = 0;
    p2Win = 0;
    gameDraw = 0;
    movePossibleWinsCt = 0;
    randSeq = 0;
    seqCt = 0;
  } else {
    //don't do anything if all matrix positions aren't 1
  }
}

Two functions were harder to develop: checkPlayerCanMoveToWin() and checkMatrixAndReset() than the remaining ones above. I needed a way to program checking if there was a draw, this was harder than I first thought. I thought there was a way to see if one person could make any move after two lights per player were already lit. This didn’t work because technically a person could move anywhere that hasn’t already been set. So I determined that after seven lights it was possible to temporarily fill empty spots with one’s and add up the number of times a “win” was possible. If the count was zero, the game results in a draw, otherwise, there are possible moves for someone to win. Next, I wanted to make sure that everything was reset properly since I chose buttons that stayed on when pressed. It just took me a while to figure what “if” statements to use and that while loops were useful in this stage. The function simply blinks the light that corresponds to the button that needs to be reset. One final note is remember what names you give the lights for sequencing or make them more obvious names. I had to re-write sequences a lot because I would forget R1 refers to the top row, not the bottom row.

Overall, I could have saved lines by writing better functions, but this program works exactly the way I want it to. However, I’d say that this could have been a lot more tedious without all the functions and may have taken up more memory. Currently, the program only uses 12,738 bytes of storage space and only 229 bytes of dynamic memory. Here is the zipped folder of the entire code:
tttFull.zip (9.0 KB)

The next step is creating an enclosure for buttons with LED indication built into them to make a final design.