0

I have a personal project I've been working on. To work, it needs to accept a lot of data (relatively) from the user, in the form of four different kinds of data for 12 users. As such, I have quite a lengthy sequence of statements similar to this:

cout << '\n' << "Monster A's name is: ";
cin >> nameA;
cout << '\n' << "Monster A rolled: ";
cin >> rollM_A;
cout << '\n' << "Monster A's Dex is: ";
cin >> DexA;
cout << '\n' << "Monster A's Mod is: ";
cin >> ModA;
cout << '\n' << "Monster A's Level is: ";
cin >> LvlA;

etc.

Occasionally, however, there might only be a need to input data for less than 12 monsters, say, 5-6 or even 1-2. I'd like to be able to use a command to skip the input section to the rest of the code based on something like a keystroke. i.e. If the user has put in data for 5 monsters, and that's all they require, they could hit the backslash to skip the rest of the input sequence.

Does what I'm talking about make any sense/is there an STL command to do what I'm looking for? Currently, this process isn't looped, but would exiting it be easier if it was inside a loop? I did have a thought of trying something like this:

while(cin.get() != '\') {
   cout << '\n' << "Monster A's name is: ";
   cin >> nameA;
   //etc...
}

EDIT: The above attempt builds, but upon entering the desired keystroke, it quickly and endlessly prints the user prompts without accepting data. Any advice? All I want is for it to break and move on. Can I use a switch statement effectively?

Thanks!

Rome_Leader
  • 2,518
  • 9
  • 42
  • 73
  • 2
    If the input of the monsters is a painful with command line input, you should maybe consider reading a file instead. This way, you could also correct small mistakes by changing the file instead of entering again the whole data. – Dr_Sam Jun 17 '13 at 15:16
  • 1
    You might want a text-mode user interface library to allow input into a form/dialog. After getting to monster D, users might e.g. cursor back up to monster B if they change their mind. Unwanted monsters - leave the names blank when accepting the whole form (though they might name monster D but not monster C). curses is a common text-mode UI library - it's portable, and probably with C++ bindings though I'm not sure - the base library is in C. I've not used it, though. It's probably not hard to write your own as well, though you'll probably need platform-specific console APIs to do it. –  Jun 17 '13 at 15:25

5 Answers5

2

That could work. You can also use EOF, which is more general, than '\'. Then when you are done, hit Ctrl-D to send the EOF, and you are done. This takes care of the situation when some player enters '\' as the Monster's name.

jh314
  • 27,144
  • 16
  • 62
  • 82
  • True! I didn't opt to cover many cases of sanitizing the user input as a precondition. I think for my purposes, it will be fine and perhaps better to use a single, seldom used keystroke for a break. – Rome_Leader Jun 15 '13 at 00:04
  • Quick extra question. If I have all the data initialized to 0, and the input section is exited, the variables will remain 0, correct? – Rome_Leader Jun 15 '13 at 00:09
  • 1
    The last value assigned to a variable is its value. – 7stud Jun 15 '13 at 00:12
  • Right. I'm still having a lot of trouble, though. If I wrap the sequence in the while condition I suggested, when I input the keystroke, it continually prints the lines but doesn't allow any further input. I want it to stop the lines. Any ideas? – Rome_Leader Jun 15 '13 at 16:54
0

You can check if the name is \, it is not user friendly but it works.

string name;
while (name != "\\") {
    cout << '\n' << "Monster A's name is: ";
    cin >> name;
    cout << "Received " << name << '\n';
    if (name != "\\") {
        // do something with name ...
    }
}

If the loop still loops endlessly, refer to How do I flush the cin buffer? and try clearing stdin buffer.

[edit] I fixed an error in the loop

Community
  • 1
  • 1
Federico
  • 1,925
  • 14
  • 19
  • I did use an .ignore statement immediately following the loop as a first try at clearing the buffer, but it didn't seem to work. I will see if using clear in conjunction with/instead of will help. I'm afraid your solution doesn't really help, since I don't have one name variable, but many, each distinct. I would have to check cin for a character, rather than a variable. – Rome_Leader Jun 17 '13 at 14:05
  • Same error, just spits out the prompts endlessly. I have a feeling it might be because I have cin.get() as the condition. Can anyone reason why this might cause the prompt looping? – Rome_Leader Jun 17 '13 at 14:08
0

I just tested this set of code and it seems to work how you would like. Of course you will have to modify it to fit your original application.

std::string in;

while (true) {
    std::cout << "Enter a name\n";
    std::cin >> in;
    if (in == "#")
        break;
    std::cout << "\nMonster A's name is: " << in << "\n";
}

In order to incorporate the limit of the number of monsters, rather than having the true parameter passed into the while loop, simply add a counter to how many monsters are created and break on that condition:

int num_monsters = 0;
while (num_monsters <= 12) {
    ...
    num_monsters++;
}

Hope this helps.

Alex Brooks
  • 1,151
  • 1
  • 10
  • 39
0

Here's something I wrote.

struct Monster {
string name;
bool roll;
float dex;
float mod;
float level;
Monster(void) :
  name(),
  roll(false),
  dex(0),
  mod(0),
  level(0) { }
};


bool getMonsterInformationFromStdin(int index, Monster& monster) {
  string end_char = "\\";
  string name, roll, dex, mod, level;
  cout << '\n' << "Monster " << index << "'s name is: ";
  cin >> name;
  if (name.compare(end_char) == 0) return false;
  monster.name = name;
  cout << '\n' << "Monster " << index << " rolled: ";
  cin >> roll;
  if (roll.compare(end_char) == 0) return false;
  monster.roll = (roll[0] == 'y' || roll[0] == 'Y') ? true : false;
  cout << '\n' << "Monster " << index << "'s Dex is: ";
  cin >> dex;
  if (dex.compare(end_char) == 0) return false;
  monster.dex = atof(dex.c_str());
  cout << '\n' << "Monster " << index << "'s Mod is: ";
  cin >> mod;
  if (mod.compare(end_char) == 0) return false;
  monster.mod = atof(mod.c_str());
  cout << '\n' << "Monster " << index << "'s Level is: ";
  cin >> level;
  if (level.compare(end_char) == 0) return false;
  monster.level = atof(level.c_str());
  return true;
}


int main(int argc, char** argv) {
  int max_monsters = 10;
  for (int i = 0; i < max_monsters; i++) {
    Monster m;
    if( !getMonsterInformationFromStdin(i, m) ) break;
    string roll = m.roll ? "rolled" : "didn't roll";
    cout << m.name << " " << roll << " dex: " << m.dex << " mod: " << m.mod << " level: " << m.level << endl;
  }
  return 0;
}
DXM
  • 1,249
  • 1
  • 14
  • 22
0

I think this is problem can be solved by using a sentinel Monster name, as u can see below.

const string SentinelName = "%^&";
while(true)
{
    cout << '\n' << "Monster A's name is(if u want to end, pls input %^&): ";
    cin >> nameA;
    if(strcmp(nameA, SentinelName.s_str())
        break;
    cout << '\n' << "Monster A rolled: ";
    cin >> rollM_A;
    cout << '\n' << "Monster A's Dex is: ";
    cin >> DexA;
    cout << '\n' << "Monster A's Mod is: ";
    cin >> ModA;
    cout << '\n' << "Monster A's Level is: ";
    cin >> LvlA;
}

Hope this can solve ur problem. Besides, A little advice for ur code, u can encapsulate the attributes of the monster, such as the name, mode level, etc into a class and this will make ur code look fancier.