Movement system with functions for text RPG - c++

I am a beginner student of C++ and I am currently working on a text RPG. I've been able to implement various functions that help the user check location, interact with items, check inventory, look around, and so on, but I cannot seem to get a good working movement system.
Now, I understand that OOP is obviously going to be MUCH more efficient and less frustrating than going the function route, but I am doing this for a class, and we haven't learned anything about classes/objects yet (We haven't even gone over vectors/arrays in our class).
Here is my code to try and get the movement working:
#include <iostream>
#include <string>
#include <boost/algorithm/string.hpp>
using namespace std;
void movement(string action, int& currentRoom) {
if (action == "MOVE NORTH") {
if (currentRoom == 1) {
currentRoom = 2;
// This part is just to check if the loop happened and changed values.
cout << currentRoom << " " << "You are now in room two." << endl;
}
}
}
int main() {
int currentRoom;
string action;
cout << "Type 'move [direction]'" << endl;
currentRoom = 1;
getline(cin, action);
boost::to_upper(action);
// This is to check (for testing purposes for me) to see if the string
// converted to uppercase properly.
cout << action << endl;
getline(cin, action);
movement(action, currentRoom);
}
Now, this is not final code that I'm implementing into my game. I've just created a small file to try and work out the logic/syntax of this movement function. When I run this code, I am able to type in 'move north' and it successfully translates into MOVE NORTH, but the function doesn't seem to be calling or doing anything. What am I doing wrong here? Is there any way I can make this easier for myself, without fully leaning into OOP?
Like I said, I haven't been able to learn classes/objects aside from a bit of reading I've done online, and I feel like I would be taking on too much right now to try and learn/implement them properly in such a short time... but maybe it would be for the better if I did? I am not sure.
Any help and input is greatly appreciated.

int main() {
int currentRoom;
string action;
cout << "Type 'move [direction]'\n";
currentRoom = 1;
getline(cin, action);
boost::to_upper(action);
cout << action << '\n'; // here you verify
getline(cin, action); // but then you read again from stdin
movement(action, currentRoom); // and pass it on without changing it toupper.
}

Related

Big problem with classes , and returning from void function c++

so that's my first time learning a language , and I was really excited to play with classes, i do have one major problem which i cant seem to understand ;
im building a bank menu . its a class ofcourse, and i have a different class of clients which is basicly an array in my bank.
so my menu function inside the bank looks like that :
void menu (){
manager();
int n,m;
cout << "welcome to our bank managment system. \n";
cout << "please choose one of the following options : \n";
cout << "1-add a new client\n";
cout << "2-remove a leaving client\n";
cout << "3-bank statistics\n";
cout << "4-if you are a costumer\n";
cout << "5-exit\n";
cin >> n ;
if()
if()
if()
if()
if()
note that my return function is been summoned a lot inside
i have a return function to go back to the menu :
void returnfunction (){
int back = 0;
cout << "\n0-back to menu \n press a diffrent number back to exit :)\n";
cin >> back ;
if (back==0){
return menu();
}
if (back!=0){
cout << "thank you for using our program ! ";
return ;
}
it is working perfect until i play with it to much , and then hit 5 to exit (that's my option for n==5)
i must emphasize that when im hitting 5 only after few simple actions its working fine...
how can i fix that return function ?
ofcourse my main looks like that :
int main()
{
srand (time(NULL));
Bank b ;
b.menu();
}
appricate all of your wisom , thanks a lot
Your function:
void returnfunction ()
is declared to return nothing (void) but you:
return menu();
do return something, that's very unclear (even though menu() returns void too)
If you want to call menu() and then return write:
menu();
return;
There are a couple problems with this code, and honestly it wouldn't compile in other imperative OO languages. But this is c++ where the rules don't matter. Aside: If you don't have a strong reason to be using C++, learn Rust first. I promise you'll thank me later.
Paul has the right of it. The compiler should error out at that statement:
return menu();
However the equivalent is perfectly legal:
menu();
return;
But this still will cause problems in theory (but maybe not in practice) because your function is almost, but not, a candidate for tail recursion optimisation. More here Which, if any, C++ compilers do tail-recursion optimization?
This becomes a problem when users return to the menu many times, it depletes your programs memory, eventually leading to a stack overflow fault. The common pattern you'll find in most every GUI / Graphics library is that of a main-loop. Something like:
int main() {
bool exit = false
while(!exit) {
int action = menu()
switch(action) {
case EXIT_SELECTION: exit = true; break;
case SHOW_STATISTICS: printStats(); break;
}
}
}
Each time you call a function, your program has to use more memory to keep track of everything related to that function call. Ordinarily this memory is released once a function ends, but because your menu function calls another function that calls your menu function that calls another function... and on and on, you will eventually run out of memory from all of the function calls since these functions cannot terminate until the functions they call terminates -- and thus your program will crash. The solution is to use a while loop and check the user's input for an exit code as a previous responder mentioned. It can look something like:
`void menu() {
char choice= '\0';
while(choice!= 3) {
std::cout << "Welcome to the menu!";
std::cout << "\t Option 1 \n";
std::cout << "\t Option 2 \n";
std::cout << "\t Option 3 \n";
std::cout << "Your option: ";
std::cin >> choice;
if(choice == 1) { /*do something*/ }
else if(choice == 2) { /*do something else*/ }
else if(choice == 3) { /*print a message and exit*/ }
else { /*bad choice -- try again*/ }
} //end while-loop
} //end menu()`
Also, notice that your functions' return types are void, which, by definition, cannot have any sort of return. C++ will allow you to say return; inside of a void function, but it is merely a way to escape the function right then and there and is not really intended to do anything more than that. Using return in any other way when working with void functions is confusing and runs a risk of causing big issues.

My homework assignment requires me to use booleans in functions. Do I need to pass them to the functions?

For my homework assignment I'm supposed to make a create-your-own-adventure story. There are certain words in the text that are in all caps to represent boolean values that I need to display at the end if the player got them, like a status effect or something. I'm having trouble figuring out how to pass the booleans to the functions so that it makes it to the end of the program where I can display it. My program has functions within functions.
I've tried making the function that sets the boolean to true a boolean itself, then returning the boolean but that just ends the program it seems. I've also tried passing it through the first function call to see if it reaches the second but it doesn't seem like it wants to.
void A1();
bool A100(bool INTIM);
void A167();
void A232();
void A290();
void A13();
void A212();
void A173();
void A159();
void A161();
int main() {
bool INTIM;
A1();
cout << INTIM << endl;
return 0;
}
void A1()
{
int choice;
cout << "Well, Mr Artanon, ...\n 1. ’It’s you who’ll get a rare cut
across that corpulent neck of yours if you don’t speed things along, you
feckless blob of festering lard.’\n 2. ’Surely in such an industrious
kitchen, there must be a starter or two ready to send along and sate His
Abhorentness’s appetite?’\n (enter a menu option): ";
cin >> choice;
while (choice != 1 && choice != 2)
{
cout << "Enter in a valid choice (1 or 2)";
cin >> choice;
}
if (choice == 1)
{
A100();
}
if (choice == 2)
{
A167();
}
}
bool A100(bool INTIM)
{
int choice;
INTIM = true;
cout << " Repugnis turns a paler...\n 1. Onwards, Mr Artanon.\n (enter
in a menu option): ";
cin >> choice;
while (choice != 1)
{
cout << "Enter in a valid option (1)";
}
return INTIM;
A232();
}
What I'm wanting to happen is, the bool INTIM to be passed along so i can display it back in main with the cout statement. I know it will just be a 1 or 0 at the end but I'm just trying to get it to show up at least in the end when I display it. Again there are functions within functions in this program and that might be my problem but I wouldn't think so. There is also functions that come after this, this is not the end of the program and if I need to post the whole thing I will
Calling A100 as written, you need to pass in INTIM and accept the return value
INTIM = A100(INTIM);
But... The initiqal state of INTIM is never used, so you could
INTIM = A100();
and change A100 to look more like
bool A100()
{
int choice;
cout << " Repugnis turns a paler...\n 1. Onwards, Mr Artanon.\n (enter in a menu option): ";
cin >> choice;
while (choice != 1)
{
cout << "Enter in a valid option (1)";
cin >> choice; // added here because otherwise choice never changes
// and this loop will go on for a long, long time.
}
A232(); // moved ahead of return. Code after a return is not run
return true;
}
But since A232 is called and may set additional flags you cannot return, you have a design flaw: What if A232 also modifies a boolean? You can only return one thing from a function. You could pass A232's boolean in by reference, but what it A232 then calls B484 and it also has a boolean?
You don't want to have to pass around every possible boolean, that would be a confusing mess, so consider making a data structure that stores all of your booleans to pass around.
And that leads to an even better idea: encapsulating the booleans and the functions in the same data structure so that you don't have to pass anything around; it's all in the same place.
Do I need to pass them [the boolean results] to the functions?
Often, but not always, it is my preference to pass them by reference, and yes, it can get to be a big chain thru many functions. sigh.
But your question is "Do you need to pass them ...".
The answer is No.
Because
a) you have tagged this post as C++, and
b) the key feature of C++ is the user-defined-class.
Consider declaring every 'adventurous function' of your story within a class scope.
Each 'adventurous function', as an attribute of the class, is implemented with one 'hidden' parameter, the 'this' pointer to the class instance.
So .. if you place all your 'result' booleans as data attributes of the class, invoking any 'adventurous function' will also 'pass' all the class instance data attributes (all your bools!) as part of the invocation. No data is actually moving, just a pointer, the 'this' pointer.
It might look something like this:
#include <iostream>
using std::cout, std::cerr, std::flush, std::endl;
// using std::cin;
#include <iomanip>
using std::setw, std::setfill;
#include <sstream>
using std::stringstream;
#include <string>
using std::string;
namespace AS // Adventure Story
{
class CreateYourOwnAdventureStory_t
{
private:
// diagnostic purposes
stringstream ssUI;
// command line arguments concatenated into one string
// contents: strings convertable to ints to mimic cin
bool INTIM;
// other results go here
public:
int operator()(int argc, char* argv[]) {return exec(argc, argv);}
private:
int exec(int argc, char* argv[])
{
int retVal = 0;
// capture all command line arguments into a string
for (int i=1; i<argc; ++i)
ssUI << argv[i] << " ";
cout << "\n ssUI: " << ssUI.str() << "\n\n\n";
A1();
cout << "\n INTIM : " << INTIM << endl;
// ?more here?
return retVal;
}
void A1()
{
int choice = 0;
cout << "Well, Mr Artanon, ...\n "
"\n 1. ’It’s you who’ll get a rare cut across that corpulent neck of yours "
"if you don’t speed things along, you feckless blob of festering lard. "
"\n 2. ’Surely in such an industrious kitchen, there must be a starter or two "
"ready to send along and sate His Abhorentness’s appetite?’"
"\n (enter a menu option): ";
ssUI >> choice; // cin >> choice;
if (choice == 1) { A100(); }
if (choice == 2) { A167(); }
}
void A100()
{
int choice = 0;
INTIM = true;
ssUI >> choice; // cin >> choice;
cout << "\n\n A100() choice:" << choice
<< " INTIM: " << INTIM << endl;
}
void A167()
{
int choice = 0;
INTIM = false;
ssUI >> choice; // cin >> choice;
cout << "\n\n A167() choice:" << choice
<< " INTIM: " << INTIM << endl;
}
// other action-functions go here
}; // class CreateYourOwnAdventureStory_t
typedef CreateYourOwnAdventureStory_t CreateYOAS_t;
} // namespace AS
int main(int argc, char* argv[]){return AS::CreateYOAS_t()(argc,argv);}
Notes:
This example grabs the command line parameters and appends them to a string stream. The result is use-able in a fashion much like your cin statements.
Did you notice you (probably) will not need forward declarations for your functions? The compiler has to scan a lot of the class declaration to decide various issues, and thus can figure out that A100 (and A167) are actually with-in the scope of AS::CreateYOAS_t::. The functions can still be moved into a cpp file, so you can still take advantage of separate compilation. (and maybe save some effort compiling smaller files, and only the changed files.)
Did you notice that the functions accessing INTIM simply use the bool, without needing any 'this->' to de-reference?
Main invokes a simple Functor. Nothing else. Main invokes operator(). Simple, minimal. The ctor and dtor are currently default. If you need to use the ctor to initialize results or other intermediate info, I would simply add it near the operator() implementation.
PS: You mentioned using bools to return results. You might as, an alternative, consider using a stringstream ... a single stream with text ... use like a log for capturing the ongoing game, or for a single simple overall report to the user.
Good luck.

Properly Store Object in Vector

I'm brand new to C++, and this is my first time posting (recipe for disaster). I've spent about a day trying to resolve my problem/question, in the mean time finding no easily recognizable solution on the forums. It's possible that my question has already been asked or that a solution has already been posted but I've overlooked it or misunderstood it. A similar post exists here, but it's not obvious to me what to do with the information.
I'll provide a concise, high-level summary of the point of this code. I'll then ask the specific question(s) to which I'm unable to find an answer, and I'll follow with the code I've written.
SUMMARY: I'm creating a program to help do bookkeeping for a game. The game may have any number of players, and each player having a small list of attributes/members (e.g. playerName, playerAllegiance, etc.) which are elements of a Player class/object. The user is first asked to input the name of each player (enteredName), and the program must create a new Player object for each name that's entered. This seems to be appropriately handled by a dynamic array, so I chose to use a vector (called playerIndex) to store each Player object. A for-loop allows the user to input names, each name instantiating a new Player object which is to be stored (copied?) into playerIndex using vector::push_back. At the conclusion of the for-loop, the user should be left with a vector of Player objects, each Player object storing a name in its playerName member.
QUESTION/PROBLEM: The code seems to work proprly when monitoring the vector inside the aforementioned for-loop. Immediately after the user enters the Nth player's name, the program spits out the playerName string stored in the Nth element of playerIndex using a Player class function getPlayerName() [actual code: playerIndex[playerCounter].getPlayerName()]. As soon as the user enters a blank playerName (i.e. presses enter without entering a name), it indicates the user has entered all player names, so the for-loop terminates. Just after this loop, a loop which is designed to output the playerName of each Player object stored in playerIndex does not output the expected names. I don't know why this is happening, but based on my very minimal knowledge of constructors, I'm guessing it has something to do with a copy or move constructor for the Player class. Can anyone clearly explain how to handle this issue? I fear I may be making a pitifully stupid, novice mistake and/or misunderstanding a key concept of C++.
CODE: This code is cropped/simplified to be as clear as possible. For example, the Player class is shown to have only one member (playerName) while, in the original code, it has four or five other members.
//HeaderPlayerClass.hpp
#include <iostream>
#include <string>
#ifndef PLAYERCLASS_HPP
#define PLAYERCLASS_HPP
using std::string;
class Player {
private:
string *playerName;
public:
Player();
Player(string);
~Player();
string getPlayerName();
};
#endif
//PlayerClass.cpp
#include "HeaderPlayerClass.hpp"
#include <iostream>
#include <string>
using std::string;
Player::Player() {
playerName = new string;
}
Player::Player(string enteredName) {
playerName = new string;
*playerName = enteredName;
}
Player::~Player() {
delete playerName;
}
string Player::getPlayerName() {
return *playerName;
}
//main.cpp
#include <cstdio>
#include <iostream>
#include <string>
#include <vector>
#include "HeaderPlayerClass.hpp"
using std::cin;
using std::cout;
using std::string;
using std::vector;
int main(int argc, char** argv) {
string buffer;
vector<Player> playerIndex;
int playerCounter = 0;
for(;;) {
if(playerCounter==0) {
cout << "\nEnter player name and press enter; leave blank and press enter to continue.\n";
}
cout << "\nPlayer " << playerCounter+1 << ":";
getline(cin, buffer);
if(buffer == "esc") {
cout << "PROGRAM EXITED BY USER\n";
return 0;
}
if(buffer.empty()) {
break;
}
playerIndex.push_back(Player(buffer));
cout << "Player " << playerCounter+1 << "'s name:" << playerIndex[playerCounter].getPlayerName() << "\n";
++playerCounter;
}
for(int ii = 0 ; ii < playerIndex.size() ; ii++) {
cout << "\nThis should display player " << ii+1 << "'s name:" << playerIndex[ii].getPlayerName();
}
return 0;
}
class Player {
private:
string *playerName;
Do not store a pointer to the string, store the string itself
class Player {
private:
string playerName;
Constructor
Player::Player() {
playerName = new string;
}
This is unnecessary if you store the string itself - the default constructor will initialize it for you.
Here is where the problems start - this will leave you vulnerable to memory leaks unless you carefully write a destructor
Player::Player(string enteredName) {
playerName = new string;
*playerName = enteredName;
}
All you need, if you store the string itself:
Player::Player( const string& enteredName)
: playerName ( enteredName )
{}
You constructor is really scary. Just leave things to the default destructor when you store the string itself
Player::~Player() {
delete playerName;
}
Next, you are working too hard keeping your own counter. std::vector maintains its own count and using
playerIndex.size()
will save trouble and bugs

Control stdin and stdout of second program (pipes/piping?)

I've been wondering how to go about running a program within another program where the the main process can output into the stdin of the secondary process as well as have that second process output to the input to the primary one.
The closest I have come to finding a term for this idea is pipes and forks but I don't quite get the examples i've seen. I've only seen ones where the same program is using pipes to launch itself again. Additionally all of these examples assume that that the programmer is writing/has access to both program's source code.
I would like to be able to interface in this way with programs that are already compiled. Here's an example of what I would like to be able to do:
This is the "compiled" program-
#include <iostream>;
using namespace std;
int main(){
int answer = 42;
int guess = 0;
do{
cout << "Guess a number..." << endl;
cin >> guess;
if(guess<answer)
cout << "Guess Higher!" << endl;
else if(guess>answer)
cout << "Guess Lower!" << endl;
}while(answer!=guess);
cout << "You win!";
return 0;
}
This is the "parent" program-
#include <iostream>;
using namespace std;
int main(){
//Code executing and connecting the other program
//while cin/cout would be nice for keeping it clean, other methods of doing this are fine
//I used cin/cout as placeholders to try and make what I am asking clearer
String out;
cin >> out;//Load initial prompt
int high=100, low=0;
do{
cout << (high+mid)/2 << endl;
cin >> out;//Load response
if(out.compare("Guess Higher!"))
low = (high+low)/2;
else
high = (high+low)/2;
}while(out.compare("You win!")!=0);
return 0;
}
The idea here is that my "parent" program could play this game for me. It would make a guess, view the response, use some logic to decide what to do next, guess, repeat until it wins. This particular example is pretty useless but the same general idea of controlling one program with another has a lot of uses. This is just a hypothetical demo of would I would like to be able to do.
Thanks to anyone kind enough to take time out of their day to help.

C++ restart main without losing variables

My program's main function displays a switch menu. When option 1 is entered, a function is called that "shuffles" an array of "cards". After the shuffling is complete, that function returns the program to the beginning by calling main(), so that the menu is shown again.
The problem I have with this is that option 4 of the menu writes the shuffled array to a file. But when the cards are shuffled and then the program is restarted, the array data is lost, and therefore the outputted file is all junk. Is there a way to restart main() WITHOUT that data being lost?
I am in a class and am limited in the tools I can use, so only the most basic code will be acceptable. Basically, I'm looking for something like goto but a little safer (goto, by the way, is also forbidden in this class).
It's actually not a good idea for a C++ program to call its own main function. In fact, this leads to undefined behavior, which means that you have no guarantees about the behavior of the program. It could crash, or proceed with corrupt data, or format your hard drive, etc. (that last one is unlikely, though).
I think that this reflects a more fundamental problem with how your program works. If you want data to persist across functions, you need to place that data somewhere where it won't get clobbered by other functions. For example, you could put the data in the heap, then pass pointers to the data around. Or, you could define it as a local variable in main, then pass it down into functions and have those functions return when they're done. You could also consider making objects representing the data, then passing those objects across the different functions.
Without seeing your code, I doubt I can give a more specific answer than this. When designing programs, keep the data flow in mind. Think about what data needs to go where and how you're going to get it there.
Hope this helps!
Why are you calling main recursively (which, by the way, is forbidden by the standard)? Just use a loop (e.g. a do ... while) to repeat the part of your main that needs to be repeated, keeping the variables that must not be resetted (and their initialization) outside the loop.
The main() function should not be called recusively.
You can encapsulate your game loop into a while() function.
Take a look at this example :
#include <iostream>
#include <string>
using namespace std;
int main()
{
bool exitGame = false;
// Game Loop
while(!exitGame) {
// Display menu
cout << "Menu :" << endl;
cout << "- Shuffle : press 1" << endl;
cout << "- Option 2 : press 2" << endl;
cout << "- Option 3 : press 3" << endl;
cout << "- Exit : press 4" << endl;
cout << "Enter your choice : ";
// Get user input
string choosenValue;
cin >> choosenValue;
cout << endl;
// Process user input
if (choosenValue == "1") {
cout << "You selected 'Shuffle'." << endl;
// Do cool stuff here !
} else if (choosenValue == "2") {
cout << "You selected 'Option 2'." << endl;
// Do cool stuff here !
} else if (choosenValue == "3") {
cout << "You selected 'Option 3'." << endl;
// Do cool stuff here !
} else if (choosenValue == "4") {
cout << "You selected 'Exit'." << endl;
exitGame = true;
} else {
cout << "Wrong value." << endl;
}
cout << endl;
}
return EXIT_SUCCESS;
}
Move main body to another function 'myMain' and call it insteadOf main.