diff options
| author | Fuwn <[email protected]> | 2023-06-07 01:36:23 -0700 |
|---|---|---|
| committer | GitHub <[email protected]> | 2023-06-07 01:36:23 -0700 |
| commit | f5da00ec29b3dc4007704d6356f65e0a5445ac3e (patch) | |
| tree | 138ec66ca3ee0bcfbf8e3f168589835cc9d0a59c | |
| parent | docs: create license (diff) | |
| download | embedded-c-final-project-f5da00ec29b3dc4007704d6356f65e0a5445ac3e.tar.xz embedded-c-final-project-f5da00ec29b3dc4007704d6356f65e0a5445ac3e.zip | |
feat: create main file
| -rw-r--r-- | simon_says.ino | 240 |
1 files changed, 240 insertions, 0 deletions
diff --git a/simon_says.ino b/simon_says.ino new file mode 100644 index 0000000..87c9b27 --- /dev/null +++ b/simon_says.ino @@ -0,0 +1,240 @@ +#include <LiquidCrystal.h> +#include <Vector.h> +#include <time.h> +#include <EEPROM.h> + +enum class Step { + Up, + Down, + Left, + Right, + Select, + Null +}; + +// Maximum number of Simon Says steps +constexpr int MAX_STEPS = 10; + +// 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 < MAX_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) { + if (analogRead(0) < 800) { + flag_menu = false; + flag_drew = false; + } + } else { + print_dialog("Press any key to", "begin."); + + 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; + } +} + +// 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) >= 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(); + } + } +} |