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.
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:
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.