...

View Full Version : Understanding C++: What am I doing wrong?



johnki
12-11-2011, 06:00 PM
I have been struggling for quite some time to understand C and C++. I have a feeling that quite a bit of that struggling is due to pointers, and not understanding how or where to use them. Following that, reading other peoples' code, I have issues all the time with understanding why sometimes the pointer reference is in the front of the word, and sometimes it's attached to the end (ex: "*char" and "char*").

I attempted building a sample program, an "interactive fiction" which only consisted of moving between rooms.




#include <iostream>

using namespace std;

bool isPlaying = true;
int playerx = 0;
int playery = 0;
char input[50];
int roomnum = 1;

void parsemov(char*);
int roomfind(int, int);
void roomdesc(int);
void updateGame();

int main()
{
if (isPlaying != true){
return 0;
}
else{
updateGame();
}
}

void updateGame()
{
roomfind(playerx, playery);
roomdesc(roomnum);
cin>> input;
parsemov(input);
}

void parsemov(char*)
{
if (input != "exit"){
if (input == "n" || input == "north"){
if (playery < 1){
playery += 1;
}
}
if (input == "s" || input == "south"){
if (playery > -1){
playery -= 1;
}
}
if (input == "e" || input == "east"){
if (playerx < 1){
playerx += 1;
}
}
if (input == "w" || input == "west"){
if (playerx > -1){
playerx -= 1;
}
}
else
{
cout<<"You cannot go that way.";
}
}
else
{
isPlaying = false;
}
}

int roomfind(int, int)
{
if (playerx == 0 && playery == 0)
{
roomnum = 1;
}
if (playerx == 1 && playery == 0)
{
roomnum = 2;
}
if (playerx == -1 && playery == 0)
{
roomnum = 3;
}
if (playerx == 0 && playery == 1)
{
roomnum = 4;
}
if (playerx == 0 && playery == -1)
{
roomnum = 5;
}
else
{
cout<<"Where are you?!";
}
}

void roomdesc(int)
{
if (roomnum == 1)
{
cout<<"You are in the middle of a dungeon.";
}
if (roomnum == 2)
{
cout<<"You are in the right wing of a dungeon.";
}
if (roomnum == 3)
{
cout<<"You are in the left wing of a dungeon.";
}
if (roomnum == 4)
{
cout<<"You are in the upper wing of a dungeon.";
}
if (roomnum == 5)
{
cout<<"You are in the lower wing of a dungeon.";
}
else
{
cout<<"Where are you?!";
}
}


It doesn't work. In fact, when it does compile (through G++, there are a few linker errors when building in Dev-C++), it outputs "Where are you?!!You are in the middle of a dungeon.Where are you?!!" Any sort of input at all will exit the program.

I'm not asking for someone to fix the code. I'm asking, based on that code there, what I'm not understanding about C++ that is hindering my progress with it. I already know I need a good explanation of pointers. I've read several tutorials regarding pointers (on cprogramming.com, cplusplus.com and a college's website), and for some reason I just can't grasp when I should use them (this includes -> pointers). I also haven't grasped the use of headers. I understand that a header is used to define functions that are used between code files, but WHEN I should use them and HOW WELL I should define said functions, I'm not sure of.

Anything else, I'm just not sure what I'm missing about it.

Thanks in advance!

oracleguy
12-11-2011, 06:45 PM
Well for starters you are defining the parameter types for your functions but you never give those parameters names. You need to give them names if you expect to access them.

Secondly, you can't compare a char* with a string literal. Well you can but it isn't doing what you think, all it is doing is comparing the pointer addresses. It is a common beginner mistake. You need to use the strcmp or stricmp functions to compare two c-strings (char* strings).

Thirdly the reason it exits after one input is that you are only calling your updateGame function once and it never loops. You need to do something like:


int main()
{
while (isPlaying)
{
updateGame();
}

return 0;
}

oracleguy
12-11-2011, 06:49 PM
Your roomfind function needs to be one if ... else if ... else construct not a bunch of seperate if statements. The reason for this is that even if one of those previous if statements is true it will still execute the last one and if it is false trigger your else condition that prints "where are you".

johnki
12-11-2011, 10:10 PM
Ah, so it's just a bunch of beginner mistakes compounded into one?

Yeah, most of my programming experience right now comes from GML and PHP, so what it sounds like is I'm taking that and putting it into a different context and falling flat on my face.

But again, for understanding, I do want to ask:

1. When do you use pointers? I've read answers like "only when you have to", but what situations warrant their usage?

2. What is the difference between front pointer (*var) and back pointer (var*)? (I'd find a code example from something but I don't feel like sifting through the dozens of open source codebases I have on the comp atm)

3. I was able to read and understand that the "::" operator is pretty much just "class::function" for referencing functions defined inside a class that's inside a header. Does the "->" operator do the same thing except for structs? Or does it work a bit differently?

Thanks again. I've had issues finding people who are receptive to such simple questions.

johnki
12-12-2011, 02:02 AM
Adding on, I changed the code to the below:



#include <iostream>
#include <string.h>

using namespace std;

bool isPlaying = true;
int playerx = 0;
int playery = 0;
char input[50];
int roomnum = 1;

void parsemov();
int roomfind(int, int);
void roomdesc(int);
void updateGame();

int main()
{
while (isPlaying == true){
updateGame();
}

return 0;
}

void updateGame()
{
roomfind(playerx, playery);
roomdesc(roomnum);
cin>> input;
parsemov();
}

void parsemov()
{
if (strcmp(input, "exit") == 0){
if (strcmp(input,"north") == 0 || strcmp(input,"n") == 0){
if (playery < 1){
playery += 1;
}
}
else if (strcmp(input,"south") == 0 || strcmp(input,"s") == 0){
if (playery > -1){
playery -= 1;
}
}
else if (strcmp(input,"east") == 0 || strcmp(input,"e") == 0){
if (playerx < 1){
playerx += 1;
}
}
else if (strcmp(input,"west") == 0 || strcmp(input,"w") == 0){
if (playerx > -1){
playerx -= 1;
}
}
else
{
cout<<"You cannot go that way. \n";
}
}
else
{
isPlaying = false;
}
}

int roomfind(int, int)
{
if (playerx == 0 && playery == 0)
{
roomnum = 1;
}
else if (playerx == 1 && playery == 0)
{
roomnum = 2;
}
else if (playerx == -1 && playery == 0)
{
roomnum = 3;
}
else if (playerx == 0 && playery == 1)
{
roomnum = 4;
}
else if (playerx == 0 && playery == -1)
{
roomnum = 5;
}
else
{
cout<<"Where are you?! \n";
}
}

void roomdesc(int)
{
if (roomnum == 1)
{
cout<<"You are in the middle of a dungeon. \n";
}
else if (roomnum == 2)
{
cout<<"You are in the right wing of a dungeon. \n";
}
else if (roomnum == 3)
{
cout<<"You are in the left wing of a dungeon. \n";
}
else if (roomnum == 4)
{
cout<<"You are in the upper wing of a dungeon. \n";
}
else if (roomnum == 5)
{
cout<<"You are in the lower wing of a dungeon. \n";
}
else
{
cout<<"Where are you?! \n";
}
}

Still has linker errors in Dev-C++, compiles in G++ but states "You are in the middle of a dungeon.", takes a single input and exits before output.

tracknut
12-12-2011, 03:08 AM
I enjoyed reading your note, because I learned C some 30 years ago by writing a similar adventure-type game where you could walk around rooms, pick up and drop stuff, etc. The whole purpose was to get the hang of pointers. So it's fun to see someone working on the same situation, years later.

Oracleguy mentioned something about parameters to functions, which you don't seem to have implemented. If you're going to call:


roomfind(playerx, playery);

and pass the x-y coordinates of where the player is, then the function roomfind ought to be declared as:


int roomfind(int x, int y)

That's how your pass the parameters (the names "x" and "y" could be anything). As it stands, you've declared global variables for playerx and playery, which are being used and could work, but doing such things with globals (as opposed to parameters) is usually discouraged. So I'd declare them as local within the updateGame fuction, which you'd do as:



void updateGame()
{
int playerx,playery;

do {
roomfind(&playerx, &playery);
roomdesc(roomnum);
cin>> input;
}
while (parsemov());
}


You also want to move your other globals to be local variables, once you get the knack of it. Then let's get rolling on the pointers. You see I've passed roomfind its coordinated by reference, right? So the function declaration should look like:


int roomfind(int *x, int *y)

i.e. "x and y are pointers to integers". Then your manipulations of them would look something like:


*x -= 1; /* Subtract one from the integer x is pointing at */


You will also want parsemov to return an integer 1/0 or true/false, as it's being used (in my code here) to decide whether the user has typed "exit" or not. And also, double-check your logic here:


if (strcmp(input, "exit") == 0){
if (strcmp(input,"north") == 0 || strcmp(input,"n") == 0){

That first test is backwards, you don't want "if the user types 'exit' then go on and check if he typed 'north'". You want 'if the user did NOT type 'exit'... right?

There are a lot of ways to write this code, I'm just suggesting a way to start using pointers, which was your goal.

Dave

johnki
12-12-2011, 03:46 AM
There are a lot of ways to write this code, I'm just suggesting a way to start using pointers, which was your goal.

Dave

Yeah, getting the hang of pointers, as well as moving myself into the C++ mindset with something relatively simple that I could enjoy writing was the goal. :)

Again, I really do appreciate the help, and definitely appreciate not getting the typical "go read a book" answer.

Okay, now for the content of the post...

First off, if playerx and playery are initialized that way, aren't they set to NULL, meaning for those local variables, I should actually declare them like...



int playerx = 0;
int playery = 0;


...so that the center room (room 0) will show on startup instead of getting a null point error, or whatever you'd call it?

Second, if I'm making the roomfind function structured like that, can I leave all the if (playerx == anumber) (except changed to match the &playerx dereferencing form) as they are or should I change them to match the function declaration's format (if (x == anumber))?

Third, I'm starting to get a better grasp of pointers the more I get help with it, but again, I still don't understand why sometimes it's "*char" and sometimes it's "char*" (not necessarily with char but the same concept applies).

Fourth, I'm still not sure when I'd want to use pointers versus when I wouldn't want to use pointers.

Fifth, "->" is a pointer for structs, right? If I were to create a struct...



struct myStruct {
int int1;
char char1;
int int2;
}

//and an object...
myStruct myObject;


...would "->" be used to point to (dereference, in this case) a member of myStruct? For example, myObject->int1;? In essence, would this be the same as the & dereferencing...except for structs? Or am I getting this entirely wrong?

tracknut
12-12-2011, 04:23 AM
First off, if playerx and playery are initialized that way, aren't they set to NULL, meaning for those local variables, I should actually declare them like...



int playerx = 0;
int playery = 0;


...so that the center room (room 0) will show on startup instead of getting a null point error, or whatever you'd call it?

Yep, good point. But not because you'll get a segment fault for an invalid address, but simply because you'd like to make sure you start the person in "room 0".


Second, if I'm making the roomfind function structured like that, can I leave all the if (playerx == anumber) (except changed to match the &playerx dereferencing form) as they are or should I change them to match the function declaration's format (if (x == anumber))?

You'd need to change them all to x rather than playerx. You can certainly use playerx, I was just trying to get you away from the idea that playerx and playery were globals and you had to use those names. The instance of playerx where you declare it is a completely different instance to the one as the parameter to the function, it would be complete coincidence to use the same names.


Third, I'm starting to get a better grasp of pointers the more I get help with it, but again, I still don't understand why sometimes it's "*char" and sometimes it's "char*" (not necessarily with char but the same concept applies).

You declare a pointer as "char * p;" meaning "this is a pointer to a char". When you dereference that pointer to use it, you might have "c = *p;" meaning "put the first character that p is pointing at into c".


Fourth, I'm still not sure when I'd want to use pointers versus when I wouldn't want to use pointers.
Certainly not "when all else fails" or whatever your first comment was at the beginning of the thread. There are tons of reasons to use them, and once you get familiar with them, ideas will pop up naturally. Let me describe one or two. Say you have some enormous memory structure (array, struct, whatever) that you need to pass to a function. It's far better to pass a pointer to that structure (ie, a 4 or 8 byte address) than to copy the entire data object onto the stack to send it to the function. Huge performance advantage. Another idea... You might have a list of common structures (ie, like a database of employee records) that you need to sort. It's going to be far better (performance and memory-wise) to sort a list of pointers to those records than it is to actually sort the records themselves.



Fifth, "->" is a pointer for structs, right? If I were to create a struct...



struct myStruct {
int int1;
char char1;
int int2;
}

//and an object...
myStruct myObject;


...would "->" be used to point to (dereference, in this case) a member of myStruct? For example, myObject->int1;? In essence, would this be the same as the & dereferencing...except for structs? Or am I getting this entirely wrong?

You got that one right. Dereferencing "c = *p;" is for a simple data type of character pointer. "c = p->int1;" is for the structure as you've described. (whoops, my answer is slightly off. I just read the one below from oracleguy, use his answer instead of mine for this struct pointer -> thing)

Dave

oracleguy
12-12-2011, 04:25 AM
The -> (arrow) operator is just like the dot operator but it is used only with pointers (mostly). It combines a dereference call with accessing a member of the object. It can be used with structs and classes.

So lets say we have this structure:


struct Vector3
{
int x;
int y;
int z;
}

If you had a pointer to that struct:


Vector3* point = new Vector3;


Both of these lines of code do the same thing:


point->x = 0;
(*point).x = 0;


But as you can see in this case the arrow operator results in a bit cleaner code code and is easier to write.

johnki
12-12-2011, 04:37 AM
The -> (arrow) operator is just like the dot operator but it is used only with pointers (mostly). It combines a dereference call with accessing a member of the object. It can be used with structs and classes.


Okay, I think I've got it, but just to be clear, when used with classes, I would want to do it like this...



class myClass {
int x, y, z;
public:
void voidFunc(int z);
int intFunc(int x, int y);
private:
void privateFunc();
}

//and an instance of that class...
myClass Class1;

//I'd dereference it like this...
Class1->voidFunc(int);

...the same way I did the structs, only with classes, right? And private functions can't be referenced because they're only available within the scope of the class? So, in that case, private functions should be fully defined within the scope of the class, more like...



class myClass {
int x, y, z;
public:
void voidFunc(int z);
int intFunc(int x, int y);
private:
void privateFunc(){
//do something
}
}

...right?

Man, this is going far beyond the scope of the original post, but I realized I should probably make sure I'm understanding all of this correctly. :)

EDIT: Updated my code with the suggestions. Now, I'm getting a "playerx (or y) was not declared in this scope" error for updateGame() and parsemov().

EDIT2: Removed the pointer references (meaning int roomfind(int x, int y) and int roomfind(playerx, playery)) and now it...sort of works. It takes input, but something broke and it will always output "You are in the middle of a dungeon."

oracleguy
12-12-2011, 05:41 AM
Okay, I think I've got it, but just to be clear, when used with classes, I would want to do it like this...



class myClass {
int x, y, z;
public:
void voidFunc(int z);
int intFunc(int x, int y);
private:
void privateFunc();
}

//and an instance of that class...
myClass Class1;

//I'd dereference it like this...
Class1->voidFunc(int);

...the same way I did the structs, only with classes, right?

No in that case you would just write Class1.voidFunc(0); because the way you declared the Class1 variable it isn't a pointer.



And private functions can't be referenced because they're only available within the scope of the class? So, in that case, private functions should be fully defined within the scope of the class, more like...



class myClass {
int x, y, z;
public:
void voidFunc(int z);
int intFunc(int x, int y);
private:
void privateFunc(){
//do something
}
}

...right?


Sort of. Yes private and protected members cannot be called from outside of the class. However you don't have to define the functions in the same place you define the class. This is where header files start to come into play.

You can define the class in a header file and then the function implementation in the class in a separate cpp file. The advantage over putting it in the header file is that then the code doesn't need to be recompiled in each place the header file is used. (Among many other reasons).

So if you had that class:


class myClass {
int x, y, z;
public:
void voidFunc(int z);
int intFunc(int x, int y);
private:
void privateFunc();
}

You can define the implementation of the functions like so:



void myClass::privateFunc()
{

}

johnki
12-12-2011, 06:02 AM
No in that case you would just write Class1.voidFunc(0); because the way you declared the Class1 variable it isn't a pointer.

Ah, so in that case, it would have had to be "myClass * Class1;" to warrant using a "->" dereferencing?

And understood with the class structure. And I'm starting to get headers now. Define the minimum that will be used in multiple places, then expand as needed. If that means fully defining a function, then fully define it. If that means simply declaring a function, then declare it. To be clear though, headers use #IFDEF and #ENDIF statements, as opposed to simply writing out the code, correct?

oracleguy
12-12-2011, 06:36 AM
Ah, so in that case, it would have had to be "myClass * Class1;" to warrant using a "->" dereferencing?

Correct.



And understood with the class structure. And I'm starting to get headers now. Define the minimum that will be used in multiple places, then expand as needed. If that means fully defining a function, then fully define it. If that means simply declaring a function, then declare it. To be clear though, headers use #IFDEF and #ENDIF statements, as opposed to simply writing out the code, correct?

Yes those are called pre-processor directives. The pre-processor is the first stage of code compilation; those are used so that the code in a header file is only included once.

Without them you can get errors about defining something multiple times.

johnki
12-12-2011, 04:26 PM
Correct.


So in that case, what does Class1 point to? Does it just point to myClass, essentially meaning it's uninitialized? Or would it be more like...



myClass Class1;

myClass * ClassPtr = Class1;


...to be initialized correctly?

Or would it just be like the below?


myClass * ClassPtr = new myClass;

johnki
12-13-2011, 12:19 AM
Changed the main loop to...



void updateGame()
{
do{
parsemov();
roomfind(playerx, playery);
roomdesc(roomnum);
cin>> input;
}
while (isPlaying == true);
}


...and changed the one function to...


if (strcmp(input, "exit") == 0)

...but it's crashing on first input again.

I did notice that maybe I should change the roomdesc function to...



void roomdesc(int x)
{
if (x == 1)
{
cout<<"You are in the middle of a dungeon. \n";
}
//else if...else...
}


...to go in line with the changes to roomfind.

I also think I need to restructure parsemov, but I haven't totally figured out a way to streamline it just yet.

Also, are there any ways that are "beginner friendly" that would make functions like roomdesc a lot...smaller? It seems kinda clunky to do the "if x = 1, print statement 1. if x = 2, blah blah..." method.

EDIT: Changed them to...


void roomdesc(int * x)
...and...

roomdesc(&roomnum);
...to try and fit pointers in...but G++ gives me errors about converting an int to an int pointer.

oracleguy
12-13-2011, 02:37 AM
So in that case, what does Class1 point to? Does it just point to myClass, essentially meaning it's uninitialized? Or would it be more like...



myClass Class1;

myClass * ClassPtr = Class1;


...to be initialized correctly?

Or would it just be like the below?


myClass * ClassPtr = new myClass;

Yes it would be like your last code sample. Just don't forget to delete it before your program exits or whenever you are done with it.

You could do this but you'd need one slight change:


myClass Class1;

myClass * ClassPtr = &Class1;


And to answer part of your second post, for your room description function look at using a switch statement. Can you post another copy of your entire program in its current state? Then I (or someone else) can answer your other questions if you haven't already figured them.

johnki
12-14-2011, 12:50 AM
Okay, after working with it a bit more, I'm getting there. Here's the code...




#include <iostream>
#include <string.h>

using namespace std;

bool isPlaying = true;
int playerx = 0;
int playery = 0;
char input[50];
int roomnum = 1;

bool parsemov();
int roomfind(int, int);
void roomdesc(int);
void updateGame();

int main()
{
while (isPlaying == true){
updateGame();
}

return 0;
}

void updateGame()
{
do{
parsemov();
roomfind(playerx, playery);
roomdesc(roomnum);
cin>> input;
}
while (isPlaying == true);
}

bool parsemov()
{
if (strcmp(input, "exit") == 0){
isPlaying = false;
}
/*else if (strcmp(input, "play") == 0){
cout<<isPlaying;
}*/
else if (strcmp(input,"north") == 0 || strcmp(input,"n") == 0){
if (playery < 1){
playery += 1;
}
}
else if (strcmp(input,"south") == 0 || strcmp(input,"s") == 0){
if (playery > -1){
playery -= 1;
}
}
else if (strcmp(input,"east") == 0 || strcmp(input,"e") == 0){
if (playerx < 1){
playerx += 1;
}
}
else if (strcmp(input,"west") == 0 || strcmp(input,"w") == 0){
if (playerx > -1){
playerx -= 1;
}
}
else
{
cout<<"You cannot go that way. \n";
}
}

int roomfind(int x, int y)
{

if (x == 0 && y == 0)
{
roomnum = 1;
}
else if (x == 1 && y == 0)
{
roomnum = 2;
}
else if (x == -1 && y == 0)
{
roomnum = 3;
}
else if (x == 0 && y == 1)
{
roomnum = 4;
}
else if (x == 0 && y == -1)
{
roomnum = 5;
}
else
{
cout<<"Where are you?! \n";
}
}

void roomdesc(int x)
{
if (x == 1)
{
cout<<"You are in the middle of a dungeon. \n";
}
else if (x == 2)
{
cout<<"You are in the right wing of a dungeon. \n";
}
else if (x == 3)
{
cout<<"You are in the left wing of a dungeon. \n";
}
else if (x == 4)
{
cout<<"You are in the upper wing of a dungeon. \n";
}
else if (x == 5)
{
cout<<"You are in the lower wing of a dungeon. \n";
}
else
{
cout<<"Where are you?! \n";
}
}


...and here's the list of issues:

1. On startup, it says "You cannot go that way. <line break> You are in the middle of a dungeon."

2. It accepts input and moves you correctly, but when you go to go off the map, it will say "Where are you?! <line break> <description of room you're in>" as opposed to saying "You cannot go that way." and maybe repeating the room description (I'll work on a way to not repeat the room description once I've got this working better).

EDIT: I lied...here's how it's working right now...

Here's the map:


*0*
000
*0*


Let's say that the 0's are rooms that exist, and the *s are rooms that don't. If you continue to attempt to go off screen in a way that DOES NOT cross an * room, it will NOT print "Where are you?!" but, rather, it will continue to print the room's description. I don't know if you will continue to go across the x or y planes, but when you go the opposite direction, it will print the center room's description, leading me to believe it just bumps you back forever.

HOWEVER, if you DO cross an * room, you'll sort of exist on two planes, where it prints the "Where are you?!" statement, and the description of the room you were last in. I'm assuming this is because TECHNICALLY, the rooms are not in a space greater than (+-1, +-1) and I don't have conditionals to stop it from happening based on the room (I'll have to work on something, it seems). Anyways, the reason I say "you'll sort of exist on two planes" is because once you DO try to move, if you move in a direction perpendicular to the direction you previously moved (say if you moved east to get to the * room, now you're moving north or south), it will print the description of the room to (insert direction you chose here) of the * room, as opposed to printing the center room. It's a weird side-effect of a rule that's clearly really poorly defined.

3. I HAD to take out the pointers. They were causing issues. I'll have to find another way to learn pointers.

4. The exit function does not work. Furthermore, as you can see, I attempted to put in a conditional statement to allow me to see if it was even setting isPlaying to false, and when I activate THAT statement, it closes, but doesn't print isPlaying.

I feel like there's something else I'm forgetting, but there's the list for now.

EDIT: I didn't notice it before, but parsemov() should probably be changed to a void function...

oracleguy
12-15-2011, 05:12 AM
You should move the input and playerx and playery variables into your updateGame function to make them local variables to that function. It will just make the program cleaner.

As for your first issue, that is because when the program starts up the input array is just random garbage data since you call parsemov before taking any input on the first loop. You could reorder the functions in the loop like this:


roomfind(playerx, playery);
roomdesc(roomnum);
cin>> input;
parsemov();


And that would solve the issue. There are other ways you could solve the program.

While I'm talking about better programming practices, yes your parsemov function should have a void return type. Your roomfind function never returns a value either; that function should return the room number and not change a global variable. As tracknut mentioned earlier globals are bad, you should avoid using them as much as possible. Your compiler must be set to some really lax settings, typically having a function that returns no value when it says it will causes a compiler error.

If you change the roomfind function to return the room number you can then store it in a local variable in your updateGame function and pass it into the roomDesc function.

So if you go to the edge of map, like start the game and go north twice the reason it keeps printing the room description and doesn't print the "You cannot go that way" because the bigger if statement evaluates true and the inner one is false so it is never going to execute that else. What you need to do is combine the if checks into one, for example:


else if ((strcmp(input,"north") == 0 || strcmp(input,"n") == 0) && playery < 1){
playery += 1;
}


The exit functionality worked for me, I typed 'exit' and the program ended.

johnki
12-15-2011, 04:15 PM
As far as the compiler goes, I've been using G++, eg. simply "g++ main.cpp" and it's been compiling. Maybe it would benefit me to use Dev-C++ again in that regard, because it was catching errors, though I must admit, I don't have a clue how to solve linker errors.

With the roomfind function, thanks for the advice. I think I understand where I am messing up with variable changes and why I've been messing up in that manner.

To change roomfind to return the room number, I'd want to change it to...



//in the update loop...
roomdesc(roomfind(playerx, playery));

roomfind(int x, int y)
{

if (x = #, y = #)
{
return <a number>;
}
//other conditionals...
}


...thus returning the roomnum variable, and nesting it in the function that relies on it. Or would it be cleaner to do something like...



//in the update loop...
roomnum = roomfind(playerx, playery);
roomdesc(roomnum);


...where it's still passing the variable, but the variable relies on a function that updates every cycle? Or would it update every cycle (given it was local) without a function explicitly changing it?

EDIT: Oh, and that's odd with the exit function. For some reason, it doesn't do anything for me.

EDIT2:

Here's my revised code...



#include <iostream>
#include <string.h>

using namespace std;

bool isPlaying = true;
int playerx = 0;
int playery = 0;
char input[50];

void parsemov();
int roomfind(int, int);
void roomdesc(int);
void updateGame();

int main()
{
while (isPlaying == true){
updateGame();
}

return 0;
}

void updateGame()
{
do{
roomdesc(roomfind(playerx, playery));
cin>> input;
parsemov();
}
while (isPlaying == true);
}

void parsemov()
{
if (strcmp(input, "exit") == 0){
isPlaying = false;
}
/*else if (strcmp(input, "play") == 0){
cout<<isPlaying;
}*/
else if ((strcmp(input,"north") == 0 || strcmp(input,"n") == 0) && playery < 1){
playery += 1;
}
else if ((strcmp(input,"south") == 0 || strcmp(input,"s") == 0) && playery > -1){
playery -= 1;
}
else if ((strcmp(input,"east") == 0 || strcmp(input,"e") == 0) && playery < 1){
playerx += 1;
}
else if ((strcmp(input,"west") == 0 || strcmp(input,"w") == 0) && playery > -1){
playerx -= 1;
}
else
{
cout<<"You cannot go that way. \n";
}
}

int roomfind(int x, int y)
{

if (x == 0 && y == 0)
{
return 1;
}
else if (x == 1 && y == 0)
{
return 2;
}
else if (x == -1 && y == 0)
{
return 3;
}
else if (x == 0 && y == 1)
{
return 4;
}
else if (x == 0 && y == -1)
{
return 5;
}
else
{
cout<<"Where are you?! \n";
}
}

void roomdesc(int x)
{
if (x == 1)
{
cout<<"You are in the middle of a dungeon. \n";
}
else if (x == 2)
{
cout<<"You are in the right wing of a dungeon. \n";
}
else if (x == 3)
{
cout<<"You are in the left wing of a dungeon. \n";
}
else if (x == 4)
{
cout<<"You are in the upper wing of a dungeon. \n";
}
else if (x == 5)
{
cout<<"You are in the lower wing of a dungeon. \n";
}
else
{
cout<<"Where are you?! \n";
}
}


...and slowly, bugs are being squashed. :) Alright, as far as I can tell, almost everything works as intended. The exit function is finally working (I could not tell you what was going on with that). Going north and then east results in "You cannot go that way. You are in the upper wing of a dungeon." which is intended, due to the way the game is built (a good exercise would be building a way to keep it from saying "You are in the upper wing of a dungeon." again unless asked to). However, going north and then west results in "Where are you?! Where are you?!" which leads me to believe it's still not working 100%, and you are, in fact, still able to get into the * rooms by going in an L-shaped pattern (tested with west and then south, the same holds true). Fortunately, this is the only issue I still see in the code.

EDIT3: The reason the variables are still global is that parsemov() still uses them. Due to its nature, requiring access to both the player's location AND input, I'm not sure what to do with it to make it more able to rely on local variables within the updateGame() function.

johnki
12-17-2011, 12:15 AM
I tried implementing it in Java, knowing it has a similar syntax to C++ and that it does not contain pointers, and did this mostly out of curiosity.

I was able to successfully move it to Java, and some of it was even as simple as copy-pasting. I'm pretty sure there are a lot of bad programming habits that I've put into this, as well.

However, it allows the player to move further into "where are you?!" territory than the C++ version did, leading me to believe I get along even less with Java than I do with C++.

So I suppose I'll wait until I get some more advice for the C++ version.

C++:


#include <iostream>
#include <string.h>

using namespace std;

bool isPlaying = true;
int playerx = 0;
int playery = 0;
char input[50];

void parsemov();
int roomfind(int, int);
void roomdesc(int);
void updateGame();

int main()
{
while (isPlaying == true){
updateGame();
}

return 0;
}

void updateGame()
{
do{
roomdesc(roomfind(playerx, playery));
cin>> input;
parsemov();
}
while (isPlaying == true);
}

void parsemov()
{
if (strcmp(input, "exit") == 0){
isPlaying = false;
}
/*else if (strcmp(input, "play") == 0){
cout<<isPlaying;
}*/
else if ((strcmp(input,"north") == 0 || strcmp(input,"n") == 0) && playery < 1){
playery += 1;
}
else if ((strcmp(input,"south") == 0 || strcmp(input,"s") == 0) && playery > -1){
playery -= 1;
}
else if ((strcmp(input,"east") == 0 || strcmp(input,"e") == 0) && playery < 1){
playerx += 1;
}
else if ((strcmp(input,"west") == 0 || strcmp(input,"w") == 0) && playery > -1){
playerx -= 1;
}
else
{
cout<<"You cannot go that way. \n";
}
}

int roomfind(int x, int y)
{

if (x == 0 && y == 0)
{
return 1;
}
else if (x == 1 && y == 0)
{
return 2;
}
else if (x == -1 && y == 0)
{
return 3;
}
else if (x == 0 && y == 1)
{
return 4;
}
else if (x == 0 && y == -1)
{
return 5;
}
else
{
cout<<"Where are you?! \n";
}
}

void roomdesc(int x)
{
if (x == 1)
{
cout<<"You are in the middle of a dungeon. \n";
}
else if (x == 2)
{
cout<<"You are in the right wing of a dungeon. \n";
}
else if (x == 3)
{
cout<<"You are in the left wing of a dungeon. \n";
}
else if (x == 4)
{
cout<<"You are in the upper wing of a dungeon. \n";
}
else if (x == 5)
{
cout<<"You are in the lower wing of a dungeon. \n";
}
else
{
cout<<"Where are you?! \n";
}
}


Java:


package test;

import java.io.*;
/**
*
* @author name
*/
public class Test {

static boolean isPlaying = true;
static int playerx = 0;
static int playery = 0;

public static void main(String args[]) {
while (isPlaying == true){
updateGame();
}
}

public static void updateGame(){
InputStreamReader istream = new InputStreamReader(System.in);
BufferedReader bufRead = new BufferedReader(istream);

while (isPlaying == true){

roomDesc(roomFind(playerx, playery));
try{
String input = bufRead.readLine();
parseMov(input);
}
catch (IOException err){
System.out.println("Error reading input.");
}
}
}

public static int roomFind(int x, int y){
if (x == 0 && y == 0)
{
return 1;
}
else if (x == 1 && y == 0)
{
return 2;
}
else if (x == -1 && y == 0)
{
return 3;
}
else if (x == 0 && y == 1)
{
return 4;
}
else if (x == 0 && y == -1)
{
return 5;
}
else
{
return 0;
}
}

public static void roomDesc(int x)
{
if (x == 1)
{
System.out.println("You are in the middle of a dungeon. \n");
}
else if (x == 2)
{
System.out.println("You are in the right wing of a dungeon. \n");
}
else if (x == 3)
{
System.out.println("You are in the left wing of a dungeon. \n");
}
else if (x == 4)
{
System.out.println("You are in the upper wing of a dungeon. \n");
}
else if (x == 5)
{
System.out.println("You are in the lower wing of a dungeon. \n");
}
else
{
System.out.println("Where are you?! \n");
}
}

public static void parseMov(String x)
{
if (new String(x).equals("exit") == true){
isPlaying = false;
}
else if ((new String(x).equals("n") == true || new String(x).equals("north") == true) && playery < 1){
playery += 1;
}
else if ((new String(x).equals("s") == true || new String(x).equals("south") == true) && playery > -1){
playery -= 1;
}
else if ((new String(x).equals("e") == true || new String(x).equals("east") == true) && playery < 1){
playerx += 1;
}
else if ((new String(x).equals("w") == true || new String(x).equals("west") == true) && playery > -1){
playerx -= 1;
}
else
{
System.err.println("You cannot go that way. \n");
}
}

}

oracleguy
12-17-2011, 11:06 PM
...thus returning the roomnum variable, and nesting it in the function that relies on it. Or would it be cleaner to do something like...



//in the update loop...
roomnum = roomfind(playerx, playery);
roomdesc(roomnum);


...where it's still passing the variable, but the variable relies on a function that updates every cycle? Or would it update every cycle (given it was local) without a function explicitly changing it?

Using a variable in the code block above is the way I would do it. However I'm not sure what you are asking in this question.



...and slowly, bugs are being squashed. :) Alright, as far as I can tell, almost everything works as intended. The exit function is finally working (I could not tell you what was going on with that). Going north and then east results in "You cannot go that way. You are in the upper wing of a dungeon." which is intended, due to the way the game is built (a good exercise would be building a way to keep it from saying "You are in the upper wing of a dungeon." again unless asked to). However, going north and then west results in "Where are you?! Where are you?!" which leads me to believe it's still not working 100%, and you are, in fact, still able to get into the * rooms by going in an L-shaped pattern (tested with west and then south, the same holds true). Fortunately, this is the only issue I still see in the code.


The reason for that is that you code currently checks to see if you can go north (or west) based only on the current position on the same axis. You'd need to add additional conditions to the if checks so you can go north as long as player y is 0.

By the way in your parsemov function you have a typo in the last two if statements, you are checking the value of playery when I think you mean to check the value of playerx.

johnki
12-18-2011, 01:20 AM
Using a variable in the code block above is the way I would do it. However I'm not sure what you are asking in this question.
For that, I just went ahead and tested it, and the current implementation is what I came up with. Pretty much the only thing that would have been different is, instead of a function call nested within a function call, I was asking if it was more efficient to assign the function call to a variable, and THEN call the variable within the other function.



The reason for that is that you code currently checks to see if you can go north (or west) based only on the current position on the same axis. You'd need to add additional conditions to the if checks so you can go north as long as player y is 0.Yeah, I figured as much. I might even go so far as to make an array of coordinates that can't be accessed by the player, and then have it check every move to see if the coordinates are within the array, granted I have the ability to implement it.



By the way in your parsemov function you have a typo in the last two if statements, you are checking the value of playery when I think you mean to check the value of playerx.
Yeah, there is a typo. Thanks for catching that. :)



EZ Archive Ads Plugin for vBulletin Copyright 2006 Computer Help Forum