Power Grid Board Game Timer. Acts like a chess timer for 3-6 people. Uses an ADXL accelerometer to pause the timer and change players. Uses an LCD screen to prompt the players for input, read that input, and change between rounds.

Dependencies:   DmTouch_UniGraphic UniGraphic-forLdelaney17FinalProject mbed

game.cpp

Committer:
ldelaney17
Date:
2017-01-25
Revision:
5:e07903df9510
Parent:
4:e14c199c2466

File content as of revision 5:e07903df9510:

#include "game.h"

void game_setup(){
    step_number = 0;
    clock_running = false;
    current_clock.reset();
    init_num_players();
    set_start_time();
    set_bonus_time();
    next_step(); // set_player_order();
}
void song_setup(){
    enum notes{ C_4 = 262, D_4 = 294, E_4 = 330, F_4 = 349, G_4 = 392, A_4 = 440, 
    Bb_4 = 466, C_5 = 523, Db_5 = 554, D_5 = 587, E_5 = 659, F_5 = 698, 
    G_5 = 784, A_5 = 880};
    
    float freq_j[31] = {C_5,F_5,C_5,F_4,C_5,F_5,C_5,C_5,F_5,C_5,F_5,A_5,G_5,F_5,E_5,D_5,Db_5,C_5,F_5,C_5,F_4,C_5,F_5,C_5,F_5,D_5,C_5,Bb_4,A_4,G_4,F_4};
    float beat_j[31] = {1,1,1,1,1,1,2,1,1,1,1,1.5,.5,.5,.5,.5,.5,1,1,1,1,1,1,2,1.5,.5,1,1,1,1,1};
    vector<float> f (freq_j, freq_j + sizeof(freq_j) / sizeof(freq_j[0]));
    vector<float> b (beat_j, beat_j + sizeof(beat_j) / sizeof(beat_j[0]));
    jeopardy = new Song(f, b, 31, 120);     
    
    
    float freq_s[8] = {F_5, E_5, D_5, C_5, Bb_4, A_4, G_4, F_4};
    float beat_s[8] = {1, 1, 1, 1, 1, 1, 1, 5};
    vector<float> f_s (freq_s, freq_s + sizeof(freq_s) / sizeof(freq_s[0]));
    vector<float> b_s (beat_s, beat_s + sizeof(beat_s) / sizeof(beat_s[0]));
    scale = new Song(f_s, b_s,8, 120);   
    
    float freq_b[1] = {F_5};
    float beat_b[1] = {60};
    vector<float> f_b (freq_b, freq_b + sizeof(freq_s) / sizeof(freq_s[0]));
    vector<float> b_b (beat_b, beat_b + sizeof(beat_s) / sizeof(beat_s[0]));
    beep = new Song(f_b, b_b, 1, 120);
}

void init_num_players(){
    prompt(6, "Select the number of players\r\n"); //sets waiting_for_touch to true
    while(waiting_for_touch == true){ //until a valid input is read, spin our wheels here
        wait(0.1); // can busy wait during setup    
    }
    num_players = prompt_input_val; // set based on the circle touched
    stringstream ss;
    ss << "press 1 to confirm that " << num_players << " players is correct. Press 2 to select a different number";
    prompt(2, ss.str());
    while(waiting_for_touch == true){ //until a valid input is read
        wait(0.1); // can busy wait during setup    
    }
    int choice = prompt_input_val;
    switch(choice){
        case 1:
        return;
        break;
        case 2:
        init_num_players();
        return;
        break;
    }
}

//blocking wait function
void set_player_order(){
    player_order.clear();
    for (int i = 0; i <  num_players; i++){
        prompt(num_players, "select the player number with the most cities. \r\nIn case of a tie, the higher numbered power \r\nplant goes first\r\n");   
        while (waiting_for_touch){
           wait(0.05); //blocking busy wait 
        }
        player_order.push_back(prompt_input_val);
    }
    //TODO: if has duplicates, display message "invalid turn order" and call set_player_order
      
    stringstream ss;
    ss << "press 1 to confirm that player order is correct. \r\nPress 2 to change";
    ss << "\r\nPlayer Order:\t";
    for (int i = 0; i < num_players; i++){
        ss << player_order[i] << "\t";   
    }
    prompt(2, ss.str());
    while(waiting_for_touch == true){ //until a valid input is read
        wait(0.1); // can busy wait during setup    
    }
    int choice = prompt_input_val;
    switch(choice){
        case 1:
        return;
        break;
        case 2:
        set_player_order();
        return;
        break;
    }
}

void set_start_time(){
    //TODO: let the user input a start time
    prompt(5, "Select a starting amount of time per player:\r\n1: 1:00\t2: 1:30\t3: 2:30\t 4: 5:00\t 5: 10:00");
    while (waiting_for_touch){ //busy wait during setup
        wait(0.1);
    }
    int time_choice = prompt_input_val;
    stringstream ss;
    float start_time;
    switch(time_choice){
        case 1:
            start_time = 60;
            break;
        case 2:
            start_time = 90;
            break;
        case 3:
            start_time = 150;
            break;
        case 4:
            start_time = 300;
            break;
        case 5:   
            start_time = 600;
            break;
        default: //never run this line
            start_time = 0;
            break;
    }
    ss << "press 1 to confirm that " << start_time << " seconds is correct. Press 2 to select a different time";
    prompt(2, ss.str());
    while(waiting_for_touch == true){ //until a valid input is read
        wait(0.1); // can busy wait during setup    
    }
    int choice = prompt_input_val;
    switch(choice){
        case 1:
        for (int i = 0; i < num_players; i++) //if chosen, initialize the timers
        {
            player_timers.push_back(start_time);
        }
        return;
        break;
        case 2:
        set_start_time();
        return;
        break;
    }
}

void set_bonus_time(){
    //TODO: let the user input a bonus time that will be added to a player's timer each time their timer is started (many times per round)
    prompt(5, "Select a bonus amount of time that will be added to a player's timer each time their timer is started:\r\n1: 0:01\t2: 0:05\t3: 0:10\t 4: 0:15\t 5: 0:30");
    while (waiting_for_touch){ //busy wait during setup
        wait(0.1);
    }
    int time_choice = prompt_input_val;
    stringstream ss;
    float start_time;
    switch(time_choice){
        case 1:
            bonus_time = 1;
            break;
        case 2:
            bonus_time = 5;
            break;
        case 3:
            bonus_time = 10;
            break;
        case 4:
            bonus_time = 15;
            break;
        case 5:   
            bonus_time = 30;
            break;
        default: //never run this line
            bonus_time = 0;
            break;
    }
    ss << "press 1 to confirm that " << bonus_time << " seconds is correct. Press 2 to select a different time";
    prompt(2, ss.str());
    while(waiting_for_touch == true){ //until a valid input is read
        wait(0.1); // can busy wait during setup    
    }
    int choice = prompt_input_val;
    switch(choice){
        case 1:
        return;
        break;
        case 2:
        set_bonus_time();
        return;
        break;
    }
}

void next_step(){
    pc.printf("starting next step\r\n");
    pause_timer();
    pc.printf("after pause_timer\r\n");
    if (step_number == 4)
        step_number = 0;
    else
        step_number++;
        
    stringstream ss;
    ss << "Step number " << step_number << ": ";
    pc.printf("entering step_number (%d) switch\r\n", step_number);
    switch(step_number-1){ //based on the last step
        case 0: //determine player order (immediately call again to move to the "auction power plants" phase
            set_player_order();
            next_step();
            return;
            break;
        case 1: //auction power plants, standard turn order
            ss << "Auction Power Plants";
            current_player = player_order[0];
            start_timer(current_player);
            break;
        case 2: //buy resources, reverse player order
            ss << "Buy Resources";
            reverse_player_order();
            current_player = player_order[0];
            current_player_index = 0;
            start_timer(current_player);
            break;
        case 3: //building, reverse player order (same as buying resources)
            ss << "Building";
            current_player = player_order[0];
            current_player_index = 0;
            start_timer(current_player);
            break;
        case 4: //bureacracy, normal player order (reverse order of building)
            ss << "Bureacracy";
            reverse_player_order();
            current_player = player_order[0];
            current_player_index = 0;
            start_timer(current_player);
            break;
        } 
        ss << "\r\nPres the button to move to the next step";
        prompt(1, ss.str()); //display a single button and the message
}


//TODO: it would be nice to include the phase changes, but it doesn't affect the
    //  parts of gameplay I am focusing on
/* prompt(2, "is this a new phase?\r\n1: yes\t 2: no");
    while(waiting_for_touch == true){ //until a valid input is read
        wait(0.1); // can busy wait between rounds  
    }
    int choice = prompt_input_val;
    switch(choice){
        case 1:
        new_phase();
        return;
        break;
        case 2:
        //not a new phase
        break;
    }  
*/

void reverse_player_order(){
    reverse(player_order.begin(),player_order.end()); //yay for library functions!  
}


//FIXME: be sure to update the previous player's timer when it is paused
void start_timer(int player_num){
    pc.printf("starting timer for player %d\r\n", player_num);
    player_timers[player_num] += bonus_time; //add the bonus for unpausing their timer
    unpause_timer(); //do the rest of the start_timer() stuff
    pc.printf("timer started\r\n");
}
void unpause_timer(){
    current_clock.stop(); //just in case
    current_clock.reset(); //set to zero
    current_clock.start(); //start it ticking
    clock_running = true; // let everything else know that the clock is actively running
    pc.printf("not attatching songs to timeouts\r\n");
    //time_after_warning.attach(jeopardy, &Song::play, time_after_warning_sound);
    //time_before_warning.attach(scale, &Song::play, player_timers[player_num] - time_before_warning_sound);
    //pc.printf("songs attached\r\n");
    pc.printf("end of unpause_timer\r\n");
    
}

void pause_timer(){
    current_clock.stop();
    clock_running = false;
    update_timer(); //resets the timer after updating the player's remaining time    
}

//pauses clock if running, starts clock if paused
void toggle_pause(){
    if (clock_running == true){
        pc.printf("pausing timer from toggle\r\n");
        pause_timer();
        clock_running = false;
        }
    else{
        pc.printf("unpausing timer from toggle\r\n");
        unpause_timer(); //start without adding bonus time
        clock_running = true;
        }
}

void next_player(){
    pause_timer(); //also calls update_timer
    current_player_index++;
    if (current_player_index >= num_players)
        current_player_index = 0;
    current_player = player_order[current_player_index];
    start_timer(current_player);     
}

void update_timer(){
    if (clock_running)
        current_clock.stop();
        
    player_timers[current_player-1] -= (current_clock.read_ms() / 1000);
    current_clock.reset();
    /*if (player_timers[current_player] <= 0)
        beep->play();
    else if (player_timers[current_player] < time_before_warning_sound)
        scale->play();*/

    if(clock_running)
        current_clock.start();
}

void display_timer(){
    stringstream ss;
    ss << "Player " << current_player << ": " << static_cast<double>(player_timers[current_player-1] - (current_clock.read_ms() /1000)) << "\r\n";
    display_msg_no_clear(ss.str());    
}