#include #include #include enum class Step { Up, Down, Left, Right, Select, Null }; // Maximum number of Simon Says steps constexpr int MAX_STEPS = 10; int game_steps = 2; // Simon's steps containers Step simon_steps[MAX_STEPS]; Step user_steps[MAX_STEPS]; LiquidCrystal lcd(8, 9, 4, 5, 6, 7); // Various state flags bool flag_menu = true; bool flag_drew = false; bool flag_user_turn = false; bool flag_simon_rolled = false; // Print a dialog given an upper and lower message void print_dialog(String line_1, String line_2) { lcd.begin(16, 2); lcd.setCursor(0, 0); lcd.print(line_1); lcd.setCursor(0, 1); lcd.print(line_2); } // Null-out an array void initialise_array(Step steps[MAX_STEPS]) { for (size_t index = 0; index < MAX_STEPS; index += 1) { steps[index] = Step::Null; } } // Obtain an array's size size_t array_size(Step steps[MAX_STEPS]) { size_t size = 0; for (size_t index = 0; index < game_steps; index += 1) { if (steps[index] != Step::Null) { size += 1; } } return size; } // Compare equality of two arrays bool compare_arrays(Step user_steps[MAX_STEPS], Step simon_steps[MAX_STEPS]) { for (size_t index = 0; index < array_size(simon_steps); index += 1) { if (simon_steps[index] != user_steps[index]) { return false; } } return true; } // Add a step to Simon's List void increment_simons_list() { simon_steps[array_size(simon_steps)] = (Step)random(4); flag_simon_rolled = true; } // Print initial menu void menu() { if (flag_drew) { int user_key = analogRead(0); if (user_key > 60 && user_key < 200) { game_steps += 1; delay(500); if (game_steps > 10) { game_steps = 1; flag_drew = false; } print_dialog("Press any to go.", String("Up to step (" + String(game_steps) + ").")); } else if (user_key < 800) { flag_menu = false; flag_drew = false; } } else { print_dialog("Press any to go.", String("Up to step (" + String(game_steps) + ").")); flag_drew = true; } } // Convert a step enumeration value to a string String step_to_string(Step step) { String step_string; switch (step) { case Step::Up: { step_string = "Up"; } break; case Step::Down: { step_string = "Down"; } break; case Step::Left: { step_string = "Left"; } break; case Step::Right: { step_string = "Right"; } break; } return step_string; } // Print out Simon's steps void show_steps() { for (size_t index = 0; index < array_size(simon_steps); index += 1) { print_dialog("Simon says:", ""); delay(500); print_dialog("Simon says:", String(step_to_string(simon_steps[index]))); delay(1000); } flag_drew = true; flag_user_turn = true; } // Instant return to menu on request void check_return_to_menu(int user_key) { if (user_key > 600 && user_key < 800) { initialise_array(user_steps); initialise_array(simon_steps); flag_menu = true; flag_drew = false; flag_simon_rolled = false; flag_user_turn = false; } } // Accept user input for Simon's steps void accept_steps(int user_key) { print_dialog("Your turn!", "Input: "); if (user_key < 60) { user_steps[array_size(user_steps)] = Step::Right; print_dialog("Your turn!", "Input: Right"); delay(500); } else if (user_key < 200) { user_steps[array_size(user_steps)] = Step::Up; print_dialog("Your turn!", "Input: Up"); delay(500); } else if (user_key < 400) { user_steps[array_size(user_steps)] = Step::Down; print_dialog("Your turn!", "Input: Down"); delay(500); } else if (user_key < 600) { user_steps[array_size(user_steps)] = Step::Left; print_dialog("Your turn!", "Input: Left"); delay(500); } } // Custom message given equality of user and Simon's steps void compare_steps() { if (array_size(user_steps) == array_size(simon_steps)) { if (compare_arrays(user_steps, simon_steps)) { print_dialog("Correct!", "Continuing ..."); initialise_array(user_steps); if (array_size(simon_steps) >= game_steps || array_size(simon_steps) >= MAX_STEPS) { print_dialog("Correct!", "You won!"); initialise_array(simon_steps); delay(500); flag_menu = true; } flag_user_turn = false; flag_simon_rolled = false; flag_drew = false; } else { print_dialog("Incorrect!", "Returning to menu ..."); initialise_array(user_steps); initialise_array(simon_steps); flag_menu = true; flag_drew = false; flag_simon_rolled = false; } delay(500); } } void setup() { const int SEED_ADDRESS = 0; unsigned long seed = EEPROM.read(SEED_ADDRESS); // Initialise random seed, serial interface, and step arrays EEPROM.write(SEED_ADDRESS, seed + 1); randomSeed(seed); Serial.begin(9600); initialise_array(user_steps); initialise_array(simon_steps); } void loop() { int user_key = analogRead(0); // Press select to return to menu at any time check_return_to_menu(user_key); if (flag_menu) { menu(); } else if (!flag_menu) { // If Simon's list is empty, a new game has begun; so, append a new step if (!flag_simon_rolled) { increment_simons_list(); } // Main game stepper; if the steps have not been printed yet, print them; // otherwise, accept user steps if (!flag_drew && !flag_user_turn) { show_steps(); } else if (flag_drew && flag_user_turn) { accept_steps(user_key); compare_steps(); } } }