// Initialization Section - start
  // SD card stuff - start
    // Include library for use of the SD card on the Display board
    #include <SD.h>
    // Pin definitions for SD card
    #define CS_SDPIN 26 // Chip select pin for SD card
    //File myFile;  // test file to check SD card
  // SD card stuff - stop

  // Libraries for random number / hold selection - start
    # include <stdlib.h> // For rand() and srand()
    #include <time.h> // For time()
  // Libraries for random number / hold selection - end

  // Touchscreen stuff - start
    #include <Adafruit_GFX.h> // Graphics library for TFT display
    #include <Adafruit_ILI9341.h> // Driver library for ILI9341 TFT display
    #include <SPI.h> // Use this SPI library for Due SPI usage

    // Pin definitions for TFT display and touchscreen
    #define CS_PIN    22 // Chip select pin for TFT
    #define DC_PIN    24  // Data/command pin for TFT

    // Initialize the TFT display object
    Adafruit_ILI9341 tft = Adafruit_ILI9341(CS_PIN, DC_PIN); // This line seems to work just fine
  // Touchscreen stuff - end

  // LED string stuff - start
    // Adafruit Library for controlling LED strips
    #include <Adafruit_NeoPixel.h> 
    
    // Initialization for LED string
    #define DATA_PIN 5    // Data pin connected to the WS2812 LED string
    #define NUM_LEDS 768  // Number of WS2812 LEDs in the strip
    #define COLOR_ORDER RGB      // if colors are mismatched; change this

    // initialize adafruit LED strip
    Adafruit_NeoPixel strip = Adafruit_NeoPixel(NUM_LEDS, DATA_PIN, NEO_GRB + NEO_KHZ800);

    // Set the intensity or brightness level of LEDs to 15%.
      // Calculated for input scale from 0 - 255 => 38 = 255 * 15%
      int globalLEDIntensity = 50; 

    // Define colors as global constants
    const uint32_t WHITE   = strip.Color(globalLEDIntensity, globalLEDIntensity, globalLEDIntensity);
    //const uint32_t SILVER  = strip.Color(192, 192, 192);
    //const uint32_t GRAY    = strip.Color(128, 128, 128);
    //const uint32_t BLACK   = strip.Color(0, 0, 0);
    //const uint32_t MAROON  = strip.Color(128, 0, 0);
    const uint32_t RED     = strip.Color(0, globalLEDIntensity, 0);
    //const uint32_t ORANGE  = strip.Color(255, 165, 0);
    const uint32_t YELLOW  = strip.Color(globalLEDIntensity, globalLEDIntensity, 0);
    //const uint32_t OLIVE   = strip.Color(128, 128, 0);
    const uint32_t GREEN    = strip.Color(globalLEDIntensity, 0, 0);
    //const uint32_t GREEN   = strip.Color(0, 128, 0);
    const uint32_t AQUA    = strip.Color(globalLEDIntensity, 0, globalLEDIntensity);
    const uint32_t BLUE    = strip.Color(0, 0, globalLEDIntensity);
    //const uint32_t NAVY    = strip.Color(0, 0, 128);
    //const uint32_t TEAL    = strip.Color(0, 128, 128);
    const uint32_t FUCHSIA = strip.Color(0, globalLEDIntensity, globalLEDIntensity);
    //const uint32_t PURPLE  = strip.Color(128, 0, 128);
  // LED string stuff - end

  // Intitializing 433MHz remote control - start
    // Libraries
    #include <RH_ASK.h> //433MHz radio head library
    #include <SPI.h> // Not actively used but needed for code to compile

    // Initialize the ASK (Amplitude Shift Keying) driver for RF communication
    // The parameters are: speed, Rx pin, Tx pin (not used), Tx enable pin (not used), and use of internal pull-up
    // Adjust the pin number according to your setup, only sending data to receiver pin6, no Tx pin, selected unused pin 7
    RH_ASK driver(2000, 6, 7, 7, false);
  // Intitializing 433MHz remote control - end

  #include <LinkedList.h> // Include the LinkedList library

  // Wall Button stuff - start
  // Enum to identify wall buttons
    enum WallButton {
      NONE, EAST_WALL_CEILING, EAST_WALL_WALL, NORTH_WALL_CEILING, NORTH_WALL_WALL
    };
  // Wall Button stuff - end

  // pre-initialize all functions - start
  // This allows the code to know that the function exists when it calls it
  // but the function is further down in the code
    void Disco1(); // Currently a sound test, play sound "M0" every 2 seconds
    void Disco2(); // Currently does nothing
    void Disco3(); // Currently LED test, toggling LEDs off/on every 0.5 seconds
    void Disco4(); // Currently does nothing
    void Disco5(); // Currently does nothing
    void Disco6(); // Currently does nothing
    void Disco7(); // Currently does nothing
    void Disco8(); // Currently does nothing
    void Test1(); // test SD card by reading file list to serial monitor
    void Test2(); // test Hold LEDs one at a time. Navigate with remote
    void Test3(); // test melody by pressing any remote control button
    void Game1(); // "Chase the Blues" game
    void Game2(); // Select 80% of 3 TBD hold files for climbing, reduce 5% with each round
    void Game3();
    void Game4();
    void Game5();
    void Game6();
    void Game7(); // added
    void Game8(); // added
    void Game9(); // added
    void Game10(); // added
    void Game11(); // added
    void handleMainMenu(); // function that handles navigation menu logic for main and submenu 
    void checkBackButton(); // function that makes back button press set navigation back to main menu
    void drawInterface(); // function that draws the navigation interface in the display
    void displayText(const String& text, int x, int y, uint16_t color, int size, bool bold); // Utility function to display text with an option for bold text
    String wordWrap(String text, int lineWidth); // word wrapping function, ensures only whole words are printed on description of selections in menu
    bool isBackPressed(); // function used for detecting Back Button pressed for navigation in menu
    bool isSelectPressed(); // function used for Select  Button pressed for navigation in menu
    bool isUpPressed(); // function used for Up  Button pressed for navigation in menu
    bool isDownPressed(); // function used for Down  Button pressed for navigation in menu
    bool isNorthWallWallPressed(); // function to detect if NorthWall Wall Button is pressed for interactive climber input
    bool isNorthWallCeilingPressed(); // function to detect if NorthWall Ceiling Button is pressed for interactive climber input
    bool isEastWallWallPressed(); // function to detect if EastWall Wall Button is pressed for interactive climber input
    bool isEastWallCeilingPressed(); // function to detect if EastWall Ceiling Button is pressed for interactive climber input
    bool isInitialized = false; // global initialization flag used with all games to run one section only once
    void LightOneHold(uint32_t color, int ledA, int ledB = -1, int ledC = -1, int ledD = -1); // function to light up the LEDs for one Hold
    void parseAndLightHoldLEDs(String line, uint32_t color); // Function to parse a CSV line, extract the LEDs belonging to hold of that line and call "LightOneHold" to light them up
    void parseAndLightRouteLEDs(String line, uint32_t color); // Function to parse a route, extract the LEDs belonging to hold of that line and call "LightOneHold" to light them up
    void clearLEDs(); // Clears all LED, i.e. turns all LEDs off
    void writeHighScoreToFile(String fileName, int highScore); // function writes a High Score to a to-be-specified file
    int readHighScoreFromFile(String fileName); // function reads a High Score from a to-be-specified file
    int loadHighScore(int gameId); // Function to load the high score for a specific game from standard high score file
    // int countTotalRows(String fileName); // Count the rows and thus the holds that are in a ".csv" file, Displaced by countLines.
    //void SelectRoute(String firstFile, String secondFile = "", String thirdFile = "", int num1 = 0, int num2 = 0); // function to randomly select a route from 1-3 csv files that contain lists of holds
    //void SelectRoute(String firstFile, String secondFile = "", String thirdFile = "", int num1 = 0, int num2 = 0);
    void SelectAndLightFromFile(String filePath); // function that pics a random file from a folder and lights up the route in the file 
    void appendFileContents(String fileName, File &destFile); // function that appends files together to create a group of holds for random selection, THIS MAY NOT BE NEEDED. I THINK WHEN WRITING A LINE TO THE CSV FILE THE LINE GETS APPENDED AUTOMATICALLY. CHECK THIS. 
    void appendFileContentsWithoutHeader(String fileName, File &destFile); // function that appends files that have one header line together to create a group of holds for random selection, THIS MAY NOT BE NEEDED. I THINK WHEN WRITING A LINE TO THE CSV FILE THE LINE GETS APPENDED AUTOMATICALLY. CHECK THIS. 
    int countLines(String fileName, bool hasHeader = false); // function that counts lines in a file, can skip a header when told, returns number of lines
    void selectRandomHoldsAndLight(File &sourceFile, File &destFile, int percentage); // function that selects the holds randomly from a list in .csv file and then lights them up
    void handleButtonPresses(); // function that listens to and then reacts to interactive wall button presses - start => WOULD BE BETTER TO SPLIT THIS IN TWO? ONE THAT LISTENS ALL THE TIME AND ONE THAT REACTS?
    // void rerunSelection(); // function to rerun the function SelectRoute with reduced percentages
    String readLineFromFile(String fileName, int lineNum); // function that reads one specific line from a data file
    WallButton checkWallButtonPress(); // function that checks Wall Buttons and returns which one was pressed, needs to be declared after enum (see above)
  // pre-initialize all functions - stop

  // Global variable declarations - start
    int lastDisplayedHoldNum = -1; // Global variable to store the last displayed hold number
    int highScore; // Global variable to storing and managing the high score of a game
    String fileName; // global declaration for fileName variable which can be used in writing/reading of files

  // Global variables that support function "SelectRoute" function - start
  /*  File curRoute;
    int PercOfHoldPool = 80;  // Initial percentage of holds
    int RedOfPercOfHoldPool = 5;  // Reduction step on each button press
  // Global variables that support function "SelectRoute" function - end
  */
  // state machine stuff - start
    // Enumeration to define different states of the program
      enum State {
        MAIN_MENU,
        GAME1,
        GAME2,
        GAME3,
        GAME4,
        GAME5,
        GAME6,
        GAME7, // added
        GAME8, // added
        GAME9, // added
        GAME10, // added
        GAME11, // added
        DISCO1,
        DISCO2,
        DISCO3,
        DISCO4,
        DISCO5,
        DISCO6,
        DISCO7,
        DISCO8,
        TEST1,
        TEST2,
        TEST3
      };

    // set default state at start up "MAIN_MENU"
    State currentState = MAIN_MENU; // Current state of the program

    // Arrays to store names of games and disco modes
      const String stateNames[] = {"Games", "Disco"};
      const int numOfStates = sizeof(stateNames) / sizeof(stateNames[0]);
      int currentStateIndex = 0;

    // Array to store submenu GameX items
      const String gameStates[] = {"Game1", "Game2", "Game3", "Game4", "Game5", "Game6", "Game7", "Game8", "Game9", "Game10", "Game11"}; // add more Game items as needed
    // number in Array used for printing on screen
      const int numOfGameStates = sizeof(gameStates) / sizeof(gameStates[0]);

    // Array to store submenu DiscoX items
      const String discoStates[] = {"Disco1", "Disco2", "Disco3", "Disco4", "Disco5", "Disco6", "Disco7", "Disco8", "Test1", "Test2", "Test3"}; // add more Disco items as needed
    // number in Array used for printing on screen
      const int numOfDiscoStates = sizeof(discoStates) / sizeof(discoStates[0]);

    // text descriptions for sub-menu - start
      // add more descriptions when game or disco menu increases
      // text description for game choices that are plotted when selecting game
      // const char* gameDescriptions[] = {"LED blink test Extra", "Description for Game2", "Description for Game3", "Description for Game4", "Description for Game5", "Description for Game6"};
      // text description for disco choices that are plotted when selecting game
      // const char* discoDescriptions[] = {"Test for Disco1 blinks an LED slowly", "Disco2", "Description for Disco3", "Description for Disco4", "Description for Disco5", "Description for Disco6", "Description for Disco7", "Description for Disco8", "SD card check. Read file list on SD card once, plot to serial monitor, then jump to main menu.", "Hold LED check. Show LEDs for one counted hold at a time. Use remote control to navigate."};
    // text descriptions for sub-menu - END

    // indexes used for navigation and selection
      int currentGameStateIndex = 0; // Index to track current game selection
      int currentDiscoStateIndex = 0; // Index to track current disco mode
      bool inSubmenu = false; // Flag to indicate if in a submenu
  // state machine stuff - end

  // Game1 stuff - start
    // global variables for game1 test code blinking LED
      unsigned long lastLedToggle = 0; // Time of the last LED state change
      const long ledToggleInterval = 150; // Interval for LED state change in milliseconds
      File holdFile;
  // Game1 stuff - end

  // Meta data for all the holds - start
    // Define a structure to hold the metadata for each climbing hold
    // The metadata itself is stored on the SD card of the TFT Display shield
      struct Hold {
          int holdNum;       // Unique number of the hold
          float holdX, holdY, holdZ; // X, Y, Z coordinates of the hold
          int panel;         // Panel number where the hold is located
          int ledA, ledB, ledC, ledD; // LED numbers associated with this hold
          float ledAX, ledAY, ledAZ; // X, Y, Z coordinates of LED A (you can add similar for other LEDs if needed)
          String wallType;   // Type of the wall, e.g., 'regular'
          String material;   // Material of the hold (if applicable)
          String occupied;   // Status of the hold (e.g., occupied or free)
          String holdCategory; // Category of the hold
          String holdType;   // Type of the hold
          String difficulty; // Difficulty rating of the hold
          String color;      // Color of the hold
          String size;       // Size of the hold
      };
  // Meta data for all the holds - end

  // variables needed to handle download and processing of hold data - start
      File myFile;
      Hold currentHold;
  // variables needed to handle download and processing of hold data - end

  // Test2 stuff - start
    #define LED_CHANNEL_A 0 // Adjust these indexes based on your setup
    #define LED_CHANNEL_B 1
    #define LED_CHANNEL_C 2
    #define LED_CHANNEL_D 3
    int currentLine = 1; // to keep track of the current line being read from the file
    // Declare the functions at the beginning of the file => SHOULD I MOVE THESE UP TO THE OTHERS?
      String readLineFromFile(String fileName, int lineNum);
      void lightLEDs(int ledA, int ledB, int ledC, int ledD);
    // global variable to hold last displayed holdnum, needed to get non-blinking display
    //int lastDisplayedHoldNum = -1; // Initialize with an impossible value for hold numbers
  // Test2 stuff - stop

// Initialization Section - end

// perform setup - start
  void setup() {
    // setup TFT display
    Serial.begin(115200); // Start serial communication
    // tft.setSPISpeed(24000000); // Optional: Set SPI speed to 24MHz, uncomment if needed
    tft.begin(); // Initialize the TFT display
    tft.setRotation(1); // Set display rotation to landscape
    tft.fillScreen(ILI9341_BLACK); // Clear the screen and make it black

    pinMode(DATA_PIN, OUTPUT); // Set the LED pin as output
    // Initialize LED strip
    //FastLED.addLeds<WS2812, DATA_PIN, RGB>(leds, NUM_LEDS);

    // Setup of buttons with internal pull-up resistors for menu navigation
    pinMode(11, INPUT_PULLUP); // up Button
    pinMode(10, INPUT_PULLUP); // down Button
    pinMode(9, INPUT_PULLUP); // select Button
    pinMode(8, INPUT_PULLUP); // back Button

    // Setup of 4x wall buttons with internal pull-up resistors for climber-program interaction
    pinMode(46, INPUT_PULLUP); // Setup for Wall Button Eastwall Ceiling
    pinMode(48, INPUT_PULLUP); // Setup for  Wall Button Eastwall Wall
    pinMode(50, INPUT_PULLUP); // Setup for  Wall Button Northwall Ceiling
    pinMode(52, INPUT_PULLUP); // Setup for  Wall Button Northwall Wall

    // Setting up pin A0 as an output for an LED for testing
    pinMode(A0, OUTPUT); 

    // Pre-initialize drawinterface function
    drawInterface();

    // Initialize Adafruit LED strip and switch off
    strip.begin(); // Initialize the NeoPixel strip
    strip.show(); // Initialize all pixels to 'off'

    // Initialize Serial3 for Arduino Due communication with Arduino Nano for Sound
    Serial3.begin(9600); // Tx3 = Pin14, Rx3 = Pin15

    // Check if initializing the RF receiver worked - start
    // use the following lines when a check with the serial monitor is needed
      if (!driver.init()) {
        Serial.println("RF receiver init failed"); // Print error message if initialization fails
      } else {
        Serial.println("RF receiver initialized"); // Confirmation message
      }
    // Check if initializing the RF receiver worked - end

    // Test for SD card functionality - May need to move to other location - start
    // Initialize SD card
    //Serial.begin(115200);
    if (!SD.begin(CS_SDPIN)) {
     Serial.println("SD card failed to initialize or not present");
     return;
    }
    Serial.println("SD Card initialization successful.");

    // random seed for random number generation
    randomSeed(analogRead(0));

  }
// perform all setup - end

// main loop - start
  void loop() {
    static unsigned long lastButtonPress = 0; // Time of the last button press for debouncing
    // Check if enough time has passed since the last button press (debouncing)
    if (millis() - lastButtonPress > 200) { // If time is longer than 200 ms it is an actual button press
        // Switch statement to handle different states
        switch (currentState) {
            case MAIN_MENU: // default state
                handleMainMenu(); // function that handles navigation menu logic for main and submenu
                break;

            // Implement cases for each game and disco state
            // Case for Game1
            case GAME1:
                Game1();
                checkBackButton(); // Check if the back button was pressed
                break;

            // Case for Game2
            case GAME2:
                Game2();
                checkBackButton(); // Check if the back button was pressed
                break;

            // Case for Game3
            case GAME3:
                Game3(); // (moved out; this is now a placeholder below)
                checkBackButton(); // Check if the back button was pressed
                break;

            // Case for Game4
            case GAME4:
                Game4();
                checkBackButton(); // Check if the back button was pressed
                break;

            // Case for Game5
            case GAME5:
                Game5();
                checkBackButton(); // Check if the back button was pressed
                break;

            // Case for Game6
            case GAME6:
                Game6();
                checkBackButton(); // Check if the back button was pressed
                break;

            // Case for Game7
            case GAME7:
                Game7(); // runs the previous Game3 logic (unchanged)
                checkBackButton(); // Check if the back button was pressed
                break;

            // Case for Game8
            case GAME8:
                Game8();
                checkBackButton(); // Check if the back button was pressed
                break;

            // Case for Game9
            case GAME9:
                Game9();
                checkBackButton(); // Check if the back button was pressed
                break;

            // Case for Game10
            case GAME10:
                Game10();
                checkBackButton(); // Check if the back button was pressed
                break;

            // Case for Game11
            case GAME11:
                Game11();
                checkBackButton(); // Check if the back button was pressed
                break;

            // Case for Disco1
            case DISCO1:
                Disco1();
                checkBackButton(); // Check if the back button was pressed
                break;

            // Case for Disco2
            case DISCO2:
                Disco2(); // Run Disco2 logic
                checkBackButton(); // Check if the back button was pressed
                break;
            
            // Case for Disco3
            case DISCO3:
                Disco3();
                checkBackButton(); // Check if the back button was pressed
                break;

            // Case for Disco4
            case DISCO4:
                Disco4();
                checkBackButton(); // Check if the back button was pressed
                break;

            // Case for Disco5
            case DISCO5:
                Disco5();
                checkBackButton(); // Check if the back button was pressed
                break;

            // Case for Disco6
            case DISCO6:
                Disco6();
                checkBackButton(); // Check if the back button was pressed
                break;

            // Case for Disco7
            case DISCO7:
                Disco7();
                checkBackButton(); // Check if the back button was pressed
                break;

            // Case for Disco8
            case DISCO8:
                Disco8();
                checkBackButton(); // Check if the back button was pressed
                break;

            // Case for Test1
            case TEST1:
                Test1();
                // checkBackButton(); // Check if the back button was pressed
                // The previous line is cancelled out because we are automatically switching back to main menu
                // The function Test1 is only run once
                // Instead of calling checkBackButton(), directly set the state to MAIN_MENU
                currentState = MAIN_MENU;
                inSubmenu = false; // Ensure we're no longer in a submenu, if applicable
                drawInterface(); // Optionally, redraw the interface for the main menu
                break;

            // Case for Test2
            case TEST2:
                Test2();
                checkBackButton(); // Check if the back button was pressed
                break;

            // Case for Test3
            case TEST3:
                Test3();
                checkBackButton(); // Check if the back button was pressed
                break;
            // Add cases for other disco states
        }
        lastButtonPress = millis();
    }
  }

// main loop - stop

// function section - start
  // function containing logic that handles navigation in main and submenus - start
  // Handles the main menu and submenu navigation
    void handleMainMenu() {
      // Check if we're currently in the main menu or a submenu
        if (!inSubmenu) {
          // Logic for main menu navigation
            if (isUpPressed() || isDownPressed()) {
              Serial3.println("M0");  // Sound feedback for button press
              currentStateIndex = 1 - currentStateIndex; // Toggle between "Games" and "Disco" in the main menu
              drawInterface(); // Refresh the display to show the current selection
              delay(200); // Delay for button debounce
            }
          // Handle the "Select" button press in the main menu
            if (isSelectPressed()) {
              Serial3.println("M0");  // Sound feedback for button press
              inSubmenu = true; // Enter the submenu (games or disco modes)
              currentGameStateIndex = 0; // Start at the first game
              currentDiscoStateIndex = 0; // Start at the first disco mode
              drawInterface(); // Refresh the display for the submenu
              delay(200); // Delay for button debounce
            }
        } else {
          // Logic for submenu navigation
            if (isUpPressed() || isDownPressed()) {
              Serial3.println("M0");  // Sound feedback for button press
              // Navigation logic for the submenu (either games or disco modes)
                if (currentStateIndex == 0) { // If in the "Games" submenu
                  currentGameStateIndex = (isUpPressed() ? 
                    (currentGameStateIndex - 1 + numOfGameStates) % numOfGameStates : 
                    (currentGameStateIndex + 1) % numOfGameStates);
                } else { // If in the "Disco" submenu
                  currentDiscoStateIndex = (isUpPressed() ? 
                    (currentDiscoStateIndex - 1 + numOfDiscoStates) % numOfDiscoStates : 
                    (currentDiscoStateIndex + 1) % numOfDiscoStates);
                }
                drawInterface(); // Refresh the display with the new submenu selection
                delay(200); // Delay for button debounce
            }
          // Handle the "Select" button press in a submenu
            if (isSelectPressed()) {
              Serial3.println("M0");  // Sound feedback for button press
              // Change the current state based on the selection
                currentState = static_cast<State>((currentStateIndex == 0 ? GAME1 : DISCO1) + 
                    (currentStateIndex == 0 ? currentGameStateIndex : currentDiscoStateIndex));
              delay(200); // Delay for button debounce
            }
          // Return to the main menu if the "Back" button is pressed
            if (isBackPressed()) {
              Serial3.println("M0");  // Sound feedback for button press
              inSubmenu = false; // Exit the submenu
              drawInterface(); // Refresh the display for the main menu
              delay(200); // Delay for button debounce
            }
        }
    }

  // function containing logic that handles navigation in main and submenus - end

  // function that checks back button, when pressed will set navigation back to main menu - start
    void checkBackButton() {
      // Check if the back button is pressed to return to the main menu
        if (isBackPressed()) {
          // Send "M0" to Nano to play "button pressed"-sound
            Serial3.println("M0");
          // conduct menu change
            currentState = MAIN_MENU;
            inSubmenu = false;
          drawInterface(); // Update the display
          isInitialized = false; //reset initialization flag
        }
    }
  // function that checks back button, when pressed will set navigation back to main menu - end

  // Button check functions - start => SHOULD ADD THE OTHER BUTTONS HERE TOO? USING THE SAME STRATEGY
    bool isUpPressed() { return digitalRead(11) == LOW; }
    bool isDownPressed() { return digitalRead(10) == LOW; }
    bool isSelectPressed() { return digitalRead(9) == LOW; }
    bool isBackPressed() { return digitalRead(8) == LOW; }
    bool isNorthWallWallPressed() {return digitalRead(46) == LOW; }
    bool isNorthWallCeilingPressed() {return digitalRead(48) == LOW; }
    bool isEastWallWallPressed() {return digitalRead(50) == LOW; }
    bool isEastWallCeilingPressed() {return digitalRead(52) == LOW; }
  // Button check functions - end

  // word wrapping function, ensures only whole words are printed - start
    String wordWrap(String text, int lineWidth) {
      String result, word, line;
      int i = 0, spaceLeft = lineWidth;

      while (i < text.length()) {
        char c = text.charAt(i);
        if (c == ' ' || c == '\n') {
          if (line.length() + word.length() > spaceLeft) {
            result += line + '\n';
            line = word + " ";
            spaceLeft = lineWidth - line.length();
          } else {
            line += word + " ";
            spaceLeft -= word.length() + 1;
          }
          word = "";
        } else {
          word += c;
        }
        i++;
      }
      result += line + word; // Add the remaining text
      return result;
    }
  // word wrapping function, ensures only whole words are printed - stop

  // function that draws the navigation interface in the display - start
    void drawInterface() {
      // Clear the entire screen to set a black background
        tft.fillRect(0, 0, 320, 240, ILI9341_BLACK);
      // Drawing the 'Up' button
      // Draw a yellow rectangle at the top-left corner for the 'Up' button
        tft.fillRect(0, 0, 80, 78, ILI9341_YELLOW); // Yellow rectangle for the 'Up' button
      // Set the position and style for the 'Up' text label
        tft.setCursor(22, 30); // Positioning the text label
        tft.setTextColor(ILI9341_BLACK); // Set text color to black
        tft.setTextSize(3); // Choose a large text size for visibility
        tft.print("Up"); // Print the 'Up' label on the button

      // Drawing the 'Down' button
      // Draw a second yellow rectangle below the first one for the 'Down' button
        tft.fillRect(0, 82, 80, 78, ILI9341_YELLOW); // Yellow rectangle for the 'Down' button
      // Set the position and style for the 'Down' text label
        tft.setCursor(5, 110); // Positioning the text label
        tft.setTextColor(ILI9341_BLACK); // Set text color to black
        tft.setTextSize(3); // Choose a large text size for visibility
        tft.print("Down"); // Print the 'Down' label on the button

      // Drawing the 'Select' button
      // Draw a green rectangle for the 'Select' button
        tft.fillRect(90, 40, 110, 80, ILI9341_GREEN); // Green rectangle for the 'Select' button

      // Drawing the 'Back' button
      // Draw a red rectangle for the 'Back' button
        tft.fillRect(210, 40, 110, 80, ILI9341_RED); // Red rectangle for the 'Back' button
      // Set the position and style for the 'Back' text label
        tft.setCursor(232, 70); // Positioning the text label
        tft.setTextColor(ILI9341_BLACK); // Set text color to black
        tft.setTextSize(3); // Choose a large text size for visibility
        tft.print("Back"); // Print the 'Back' label on the button

      // Logic for displaying menu and submenu items
        if (!inSubmenu) {
          // If not in a submenu, display the main menu item ('Games' or 'Disco')
            displayText(stateNames[currentStateIndex], 145, 70, ILI9341_BLACK, 3, true);
        } else {
          // If in a submenu, display the appropriate submenu items
          // Determine the current array of items (games or disco states)
          // String* currentArray = currentStateIndex == 0 ? gameStates : discoStates;
            const String* currentArray = currentStateIndex == 0 ? gameStates : discoStates;
            int numOfStates = currentStateIndex == 0 ? numOfGameStates : numOfDiscoStates;
            int currentIndex = currentStateIndex == 0 ? currentGameStateIndex : currentDiscoStateIndex;

          // Define positions for submenu items
            int middleIndex = 2; 
            int yPos[5] = {5, 24, 70, 123, 142}; // Y-positions for submenu items

          // Loop through and display the submenu items
            for (int i = 0; i < 5; i++) {
              int arrayIndex = (currentIndex - middleIndex + i + numOfStates) % numOfStates;
              bool isBold = (i == middleIndex); // Highlight the selected item
              // Display each item in the submenu
                displayText(currentArray[arrayIndex], 145, yPos[i], isBold ? ILI9341_BLACK : ILI9341_WHITE, isBold ? 3 : 2, isBold);
            }

          String description; // Variable to hold the description text

          if (inSubmenu) {
            // Determine the file name based on current menu (games or disco)
              String fileName = currentStateIndex == 0 ? "DesGames.txt" : "DesDisco.txt";
              int lineNum = currentStateIndex == 0 ? currentGameStateIndex + 1 : currentDiscoStateIndex + 1; // Line number to read (add 1 assuming file lines start at 1)

            // Open the file for reading
              File file = SD.open(fileName);
            if (file) {
            // Skip to the correct line
              for (int i = 1; i < lineNum && file.available(); i++) {
                file.readStringUntil('\n'); // Skip lines
              }
              // Read the target line
                if (file.available()) {
                  description = file.readStringUntil('\n');
                }
              file.close(); // Close the file after reading
            } else {
              description = "Error: File not found";
            }
            // Additional code to display the description...
          }

          // Wrap the text
          //String wrappedText = wordWrap(String(buffer), 46/* = max characters on line width */);
          // Wrap the text
            String wrappedText = wordWrap(description, 46); // Use 'description' instead of 'buffer'

          // Set the position, color, and size for the description text
            tft.setCursor(0, 160); // (x,y) Position for the text at the bottom
            tft.setTextColor(ILI9341_ORANGE, ILI9341_BLACK); // Text color
            tft.setTextSize(2); // Suitable text size

          // Print the wrapped description text
            tft.print(wrappedText);
        }
    }

// draw the navigation interface in the display - end

// Utility function to display text with an option for bold text - start
  void displayText(const String& text, int x, int y, uint16_t color, int size, bool bold) {
    if (bold) {
      // Display bold text by printing multiple times with slight offsets
        for (int i = -1; i <= 1; i++) {
            tft.setCursor(x - (text.length() * 6 * size) / 2 + i, y);
            tft.setTextColor(color);
            tft.setTextSize(size);
            tft.print(text);
        }
    } else {
        // Regular text display
        tft.setCursor(x - (text.length() * 6 * size) / 2, y);
        tft.setTextColor(color);
        tft.setTextSize(size);
        tft.print(text);
    }
  }
// Utility function to display text with an option for bold text - end

// Function parseCSVLineToHold description needed - start
// This function does not seem to be complete.
// I think this is supposed to read a single line from the Hold Meta Data and writes it into the "hold structure" Need more work to understand this. 
  void parseCSVLineToHold(String line, Hold &hold) {
    // Implementation to parse a CSV line and populate the hold structure
    // You'll likely use `strtok` or similar to split the line by commas
    // and then convert each segment into the appropriate data type
  }
// Function parseCSVLineToHold description needed - end

// function for reading data from file - start
  void readDataFromFile(String fileName) {
    File dataFile = SD.open(fileName);
    if (dataFile) {
      while (dataFile.available()) {
        Serial.write(dataFile.read());
      }
      dataFile.close();
    } else {
      Serial.println("Error opening file for reading");
    }
  }
// function for reading data from file - end

// function for writing data to file - start
// I don't this is doing anything
  void writeDataToFile(String fileName, String data) {
    File dataFile = SD.open(fileName, FILE_WRITE);
    if (dataFile) {
      dataFile.println(data);
      dataFile.close();
    } else {
      Serial.println("Error opening file for writing");
    }
  }

// read High Score from File - start
  // This file returns an integer number
  // read the high score by:
  // int highScore = readHighScoreFromFile("HSGame1.txt"); // with HSGame1.txt being the file the high score for game1 is stored in.
  int readHighScoreFromFile(String fileName) {
    File dataFile = SD.open(fileName);
    if (dataFile) {
      if(dataFile.available()) {
        int highScore = dataFile.parseInt(); // Read the high score
        dataFile.close(); // Close the file
        return highScore;
      }
      dataFile.close(); // Ensure the file is closed even if no data available
    } else {
      Serial.println("Error opening high score file for reading.");
    }
    return 0; // Return 0 if file does not exist or is empty
  }
// read High Score from File - end

// write a High Score to a file - start
  // write high score by:
  // writeHighScoreToFile("HSGame1.txt", newHighScore); // with newHighScore being the variable the HighScore is in.
  void writeHighScoreToFile(String fileName, int highScore) {
    // First, remove the existing file to ensure we're starting fresh
    SD.remove(fileName);  
    // Now, open a new file for writing that uses the same name
    File dataFile = SD.open(fileName, FILE_WRITE);
    if (dataFile) {
      dataFile.println(highScore); // Write the new high score
      dataFile.close(); // Close the file
      Serial.println("High score updated.");
    } else {
      Serial.println("Error opening high score file for writing.");
    }
  }
// write a High Score to a file - end

/* 
//examples for reading writing in game or disco function:
void Game1() {
  readDataFromFile("game1data.csv");
  // Game logic...
  writeDataToFile("game1data.csv", "New,Data,Here");
}
*/
// enable reading or writing Data from file - stop

// Game1 "Chase the Blues" - start
  void Game1() {
    //static bool isInitialized = false; // Keep track of whether the game has been initialized
    static int clicksNum = 0; // Keep track of the number of clicks/remote inputs
    static int lastclicksCount = -1; // To check against clicksNum to update the display only on change
    static int highScore = 0; // Current session high score
    static int HiHiScore = 0; // All-time high score initiate locally
    

    // Only run initialization part once
    if (!isInitialized) {
        Serial.println("Starting Game1..."); // Indicate game start
        // You can use these alternative lines to use readLineFromFile to get the all-time high score from "HiScores.txt"
        // For the current session the high score is 0 when the game is started
        // For the All-time HiHiScore is read from HSGame1.txt
        // String HiHiScoreStr = readLineFromFile("HiScores.txt", 1); // Reading the first line for Game1's high score
        // HiHiScore = HiHiScoreStr.toInt(); // Convert the high score string to an integer
        HiHiScore = readHighScoreFromFile("HSGame1.txt"); // Read the all-time high score from HSGame1.txt
        Serial.print("Read HiHiScore from file: "); // Print to serial monitor for debugging
        Serial.println(HiHiScore); // Display the read HiHiScore
        
        //int totalRows = countTotalRows("HoldHold.csv"); // Count the holds in "HoldHold.csv"
        int totalRows = countLines("HoldHold.csv", true); // Pass 'true' to indicate that the file has a header
        int totalHolds = totalRows - 1; // Subtracting header row
        int selectedRow = random(2, totalHolds + 2); // Select a row randomly

        String line = readLineFromFile("HoldHold.csv", selectedRow);
        if (line != "") {
            strip.clear(); // Turn off all LEDs before setting new ones
            parseAndLightHoldLEDs(line, strip.Color(0, 0, 255)); // Assuming Blue color
            
            Serial.print("Parsed Hold Number: ");
            // The function parseAndLightHoldLEDs already prints the hold number
        } else {
            Serial.println("Line is empty or file not found");
        }

        isInitialized = true; // Prevent re-initialization
    }

    // Handle remote control input
    if (driver.available()) {
        uint8_t buf[RH_ASK_MAX_MESSAGE_LEN];
        uint8_t buflen = sizeof(buf);
        if (driver.recv(buf, &buflen)) {
            char cmd = (char)buf[0];
            
            // Restart the game if 'X' or 'Y' is received, keeping the high score intact
            if (cmd == 'X' || cmd == 'Y') {
                // Game restart logic
                if (clicksNum > HiHiScore) {
                    HiHiScore = clicksNum; // Update HiHiScore if current session's score is higher
                    // select random Melody from M3 - M13
                      int randomNumber = random(3, 14); // random(min, max) generates numbers from min to max-1
                      String message = "M" + String(randomNumber);  // Concatenate "M" with the random number
                      Serial3.println(message);  // Send the sound feedback for updated HiHiScore to "HiScores.txt"
                    // writeDataToFile("HiScores.txt", String(HiHiScore)); 
                    writeHighScoreToFile("HSGame1.txt", HiHiScore);
                }
                clicksNum = 0; // Reset clicks number
                // No need to reset highScore here as we're keeping the high score intact

            } else {
                // Increase clicksNum for any other button press
                clicksNum++;
                Serial3.println("M1");  // Sound feedback for button press
                // Update highScore if clicksNum exceeds it
                if (clicksNum > highScore) {
                    highScore = clicksNum;
                    // Optionally, save the new high score to "HiScores.txt" here
                    // writeDataToFile("HiScores.txt", String(HiHiScore)); // Assume this function overwrites the first line with the new high score
                }

                // Continue with selecting a new hold and updating LEDs (unchanged code)
                //int totalRows = countTotalRows("HoldHold.csv");
                int totalRows = countLines("HoldHold.csv", true); // Pass 'true' to indicate that the file has a header
                int totalHolds = totalRows - 1;
                int selectedRow = random(2, totalHolds + 2);
                String line = readLineFromFile("HoldHold.csv", selectedRow);
                if (line != "") {
                  strip.clear(); // Turn off all LEDs before setting new ones
                  parseAndLightHoldLEDs(line, strip.Color(0, 0, 255));
                }
            }
        }
    }

    // Display update for clicksNum
    if (clicksNum != lastclicksCount) {
        tft.fillRect(0, 160, 320, 80, ILI9341_BLACK); // Clear previous display
        tft.setTextColor(ILI9341_BLUE);
        tft.setTextSize(5);
        tft.setCursor(30, 170);
        tft.print("Blues: ");
        tft.println(clicksNum);
        lastclicksCount = clicksNum; // Update lastclicksCount

        // Display High Score
        tft.setTextColor(ILI9341_BLUE); // Set text color for high score
        tft.setTextSize(2); // Set a smaller text size for high score
        tft.setCursor(10, 220); // Adjust this position as needed
        tft.print("HiScore: "); 
        tft.println(highScore); // print the session high Score onto the screen
        tft.setCursor(160, 220); // Adjust this position as needed
        tft.print("HiHiScore: "); 
        tft.println(HiHiScore); // print the session high Score onto the screen
        
     }
}
// Game1 "Chase the Blues" - end

//Game2 "Theme Routes" - start
void Game2() {

  String filePath = "Themes/"; // Define the starting path as the path to the Handhold files for this game
  static int HiHiScore = 0; // All-time high score initiate locally
  static int ButtonNum = 0; // Keep track of the number of Button clicks for the high score
  static int lastclicksCount = -1; // To check against clicksNum to update the display only on change

  if (!isInitialized) {
    clearLEDs(); // shut off all LEDs at the start of Game 2
    Serial.println("Entering Game2 for the first time.");

    HiHiScore = readHighScoreFromFile("HSGame2.txt"); // Read the all-time high score from HSGame1.txt
    Serial.print("Read HiHiScore from file: "); // Print to serial monitor for debugging
    Serial.println(HiHiScore); // Display the read HiHiScore
    
    //SelectRoute("CoWhite.csv", "CoWood.csv", "CoPink.csv", 80, 5);
    //SelectAndLightFromFile(filePath, FUCHSIA); // Pass the file path
    //filePath = "Hand/25Perc/"; // Define the path to the Handhold files for this game
    SelectAndLightFromFile(filePath, RED); // Pass the file path
    //filePath = "Feet/25Perc/"; // Define the path to the Foothold files for this game
    //SelectAndLightFromFile(filePath, BLUE); // Pass the file path
    Serial.println("SelectAndLightFromFile called");
    isInitialized = true;
  }

  if (isNorthWallCeilingPressed() || isNorthWallWallPressed() ||
    isEastWallCeilingPressed() || isEastWallWallPressed()) {
    Serial.println("Wall button pressed in Game2. Reloading new route.");
    //PercOfHoldPool = max(PercOfHoldPool - 5, 5);  // Ensuring at least 5% is always selected
    //SelectRoute("CoWhite.csv", "CoWood.csv", "CoPink.csv", PercOfHoldPool, 5);
    clearLEDs(); // shut off all LEDs prior to resetting Route for Game 2

    // select and play random Melody from M3 - M13
    int randomNumber = random(3, 14); // random(min, max) generates numbers from min to max-1
    String message = "M" + String(randomNumber);  // Concatenate "M" with the random number
    Serial3.println(message);  // Send the sound feedback for updated HiHiScore to "HiScores.txt"

    // Increase ButtonNum for any button press
    ButtonNum++;

    if (ButtonNum > HiHiScore) {
      HiHiScore = ButtonNum; // Update HiHiScore if current session's score is higher
      writeHighScoreToFile("HSGame2.txt", HiHiScore);
    }

    static bool toggleColor = false; // Static variable to toggle between colors
    if (toggleColor) {
      //SelectAndLightFromFile(filePath, FUCHSIA);
      //filePath = "Hand/25Perc/"; // Define the path to the Foothold files for this game
      SelectAndLightFromFile(filePath, RED);
      //filePath = "Feet/25Perc/"; // Define the path to the Foothold files for this game
      //SelectAndLightFromFile(filePath, BLUE);
      Serial.println("Color set to FUCHSIA");
    } else {
      //SelectAndLightFromFile(filePath, AQUA);
      //filePath = "Hand/25Perc/"; // Define the path to the Foothold files for this game
      SelectAndLightFromFile(filePath, AQUA);
      //filePath = "Feet/25Perc/"; // Define the path to the Foothold files for this game
      //SelectAndLightFromFile(filePath, FUCHSIA);
      Serial.println("Color set to AQUA");
    }
    toggleColor = !toggleColor; // Toggle the color for next button press

    Serial.println("SelectAndLightFromFile called due to button click");
  }

  Serial.println("Game2 is running.");

  checkBackButton();

  // Display update for clicksNum
  if (ButtonNum != lastclicksCount) {
    tft.fillRect(0, 160, 320, 80, ILI9341_BLACK); // Clear previous display
    tft.setTextColor(ILI9341_BLUE);
    tft.setTextSize(5);
    tft.setCursor(30, 170);
    tft.print("Routes: ");
    tft.println(ButtonNum);
    lastclicksCount = ButtonNum; // Update lastclicksCount

    // Display High Score
    tft.setTextColor(ILI9341_BLUE); // Set text color for high score
    tft.setTextSize(2); // Set a smaller text size for high score
    tft.setCursor(10, 220); // Adjust this position as needed
    tft.print("High Score: "); 
    tft.println(HiHiScore); // print the all time high score onto the screen
        
  }
}
//Game2 "Theme Routes" - end

//Game3 "25% Game" - start
void Game3() {
  //static bool Game2initialized = false; // To ensure some initialization happens only once
  //String filePath = "All/30Perc/"; // Define the path to the files for this game
  String filePath = "Hand/25Perc/"; // Define the starting path as the path to the Handhold files for this game
  static int HiHiScore = 0; // All-time high score initiate locally
  static int ButtonNum = 0; // Keep track of the number of Button clicks for the high score
  static int lastclicksCount = -1; // To check against clicksNum to update the display only on change

  if (!isInitialized) {
    clearLEDs(); // shut off all LEDs at the start of Game 3
    Serial.println("Entering Game3 for the first time.");

    HiHiScore = readHighScoreFromFile("HSGame3.txt"); // Read the all-time high score from HSGame1.txt
    Serial.print("Read HiHiScore from file: "); // Print to serial monitor for debugging
    Serial.println(HiHiScore); // Display the read HiHiScore
    
    //SelectRoute("CoWhite.csv", "CoWood.csv", "CoPink.csv", 80, 5);
    //SelectAndLightFromFile(filePath, FUCHSIA); // Pass the file path
    filePath = "Hand/25Perc/"; // Define the path to the Handhold files for this game
    SelectAndLightFromFile(filePath, FUCHSIA); // Pass the file path
    //filePath = "Feet/25Perc/"; // Define the path to the Foothold files for this game
    //SelectAndLightFromFile(filePath, BLUE); // Pass the file path
    Serial.println("SelectAndLightFromFile called");
    isInitialized = true;
  }

  if (isNorthWallCeilingPressed() || isNorthWallWallPressed() ||
    isEastWallCeilingPressed() || isEastWallWallPressed()) {
    Serial.println("Wall button pressed in Game3. Reloading new route.");
    //PercOfHoldPool = max(PercOfHoldPool - 5, 5);  // Ensuring at least 5% is always selected
    //SelectRoute("CoWhite.csv", "CoWood.csv", "CoPink.csv", PercOfHoldPool, 5);
    clearLEDs(); // shut off all LEDs prior to resetting Route for Game 3

    // select and play random Melody from M3 - M13
    int randomNumber = random(3, 14); // random(min, max) generates numbers from min to max-1
    String message = "M" + String(randomNumber);  // Concatenate "M" with the random number
    Serial3.println(message);  // Send the sound feedback for updated HiHiScore to "HiScores.txt"

    // Increase ButtonNum for any button press
    ButtonNum++;

    if (ButtonNum > HiHiScore) {
      HiHiScore = ButtonNum; // Update HiHiScore if current session's score is higher
      writeHighScoreToFile("HSGame3.txt", HiHiScore);
    }

    static bool toggleColor = false; // Static variable to toggle between colors
    if (toggleColor) {
      //SelectAndLightFromFile(filePath, FUCHSIA);
      filePath = "Hand/25Perc/"; // Define the path to the Foothold files for this game
      SelectAndLightFromFile(filePath, FUCHSIA);
      //filePath = "Feet/25Perc/"; // Define the path to the Foothold files for this game
      //SelectAndLightFromFile(filePath, BLUE);
      Serial.println("Color set to FUCHSIA");
    } else {
      //SelectAndLightFromFile(filePath, AQUA);
      filePath = "Hand/25Perc/"; // Define the path to the Foothold files for this game
      SelectAndLightFromFile(filePath, BLUE);
      //filePath = "Feet/25Perc/"; // Define the path to the Foothold files for this game
      //SelectAndLightFromFile(filePath, FUCHSIA);
      Serial.println("Color set to AQUA");
    }
    toggleColor = !toggleColor; // Toggle the color for next button press

    Serial.println("SelectAndLightFromFile called due to button click");
  }

  Serial.println("Game3 is running.");

  checkBackButton();

  // Display update for clicksNum
  if (ButtonNum != lastclicksCount) {
    tft.fillRect(0, 160, 320, 80, ILI9341_BLACK); // Clear previous display
    tft.setTextColor(ILI9341_BLUE);
    tft.setTextSize(5);
    tft.setCursor(30, 170);
    tft.print("Routes: ");
    tft.println(ButtonNum);
    lastclicksCount = ButtonNum; // Update lastclicksCount

    // Display High Score
    tft.setTextColor(ILI9341_BLUE); // Set text color for high score
    tft.setTextSize(2); // Set a smaller text size for high score
    tft.setCursor(10, 220); // Adjust this position as needed
    tft.print("High Score: "); 
    tft.println(HiHiScore); // print the all time high score onto the screen
        
  }
}
//Game3 "25% Game" - end


//Game4 "20% Game" - start
void Game4() {
  //static bool Game2initialized = false; // To ensure some initialization happens only once
  //String filePath = "All/30Perc/"; // Define the path to the files for this game
  String filePath = "Hand/20Perc/"; // Define the starting path as the path to the Handhold files for this game
  static int HiHiScore = 0; // All-time high score initiate locally
  static int ButtonNum = 0; // Keep track of the number of Button clicks for the high score
  static int lastclicksCount = -1; // To check against clicksNum to update the display only on change

  if (!isInitialized) {
    clearLEDs(); // shut off all LEDs at the start of Game 3
    Serial.println("Entering Game4 for the first time.");

    HiHiScore = readHighScoreFromFile("HSGame4.txt"); // Read the all-time high score from HSGame4.txt
    Serial.print("Read HiHiScore from file: "); // Print to serial monitor for debugging
    Serial.println(HiHiScore); // Display the read HiHiScore
    
    //SelectRoute("CoWhite.csv", "CoWood.csv", "CoPink.csv", 80, 5);
    //SelectAndLightFromFile(filePath, FUCHSIA); // Pass the file path
    filePath = "Hand/20Perc/"; // Define the path to the Handhold files for this game
    SelectAndLightFromFile(filePath, FUCHSIA); // Pass the file path
    //filePath = "Feet/25Perc/"; // Define the path to the Foothold files for this game
    //SelectAndLightFromFile(filePath, BLUE); // Pass the file path
    Serial.println("SelectAndLightFromFile called");
    isInitialized = true;
  }

  if (isNorthWallCeilingPressed() || isNorthWallWallPressed() ||
    isEastWallCeilingPressed() || isEastWallWallPressed()) {
    Serial.println("Wall button pressed in Game4. Reloading new route.");
    //PercOfHoldPool = max(PercOfHoldPool - 5, 5);  // Ensuring at least 5% is always selected
    //SelectRoute("CoWhite.csv", "CoWood.csv", "CoPink.csv", PercOfHoldPool, 5);
    clearLEDs(); // shut off all LEDs prior to resetting Route for Game 3

    // select and play random Melody from M3 - M13
    int randomNumber = random(3, 14); // random(min, max) generates numbers from min to max-1
    String message = "M" + String(randomNumber);  // Concatenate "M" with the random number
    Serial3.println(message);  // Send the sound feedback for updated HiHiScore to "HiScores.txt"

    // Increase ButtonNum for any button press
    ButtonNum++;

    if (ButtonNum > HiHiScore) {
      HiHiScore = ButtonNum; // Update HiHiScore if current session's score is higher
      writeHighScoreToFile("HSGame4.txt", HiHiScore);
    }

    static bool toggleColor = false; // Static variable to toggle between colors
    if (toggleColor) {
      //SelectAndLightFromFile(filePath, FUCHSIA);
      filePath = "Hand/20Perc/"; // Define the path to the Foothold files for this game
      SelectAndLightFromFile(filePath, FUCHSIA);
      //filePath = "Feet/25Perc/"; // Define the path to the Foothold files for this game
      //SelectAndLightFromFile(filePath, BLUE);
      Serial.println("Color set to FUCHSIA");
    } else {
      //SelectAndLightFromFile(filePath, AQUA);
      filePath = "Hand/20Perc/"; // Define the path to the Foothold files for this game
      SelectAndLightFromFile(filePath, BLUE);
      //filePath = "Feet/25Perc/"; // Define the path to the Foothold files for this game
      //SelectAndLightFromFile(filePath, FUCHSIA);
      Serial.println("Color set to AQUA");
    }
    toggleColor = !toggleColor; // Toggle the color for next button press

    Serial.println("SelectAndLightFromFile called due to button click");
  }

  Serial.println("Game4 is running.");

  checkBackButton();

  // Display update for clicksNum
  if (ButtonNum != lastclicksCount) {
    tft.fillRect(0, 160, 320, 80, ILI9341_BLACK); // Clear previous display
    tft.setTextColor(ILI9341_BLUE);
    tft.setTextSize(5);
    tft.setCursor(30, 170);
    tft.print("Routes: ");
    tft.println(ButtonNum);
    lastclicksCount = ButtonNum; // Update lastclicksCount

    // Display High Score
    tft.setTextColor(ILI9341_BLUE); // Set text color for high score
    tft.setTextSize(2); // Set a smaller text size for high score
    tft.setCursor(10, 220); // Adjust this position as needed
    tft.print("High Score: "); 
    tft.println(HiHiScore); // print the all time high score onto the screen
        
  }
}
//Game4 "20% Game" - end

// Game5 "25% Hands + Clipping Game" - start
void Game5() {

  String filePath = "Hand/25Perc/"; // Define the starting path as the path to the Handhold files for this game
  static int HiHiScore = 0; // All-time high score initiate locally
  static int ButtonNum = 0; // Keep track of the number of Button clicks for the high score
  static int lastclicksCount = -1; // To check against clicksNum to update the display only on change

  if (!isInitialized) {
    clearLEDs(); // shut off all LEDs at the start of Game 5
    Serial.println("Entering Game7 for the first time.");

    HiHiScore = readHighScoreFromFile("HSGame5.txt"); // Read the all-time high score from HSGame7.txt
    Serial.print("Read HiHiScore from file: "); // Print to serial monitor for debugging
    Serial.println(HiHiScore); // Display the read HiHiScore
    
    // Light up initial holds for Game5
    filePath = "Hand/25Perc/"; // Define the path to the Handhold files for this game
    SelectAndLightFromFile(filePath, FUCHSIA); // Pass the file path
    filePath = "Hangers/25Perc/"; // Define the path to the Hanger files for this game
    SelectAndLightFromFile(filePath, GREEN); // Pass the file path
    //filePath = "Feet/25Perc/"; // Define the path to the Foothold files for this game
    //SelectAndLightFromFile(filePath, BLUE); // Pass the file path
    Serial.println("SelectAndLightFromFile called");
    isInitialized = true;
  }

  if (isNorthWallCeilingPressed() || isNorthWallWallPressed() ||
    isEastWallCeilingPressed() || isEastWallWallPressed()) {
    Serial.println("Wall button pressed in Game5. Reloading new route.");
    clearLEDs(); // shut off all LEDs prior to resetting Route

    // Select and play random melody from M3 - M13
    int randomNumber = random(3, 14); // random(min, max) generates numbers from min to max-1
    String message = "M" + String(randomNumber);  // Concatenate "M" with the random number
    Serial3.println(message);  // Send the sound feedback

    // Increase ButtonNum for any button press
    ButtonNum++;

    if (ButtonNum > HiHiScore) {
      HiHiScore = ButtonNum; // Update HiHiScore if current session's score is higher
      writeHighScoreToFile("HSGame5.txt", HiHiScore); // Write to dedicated high score file
    }

    static bool toggleColor = false; // Static variable to toggle between colors
    if (toggleColor) {
      filePath = "Hand/25Perc/";
      SelectAndLightFromFile(filePath, FUCHSIA);
      filePath = "Hangers/25Perc/"; 
      SelectAndLightFromFile(filePath, GREEN);
      //filePath = "Feet/25Perc/";
      //SelectAndLightFromFile(filePath, BLUE);
      Serial.println("Color set to FUCHSIA");
    } else {
      filePath = "Hand/25Perc/";
      SelectAndLightFromFile(filePath, BLUE);
      filePath = "Hangers/25Perc/";
      SelectAndLightFromFile(filePath, RED);
      //filePath = "Feet/25Perc/";
      //SelectAndLightFromFile(filePath, FUCHSIA);
      Serial.println("Color set to AQUA");
    }
    toggleColor = !toggleColor; // Toggle the color for next button press

    Serial.println("SelectAndLightFromFile called due to button click");
  }

  Serial.println("Game5 is running.");

  checkBackButton();

  // Display update for clicksNum
  if (ButtonNum != lastclicksCount) {
    tft.fillRect(0, 160, 320, 80, ILI9341_BLACK); // Clear previous display
    tft.setTextColor(ILI9341_BLUE);
    tft.setTextSize(5);
    tft.setCursor(30, 170);
    tft.print("Routes: ");
    tft.println(ButtonNum);
    lastclicksCount = ButtonNum; // Update lastclicksCount

    // Display High Score
    tft.setTextColor(ILI9341_BLUE); // Set text color for high score
    tft.setTextSize(2); // Set a smaller text size for high score
    tft.setCursor(10, 220); // Adjust this position as needed
    tft.print("High Score: "); 
    tft.println(HiHiScore); // Print the all-time high score onto the screen
  }
}
// Game5 "25% Hands + Clipping Game" - end

// Game6 "20% Hands + Clipping Game" - start
void Game6() {

  String filePath = "Hand/20Perc/"; // Define the starting path as the path to the Handhold files for this game
  static int HiHiScore = 0; // All-time high score initiate locally
  static int ButtonNum = 0; // Keep track of the number of Button clicks for the high score
  static int lastclicksCount = -1; // To check against clicksNum to update the display only on change

  if (!isInitialized) {
    clearLEDs(); // shut off all LEDs at the start of Game 6
    Serial.println("Entering Game6 for the first time.");

    HiHiScore = readHighScoreFromFile("HSGame6.txt"); // Read the all-time high score from HSGame6.txt
    Serial.print("Read HiHiScore from file: "); // Print to serial monitor for debugging
    Serial.println(HiHiScore); // Display the read HiHiScore
    
    // Light up initial holds for Game6
    filePath = "Hand/20Perc/"; // Define the path to the Handhold files for this game
    SelectAndLightFromFile(filePath, FUCHSIA); // Pass the file path
        filePath = "Hangers/20Perc/"; // Define the path to the Hanger files for this game
    SelectAndLightFromFile(filePath, GREEN); // Pass the file path
    //filePath = "Feet/25Perc/"; // Define the path to the Foothold files for this game
    //SelectAndLightFromFile(filePath, BLUE); // Pass the file path
    Serial.println("SelectAndLightFromFile called");
    isInitialized = true;
  }

  if (isNorthWallCeilingPressed() || isNorthWallWallPressed() ||
    isEastWallCeilingPressed() || isEastWallWallPressed()) {
    Serial.println("Wall button pressed in Game6. Reloading new route.");
    clearLEDs(); // shut off all LEDs prior to resetting Route

    // Select and play random melody from M3 - M13
    int randomNumber = random(3, 14); // random(min, max) generates numbers from min to max-1
    String message = "M" + String(randomNumber);  // Concatenate "M" with the random number
    Serial3.println(message);  // Send the sound feedback

    // Increase ButtonNum for any button press
    ButtonNum++;

    if (ButtonNum > HiHiScore) {
      HiHiScore = ButtonNum; // Update HiHiScore if current session's score is higher
      writeHighScoreToFile("HSGame6.txt", HiHiScore); // Write to dedicated high score file
    }

    static bool toggleColor = false; // Static variable to toggle between colors
    if (toggleColor) {
      filePath = "Hand/20Perc/";
      SelectAndLightFromFile(filePath, FUCHSIA);
      filePath = "Hangers/20Perc/"; 
      SelectAndLightFromFile(filePath, GREEN);
      //filePath = "Feet/25Perc/";
      //SelectAndLightFromFile(filePath, BLUE);
      Serial.println("Color set to FUCHSIA");
    } else {
      filePath = "Hand/20Perc/";
      SelectAndLightFromFile(filePath, BLUE);
      filePath = "Hangers/20Perc/";
      SelectAndLightFromFile(filePath, RED);
      //filePath = "Feet/25Perc/";
      //SelectAndLightFromFile(filePath, FUCHSIA);
      Serial.println("Color set to AQUA");
    }
    toggleColor = !toggleColor; // Toggle the color for next button press

    Serial.println("SelectAndLightFromFile called due to button click");
  }

  Serial.println("Game6 is running.");

  checkBackButton();

  // Display update for clicksNum
  if (ButtonNum != lastclicksCount) {
    tft.fillRect(0, 160, 320, 80, ILI9341_BLACK); // Clear previous display
    tft.setTextColor(ILI9341_BLUE);
    tft.setTextSize(5);
    tft.setCursor(30, 170);
    tft.print("Routes: ");
    tft.println(ButtonNum);
    lastclicksCount = ButtonNum; // Update lastclicksCount

    // Display High Score
    tft.setTextColor(ILI9341_BLUE); // Set text color for high score
    tft.setTextSize(2); // Set a smaller text size for high score
    tft.setCursor(10, 220); // Adjust this position as needed
    tft.print("High Score: "); 
    tft.println(HiHiScore); // Print the all-time high score onto the screen
  }
}
// Game6 "20% Hands + Clipping Game" - end

// Game7 "25% Hands + Clipping + Feet Game" - start
void Game7() {

  String filePath = "Hand/25Perc/"; // Define the starting path as the path to the Handhold files for this game
  static int HiHiScore = 0; // All-time high score initiate locally
  static int ButtonNum = 0; // Keep track of the number of Button clicks for the high score
  static int lastclicksCount = -1; // To check against clicksNum to update the display only on change

  if (!isInitialized) {
    clearLEDs(); // shut off all LEDs at the start of Game 7
    Serial.println("Entering Game7 for the first time.");

    HiHiScore = readHighScoreFromFile("HSGame7.txt"); // Read the all-time high score from HSGame7.txt
    Serial.print("Read HiHiScore from file: "); // Print to serial monitor for debugging
    Serial.println(HiHiScore); // Display the read HiHiScore
    
    // Light up initial holds for Game7
    filePath = "Hand/25Perc/"; // Define the path to the Handhold files for this game
    SelectAndLightFromFile(filePath, FUCHSIA); // Pass the file path
    filePath = "Feet/25Perc/"; // Define the path to the Foothold files for this game
    SelectAndLightFromFile(filePath, BLUE); // Pass the file path
    filePath = "Hangers/25Perc/"; // Define the path to the Hanger files for this game
    SelectAndLightFromFile(filePath, GREEN); // Pass the file path
    Serial.println("SelectAndLightFromFile called");
    isInitialized = true;
  }

  if (isNorthWallCeilingPressed() || isNorthWallWallPressed() ||
    isEastWallCeilingPressed() || isEastWallWallPressed()) {
    Serial.println("Wall button pressed in Game7. Reloading new route.");
    clearLEDs(); // shut off all LEDs prior to resetting Route

    // Select and play random melody from M3 - M13
    int randomNumber = random(3, 14); // random(min, max) generates numbers from min to max-1
    String message = "M" + String(randomNumber);  // Concatenate "M" with the random number
    Serial3.println(message);  // Send the sound feedback

    // Increase ButtonNum for any button press
    ButtonNum++;

    if (ButtonNum > HiHiScore) {
      HiHiScore = ButtonNum; // Update HiHiScore if current session's score is higher
      writeHighScoreToFile("HSGame7.txt", HiHiScore); // Write to dedicated high score file
    }

    static bool toggleColor = false; // Static variable to toggle between colors
    if (toggleColor) {
      filePath = "Hand/25Perc/";
      SelectAndLightFromFile(filePath, FUCHSIA);
      filePath = "Feet/25Perc/";
      SelectAndLightFromFile(filePath, BLUE);
      filePath = "Hangers/25Perc/"; 
      SelectAndLightFromFile(filePath, GREEN);
      Serial.println("Color set to FUCHSIA");
    } else {
      filePath = "Hand/25Perc/";
      SelectAndLightFromFile(filePath, BLUE);
      filePath = "Feet/25Perc/";
      SelectAndLightFromFile(filePath, FUCHSIA);
      filePath = "Hangers/25Perc/";
      SelectAndLightFromFile(filePath, RED);
      Serial.println("Color set to AQUA");
    }
    toggleColor = !toggleColor; // Toggle the color for next button press

    Serial.println("SelectAndLightFromFile called due to button click");
  }

  Serial.println("Game7 is running.");

  checkBackButton();

  // Display update for clicksNum
  if (ButtonNum != lastclicksCount) {
    tft.fillRect(0, 160, 320, 80, ILI9341_BLACK); // Clear previous display
    tft.setTextColor(ILI9341_BLUE);
    tft.setTextSize(5);
    tft.setCursor(30, 170);
    tft.print("Routes: ");
    tft.println(ButtonNum);
    lastclicksCount = ButtonNum; // Update lastclicksCount

    // Display High Score
    tft.setTextColor(ILI9341_BLUE); // Set text color for high score
    tft.setTextSize(2); // Set a smaller text size for high score
    tft.setCursor(10, 220); // Adjust this position as needed
    tft.print("High Score: "); 
    tft.println(HiHiScore); // Print the all-time high score onto the screen
  }
}
// Game7 "25% Hands + Clipping + Feet Game" - end


// Game8 "20% Hands + Clipping + Feet Game" - start
void Game8() {

  String filePath = "Hand/20Perc/"; // Define the starting path as the path to the Handhold files for this game
  static int HiHiScore = 0; // All-time high score initiate locally
  static int ButtonNum = 0; // Keep track of the number of Button clicks for the high score
  static int lastclicksCount = -1; // To check against clicksNum to update the display only on change

  if (!isInitialized) {
    clearLEDs(); // shut off all LEDs at the start of Game 8
    Serial.println("Entering Game8 for the first time.");

    HiHiScore = readHighScoreFromFile("HSGame8.txt"); // Read the all-time high score
    Serial.print("Read HiHiScore from file: "); // Print to serial monitor for debugging
    Serial.println(HiHiScore); // Display the read HiHiScore
    
    //SelectRoute("CoWhite.csv", "CoWood.csv", "CoPink.csv", 80, 5);
    //SelectAndLightFromFile(filePath, FUCHSIA); // Pass the file path
    filePath = "Hand/20Perc/"; // Define the path to the Handhold files for this game
    SelectAndLightFromFile(filePath, FUCHSIA); // Pass the file path
    filePath = "Feet/20Perc/"; // Define the path to the Foothold files for this game
    SelectAndLightFromFile(filePath, BLUE); // Pass the file path
    filePath = "Hangers/20Perc/"; // Define the path to the Handhold files for this game
    SelectAndLightFromFile(filePath, GREEN); // Pass the file path
    Serial.println("SelectAndLightFromFile called");
    isInitialized = true;
  }

  if (isNorthWallCeilingPressed() || isNorthWallWallPressed() ||
    isEastWallCeilingPressed() || isEastWallWallPressed()) {
    Serial.println("Wall button pressed in Game8. Reloading new route.");
    //PercOfHoldPool = max(PercOfHoldPool - 5, 5);  // Ensuring at least 5% is always selected
    //SelectRoute("CoWhite.csv", "CoWood.csv", "CoPink.csv", PercOfHoldPool, 5);
    clearLEDs(); // shut off all LEDs prior to resetting Route

    // select and play random Melody from M3 - M13
    int randomNumber = random(3, 14); // random(min, max) generates numbers from min to max-1
    String message = "M" + String(randomNumber);  // Concatenate "M" with the random number
    Serial3.println(message);  // Send the sound feedback for updated HiHiScore to "HiScores.txt"

    // Increase ButtonNum for any button press
    ButtonNum++;

    if (ButtonNum > HiHiScore) {
      HiHiScore = ButtonNum; // Update HiHiScore if current session's score is higher
      // Change to HSGame8.txt if you want a separate high score file
      writeHighScoreToFile("HSGame8.txt", HiHiScore);
    }

    static bool toggleColor = false; // Static variable to toggle between colors
    if (toggleColor) {
      //SelectAndLightFromFile(filePath, FUCHSIA);
      filePath = "Hand/20Perc/"; // Define the path to the Foothold files for this game
      SelectAndLightFromFile(filePath, FUCHSIA);
      filePath = "Feet/20Perc/"; // Define the path to the Foothold files for this game
      SelectAndLightFromFile(filePath, BLUE);
      filePath = "Hangers/20Perc/"; // Define the path to the Handhold files for this game
      SelectAndLightFromFile(filePath, GREEN); // Pass the file path
      Serial.println("Color set to FUCHSIA");
    } else {
      //SelectAndLightFromFile(filePath, AQUA);
      filePath = "Hand/20Perc/"; // Define the path to the Foothold files for this game
      SelectAndLightFromFile(filePath, BLUE);
      filePath = "Feet/20Perc/"; // Define the path to the Foothold files for this game
      SelectAndLightFromFile(filePath, FUCHSIA);
      filePath = "Hangers/20Perc/"; // Define the path to the Handhold files for this game
      SelectAndLightFromFile(filePath, RED); // Pass the file path
      Serial.println("Color set to AQUA");
    }
    toggleColor = !toggleColor; // Toggle the color for next button press

    Serial.println("SelectAndLightFromFile called due to button click");
  }

  Serial.println("Game8 is running.");

  checkBackButton();

  // Display update for clicksNum
  if (ButtonNum != lastclicksCount) {
    tft.fillRect(0, 160, 320, 80, ILI9341_BLACK); // Clear previous display
    tft.setTextColor(ILI9341_BLUE);
    tft.setTextSize(5);
    tft.setCursor(30, 170);
    tft.print("Routes: ");
    tft.println(ButtonNum);
    lastclicksCount = ButtonNum; // Update lastclicksCount

    // Display High Score
    tft.setTextColor(ILI9341_BLUE); // Set text color for high score
    tft.setTextSize(2); // Set a smaller text size for high score
    tft.setCursor(10, 220); // Adjust this position as needed
    tft.print("High Score: "); 
    tft.println(HiHiScore); // print the all time high score onto the screen
  }
}
// Game8 "20% Hands + Clipping + Feet Game" - end


//Game9 "Hot Lava 3% Game" - start
// Behavior:
// - On first entry: LEDs are cleared, nothing is lit.
// - Each press of any wall button adds (does not replace) another 3% route.
// - Routes are selected randomly from SD folder "Holds/3Perc/".
// - All holds in each added route are lit in RED.
// - Plays a random melody M3..M13 on each successful add.
// - Tracks a session counter ("Routes:") and a persistent all-time high score in HSGame9.txt.

void Game9() {
  const String filePathBase = "Holds/3Perc/"; // Folder with 3% route CSVs
  static int HiHiScore = 0;                   // All-time high score for Game9
  static int routesAdded = 0;                 // Session counter: how many 3% routes added so far
  static int lastShownCount = -1;             // For display updates only on change

  // --- One-time initialization for Game9 ---
  if (!isInitialized) {
    clearLEDs(); // Ensure we start with a blank wall
    Serial.println("Entering Game9 (Additive 3% Routes).");
    HiHiScore = readHighScoreFromFile("HSGame9.txt"); // Persistent high score file
    Serial.print("Game9 HiHiScore: ");
    Serial.println(HiHiScore);

    routesAdded = 0;        // fresh session counter
    lastShownCount = -1;    // force a screen refresh
    isInitialized = true;   // mark initialized
  }

  // --- Input: any of the four wall buttons adds another 3% route ---
  if (isNorthWallCeilingPressed() || isNorthWallWallPressed() ||
      isEastWallCeilingPressed()  || isEastWallWallPressed()) {

    // Play a happy chirp
    int rnd = random(3, 14);            // M3..M13 inclusive
    Serial3.println("M" + String(rnd)); // trigger melody on the Nano

    // IMPORTANT: Do NOT clear LEDs here — we're additive
    // Light one random 3% route in RED
    SelectAndLightFromFile(filePathBase, RED);

    // Update counts / scores
    routesAdded++;
    if (routesAdded > HiHiScore) {
      HiHiScore = routesAdded;
      writeHighScoreToFile("HSGame9.txt", HiHiScore);
    }
  }

  // --- UI: update the bottom bar only when the count changes ---
  if (routesAdded != lastShownCount) {
    tft.fillRect(0, 160, 320, 80, ILI9341_BLACK); // Clear the footer area

    // Big counter
    tft.setTextColor(ILI9341_BLUE);
    tft.setTextSize(5);
    tft.setCursor(20, 170);
    tft.print("Routes: ");
    tft.println(routesAdded);

    // High score line
    tft.setTextColor(ILI9341_BLUE);
    tft.setTextSize(2);
    tft.setCursor(10, 220);
    tft.print("High Score: ");
    tft.println(HiHiScore);

    lastShownCount = routesAdded;
  }

  // Esc handling remains via your global checkBackButton() in loop()
  // (When Back is pressed, your checkBackButton() returns to MAIN_MENU
  //  and resets isInitialized = false.)
}
//Game9 "Hot Lava 3% Game" - end

//Game10 "Hot Lava 5% Game" - start
// Behavior:
// - On first entry: LEDs are cleared, nothing is lit.
// - Each press of any wall button adds (does not replace) another 5% route.
// - Routes are selected randomly from SD folder "Holds/5Perc/".
// - All holds in each added route are lit in RED.
// - Plays a random melody M3..M13 on each successful add.
// - Tracks a session counter ("Routes:") and a persistent all-time high score in HSGame10.txt.

void Game10() {
  const String filePathBase = "Holds/5Perc/"; // Folder with 5% route CSVs
  static int HiHiScore = 0;                   // All-time high score for Game10
  static int routesAdded = 0;                 // Session counter: how many 5% routes added so far
  static int lastShownCount = -1;             // For display updates only on change

  // --- One-time initialization for Game9 ---
  if (!isInitialized) {
    clearLEDs(); // Ensure we start with a blank wall
    Serial.println("Entering Game10 (Additive 5% Routes).");
    HiHiScore = readHighScoreFromFile("HSGame10.txt"); // Persistent high score file
    Serial.print("Game10 HiHiScore: ");
    Serial.println(HiHiScore);

    routesAdded = 0;        // fresh session counter
    lastShownCount = -1;    // force a screen refresh
    isInitialized = true;   // mark initialized
  }

  // --- Input: any of the four wall buttons adds another 3% route ---
  if (isNorthWallCeilingPressed() || isNorthWallWallPressed() ||
      isEastWallCeilingPressed()  || isEastWallWallPressed()) {

    // Play a happy chirp
    int rnd = random(3, 14);            // M3..M13 inclusive
    Serial3.println("M" + String(rnd)); // trigger melody on the Nano

    // IMPORTANT: Do NOT clear LEDs here — we're additive
    // Light one random 5% route in RED
    SelectAndLightFromFile(filePathBase, RED);

    // Update counts / scores
    routesAdded++;
    if (routesAdded > HiHiScore) {
      HiHiScore = routesAdded;
      writeHighScoreToFile("HSGame10.txt", HiHiScore);
    }
  }

  // --- UI: update the bottom bar only when the count changes ---
  if (routesAdded != lastShownCount) {
    tft.fillRect(0, 160, 320, 80, ILI9341_BLACK); // Clear the footer area

    // Big counter
    tft.setTextColor(ILI9341_BLUE);
    tft.setTextSize(5);
    tft.setCursor(20, 170);
    tft.print("Routes: ");
    tft.println(routesAdded);

    // High score line
    tft.setTextColor(ILI9341_BLUE);
    tft.setTextSize(2);
    tft.setCursor(10, 220);
    tft.print("High Score: ");
    tft.println(HiHiScore);

    lastShownCount = routesAdded;
  }

  // Esc handling remains via your global checkBackButton() in loop()
  // (When Back is pressed, your checkBackButton() returns to MAIN_MENU
  //  and resets isInitialized = false.)
}
//Game10 "Hot Lava 5% Game" - end

//Game11 "Hot Lava 10% Game" - start
// Behavior:
// - On first entry: LEDs are cleared, nothing is lit.
// - Each press of any wall button adds (does not replace) another 10% route.
// - Routes are selected randomly from SD folder "Holds/10Perc/".
// - All holds in each added route are lit in RED.
// - Plays a random melody M3..M13 on each successful add.
// - Tracks a session counter ("Routes:") and a persistent all-time high score in HSGame11.txt.

void Game11() {
  const String filePathBase = "Holds/10Perc/"; // Folder with 10% route CSVs
  static int HiHiScore = 0;                   // All-time high score for Game10
  static int routesAdded = 0;                 // Session counter: how many 10% routes added so far
  static int lastShownCount = -1;             // For display updates only on change

  // --- One-time initialization for Game9 ---
  if (!isInitialized) {
    clearLEDs(); // Ensure we start with a blank wall
    Serial.println("Entering Game11 (Additive 10% Routes).");
    HiHiScore = readHighScoreFromFile("HSGame11.txt"); // Persistent high score file
    Serial.print("Game11 HiHiScore: ");
    Serial.println(HiHiScore);

    routesAdded = 0;        // fresh session counter
    lastShownCount = -1;    // force a screen refresh
    isInitialized = true;   // mark initialized
  }

  // --- Input: any of the four wall buttons adds another 10% route ---
  if (isNorthWallCeilingPressed() || isNorthWallWallPressed() ||
      isEastWallCeilingPressed()  || isEastWallWallPressed()) {

    // Play a happy chirp
    int rnd = random(3, 14);            // M3..M13 inclusive
    Serial3.println("M" + String(rnd)); // trigger melody on the Nano

    // IMPORTANT: Do NOT clear LEDs here — we're additive
    // Light one random 10% route in RED
    SelectAndLightFromFile(filePathBase, RED);

    // Update counts / scores
    routesAdded++;
    if (routesAdded > HiHiScore) {
      HiHiScore = routesAdded;
      writeHighScoreToFile("HSGame11.txt", HiHiScore);
    }
  }

  // --- UI: update the bottom bar only when the count changes ---
  if (routesAdded != lastShownCount) {
    tft.fillRect(0, 160, 320, 80, ILI9341_BLACK); // Clear the footer area

    // Big counter
    tft.setTextColor(ILI9341_BLUE);
    tft.setTextSize(5);
    tft.setCursor(20, 170);
    tft.print("Routes: ");
    tft.println(routesAdded);

    // High score line
    tft.setTextColor(ILI9341_BLUE);
    tft.setTextSize(2);
    tft.setCursor(10, 220);
    tft.print("High Score: ");
    tft.println(HiHiScore);

    lastShownCount = routesAdded;
  }

  // Esc handling remains via your global checkBackButton() in loop()
  // (When Back is pressed, your checkBackButton() returns to MAIN_MENU
  //  and resets isInitialized = false.)
}
//Game11 "Hot Lava 10% Game" - end

// function to light up a route from file on SD card - start
  void SelectAndLightFromFile(String path, uint32_t color) {  // Add color parameter
    File dir = SD.open(path);
    if (!dir) {
        Serial.println("Failed to open directory");
        return;
    }

    LinkedList<String> fileNames; // Create a LinkedList of Strings

    while (File file = dir.openNextFile()) {
        if (!file.isDirectory()) {
            fileNames.add(String(file.name())); // Add file name to the list
            Serial.println("Found file: " + String(file.name()));
        }
        file.close();
    }
    dir.close();

    if (fileNames.size() == 0) {
        Serial.println("No files found in directory");
        return;
    }

    // Select a random file
    int index = random(fileNames.size());
    String selectedFile = path + fileNames.get(index);
    Serial.println("Selected file: " + selectedFile);

    // Open the selected file
    File file = SD.open(selectedFile);
    if (!file) {
        Serial.println("Failed to open selected file: " + selectedFile);
        return;
    }

    // Ignore the header
    file.readStringUntil('\n');

    // Parse and light each hold
    while (file.available()) {
        String line = file.readStringUntil('\n');
        Serial.println("Reading line: " + line); // Debug: log the line being read
        if (line.length() > 0) {
            parseAndLightRouteLEDs(line, color); // Light up with green color
        }
    }
    file.close();
  }
// function to light up a route from file on SD card - end


// function to randomly select route from group of holds - start
  /*
     + group of holds will be defined by 1-3 file names of hold lists on the SD card
     + firstFile = first file containing holds
     + secondFile = second file containing holds
     + thirdFile = third file containing holds
     + num1 = Percentage of Holds to be selected from pool of holds
     + num2 = Percentage of Holds to be subtracted with each button click
     + EXAMPLE on how to call:
         SelectRoute(CoWhite.csv, CoWood.csv, CoPink.csv, 80, 5)
  */
/* void SelectRoute(String firstFile, String secondFile, String thirdFile, int num1, int num2) {
    unsigned long startTime = millis();
    PercOfHoldPool = num1;
    RedOfPercOfHoldPool = num2;

    Serial.println("Starting SelectRoute...");

    // Check if "TempFile.txt" exists and remove it if it does
    if (SD.exists("TempFile.txt")) {
        SD.remove("TempFile.txt");
        Serial.println("TempFile.txt exists and was removed.");
    }

    // Create a new TempFile for appending data
    File tempFile = SD.open("TempFile.txt", FILE_WRITE);
    if (!tempFile) {
        Serial.println("Failed to create TempFile.txt.");
        return;
    }

    // Function to write content from a file, ignoring the header line
    auto writeContent = [&](const String& fileName) {
        File sourceFile = SD.open(fileName);
        if (!sourceFile) {
            Serial.println("Failed to open " + fileName);
            return;
        }
        // Skip the first line (header)
        sourceFile.readStringUntil('\n');
        // Write the rest of the content to the temp file
        while (sourceFile.available()) {
            int c = sourceFile.read(); // Read a byte
            if (c != -1) { // Check if the read was successful
                tempFile.write(c); // Write the byte to the temp file
            }
        }
        sourceFile.close();
    };

    // Process each file
    writeContent(firstFile);
    if (secondFile != "") {
        writeContent(secondFile);
    }
    if (thirdFile != "") {
        writeContent(thirdFile);
    }

    tempFile.close();
    Serial.println("Finished preparing TempFile.");

    // Measure how long it takes to prepare the file
    unsigned long filePrepTime = millis() - startTime;
    Serial.print("File preparation took: "); Serial.print(filePrepTime); Serial.println(" ms");

    // Open the new TempFile and reselect random holds
    File sourceFile = SD.open("TempFile.txt", FILE_READ);
    if (!sourceFile) {
        Serial.println("Failed to open TempFile.txt for reading.");
        return;
    }

    startTime = millis();
    selectRandomHoldsAndLight(sourceFile, tempFile, PercOfHoldPool);
    sourceFile.close();

    // Measure the time taken to select and light holds
    unsigned long selectionTime = millis() - startTime;
    Serial.print("Selection and lighting took: "); Serial.print(selectionTime); Serial.println(" ms");
}
*/ 

// function to randomly select route from group of holds - end

/*
// function that listens to and then reacts to interactive wall button presses - start => WOULD BE BETTER TO SPLIT THIS IN TWO? ONE THAT LISTENS ALL THE TIME AND ONE THAT REACTS?
// SHOULD USE SAME Than the 
  void handleButtonPresses() {
    static unsigned long lastDebounceTime = 0;
    unsigned long debounceDelay = 200;
    bool buttonPressed = !digitalRead(46) || !digitalRead(48) || !digitalRead(50) || !digitalRead(52);

    if (buttonPressed) {
        unsigned long currentTime = millis();
        if (currentTime - lastDebounceTime > debounceDelay) {
            lastDebounceTime = currentTime;
            rerunSelection();
        }
    }
  }
// function to handle interactive wall button presses - end
*/

// function that handles input from the wall buttons for Game2 - start
  void Game2HandleWallButtonPresses() {
    static unsigned long lastButtonPressTime = 0;
    const unsigned long debounceDelay = 200; // milliseconds for debouncing buttons
    if (millis() - lastButtonPressTime > debounceDelay) {
      // Check if any wall button is pressed using existing button press functions
      if (isNorthWallCeilingPressed() || isNorthWallWallPressed() || isEastWallCeilingPressed() || isEastWallWallPressed()) {
            // Handle East Wall Ceiling Button logic
            Serial.println("A Button Was Pressed");
            lastButtonPressTime = millis();
        }
    }
  }
// function that handles input from the wall buttons for Game2 - end

// function to rerun the function SelectRoute with reduced percentages - start
/*  void rerunSelection() {
    PercOfHoldPool -= RedOfPercOfHoldPool;
    if (PercOfHoldPool < 0) PercOfHoldPool = 0;  // Ensure percentage does not go below zero

    // Re-select holds based on new percentage
    if (SD.exists("CurRoute.txt")) {
        SD.remove("CurRoute.txt");
    }
    curRoute = SD.open("CurRoute.txt", FILE_WRITE);

    File tempFile = SD.open("TempFile.txt", FILE_READ);
    selectRandomHoldsAndLight(tempFile, curRoute, PercOfHoldPool);
    tempFile.close();
    curRoute.close();

    Serial.print("New percentage: ");
    Serial.println(PercOfHoldPool);
  }
// function to rerun the function SelectRoute with reduced percentages - end
*/ 
// function that appends files together to create a group of holds for random selection - start
// CHECK IF THIS CAN BE DONE WITH A SIMPLE WRITE COMMAND
  void appendFileContents(String fileName, File &destFile) {
    File sourceFile = SD.open(fileName);
    if (sourceFile) {
        while (sourceFile.available()) {
            destFile.write(sourceFile.read());
        }
        sourceFile.close();
    } else {
        Serial.println("Failed to open " + fileName);
    }
  }
// function that appends files together to create a group of holds for random selection - end

// function that appends files together ignoring a header line to create a group of holds for random selection - start
  void appendFileContentsWithoutHeader(String fileName, File &destFile) {
    File sourceFile = SD.open(fileName);
    if (sourceFile) {
        // Skip the first line (header)
        sourceFile.readStringUntil('\n');
        // Continue with the rest of the file
        while (sourceFile.available()) {
            destFile.write(sourceFile.read());
        }
        sourceFile.close();
    } else {
        Serial.println("Failed to open " + fileName);
    }
  }
// function that appends files together ignoring a header line to create a group of holds for random selection - end

// function that counts the lines in a file that contains hold information - start
  // Counts lines in a file, can skip a header when told
  // When file has header call as:
    //int totalHolds = countLines("HoldHold.csv", true);  // Pass true because it has a header
  // When file does not have a header call as:
    //int totalLines = countLines("TempFile.txt");  // Default or explicitly pass false
  int countLines(String fileName, bool hasHeader) {
    File file = SD.open(fileName);
    if (!file) {
        Serial.println("Failed to open file " + fileName);
        return 0;  // Return 0 if the file can't be opened
    }

    int lineCount = 0;
    while (file.available()) {
        if (file.read() == '\n') {
            lineCount++;
        }
    }
    file.close();

    // Subtract one if there is a header that should not be counted as data
    if (hasHeader) {
        lineCount = max(0, lineCount - 1);
    }
    return lineCount;
  }
// function that counts the lines in a file that contains hold information - end

// function that selects the holds randomly and then lights them up - start
  void selectRandomHoldsAndLight(File &sourceFile, File &destFile, int percentage) {
    int totalLines = countLines(sourceFile.name()); // Ensure this function is defined to just count lines without any condition for headers
    int linesToSelect;

    if (percentage == 100) {
        linesToSelect = totalLines;
    } else {
        linesToSelect = (totalLines * percentage + 99) / 100; // Rounding up
    }
    
    linesToSelect = min(linesToSelect, totalLines); // Ensure not to exceed the total lines
 
    Serial.print("Holds to select: ");
    Serial.println(linesToSelect);

    sourceFile.seek(0);  // Reset to start of file
    for (int i = 0; i < linesToSelect; ++i) {
        if (!sourceFile.available()) break;  // Prevent reading past EOF
        String line = sourceFile.readStringUntil('\n');
        destFile.println(line);
        parseAndLightHoldLEDs(line, strip.Color(0, 255, 0)); // Example: lighting green
    }
  }
// function that selects the holds randomly and then lights them up - end

// Function that handles the logic for Game6 - start
// Game6 logic: checks for RF remote control signals
/*void Game6() {
    uint8_t buf[RH_ASK_MAX_MESSAGE_LEN]; // Buffer for the incoming message
    uint8_t buflen = sizeof(buf); // Length of the buffer

    // Attempt to receive a message
    if (driver.recv(buf, &buflen)) {
        // If a message is received, send a signal to play a sound
        Serial3.println("M2"); // Signal for the sound system
        Serial.print("Received: "); // Debug message
        Serial.println((char*)buf); // Print the received message for debugging
    }
}
// Function that handles the logic for Game6 - stop
*/

// function that plays sound test "M0" every 2 seconds - start
  void Disco1() {
    static unsigned long lastCommandTime = 0;
    const long commandInterval = 2000; // 2 seconds

    unsigned long currentMillis = millis();

    if (currentMillis - lastCommandTime >= commandInterval) {
      lastCommandTime = currentMillis;
      Serial3.println("M0"); // Send "M0" to the Nano
    }
  }
// function that plays sound test "M0" every 2 seconds - end

// placeholder for Disco2 function. This function does nothing
void Disco2() {
    // Empty function: no operation (NOP)
}

// first attempt at creating a lightshow effect. Not sure if working, focusing on games right now.
/*void Disco2() {
    static int colorIndex = 0;
    static int ledIndex = -1;
    static unsigned long lastUpdate = 0;
    const long interval = 50; // Interval for changing LEDs

    if (millis() - lastUpdate >= interval) {
        lastUpdate = millis(); // Update the last change time

        // Proceed to the next LED
        ledIndex++;
        if (ledIndex >= NUM_LEDS) {
            ledIndex = 0;
            colorIndex++;
            if (colorIndex >= sizeof(colors) / sizeof(colors[0])) colorIndex = 0;
        }

        // Set all LEDs to black
        for (int i = 0; i < NUM_LEDS; i++) leds[i] = CRGB::Black;

        // Then light up the current LED
        int globalIntensityReduction = map(globalIntensityPercentage, 0, 100, 0, 255);
        CRGB currentColor = colors[colorIndex];
        leds[ledIndex] = currentColor;
        leds[ledIndex].fadeToBlackBy(255 - globalIntensityReduction);

        FastLED.show(); // Apply the LED changes
    }
}
*/

// Adafruit version of Disco3
/* void Disco3() {
    static unsigned long lastToggleTime = 0;
    const long toggleInterval = 500; // 0.5 seconds

    unsigned long currentMillis = millis();

    if (currentMillis - lastToggleTime >= toggleInterval) {
        lastToggleTime = currentMillis;

        static bool ledsOn = false;
        ledsOn = !ledsOn;

        for (int i = 0; i < strip.numPixels(); i++) {
            strip.setPixelColor(i, ledsOn ? strip.Color(0, 0, 255) : strip.Color(0, 0, 0)); // Blue or off
        }

        strip.show();
    }
}
*/

// function that performs a LED test, toggling LEDs off/on every 0.5 seconds - start
  void Disco3() {
    static unsigned long lastToggleTime = 0; // Store the last time the LEDs were toggled
    const long toggleInterval = 500; // Interval between toggles in milliseconds (0.5 seconds)

    unsigned long currentMillis = millis(); // Get the current time

    // Check if the interval has passed since the last toggle
    if (currentMillis - lastToggleTime >= toggleInterval) {
      lastToggleTime = currentMillis; // Update the last toggle time

      static bool ledsOn = false; // Keep track of the LED state (on or off)
      ledsOn = !ledsOn; // Toggle the LED state

      // Loop through all pixels in the strip
        for (int i = 0; i < strip.numPixels(); i++) {
          if (ledsOn) {
            // If LEDs should be on, set them to blue color with the global intensity
              strip.setPixelColor(i, strip.Color(0, 0, globalLEDIntensity)); // Blue color with scaled intensity
          } else {
            // If LEDs should be off, set them to no color (off)
              strip.setPixelColor(i, strip.Color(0, 0, 0)); // Turn off the LED
          }
        }

      strip.show(); // Send the updated color data to the strip
    }
  }
// function that performs a LED test, toggling LEDs off/on every 0.5 seconds - end

// Disco4 function - start
  // placeholder for Disco4 function. This function does nothing
  void Disco4() {
    // Empty function: no operation (NOP)
  }
// Disco4 function - end

// Disco5 function - start
  // placeholder for Disco5 function. This function does nothing
  void Disco5() {
    // Empty function: no operation (NOP)
  }
// Disco5 function - end

// Disco6 function - start
  // placeholder for Disco6 function. This function does nothing
  void Disco6() {
    // Empty function: no operation (NOP)
  }
// Disco6 function - end

// Disco7 function - start
  // placeholder for Disco7 function. This function does nothing
  void Disco7() {
    // Empty function: no operation (NOP)
  }
// Disco7 function - end

// Disco8 function - start
  // placeholder for Disco8 function. This function does nothing
  void Disco8() {
    // Empty function: no operation (NOP)
  }
// Disco8 function - end

// test function that checks the functionality of reading the SD card
// when called the file list on the SD card is printed to the serial monitor
void Test1() {
  static bool hasListedFiles = false; // Static flag to ensure listing happens only once

  if (!hasListedFiles) {
    File root = SD.open("/");
    while (File file = root.openNextFile()) {
      if (file.isDirectory()) {
        Serial.print("DIR : ");
        Serial.println(file.name());
      } else {
        Serial.print("FILE: ");
        Serial.print(file.name());
        Serial.print("\tSIZE: ");
        Serial.println(file.size());
      }
    }
    hasListedFiles = true; // Set flag to true after listing

    // Optional: Add a small delay before changing state, if needed
    // delay(1000); // Delay for 1 second

    // Simulate pressing the red button by changing the state
    currentState = MAIN_MENU; // Change to MAIN_MENU or another appropriate state
  }
}

// function that tests Hold LEDs one at a time. Navigate with remote - start
  void Test2() {
    String line = readLineFromFile("MetaData.csv", currentLine + 1);
    if (line != "") {
      // Parse the CSV line and light up LEDs
        //parseAndLightHoldLEDs(line, strip.Color(255, 0, 0));
      strip.clear(); // Turn off all LEDs before setting new ones
      parseAndLightHoldLEDs(line, GREEN);

      // Extract HoldNum from the line
        int holdNum;
        sscanf(line.c_str(), "%d,", &holdNum); // Parse the hold number from the line

      // Check if the hold number has changed since the last display update
        if (holdNum != lastDisplayedHoldNum) {
            // Clear a specific area of the screen
            int rectX = 0, rectY = 160; // Start point for the rectangle
            int rectWidth = 320, rectHeight = 80; // Width and height of the rectangle
            tft.fillRect(rectX, rectY, rectWidth, rectHeight, ILI9341_BLACK);

            // Update the display with the new hold number
            tft.setTextColor(ILI9341_ORANGE); // Set text color
            tft.setTextSize(5); // Set text size
            tft.setCursor(30, rectY + 10); // Set cursor position
            tft.print("Hold: ");
            tft.println(holdNum);

            // Update the last displayed hold number
            lastDisplayedHoldNum = holdNum;
        }
    } else {
        Serial.println("Line is empty or file not found");
    }
    // Handle remote input for navigating through holds
    if (driver.available()) {
      uint8_t buf[RH_ASK_MAX_MESSAGE_LEN];
      uint8_t buflen = sizeof(buf);
      if (driver.recv(buf, &buflen)) {
        char cmd = (char)buf[0];
        int maxLine = 770; // Assuming 770 is the max number of lines
          switch (cmd) {
            case 'U':
              currentLine = (currentLine % maxLine) + 1;
              break;
            case 'D':
              currentLine = (currentLine - 2 + maxLine) % maxLine + 1;
              break;        
            case 'R':
              currentLine = (currentLine - 1 + 10) % maxLine + 1;
              break;
            case 'L':
              currentLine = (currentLine - 11 + maxLine) % maxLine + 1;
              break;
            case 'Y':
              currentLine = (currentLine - 1 + 100) % maxLine + 1;
              break;
            case 'X':
              currentLine = (currentLine - 101 + maxLine) % maxLine + 1;
              break;
          }
        Test2(); // Recursively call Test2 to handle the next line
        }
    }
  }
// function that tests Hold LEDs one at a time. Navigate with remote - end

// function that reads one specific line from a data file - start
  String readLineFromFile(String fileName, int lineNum) {
    File file = SD.open(fileName);
    if (!file) {
      Serial.println("Failed to open file");
      return ""; // Return an empty string if the file couldn't be opened
    }

    String line;
    int currentLine = 0;
    while (file.available()) {
      line = file.readStringUntil('\n');
      currentLine++;
      if (currentLine == lineNum) {
        file.close();
        return line;
      }
    }
    file.close();
    return ""; // Return an empty string if the line number was not found
  }
// function that reads one specific line from a data file - end

// Function to parse a CSV line and light up LEDs based on extracted indices - start
  // This program uses entire MetaData File
  // Adds a color parameter to customize LED color.
  void parseAndLightHoldLEDs(String line, uint32_t color) {
    int holdNum, ledA, ledB = -1, ledC = -1, ledD = -1; // Initialize default values.
    char buffer[100];
    line.toCharArray(buffer, sizeof(buffer));

    // Debugging: Print the line being parsed
    Serial.print("Parsing line: ");
    Serial.println(line);

    // Parse the CSV line to extract hold information and LED indices.
    int parsed = sscanf(buffer, "%d,%d,%d,%d,%d", &holdNum, &ledA, &ledB, &ledC, &ledD);
    if (parsed >= 2) { // Ensure at least holdNum and ledA are parsed.
      Serial.print("Parsed Hold Number: "); 
      Serial.println(holdNum);
      Serial.print("LEDs: ");
      Serial.print(ledA); 
      Serial.print(", ");
      Serial.print(ledB); 
      Serial.print(", ");
      Serial.print(ledC); 
      Serial.print(", ");
      Serial.println(ledD);
      // Light up LEDs with the specified color.
      LightOneHold(color, ledA, ledB, ledC, ledD);
    } else {
    Serial.println("Error parsing line");
    }
  }
// Function to parse a CSV line and light up LEDs based on extracted indices - end

// Function to parse a CSV line and light up route LEDs based on extracted indices - start
  // This function uses a route file, i.e. four columns with hold number, and 1-4 LED numbers only
  // This file has a header file.
  void parseAndLightRouteLEDs(String line, uint32_t color) {
    int holdNum, ledA, ledB, ledC, ledD; // Initialize variables for each column in the CSV.
    char buffer[100]; // Buffer to store the CSV line for parsing.
    line.toCharArray(buffer, sizeof(buffer)); // Copy the line into a character array for sscanf.

    // Parse the CSV line. Ensure all five integers are read.
    int parsed = sscanf(buffer, "%d,%d,%d,%d,%d", &holdNum, &ledA, &ledB, &ledC, &ledD);
    if (parsed == 5) { // Check if all five columns are successfully parsed.
        Serial.print("Parsed Hold Number: "); Serial.println(holdNum);
        // Light up LEDs with the specified color.
        LightOneHold(color, ledA, ledB, ledC, ledD);
    } else {
        Serial.println("Error parsing line: Not enough data");
    }
  }
// Function to parse a CSV line and light up route LEDs based on extracted indices - end

// function to light up the LEDs for one Hold - start
  // using the color order Green/Red/Blue and the following code:
  // LightOneHold(strip.Color(0, 0, 255), hold.ledA, hold.ledB, hold.ledC, hold.ledD);
  void LightOneHold(uint32_t color, int ledA, int ledB, int ledC, int ledD) {
    strip.setBrightness(38); // Set brightness to ~15%
    // clear the LED strip
    //strip.clear(); // Turn off all LEDs before setting new ones
    strip.setPixelColor(ledA, color); // Set color for LEDA
    // Check if LEDB, LEDC, LEDD are used (-1 indicates they are not used)
    if (ledB >= 0) strip.setPixelColor(ledB, color);
    if (ledC >= 0) strip.setPixelColor(ledC, color);
    if (ledD >= 0) strip.setPixelColor(ledD, color);
    strip.show(); // Update the strip with set colors
  }
// code to light up the LEDs for one Hold - end

// function that switches all LEDs off - start
  void clearLEDs() {
    strip.clear(); // Clears all LEDs
    strip.show();  // Ensures the clear is applied immediately
    Serial.println("Clearing all LEDs.");
  }
// function that switches all LEDs off - end


// test3 function - start
  // test function to check if melody is playing, press any remote control button to play the melody
  void Test3() {
    uint8_t buf[RH_ASK_MAX_MESSAGE_LEN]; // Buffer for the incoming message
    uint8_t buflen = sizeof(buf); // Length of the buffer

    // Attempt to receive a message
    if (driver.recv(buf, &buflen)) {
      // Upon receiving a message, send "M2" to the sound system Arduino Nano
      Serial3.println("M2");
      // Print the received message for debugging purposes
      Serial.print("Received: ");
      Serial.println((char*)buf); // Casting buffer to a string for printing
    }
  }
// test3 function - end

// Function to load the high score for a specific game - start
  // The gameId parameter is the index of the game (e.g., 1 for Game1, 2 for Game2, etc.)
  // call this function as follows:
  // int highScoreForGame1 = loadHighScore(1);
  // int highScoreForGame6 = loadHighScore(6);
  int loadHighScore(int gameId) {
    File file = SD.open("HiScores.txt"); // Open the high scores file
    if (!file) {
      Serial.println("Failed to open HiScores.txt for reading");
      return 0; // Return 0 if the file can't be opened
    }
    int currentLine = 0;
    String line;
    int highScore = 0;
    // Read through the file until you find the desired game's high score
    while (file.available()) {
      line = file.readStringUntil('\n'); // Read each line
      currentLine++; // Increment the line counter
      // Check if the current line matches the gameId
        if (currentLine == gameId) {
          highScore = line.toInt(); // Convert the line to an integer
          break; // Exit the loop once the correct line is found
        }
    }
    file.close(); // Close the file
    return highScore; // Return the high score
  }
// Function to load the high score for a specific game - end

/* I don't think I want to use this function but rather the simpler method
// Function to check wall button presses and return which button was pressed - start
  WallButton checkWallButtonPress() {
    if (isEastWallCeilingPressed()) {
      return EAST_WALL_CEILING;
    }
    if (isEastWallWallPressed()) {
      return EAST_WALL_WALL;
    }
    if (isNorthWallCeilingPressed()) {
      return NORTH_WALL_CEILING;
    }
    if (isNorthWallWallPressed()) {
      return NORTH_WALL_WALL;
    }
    return NONE; // No button pressed
  }
// Function to check wall button presses and return which button was pressed - end
*/

/*
// Code example for handling Wall Button clicks and distinguish between specific wall buttons - start
    // Check for wall button presses and handle accordingly
    WallButton pressedButton = checkWallButtonPress();
    switch (pressedButton) {
        case EAST_WALL_CEILING:
            // Handle East Wall Ceiling button press
            Serial.println("Game1: East Wall Ceiling Button Pressed");
            // Specific logic for handling this button in Game1
            break;
        case EAST_WALL_WALL:
            // Handle East Wall Wall button press
            Serial.println("Game1: East Wall Wall Button Pressed");
            // Specific logic for this button
            break;
        case NORTH_WALL_CEILING:
            // Handle North Wall Ceiling button press
            Serial.println("Game1: North Wall Ceiling Button Pressed");
            // Additional logic here
            break;
        case NORTH_WALL_WALL:
            // Handle North Wall Wall button press
            Serial.println("Game1: North Wall Wall Button Pressed");
            // Additional logic here
            break;
        case NONE:
            // No button was pressed, so do nothing
            break;
    }
// Code example for handling Wall Button clicks and distinguish between specific wall buttons - end
*/
