Monday, September 28, 2009

Arduino Tic Tac Toe

This weekend I spend some time building a simple game of tic tac toe using an Arduino and a variety of simple components, both analog and digital. Here is a video that takes you through the process of creating this game. Below you will find the code that I used to program the Arduino. I have left all comments in the code so that you understand how it is built. I am sure there are many ways that this code can be improved and/or streamlined.



Tic Tac Toe Code
// setting a variable to pin number 13
int tictacPins [] = {2,3,4,5,6,7,8,9,10,11};     // holds pin location of each LED (including the active user one at 0)
int userPin = 0;                                 // holds the location on the array where the active user is displayed
int winnerPin = 13;                               // holds the location on the array wher the winnerPin is located
int buttonPin = 12;                              // holds number of pin for button input
int potPin = 0;                                  // holds number of pin for the potentionmeter

int potRead = 0;                                 // holds the pot value
int potRange = 0;                                // holds the value of the pot range to go from one LED to the next
int activeUser = 1;                              // holds the active user (1 or 0)
boolean buttonState = false;                     // holds buttonState (true means it has been pressed)
int user2counter = 0;                            // holds variable to enable the active user LED to blink
int blinkStateUser2 = 1;                         // holds the current blink state for all player two LEDs
int blinnkStateSelect = 0;

long unsigned timeButton;                        // holds time variable that ensures only one button press is read at a time
long unsigned timeButtonInter = 500;             // holds the interval between button presses
long unsigned timeUserLED;                       // holds time variable that governs blinking of the LED light that is currently active (prior to being selected)
long unsigned timeUserInter = 150;               // holds the interval for the blinking of the LED lights described above
long unsigned timePlayerLED;                     // holds time variable that governs the blinking of the LED lights on the spots that were selected by player 2
long unsigned timePlayerInter = 1200;            // holds the interval for the blinking of the LED lights described above
long unsigned timeHolder;

int tempActiveLoc = 1;                           // holds number of active locations on board           
int activeLoc = 1;                               // holds current LED selected 
int availableLoc = 9;                            // holds number of available locations
boolean locState [] = {true, false, false, false, false, false, false, false, false, false};              // holds current state of each location board - true = taken; false = available
boolean user1select [] = {false, false, false, false, false, false, false, false, false, false};          // holds current state of board for player 1 - true = taken by player 1; false = not taken by player 1
boolean user2select [] = {false, false, false, false, false, false, false, false, false, false};          // holds current state of board for player 2 - true = taken by player 2; false = not taken by player 2
boolean gameStatus = true;                       // holds whether game is active or over
int gameWinner = 0;


// set-up the output pin where LED will be attached

void setup()   {           
  for (int counter = 0; counter <= 9;  counter++) {                  // counter to set pinMode for all tic tact toe board pins (and active user pin)
    pinMode(tictacPins[counter], OUTPUT);                            // setting each pin as output
  } 
  pinMode(winnerPin, OUTPUT);                                        // set win notification pin as output
  pinMode(buttonPin, INPUT);                                         // set button switch as input
  resetGame();                                                       // call reset game function to initialize the game
}

// the loop() method runs continuously
void loop()                     
{
  setAvailableLoc();                                         
  blinkCounters();
  setUser();
  browsePin();
  setButtonState();
  selectPin();
  displaySelect();
  displayUserStatus();
  displayGame();
  checkWin();
} 

// function that reads if the button has been pressed. Then it sets buttonState to true if button was pressed
void setButtonState() {
  if (millis() - timeButton > timeButtonInter) {
    if (digitalRead(buttonPin) == HIGH) {                                               // if the button is pressed
        buttonState = true;                                                             // set buttonState to true
        timeButton = millis();                                                          // record that time when button was pressed
    }
  }
}

// function to set counter for player 2 pins to blink properly

// function that changes the active user if button has been pressed (e.g. player has made a selection
// function also calls setUser2PinState function to set counter for blinking player 2 lights
void setUser() {
    if (buttonState == true && activeUser == 1) {      // if button has been pressed and active user is 0    
        activeUser = 2;                                // set active user to 1
        buttonState = false;                           // set button state to false 
      }
    else if (buttonState == true && activeUser == 2) { // if button has been pressed and active user is 1     
        activeUser = 1;                                // set active user to 0
        buttonState = false;                           // set button state to false
    }
}

// function regulates the blinking of the user status pin based on what user is currently active
void displayUserStatus () {
  if (gameWinner == 0) {                                 // confirm that no one has won the game
    displayPin(userPin, activeUser);                     // calls displayPin function with to change state of userPin to currect active user
  } else {
    if (gameWinner == 1) {                              // check if user 1 won
      displayPin(userPin, 1);                           // calls displayPin function to show the winner if user 1
    } else if (gameWinner == 2) {                       // check is user 2 won
      displayPin(userPin, 2);                           // calls displayPin function to show the winner ifuser 2
    }
  }
}

// function that governs the activity of each selected pin based on whether it is a user 1 or user 2 pin
void displayPin (int tempPin, int tempUser) {
  if (tempUser == 1) {                                     // checks if current user is user 1 (0)
    digitalWrite(tictacPins[tempPin], HIGH);               // if it is user 1 then turn on the pin pin 
  } else if (tempUser == 2) { 
    if (blinkStateUser2 == 1) {                            // checks if current user is user 2 (1)
      digitalWrite(tictacPins[tempPin], HIGH);             // turn on the pin
    }  
    if (blinkStateUser2 == 2) {                            // check counter number if equal to one
      digitalWrite(tictacPins[tempPin], LOW);              // turn off the pin
    }
  }
}

// counter function that governs the blinking of all user 2 lights
void blinkCounters () {   
    if (millis() - timePlayerLED < timePlayerInter/2) {                    // checks if enough time has elapsed sine light was turned on
       blinkStateUser2 = 1;                                                // keeps the light on until the time has exceed a given interval
     }  else if (millis() - timePlayerLED > timePlayerInter/2) {           // once interval has passed
       blinkStateUser2 = 2;                                                // set light off by change blink state to two
     }       
    if (millis() - timePlayerLED > timePlayerInter) {                      // once a full cycle has passed of turning the light on and off
      timePlayerLED = millis();                                            // reset the time tracker for the next loop
    }
}

// function that displays the game
void displayGame () {
    if (gameWinner == 1 || gameWinner == 2) {                            // if the game has been won be either player
      digitalWrite(winnerPin, HIGH);                                     // turn on green LED
      displayPin(userPin, gameWinner);                                   // display the winner's blink pattern on user LED
    } else {                                                             // if the game has not been won
      digitalWrite(winnerPin, LOW);                                      // keep green LED off
    }     
    for (int counter = 1; counter <= 9; counter++) {                     // loop through each location on the tic tac toe board
      if (locState[counter] == true) {                                   // if location has been selected/taken
        if (user1select[counter] == true) {                              // check if player one has taken this location
           displayPin(counter, 1);                                       // turn on LED to denote space taken by player 1
        } else if (user2select[counter] == true) {                       // check if player 2 has taken this location
          displayPin(counter, 2);                                        // blink LED to denote space taken by player 2
        }
      }
    }
}

// function that re-initialized the game once someone has won
void resetGame() {
  potRead = 0;                                         // holds the pot value
  potRange = 0;                                        // holds the value of the pot range to go from one LED to the next
  activeUser = 1;                                      // holds the active user (1 or 0)
  buttonState = false;                                 // holds buttonState (true means it has been pressed)
  user2counter = 0;                                    // holds variable to enable the active user LED to blink
  tempActiveLoc = 1;                                   // holds number of active locations on board           
  activeLoc = 1;                                       // holds current LED selected 
  availableLoc = 9;                                    // holds number of available locations
  gameStatus = true;                                   // holds whether game is active or over
  gameWinner = 0;
  timeButton = millis();
  timeUserLED = millis();
  timePlayerLED = millis();
  for (int counter = 1; counter <= 9; counter++) {                // loop to set all initialize all arrays and turn off all LEDs on tic tact toe board
     locState [counter] = false;                                  // reset locState array
     user1select [counter] = false;                               // reset user 1 location array
     user2select [counter] = false;                               // reset user 2 location array
     digitalWrite(tictacPins [counter], LOW);                     // turn off all LEDs on tic tac toe board
     
  }
  
}


// function that makes the current selected pin blink on and off
void displaySelect() {  
  if (availableLoc != 0 && gameWinner == 0) {                        // if there is a space available on the tic tac toe board and no winner
    if ((millis() - timeUserLED) > (timeUserInter)) {                // if sufficient has passed since the beggining of the last cycle
      digitalWrite(tictacPins[activeLoc], HIGH);                     // turn on the selected LED
      delay (150);                                                   // wait for 150 milliseconds
      digitalWrite(tictacPins[activeLoc], LOW);                      // turn off the LED lights
      timeUserLED = millis();                                        // reset cycle start time
      }
  }
}


// function that reads the potentiometer and uses this information to select a pin
void browsePin () {
  int openLoc = 0;                                            // variable that holds how many open locations have been found in the array

  potRead = analogRead(potPin);                               // read the potentionmeter
  tempActiveLoc = map (potRead, 0, 1024, 1, availableLoc+1);  // set the size of the range
  
  for (int counter = 1; counter <= 9; counter++) {            // loop to identify current pin based on number of available pins and range 
    if(locState[counter] == false) {                          // if the pin has not been selected yet 
     openLoc++;                                               // then add 1 to openLoc
    }
    if (openLoc == tempActiveLoc) {                           // if openLoc is equal to tempActiveLoc
      activeLoc = counter;                                    // then make activeLoc equal to counter 
      openLoc++;
   }  
  }
}
  
// identifies the number of available locations on the board
int setAvailableLoc () {
  availableLoc = 0;                                          // initialize the availableLoc to 0
  for (int counter = 1; counter <= 9 ; counter++) {          // loop from 1 to 9
    if (locState[counter] == false) {                        // if the location is set to false (e.g. not yet selected)
       availableLoc = availableLoc + 1;                      // add one to the availableLoc variable 
    }
  }
}

// function that enables a user to select a pin
void selectPin () {
  if (gameWinner == 0) {                                      // check if the game has been won, if it has not then
    if (buttonState == true && activeUser == 1) {             // if the button has been pressed and the active user is 1
      locState[activeLoc] = true;                             // set the current location to taken
      user1select[activeLoc] = true;                          // register the location as selected by user 1
    } else if (buttonState == true && activeUser == 2) {      // if the button has been pressed and the active user is 2
      locState[activeLoc] = true;                             // set the current location to taken
      user2select[activeLoc] = true;                          // register the location as selected by user 2
    } 
  } else if (gameWinner == 1 || gameWinner == 2) {            // if game has been won
      if (buttonState == true) {                              // and if button has been pressed
        resetGame();                                          // reset the game
      }
  }
}

// function that confirms whether either player has won the game
void checkWin() {
  
  // check to see if player one won
  if ((user1select[1] == true) && (user1select[2] == true) && (user1select[3] == true)) {
        gameWinner = 1;
  } else if ((user1select[1] == true) && (user1select[4] == true) && (user1select[7] == true)) {
        gameWinner = 1;
  } else if ((user1select[1] == true) && (user1select[5] == true) && (user1select[9] == true)) { 
        gameWinner = 1;
  } else if ((user1select[2] == true) && (user1select[5] == true) && (user1select[8] == true)) {
        gameWinner = 1;
  } else if ((user1select[9] == true) && (user1select[3] == true) && (user1select[6] == true)) {
        gameWinner = 1;
  } else if ((user1select[9] == true) && (user1select[7] == true) && (user1select[8] == true)) {
        gameWinner = 1;
  } else if ((user1select[7] == true) && (user1select[5] == true) && (user1select[3] == true)) {
        gameWinner = 1;
  } else if ((user1select[4] == true) && (user1select[5] == true) && (user1select[6] == true)) {
        gameWinner = 1;
  } 

  // check to see if player two won
  if ((user2select[1] == true) && (user2select[2] == true) && (user2select[3] == true)) {
        gameWinner = 2;
  } else if ((user2select[1] == true) && (user2select[4] == true) && (user2select[7] == true)) {
        gameWinner = 2;
  } else if ((user2select[1] == true) && (user2select[5] == true) && (user2select[9] == true)) { 
        gameWinner = 2;
  } else if ((user2select[2] == true) && (user2select[5] == true) && (user2select[8] == true)) {
        gameWinner = 2;
  } else if ((user2select[9] == true) && (user2select[3] == true) && (user2select[6] == true)) {
        gameWinner = 2;
  } else if ((user2select[9] == true) && (user2select[7] == true) && (user2select[8] == true)) {
        gameWinner = 2;
  } else if ((user2select[7] == true) && (user2select[5] == true) && (user2select[3] == true)) {
        gameWinner = 2;
  } else if ((user2select[4] == true) && (user2select[5] == true) && (user2select[6] == true)) {
        gameWinner = 2;
  } 

}
 

2 comments:

jasim alqam said...

great job :) !
what if i don't want to use any input. how can i do that? can u send me the schematic diagram?

Blake C said...

can u send me the schematic diagram?