Skip to main content
Code Review

Return to Answer

replaced http://stackoverflow.com/ with https://stackoverflow.com/
Source Link

Putting using namespace std at the top of every program is a bad habit a bad habit that you'd do well to avoid. I don't know that you've actually done that, but it's an alarmingly common thing for new C++ programmers to do.

Putting using namespace std at the top of every program is a bad habit that you'd do well to avoid. I don't know that you've actually done that, but it's an alarmingly common thing for new C++ programmers to do.

Putting using namespace std at the top of every program is a bad habit that you'd do well to avoid. I don't know that you've actually done that, but it's an alarmingly common thing for new C++ programmers to do.

Improved formatting.
Source Link
Morwenn
  • 20.2k
  • 3
  • 69
  • 132

There are two problems with this approach. One is that the low order bits of the random number generator are not particularly random, so neither with random1 be. On my machine, there's a slight but measurable bias toward 0 with that. The second problem is that it's not thread safe because rand stores hidden state. A better solution, if your compiler and library supports it, would be to use the C++11 `std::uniform_int_distributionstd::uniform_int_distribution. It looks complex, but it's actually pretty easy to use. One way to do that (from Stroustrup) is like this:

There are two problems with this approach. One is that the low order bits of the random number generator are not particularly random, so neither with random1 be. On my machine, there's a slight but measurable bias toward 0 with that. The second problem is that it's not thread safe because rand stores hidden state. A better solution, if your compiler and library supports it, would be to use the C++11 `std::uniform_int_distribution. It looks complex, but it's actually pretty easy to use. One way to do that (from Stroustrup) is like this:

There are two problems with this approach. One is that the low order bits of the random number generator are not particularly random, so neither with random1 be. On my machine, there's a slight but measurable bias toward 0 with that. The second problem is that it's not thread safe because rand stores hidden state. A better solution, if your compiler and library supports it, would be to use the C++11 std::uniform_int_distribution. It looks complex, but it's actually pretty easy to use. One way to do that (from Stroustrup) is like this:

added lengthy example code
Source Link
Edward
  • 67.2k
  • 4
  • 120
  • 284

Specifically, here's how I might approach this. I'd create a Menu object:

class Menu
{
public:
 Menu(const string &name, const string &prompt, 
 const std::vector<std::pair<string, string> > &choices 
 = std::vector<std::pair<string, string> >{});
 virtual ~Menu();
 const string& getChoice() const;
 bool operator==(const string &name) const;
private:
 static const string menuend;
 string _name, _prompt;
 std::vector<std::pair<string, string> > _choices;
};

Implementations are here:

Menu::Menu(const string &name, const string &prompt, 
 const std::vector<std::pair<string, string> > &choices) 
 : _name(name), _prompt(prompt), _choices(choices) 
{}
bool Menu::operator==(const string &name) const
{
 return name==_name;
}
const string& Menu::getChoice() const
{ 
 if (_choices.size() == 0) {
 cout << _prompt;
 return menuend;
 }
 unsigned choice; 
 int i;
 do { 
 cout << _prompt;
 i = 1;
 for (auto ch : _choices)
 cout << i++ << ": " << ch.first << '\n';
 cin >> choice; 
 --choice;
 } while (choice >= _choices.size()); 
 return _choices[choice].second; 
}
Menu::~Menu() 
{}
const string Menu::menuend{"END"};

Finally, we can construct the game itself as a std::vector of these Menu objects:

std::vector<Menu> game{ 
 Menu("mainroad", 
 "You are on a road that heads west and east of your position.\n" 
 "Which way will you go?\n", std::vector<std::pair<string,string> >{
 {"Go West", "spider"}, 
 {"Go East", "brickhouse"}, 
 {"Wait for something to happen", "dragon"}}),
 Menu("spider", 
 "You travel down the road, about only 100 metres and you encounter \n" 
 "a giant spider with vicious poison coated fangs.\n" 
 "its hideous appearance causes your throat to dry and your knees to shake!\n"
 "What on earth will you do?\n\n", std::vector<std::pair<string, string> >{
 {"Attempt to attack the spider with your sword.","spiderattack"},
 {"Throw your sword in the off chance it might kill it.","throwsword"},
 {"RUN FOR YOUR LIFE!", "running"}}),
 Menu("spiderattack",
 "You viscously swing your sword at the spiders general direction.\n" 
 "The swing was so great, your arms jolts out of place,\n"
 "creating a surge of pain.\n" 
 "Your arm is now broken, and you fall to the ground in pain....\n" 
 "The spider launches 3 metres straight into your body...\n"
 "What on earth is it doing?\n" 
 "Oh My God! The spider is devouring everything....\n" 
 "All that remained was bones of the once mobile adventurer.\n"), 
 Menu("brickhouse",
 "After a mile walk, you arrive at an old brick house.\n" 
 "You walk slowly inside.\n" 
 "The door slams behind you and the room lightens up.\n" 
 "What on earth is going on...?\n\n" 
 "Unable to open the door, you look around for anything of use.\n" 
 "Nothing, not a single piece of furniture.\n" 
 "What will you do?\n", std::vector<std::pair<string, string> >{
 {"Wait for someone to save you.", "trapdoor"}, 
 {"Or Wait for someone to save you.", "library"}})
};

The game itself becomes entirely data-driven:

void road() {
 auto menu = std::find(game.begin(), game.end(), "mainroad"); 
 while (menu != game.end())
 menu = std::find(game.begin(), game.end(), menu->getChoice());
}

If you need more than the plain Menu class provides, you can simply derive a new kind of class and put that into the vector. It should also be obvious that this could very easily all be read as a script from a file, simply by defining an ostream extractor for the Menu class.

Specifically, here's how I might approach this. I'd create a Menu object:

class Menu
{
public:
 Menu(const string &name, const string &prompt, 
 const std::vector<std::pair<string, string> > &choices 
 = std::vector<std::pair<string, string> >{});
 virtual ~Menu();
 const string& getChoice() const;
 bool operator==(const string &name) const;
private:
 static const string menuend;
 string _name, _prompt;
 std::vector<std::pair<string, string> > _choices;
};

Implementations are here:

Menu::Menu(const string &name, const string &prompt, 
 const std::vector<std::pair<string, string> > &choices) 
 : _name(name), _prompt(prompt), _choices(choices) 
{}
bool Menu::operator==(const string &name) const
{
 return name==_name;
}
const string& Menu::getChoice() const
{ 
 if (_choices.size() == 0) {
 cout << _prompt;
 return menuend;
 }
 unsigned choice; 
 int i;
 do { 
 cout << _prompt;
 i = 1;
 for (auto ch : _choices)
 cout << i++ << ": " << ch.first << '\n';
 cin >> choice; 
 --choice;
 } while (choice >= _choices.size()); 
 return _choices[choice].second; 
}
Menu::~Menu() 
{}
const string Menu::menuend{"END"};

Finally, we can construct the game itself as a std::vector of these Menu objects:

std::vector<Menu> game{ 
 Menu("mainroad", 
 "You are on a road that heads west and east of your position.\n" 
 "Which way will you go?\n", std::vector<std::pair<string,string> >{
 {"Go West", "spider"}, 
 {"Go East", "brickhouse"}, 
 {"Wait for something to happen", "dragon"}}),
 Menu("spider", 
 "You travel down the road, about only 100 metres and you encounter \n" 
 "a giant spider with vicious poison coated fangs.\n" 
 "its hideous appearance causes your throat to dry and your knees to shake!\n"
 "What on earth will you do?\n\n", std::vector<std::pair<string, string> >{
 {"Attempt to attack the spider with your sword.","spiderattack"},
 {"Throw your sword in the off chance it might kill it.","throwsword"},
 {"RUN FOR YOUR LIFE!", "running"}}),
 Menu("spiderattack",
 "You viscously swing your sword at the spiders general direction.\n" 
 "The swing was so great, your arms jolts out of place,\n"
 "creating a surge of pain.\n" 
 "Your arm is now broken, and you fall to the ground in pain....\n" 
 "The spider launches 3 metres straight into your body...\n"
 "What on earth is it doing?\n" 
 "Oh My God! The spider is devouring everything....\n" 
 "All that remained was bones of the once mobile adventurer.\n"), 
 Menu("brickhouse",
 "After a mile walk, you arrive at an old brick house.\n" 
 "You walk slowly inside.\n" 
 "The door slams behind you and the room lightens up.\n" 
 "What on earth is going on...?\n\n" 
 "Unable to open the door, you look around for anything of use.\n" 
 "Nothing, not a single piece of furniture.\n" 
 "What will you do?\n", std::vector<std::pair<string, string> >{
 {"Wait for someone to save you.", "trapdoor"}, 
 {"Or Wait for someone to save you.", "library"}})
};

The game itself becomes entirely data-driven:

void road() {
 auto menu = std::find(game.begin(), game.end(), "mainroad"); 
 while (menu != game.end())
 menu = std::find(game.begin(), game.end(), menu->getChoice());
}

If you need more than the plain Menu class provides, you can simply derive a new kind of class and put that into the vector. It should also be obvious that this could very easily all be read as a script from a file, simply by defining an ostream extractor for the Menu class.

added caveat about state
Source Link
Edward
  • 67.2k
  • 4
  • 120
  • 284
Loading
added example of rand_int
Source Link
Edward
  • 67.2k
  • 4
  • 120
  • 284
Loading
Source Link
Edward
  • 67.2k
  • 4
  • 120
  • 284
Loading
lang-cpp

AltStyle によって変換されたページ (->オリジナル) /