5

I'm totally new and I don't know how else to ask this or what to even search for.

The case is this: I want to navigate through a menu with several sub-menus. In this example I'll just use "options" and a "game" to illustrate what I mean. Say you have a menu with 3 options.

1 - Start

2 - Options

3 - Quit

Choosing options should take you to another menu. Which would then look something like

1 - Difficulty

2 - Sound

3 - Back

Depending on where you go from here, there will be more sub menus obviously. I've tried nesting do-while loops and all kinds of things but I just don't have enough understanding to know what it is I'm doing wrong.

Here is what I have so far:

#include <cstdlib>
#include <iostream>

using namespace std;

int main(int argc, char *argv[])
{
  int choice;

    do{
    cout << "Main Menu\n";
    cout << "Please make your selection\n";
    cout << "1 - Start game\n";
    cout << "2 - Options\n";
    cout << "3 - Quit\n";
    cout << "Selection: ";
    cin >> choice;

         switch(choice) {
           case 1:
             cout << "Pew pew!\n";
             break;
           case 2:
             cout <<"????\n";
             break;
           case 3:
             cout << "Goodbye!";
             break;
           default:
             cout << "Main Menu\n";
             cout << "Please make your selection\n";
             cout << "1 - Start game\n";
             cout << "2 - Options\n";
             cout << "3 - Quit\n";
             cout << "Selection: ";
             cin >> choice;    
         }
      } while(choice !=3);                            
    system("PAUSE");
    return EXIT_SUCCESS;
}

Which works like a regular menu. But I have no idea where to go from here. I consulted some books, but finding anything even remotely related to this was completely random. Any help or examples would be greatly appreciated.

What happened with nesting tons of loops just made all loops execute simultaneously every time. How do I keep this from happening? Making more choices? (choice1-2-3 etc ? or what?)

Community
  • 1
  • 1
fanatical
  • 103
  • 1
  • 1
  • 6

4 Answers4

5

Ok guys. Thanks for all the help. This is what I ended up with in the end. It runs as I want it to and by max_'s example and Mike B's commentary I think this works pretty well.

Thanks alot everyone =)

#include <iostream>
#include <cstdlib>


using namespace std;

void menu();
void mainMenu();
void optionsMenu();
void options();
int choice1 = 0;
int choice2 = 3;

int main(int argc, char** argv) {



    menu();



    return 0;
}


void menu(){

        do {
        choice2 = 0;
        mainMenu();

        switch(choice1) {

            case 1:
                cout << "Pew pew!\n";
                break;

            case 2:
                options();
                break;

            case 3:
                break;

        }

    } while(choice1 != 3);


}

void options(void) {

    do {
        optionsMenu();

        switch(choice2){

            case 1:
                cout << "So difficult!\n";
                break;

            case 2: 
                cout << "Beep!\n";
                break;

            case 3:
                break;

            default: 
                break;

        }

    } while(choice2 != 3);


}




void mainMenu(void) {



    cout << "Main Menu\n";
    cout << "1 - Start game\n";
    cout << "2 - Options\n";
    cout << "3 - Quit\n";
    cout << "Please choose: ";
            cin >> choice1;

}

void optionsMenu(void) {



    cout << "Options Menu\n";
    cout << "1 - Difficulty\n";
    cout << "2 - Sound";
    cout << "3 - Back\n";
    cout << "Please choose: ";
            cin >> choice2;

}
fanatical
  • 103
  • 1
  • 1
  • 6
4

How about this (dunno if it compiles though):

     #include <cstdlib>
     #include <iostream>

     using namespace std;

     int GetInput()
     {
         int choice;    
        cin >> choice;
        return choice;
     }

     void DisplayMainMenu()
     {
     cout << "Main Menu\n";
         cout << "Please make your selection\n";
         cout << "1 - Start game\n";
         cout << "2 - Options\n";
         cout << "3 - Quit\n";
         cout << "Selection: ";
     }

     void DisplayOptionsMenu()
     {
         cout << "Options Menu\n";
         cout << "Please make your selection\n";
         cout << "1 - Difficulty\n";
         cout << "2 - Sound\n";
         cout << "3 - Back\n";
         cout << "Selection: ";
     }

     void Options()
     {
        int choice = 0;
        do
        {
            system("cls");
            DisplayOptionsMenu();
            choice = GetInput();
            switch(choice)
            {
                case 1:
                    cout << "difficulty stuff";
                    break;
                case 2:
                    cout << "sound stuff";
                    break;
                case 3:
                    break;
                default:
                    break;
            }
        } while(choice!=3);
     }

     int main(int argc, char *argv[])
     {
         int choice = 0;

         do
         {
            system("cls");
            DisplayMainMenu();
            choice = GetInput();
            switch(choice) {
                    case 1:
                            cout << "Pew pew!\n";
                            break;
                    case 2: 
                            Options();
                            break;
                    case 3: 
                            cout << "Goodbye!";
                            break;

                    default: 
                            break;
                   }
           } while(choice!=3);
         system("PAUSE");
         return EXIT_SUCCESS;
     }
max_
  • 324
  • 1
  • 7
  • This produces roughly the problem I have. You get everything working right, except for going back to the main menu. That just doesn't happen. – fanatical May 31 '13 at 13:16
  • Ok I have tested my code and made a small improvement regarding the choice variable, which ought to be declared outside the do-while loop of course (I have updated the code in my post accordingly). But beside that minor flaw it worked perfectly for me. – max_ May 31 '13 at 15:35
4

I'd recommend that you change a few things here. Are you familiar with object-oriented design? If not, it's highly recommended that you read about that if you're looking to write code in C++ (Or just writing code in general, as it's a pretty major aspect of many programming languages)

Consider treating each of your menus and submenus as individual objects. Each time you enter the loop, use an object pointer to call a method that prints the current menu text.

Then, take the input from the user as normal, and change the menu object you're using now.

This is perhaps not the most ideal way to do a console menu, but it will give you a very strong grounding in how objected-oriented programming works.

I've attached an example :

#include <iostream>
#include <string>

class BaseMenu
{
public:
    BaseMenu() { m_MenuText = "This shouldn't ever be shown!"; } // This is the constructor - we use it to set class-specific information. Here, each menu object has its own menu text.
    virtual ~BaseMenu() { } // This is the virtual destructor. It must be made virtual, else you get memory leaks - it's not a quick explaination, I recommend you read up on it
    virtual BaseMenu *getNextMenu(int iChoice, bool& iIsQuitOptionSelected) = 0; // This is a 'pure virtual method', as shown by the "= 0". It means it doesn't do anything. It's used to set up the framework
    virtual void printText() // This is made virtual, but doesn't *have* to be redefined. In the current code I have written, it is not redefined as we store the menu text as a string in the object
    {
        std::cout << m_MenuText << std::endl;
    }

protected:
    std::string m_MenuText; // This string will be shared by all children (i.e. derived) classes
};

class FirstMenu : public BaseMenu // We're saying that this FirstMenu class is a type of BaseMenu
{
    FirstMenu()
    {
        m_MenuText = "Main Menu\n"                         // What we are doing here is setting up the string to be displayed later
                    + "Please make your selection\n"       // What we are doing here is setting up the string to be displayed later
                    + "1 - Start game\n"                   // What we are doing here is setting up the string to be displayed later
                    + "2 - Options\n"                      // What we are doing here is setting up the string to be displayed later
                    + "3 - Quit\n"                         // What we are doing here is setting up the string to be displayed later
                    + "Selection: ";                       // What we are doing here is setting up the string to be displayed later
    }

    BaseMenu *getNextMenu(int choice, bool& iIsQuitOptionSelected) // This is us actually defining the pure virtual method above
    {
        BaseMenu *aNewMenu = 0; // We're setting up the pointer here, but makin sure it's null (0)

        switch (choice) // Notice - I have only done "options". You would obviously need to do this for all of your menus
        {
            case 2:
            {
                aNewMenu = new SecondMenu; // We're creating our new menu object here, and will send it back to the main function below
            }

            case 3:
            {
                // Ah, they selected quit! Update the bool we got as input
                iIsQuitOptionSelected = true;
            }

            default:
            {
                // Do nothing - we won't change the menu
            }

        }

        return aNewMenu; // Sending it back to the main function
    }

};

class SecondMenu : public BaseMenu
{
    SecondMenu()
    {
        m_MenuText = "OptionsMenu\n"
                    + "Please make your selection\n"
                    + "1 - ????"
                    + "2 - dafuq?";
    }

    BaseMenu *getNextMenu(int choice, bool& iIsQuitOptionSelected) // This is us actually defining the pure virtual method above
    {
        BaseMenu *aNewMenu = 0; // We're setting up the pointer here, but makin sure it's null (0)

        switch (choice) // Notice - I have only done options. You would obviously need to do this for all of your menus
        {
            case 1:
            {
                aNewMenu = new FirstMenu; // We're creating our new menu object here, and will send it back to the main function below
            }
            break;
            case 2:
            {
                aNewMenu = new FirstMenu; // We're creating our new menu object here, and will send it back to the main function below
            }
            break;

            default:
            {
                // Do nothing - we won't change the menu
            }

        }

        return aNewMenu; // Sending it back to the main function
    }
};

int main (int argc, char **argv)
{
    BaseMenu* aCurrentMenu = new FirstMenu; // We have a pointer to our menu. We're using a pointer so we can change the menu seamlessly.
    bool isQuitOptionSelected = false;
    while (!isQuitOptionSelected) // We're saying that, as long as the quit option wasn't selected, we keep running
    {
        aCurrentMenu.printText(); // This will call the method of whichever MenuObject we're using, and print the text we want to display

        int choice = 0; // Always initialise variables, unless you're 100% sure you don't want to.
        cin >> choice;

        BaseMenu* aNewMenuPointer = aBaseMenu.getNextMenu(choice, isQuitOptionSelected); // This will return a new object, of the type of the new menu we want. Also checks if quit was selected

        if (aNewMenuPointer) // This is why we set the pointer to 0 when we were creating the new menu - if it's 0, we didn't create a new menu, so we will stick with the old one
        {
            delete aCurrentMenu; // We're doing this to clean up the old menu, and not leak memory.
            aCurrentMenu = aNewMenuPointer; // We're updating the 'current menu' with the new menu we just created
        }
    }

    return true;    
}

Note that this might be a bit complex for starting out. I strongly recommend you read the other answers people have posted. It should give you a few approaches on how to do it, and you can progress from the basic up to the more complex, examining each change.

Mike B
  • 478
  • 2
  • 11
  • This is going way over my head, but I'll try to read up and see what I find. Thanks =) – fanatical May 31 '13 at 13:17
  • Great start on OOP + menus, +1. I'm on quest to find a good menu class. I asked on SO and got yelled at and shamed into deleting my question... – Krista K Sep 06 '13 at 04:07
1

Looking at what you are trying to do, I would change how you are ensuring the user still want's to play the game first. Look at using a while loop to check if a variable is true or false (people tend to use boolean variables(bool's) for this, an int set to 1 or 0 will do the same). That removes the need for the do-while. Reading up on control logic (if/else, while, for loops) and logical operators (&& - and, || - or, != - not equal to) is recommended. Control logic makes your code do different things, booleans are quick for checking yes/no scenarios and logical operators allow you to check multiple items in one if statement. Some reading: Loops

Edit: Have more links for reading material, don't have the rep to post them.

Secondly, use another variable (int or whatever suits you) to track what screen you are on. Based on this selection, display different options but still take input 1,2,3 to decide upon the next action.

In some terrible pseudo-code here is what I would lean towards:

main()
{
   int choice
   int screen = 1
   bool running = true

   while(running) {
       //Screen 1, Main menu
       if(screen == 1) {
       cout << stuff
       cout << stuff
       cout << option 1
       cout << option 2
       cout << option 3
       cout << selection:
       cin >> choice
       }
       else if(screen == 2){
       //options screen here

       }
       else {
       //default/error message
       }

       //add some choice logic here
       if(screen == 1 && choice == 3){
           //being on screen one AND choice three is quit
           running = false;
       }
       else if(screen == 1 && choice == 2){
           //etc..
       }

  }

}

This is my first proper answer, all terrible criticism is well recieved.

John Langan
  • 51
  • 1
  • 6
  • 3
    You said *use another variable (int or whatever suits you)*, `enum` are great for this. They are the wonderful combination of `#define` and an array at the same time. BTW, please edit your post to add the links. Leave off http:// or change to (dot) (com) as needed to post them. I am particularly irked at stackexchange limiting people helping others. – Krista K Sep 06 '13 at 05:23