Final Project - Bop It

Dependencies:   mbed wave_player 4DGL-uLCD-SE SDFileSystem_1 MMA8452

main.cpp

Committer:
ocrank3
Date:
2019-12-09
Revision:
0:b04853f39afa

File content as of revision 0:b04853f39afa:

#include "mbed.h"
#include "MMA8452.h"
#include "wave_player.h"
#include "SDFileSystem.h"
#include <ctime>
#include <iostream>
#include <string>
#include <vector>
#include <algorithm>
#include <sstream>
#include "uLCD_4DGL.h"

#define YELLOW 0xF1C40F

/* Instantiate devices */
uLCD_4DGL uLCD(p13,p14,p11);
DigitalIn bop(p21);
AnalogIn twist(p19);
AnalogIn slide(p20);
SDFileSystem sd(p5, p6, p7, p8, "sd"); 
AnalogOut DACout(p18);
wave_player player(&DACout);
Serial pc(USBTX,USBRX); // setup for accelerometer
RawSerial dev(p28,p27);
MMA8452 accel(p9, p10, 100000); // use for accelerometer

/* variables for reading in textfile */
char myString[256]; 
char delim[] = ":"; 
string nameOfPlayer = ""; 
 
/* game data */
enum states {name, diffLevel, randomNum, replay, play} state;
double timeLimit = 3; // this is set by the difficulty level in seconds
double decrement;
bool gameDone = false;
int score = 0;
int seed = 0;
double twistStart;
double slideStart;
double xStart, yStart, zStart, xCurr, yCurr, zCurr;

struct Players{
    string name; 
    int score; 
};

/* Instantiate struct of players array */
vector<Players> playersVec; 

bool cmp(Players i , Players j) {
    return i.score > j.score; 
    
}

/* prints "Welcome to Bop It!" on the uLCD */
void printWelcome() {
    uLCD.cls();
    uLCD.text_width(2); //2X size text
    uLCD.text_height(2);
    uLCD.locate(0,2);
    uLCD.printf(" Welcome ");
    uLCD.locate(0,4);
    uLCD.printf("   To   ");
    uLCD.locate(0,6);
    uLCD.printf(" Bop It! ");
}

/* prinf the command on the uLCD */
void printCommand(char *command, int color) {
    uLCD.cls();
    uLCD.text_width(2); //2X size text
    uLCD.text_height(3);
    uLCD.locate(0, 2);
    uLCD.color(color);
    uLCD.printf(command);
}

/* reads the text file, puts in Vector, Sorts Vector opens file and reads until end */
void readTextFile() {  
    FILE *fp = fopen("/sd/sdtest.txt", "r"); 
    while (!feof(fp)) {
        fgets(myString, 256, fp);
        char *token = strtok(myString, delim);
        while (token != NULL) {
            string currName = token; 
            token = strtok(NULL,delim);
            
            int currScore = atoi(token);
            token = strtok(NULL, delim); 
            
            //Instatiates vector of currPlayer objects, Pushes into the Vector, and Sorts by Score as Pushing 
            Players currPlayer = {currName, currScore}; 
            playersVec.push_back(currPlayer);
            sort(playersVec.begin(), playersVec.end(), cmp); 
        }
    }
    fclose(fp);  
}

/* Reads the Vec of Player objects, takes in teh name from the phone user's name input, and reorders and rewrites to the text file */
void updateHighScore(string newName, int newScore) {
    Players addPlayer = {newName, newScore} ;  
    playersVec.push_back(addPlayer); 
    sort(playersVec.begin(), playersVec.end(), cmp); 
    playersVec.erase(playersVec.begin() + 5);
    string outputString;  
    dev.printf("\nHIGHSCORES:\n"); 
    for (int i = 0; i < 5; i++) { 
        dev.printf("%s : %d\n\r", playersVec[i].name, playersVec[i].score); 
        char myNum[80]; 
        sprintf(myNum, "%d", playersVec[i].score); 
        outputString += ":"; 
        outputString += playersVec[i].name; 
        outputString += ":"; 
        outputString += myNum; 
    }  
    pc.printf("%s", outputString); 
    FILE *fp = fopen("/sd/sdtest.txt", "w"); 
    fprintf(fp, "%s", outputString); 
    fclose(fp); 
}

/* Bluetooth interupt handler
    Records the user's inputs */ 
void dev_recv()
{
    char currChar;
    if (state == name) {
        while(dev.readable()) {
            currChar = (char) dev.getc();
            pc.printf("state = 0, currChar = @%c\n\r", currChar);
            if (currChar == '\n') { // end of user input
                state = diffLevel;
                dev.printf("ENTER DIFFICULTY LEVEL (1, 2, 3)");
                pc.printf("ENTER DIFFICULTY LEVEL (1, 2, 3)");
                return;
            } 
            nameOfPlayer += currChar;    
        }
    } else if (state == diffLevel) {
        currChar = (char) dev.getc();
        pc.printf("state = 1, currChar = @%c\n\r", currChar);
        dev.getc(); // clear newline character
        switch (currChar) {
            case '1':
                decrement = 0.05;
                break;
            case '2':
                decrement = 0.1;
                break;
            case '3':
                decrement = 0.15;
                break;
        }
        state = randomNum;
        dev.printf("PLEASE ENTER A RANDOM NUMBER BETWEEN 0 AND 9\n");
    } else if (state == randomNum) {
        currChar = (char) dev.getc();
        dev.getc(); // clear newline character
        seed = (int) currChar - 48; // convert to int
        state = play;
    } else if (state == replay) {
        currChar = (char) dev.getc();
        dev.getc(); // clear newline character
        switch(currChar) {
            case 'y':
                state = name;
                break;
            case 'n':
                dev.printf("Thanks for playing! Goodbye!\n");
                exit(0);
                break;
        }
    }
}

/* Bluetooth handler */
void pc_recv()
{
    while(pc.readable()) {
        dev.putc(pc.getc());
    }
}


/* Plays a wavefile through the speaker */
void playFile(char * filename) {
     char result [50];
     sprintf(result, "/sd/%s.wav", filename);
     FILE *fp = fopen(result, "r");
     player.play(fp);
     fclose(fp);
}
 
/* Actions to be completed when the game is over 
    - display high score
    - asks user if they want to play again */
void gameOver(bool wrong) {
    updateHighScore(nameOfPlayer, score);
    if (wrong) {
        playFile("gameoversound");
    }
    playFile("gameover");
    printCommand("  GAME\n   OVER", RED);
    gameDone = true;
}

/* returns true if the potentiometer was twisted */
bool wasTwisted() {
    double currTwist = (double) twist;
    pc.printf("curr twist: %f\n", currTwist);
    return (abs(currTwist - (double)twistStart) > 0.4);
}

/* returns true if the pushbutton was hit */
bool wasBopped() {
    return !bop; // waiting for button press (active low)
}

/* returns true if the device was shaken */
bool wasShaken() {
    accel.readXYZGravity(&xCurr,&yCurr,&zCurr);
    return (abs(xCurr - xStart) > 0.3 || abs(yCurr - yStart) > 0.3 || abs(zCurr - zStart) > 0.3);
}

/* returns true if the potentiometer was slid */
bool wasSlid() {
    double currSlide = (double) slide;
    pc.printf("curr slide: %f\n", currSlide);
    return (abs((double)slide - slideStart) > 0.5);
}
 
/* prompts user with command (bopIt) and waits for them to complete it
    The game ends if they run out of time or they perform the wrong command */
void bopIt(){
    printCommand("   BOP\n    IT ", 0xFFA500);
    playFile("bopit");
    std::clock_t start = clock();
    while (!wasBopped()) { 
        if (wasTwisted() || wasSlid()) {
            gameOver(true);
            return;
        }
        if (((clock() - start) / (double) CLOCKS_PER_SEC) > timeLimit) {
            gameOver(false);
            return;
        }
    }
    playFile("bopsound");
    return;
}
 
/* prompts user with command (twistIt) and waits for them to complete it
    The game ends if they run out of time or they perform the wrong command */
void twistIt() {
   printCommand("  TWIST\n    IT", WHITE);
   playFile("twistit");
   std::clock_t start = clock();
   while (!wasTwisted()) { 
        if (wasSlid() || wasBopped()) {
            gameOver(true);
            return;
        }
        if (((clock() - start) / (double) CLOCKS_PER_SEC) > timeLimit) {
            gameOver(false);
            return;
        }
    }
    pc.printf("final twist: %f\n", (double)twist.read());
    playFile("twistsound");
   return;
}
 
/* prompts user with command (slideIt) and waits for them to complete it
    The game ends if they run out of time or they perform the wrong command */
void slideIt(){
   printCommand("  SLIDE\n    IT", YELLOW);
   playFile("slideit");
   std::clock_t start = clock();
   while (!wasSlid()) {
        if (wasTwisted() || wasBopped()) {
            gameOver(true);
            return;
        }
        if (((clock() - start) / (double) CLOCKS_PER_SEC) > timeLimit) {
            gameOver(false);
            return;
        }
    }
    playFile("slidesound");
   return;
}
 
/* prompts user with command (shakeIt) and waits for them to complete it
    The game ends if they run out of time or they perform the wrong command */
void shakeIt(){
    printCommand("  SHAKE\n    IT", GREEN);
    playFile("shakeit");
    std::clock_t start = clock();
    while (!wasShaken()) {
        if (wasBopped() || wasTwisted() || wasSlid()) {
            gameOver(true);
            return;
        }
        if (((clock() - start) / (double) CLOCKS_PER_SEC) > timeLimit) {
            gameOver(false);
            return;
        }
    }
    playFile("shakesound");
    return;
}
 
/* sets up game and loops through the game states */
int main() {
    playFile("welcome");
    printWelcome();
    state = name;
    readTextFile();
    pc.baud(9600);
    dev.baud(9600);
    pc.attach(&pc_recv, Serial::RxIrq);
    dev.attach(&dev_recv, Serial::RxIrq);
    string directions = "Welcome to BOP IT! \n-If it says BOP-IT, press the button. \n-If it says SLIDE IT, slide the switch. \n-If it says SHAKE IT, shake the box. \n-If it says TWIST IT, twist the knob. ";
    dev.printf("%s\n\r", directions); 
    dev.printf("ENTER YOUR NAME BELOW!"); 
    bop.mode(PullUp); // enable pullup mode to use internal resistance
    while (state != play);
    srand(seed);
    int whichCommand;
    while(1) {
        if (gameDone) {
            gameDone = false;
            state = replay;
            score = 0;
            nameOfPlayer = "";
            dev.printf("Start new game? y/n\n");
            while (state == replay); // wait for user's response
            dev.printf("ENTER YOUR NAME BELOW!\n");
            while (state != play);
        } 
        // record initial readings
        twistStart = (double)twist; 
        slideStart = (double)slide;
        accel.readXYZGravity(&xStart,&yStart,&zStart);
        // choose command
        whichCommand = rand() % 4;
        switch (whichCommand) {
            case 0:
                bopIt();
                break;
            case 1:
                pc.printf("startTwist: %f\n", (double)twist);
                twistIt();
                break;
            case 2:
                pc.printf("startSlide: %f\n", (double)slide);
                slideIt();
                break;
            case 3:
                shakeIt();
                break;
        }
        // don't let the alloted time go below 2 seconds
        if (timeLimit > 2) {
            timeLimit -= decrement;
        }
        wait(1);
        score++;
    }
 
}