summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorFuwn <[email protected]>2023-06-07 01:36:23 -0700
committerGitHub <[email protected]>2023-06-07 01:36:23 -0700
commitf5da00ec29b3dc4007704d6356f65e0a5445ac3e (patch)
tree138ec66ca3ee0bcfbf8e3f168589835cc9d0a59c
parentdocs: create license (diff)
downloadembedded-c-final-project-f5da00ec29b3dc4007704d6356f65e0a5445ac3e.tar.xz
embedded-c-final-project-f5da00ec29b3dc4007704d6356f65e0a5445ac3e.zip
feat: create main file
-rw-r--r--simon_says.ino240
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();
+ }
+ }
+}