Switch statement not reaching a case

So I am trying to use a switch statement to control states in my simple game but the issue I am experiencing is that when I switch to the play state, it doesnt run it at all, in the ready state I change the current_state and it also prints the play state ID (3) and it just doesnt run it at all, I am lost for words what I am doing wrong.

I am not sure what I am doing wrong, if I change it from play to another state like Select, that works but I cant change to play, I AM SAD!

#include <pitches.h>
#include <Button.h>

// PINS
const int buzzer_pin = 9;
// Button pins
const int button_pin_1 = 8;
const int button_pin_2 = 7;
const int button_pin_3 = 6;
const int button_pin_4 = 5;

Button button_1 = Button(button_pin_1);
Button button_2 = Button(button_pin_2);
Button button_3 = Button(button_pin_3);
Button button_4 = Button(button_pin_4);

enum states {Ready,Select,Check,Play,Won,Lost,Reset};
// Ready setups the game
// Select allow input from the player
// Check if the player has guessed correctly or incorrectly
// Play Plays the sequence
// Won plays a win tune and then goes to reset
// Lost plays a tune and then transitions to reset
// Reset resets the game and goes back to ready - creating a loop!

// The start controller
int current_state = Ready;

int won_tune[] = {
  NOTE_C5, NOTE_E5, NOTE_G5, NOTE_C6, // ascending major triad
  NOTE_G5, NOTE_E5, NOTE_C5,          // descending
  NOTE_F5, NOTE_A5, NOTE_C6, NOTE_F6, // new lift
  NOTE_C6                             // final accent
};

int won_durations[] = {
  8, 8, 8, 4,
  8, 8, 4,
  8, 8, 8, 4,
  2
};

int lost_tune[] = {
  NOTE_E3, NOTE_C3, NOTE_D3, NOTE_G2,
  NOTE_E2, NOTE_C2
};

int lost_durations[] = {
  4, 4, 4, 4,
  2, 2
};

int scale_duration = 250;
int scale_sounds[] = {
  NOTE_C3,  // 1 - Low
  NOTE_C4,  // 2 - Mid-low (1 octave up)
  NOTE_C5,  // 3 - Mid-high (2 octaves up)
  NOTE_C6   // 4 - High (3 octaves up)
};

// Guesses is what the player has tried to guess
int guesses[10];
// Results is what we need to guess correctly
int results[10];
int game_length = 9;
int current_index = 0;
int current_target = 0;
int target = 2;

void setup() {
  // put your setup code here, to run once:
  Serial.begin(9600);
  init_buttons();
  // Delaying for 1 second avoids running code again
  delay(1000);
  
}

void loop() {
  handle_states();
}

void handle_states() {
  switch(current_state) {
    case Ready:
      //
      
      generate_results();
      play_scales();
      delay(150);
      Serial.println(current_state);
      current_state = Play;
      break;

    case Select:
      //
      bool result = select_input();

      if (result){
        int pitch = guesses[current_index];
        play_pitch(pitch);
        current_state = Check;
        break;
      }
      
      break;
    case Check:
      //
      break;
    case Play:
      //
      Serial.println("In the play state");
      play_sequence();
      current_state = Select;
      break;
    case Won:
      //
      break;
    case Lost:
      //
      break;
    case Reset:
      //
      break;
  }
}

void init_buttons() {
  button_1.begin();
  button_2.begin();
  button_3.begin();
  button_4.begin();
}

bool select_input() {
// put your main code here, to run repeatedly:
  if (button_1.is_just_pressed()) {
    guesses[current_index] = 1;
    return true;

  }
  if (button_2.is_just_pressed()) {
    guesses[current_index] = 2;
    return true;

  }
  if (button_3.is_just_pressed()) {
    guesses[current_index] = 3;
    return true;

  }
  if (button_4.is_just_pressed()) {
    guesses[current_index] = 4;
    return true;

  }

  return false;
}

void play_victory_tune() {
  for (int i = 0; i < sizeof(won_tune) / sizeof(int); i++) {
    int duration = 1000 / won_durations[i];
    tone(buzzer_pin, won_tune[i], duration);
    delay(duration * 1.3);
    noTone(buzzer_pin);
  }
}

void generate_results() {
  //
  for (int i = 0; i < game_length; i++) {
    results[i] = random(1,5);
  }
}

void play_scales() {
  //
  for (int i = 0; i < 4; i++) {
    play_pitch(i + 1);
    delay(150);
  }
}

void play_sequence() {
  for (int i = 0; i < target; i = i + 1) {
    int result = results[i];
    Serial.println(result);
    play_pitch(result);
    delay(300);
  }
}

void play_pitch(int guess) {

  if (guess <= 0) {
    return;
  }

  if (guess > 4) {
    return;
  }
  switch(guess) {
    case 1:
      tone(buzzer_pin, scale_sounds[0]);
      delay(scale_duration);
      noTone(buzzer_pin);

      break;
    case 2:
      tone(buzzer_pin, scale_sounds[1]);
      delay(scale_duration);
      noTone(buzzer_pin);
      break;
    case 3:
      tone(buzzer_pin, scale_sounds[2]);
      delay(scale_duration);
      noTone(buzzer_pin);
      break;
    case 4:
      tone(buzzer_pin, scale_sounds[3]);
      delay(scale_duration);
      noTone(buzzer_pin);
      break;
  }
}

How about replacing this:

  switch(guess) {
    case 1:
      tone(buzzer_pin, scale_sounds[0]);
      delay(scale_duration);
      noTone(buzzer_pin);

      break;
    case 2:
      tone(buzzer_pin, scale_sounds[1]);
      delay(scale_duration);
      noTone(buzzer_pin);
      break;
    case 3:
      tone(buzzer_pin, scale_sounds[2]);
      delay(scale_duration);
      noTone(buzzer_pin);
      break;
    case 4:
      tone(buzzer_pin, scale_sounds[3]);
      delay(scale_duration);
      noTone(buzzer_pin);
      break;
  }
}

With this:

tone(buzzer_pin, scale_sounds[guess-1]);
delay(scale_duration);
noTone(buzzer_pin);
3 Likes

You should never declare a variable directly inside a case statement. Use an extra pair of braces {} to create a scope inside the case block.

    case Select:
    {
      bool result = select_input();
      if (result){
        int pitch = guesses[current_index];
        play_pitch(pitch);
        current_state = Check;
        break;
      }
      break;
    }
4 Likes

If you declare a variable with an initializer within a case, you need to enclose the entire case within brackets to limit the scope of the variable.

2 Likes

I believe even the limited warnings available in the IDE would catch this mistake, which I for one learned the hard way.

In any case, using the IDE preferences to crank up the verbosity and warnings will help you with other gotchas.

a7

1 Like

Yeah, that definitely can be improved, thanks!

1 Like

This really stumped me, thanks, also how does memory allocation work in this, does it automatically clear memory not be used e.g garbage collection?

I will do that, I come from python and lua where the syntax can be lax.

Those variables are automatic, space for them is on the stack when they exist. There is no garbage collection entering into this.

The problem with the variable that is not in a { block } in the case code is that it can be seen and used before it might have been intialized or maybe even created, dunno for sure, but in any case it invokes the dreaded undefined behaviour which basically means anything can happen.

In C/C++ when anything can happen, it all too often does, and can cause real head-scratchers.

I think it bites eveyone once, some of us more than once. :expressionless:

a7

1 Like

The problem is that a variable declared in a case exists until the end of the switch statement, unless the scope is limited by brackets to the case in which it is created. This causes the compiler to see the variable within scope of any subsequent case, but with the problem that the initialization has been bypassed. The practical result is that no subsequent case ever executes.

Note that there is no problem with declaring an uninitialized variable within a case, and then setting its initial value in a separate line of code. The problem only occurs when the variable is declared with an initializer.

1 Like

Use descriptive words.

Is the Button.h library specially written? Where did you get it? I do not find the class member button_1.is_just_pressed

Hello, yes you are right I should of been more descriptive but I think the rest of the post was clear enough on that I was having issues running a case in the switch statement, and the button lib is custom made, its just the button debounce code made into a lib for reducing script length, and the function is_just_pressed me taking something from godot and it returns a bool when the button has been pressed.