What is wrong here?

M

Matthew

I am working on a simple text adventure game. I have implemented one
word commands and a bit for two words. I have a problem though the
movement commands n and s (north and south respectivly) don't work. I
can't figure out why!

#include <string>
#include <iostream>
#include <vector>
using namespace std;

struct command_v
{
string name;
bool (*vfunc)();
bool (*dfunc)();
};

struct command_vd
{
string name;
bool (*vfunc)(vector<string> input);
bool (*dfunc)(vector<string> input);
};

enum dirName{ n, s, e, w, north, south, east, west };

class Exit;


class Item
{
public:
string name;
vector<command_vd> theVDCmds;
};

class Character
{
public:
vector<Item> inven;
string name;
string desc;
vector<command_vd> theVDCmds;
};

class Location
{
public:
string name;
string desc;
vector<Exit> exits;
vector<Item> items;
vector<Character> chars;
vector<command_vd> theVDCmds;
};

class Exit
{
public:
Location leadsTo;
int shortName;
int longName;
string name;
vector<command_vd> theVDCmds;
};

void interpreter();
vector<string> split(string input);
bool parse(string input);
void setup();
bool vquit();
bool dquit();
bool vlook();
bool dlook();
bool vn();
bool dn();
bool vs();
bool ds();

vector<command_v> theVCmds;
Character mainChar;
Location currentRoom;
Location room1;
Location room2;
Exit ex1;
Exit ex2;

int main (int argc, const char * argv[])
{
setup();
interpreter();
return 0;
}

void interpreter()
{
cout << "Parser v0\n";
bool quit = false;
bool un;
string input;
dlook();
while(!quit)
{
cout << ":> ";
getline(cin, input);
un = parse(input);
if(!un)
{
cout << "Huh?\n";
continue;
}
}
}

void setup()
{
// set up standalone commands
command_v quit;
quit.name = "quit";
quit.vfunc = vquit;
quit.dfunc = dquit;
theVCmds.push_back(quit);

command_v look;
look.name = "look";
look.vfunc = vlook;
look.dfunc = dlook;
theVCmds.push_back(look);

command_v north1;
north1.name = "n";
north1.vfunc = vn;
north1.dfunc = dn;
theVCmds.push_back(north1);

command_v south1;
south1.name = "s";
south1.vfunc = vs;
south1.dfunc = ds;
theVCmds.push_back(south1);

mainChar.name = "Matthew";
mainChar.desc = "A valiant warrior!";

ex1.leadsTo = room1;
ex1.shortName = s;
ex1.longName = south;
ex1.name = "To the kitchen";

ex2.leadsTo = room2;
ex2.shortName = n;
ex2.longName = north;
ex2.name = "To the family room";

room1.name = "Family Room";
room1.desc = "A cozy room with a fireplace.";
room1.exits.push_back(ex1);

room2.name = "Kitchen";
room2.desc = "A warm kitchen.";
room2.exits.push_back(ex2);

currentRoom = room2;
}

vector<string> split(string input)
{
input += ' ';
vector<string> theStrings;
for(int i = 0, j = input.size(); i < j; ++i)
{
if(input == ' ' || input == '\n')
{
string temp(input.substr(0, i));
input.erase(0, i+1);
theStrings.push_back(temp);
i = 0;
j = input.size();
}
}
return theStrings;
}

bool parse(string input)
{
vector<string> theInput = split(input);

if(theInput[0] == "say" && theInput.size() > 1)
{
for(int i = 1; i < theInput.size(); ++i)
cout << theInput << " ";
cout << endl;
return true;
}

if(theInput.size() == 2)
{
for(int i = 0; i < currentRoom.items.size(); ++i)
{
for(int j = 0; j < currentRoom.items.theVDCmds.size();
++j)
{
if(theInput[0] ==
currentRoom.items.theVDCmds[j].name)
{
if(currentRoom.items.theVDCmds[j].vfunc(theInput))
return
currentRoom.items.theVDCmds[j].dfunc(theInput);
}
}
}
}
else if (theInput.size() == 1)
{
for(int i = 0; i < theVCmds.size(); ++i)
{
if(theInput[0] == theVCmds.name)
{
if(theVCmds.vfunc())
return theVCmds.dfunc();
}
}
}
return false;
}

bool vquit()
{
return true;
}

bool dquit()
{
string c;
cout << "Are you sure you want to quit? (yn): ";
cin >> c;

if(c == "y" || c == "yes")
{
cout << "Bye!\n";
exit(0);
return true;
}
if(c == "n" || c == "no")
{
getchar();
return true;
}
}

bool vlook()
{
return true;
}

bool dlook()
{
cout << currentRoom.name << "\n";
cout << "\n" << currentRoom.desc << "\n";
cout << "Exits: \n";
for(int i = 0; i < currentRoom.exits.size(); i++)
{
cout << "\t";
cout << currentRoom.exits.name << " (" <<
currentRoom.exits.shortName << ") " << endl;
}
cout << "Items: \n";
for(int i = 0; i < currentRoom.items.size(); i++)
{
cout << "\t";
cout << currentRoom.items.name << endl;
}
cout << "\nCharacters: \n";
for(int i = 0; i < currentRoom.chars.size(); i++)
{
cout << "\t";
cout << currentRoom.chars.name << endl;
}
cout << endl;
return true;
}

bool vn()
{
return true;
}

bool dn()
{
for(int i = 0; i < currentRoom.exits.size(); ++i)
{
if(currentRoom.exits.shortName == n)
{
currentRoom = currentRoom.exits.leadsTo;
break;
}
else
{
cout << "You can't go there!\n";
return true;
}
}
dlook();
return true;
}

bool vs()
{
return true;
}

bool ds()
{
for(int i = 0; i < currentRoom.exits.size(); ++i)
{
if(currentRoom.exits.shortName == s)
{
currentRoom = currentRoom.exits.leadsTo;
break;
}
else
{
cout << "You can't go there!\n";
return true;
}
}
dlook();
return true;
}
 
R

Rolf Magnus

Matthew said:
I am working on a simple text adventure game. I have implemented one
word commands and a bit for two words. I have a problem though the
movement commands n and s (north and south respectivly) don't work.

What exactly does "don't work" mean?
Don't they compile? What did the compiler say?
Are they doing something unexpected? What?
Are they crashing? Where?
I can't figure out why!

Reduce your code to the minimum possible, but complete program that
shows the error. It often happens that, while reducing the code, you
find the error yourself. If not, post the result again. Your current
program is too long, so probably nobody will bother reading through it.
 
T

Thomas Matthews

Matthew said:
I am working on a simple text adventure game. I have implemented one
word commands and a bit for two words. I have a problem though the
movement commands n and s (north and south respectivly) don't work. I
can't figure out why!
There are better methods for what you want to do.
I suggest tables of constant <token, function pointer> for
standard commands. This will allow you to add commands without
having to change the driver (table lookup & execution).

You may want to make a generic parser {Factory} that reads in
the text and creates pointer to a base <token, functor> object.
You may not need the token field, as the functor could contain
the token.
#include <string>
#include <iostream>
#include <vector>
using namespace std;

struct command_v
{
string name;
bool (*vfunc)();
bool (*dfunc)();
};

struct command_vd
{
string name;
bool (*vfunc)(vector<string> input);
bool (*dfunc)(vector<string> input);
};
What is the difference between command_v and command_vd?
Comments would be helpful here.

enum dirName{ n, s, e, w, north, south, east, west };
I think a table lookup would be better here.
You could add: in, out, up, down, nw, sw, etc, without
changing the driver.

class Exit;
What is this for?
Exiting the program?
Exit from a room?

class Item
{
public:
string name;
vector<command_vd> theVDCmds;
};
This describes an Item. The Item _has_ a name.
It _has_ commands. Why?
Are these actions that can be performed on an
item (i.e. throw rock)?

class Character
{
public:
vector<Item> inven;
string name;
string desc;
vector<command_vd> theVDCmds;
};
A Character _has_:
name
description (this may need more clarification,
such as can the description be "green").
a vector of Items
a vector of commands.
I don't understand what the commands are. Are
they actions, behaviors, etc?


class Location
{
public:
string name;
string desc;
vector<Exit> exits;
vector<Item> items;
vector<Character> chars;
vector<command_vd> theVDCmds;
};
Perhaps a location should contain a vector
of other locations or pointers to other locations.

Should a location contain a character or a character
contain a reference (or pointer) to a location. A
character could be in any location. This design
decision depends on whether you are operating on
characters or locations.
class Exit
{
public:
Location leadsTo;
int shortName;
int longName;
string name;
vector<command_vd> theVDCmds;
};
This class _could_be_ eliminated by redesigning the
Location class.

[snip]
void interpreter()
{
cout << "Parser v0\n";
bool quit = false;
bool un;
This variable could be declared within the while
loop below, because it is not used outside of the
loop.

string input;
dlook();
Prefer a more descriptive function name.

while(!quit)
{
cout << ":> ";
getline(cin, input);
un = parse(input);
if(!un)
{
cout << "Huh?\n";
continue;
}
}
}
Where does the variable 'quit' modified within
the while loop?

Is the above function really an interpreter or
is it the main function executing the program?

void setup()
{
// set up standalone commands
command_v quit;
quit.name = "quit";
quit.vfunc = vquit;
quit.dfunc = dquit;
theVCmds.push_back(quit);
[snip -- initialiation of Command variables]
I don't see the need for command variables when the
variables don't change (hence not 'variable').
I believe a table would be better.

mainChar.name = "Matthew";
mainChar.desc = "A valiant warrior!";

ex1.leadsTo = room1;
ex1.shortName = s;
ex1.longName = south;
ex1.name = "To the kitchen";
If you convert the directions to tokens, there will
be no need for both "shortName" and "longName" fields.
It may revert to "direction".

[snip -- I can't take it anymore]

I think you need to put some thought into the design
and simplify it (reduce, reuse, recycle).

Let us consider that there is one primary character.
The character traverses a set of locations. Each
location has N possible routes to other locations.
These routes may be null for directions that are
not possible or implemented. Each location has a
name and a description, as well as zero or more
objects and zero or more other characters (i.e.
monsters). The objects and characters are the
variable data. The routes, name and description
are the constant data.

I suggest using some database theory and placing
the data into tables. One table would contain the
names and descriptions, indexed by room number:
| Room Number | Name | Description |
+-------------+------+-------------+
| 25 | swamp| Muggy, wet |
+-------------+------+-------------+

Another table would contain the routes:
| Room Number | Direction | Next Room |
+-------------+-----------+-----------+
| 25 | South | 26 |
+-------------+-----------+-----------+

Another table, initialized at startup, would contain
variables {maps} for objects and characters:
std::map<unsigned int, /* room ID */
Object *> /* pointer to an object child */
std::map<unsigned int, Character>

I let the OP and readers figure out how to perform the
table look-ups.

--
Thomas Matthews

C++ newsgroup welcome message:
http://www.slack.net/~shiva/welcome.txt
C++ Faq: http://www.parashift.com/c++-faq-lite
C Faq: http://www.eskimo.com/~scs/c-faq/top.html
alt.comp.lang.learn.c-c++ faq:
http://www.raos.demon.uk/acllc-c++/faq.html
Other sites:
http://www.josuttis.com -- C++ STL Library book
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,769
Messages
2,569,582
Members
45,065
Latest member
OrderGreenAcreCBD

Latest Threads

Top