#include "Room.h"
#include <iostream>
#include <string>
#include <cctype>
using namespace std;
void menu();
void look(Room* current_room);
void exits(Room* current_room);
void add(Room* current, vector<Room*>& allRooms);
void connect(Room* current, vector<Room*> allRooms);
void rename(Room* current);
void description(Room* current);
void printRooms(vector<Room*> allRooms);
Direction ch2Direct(char c);
string userName;
string userDescription;
int main()
{
// initialize
Room* current_room = new Room();
vector<Room*> allRooms;
allRooms.push_back(current_room);
char choice;
// menu loop
do
{
cout<<"Enter a command (Press '?' to view command list): "<<endl;
cin>>choice;
cin.ignore();
switch(choice)
{
case '?':
menu(); break;
case 'a':
case 'A': // add a room and connect to current
add(current_room, allRooms); break;
case 'p':
case 'P': //
printRooms(allRooms); break;
case 'n':
case 'N':
if (current_room->north()!= NULL){
current_room = current_room->north();
cout << "Moving north..." << endl;
}
else
cout<<"You cannot go that way"<<endl;
break;
case 'r':
case 'R':
rename(current_room); break;
case 'd':
case 'D':
description(current_room); break;
case 's':
case 'S':
if (current_room->south()!= NULL){
current_room = current_room->south();
cout << "Moving south..." << endl;
}
else
cout<<"You cannot go that way"<<endl;
break;
case 'c':
case 'C': // user selects room to connect to existing room
// from the allRooms vector
connect(current_room, allRooms); break;
case 'e':
case 'E':
if (current_room->east()!= NULL){
current_room = current_room->east();
cout << "Moving east..." << endl;
}
else
cout<<"You cannot go that way"<<endl;
break;
case 'w':
case 'W':
if (current_room->west()!= NULL){
current_room = current_room->west();
cout << "Moving west..." << endl;
}
else
cout<<"You cannot go that way"<<endl;
break;
case 'l':
case 'L':
look(current_room); break;
case 'x':
case 'X':
exits(current_room);break;
case 'q':
case 'Q':
cout << "Quitting..." << endl;
break;
default:
cout<<"invalid command"<<endl;
}
}while(choice != 'q');
// cleanup before quitting
return 0;
}
// Show the name and description of a room */
void look(Room* r)
{
cout << *r << endl;
}
void printRooms(vector<Room*> allRooms){
for(int k =0; k<allRooms.size(); k++)
cout<<k<<" " << allRooms[k]->name()<<endl;
}
// add a new room, connected to the current room
// Parameters
// current -- the current room we are in
// allRooms-- a vector of pointers to (addresses of) all the rooms in the game
// Precondition
// current refers to an existing room
// Postcondition
// if possible (current must have a free exit)
// a) a new room has been added off one of the exits of current
// b) the address of the new room has also been added to the allRooms vector
void add(Room* current, vector<Room*>& allRooms)
{
char dir;
char exitDir;
bool free = false;
char response;
bool goBack = false;
bool input = false;
bool valid = false;
string nRoom = "New Room #" + to_string(allRooms.size());
if(current->north() != nullptr && current->south() != nullptr && current->east() != nullptr && current->west() != nullptr){
cout<<"Cannot add another room from this room, all exits occupied."<<endl;
}
else{
while(free == false && goBack == false){
cout << "Connect Room in which direction (N, S, E, W): "<< endl;
cin>>dir;
dir = toupper(dir);
if(dir == 'N' || dir == 'S' || dir == 'E' || dir == 'W'){
valid = true;
}
while(valid == false){
cout << "Not a valid direction. Please enter N, S, E, W." << endl;
cin>>dir;
dir = toupper(dir);
if(dir == 'N' || dir == 'S' || dir == 'E' || dir == 'W'){
valid = true;
}
}
if(ch2Direct(dir) == 0 && current->north() == nullptr){
free = true;
}
else if(ch2Direct(dir) == 1 && current->east() == nullptr){
free = true;
}
else if(ch2Direct(dir) == 2 && current->south() == nullptr){
free = true;
}
else if(ch2Direct(dir) == 3 && current->west() == nullptr){
free = true;
}
if(free == true){
cout <<"Which exit of the new room leads to this room (N, S, E, W): " << endl;
cin>>exitDir;
exitDir = toupper(exitDir);
if(exitDir == 'N' || exitDir == 'S' || exitDir == 'E' || exitDir == 'W'){
input = true;
}
while(input == false){
cout << "Not a valid direction. Please enter N, S, E, W." << endl;
cin>>exitDir;
exitDir = toupper(exitDir);
if(exitDir == 'N' || exitDir == 'S' || exitDir == 'E' || exitDir == 'W'){
input = true;
}
}
//to_string(allRooms.size());
Room* temp = new Room(nRoom, "Null -- Add Description");
allRooms.push_back(temp);
current->connect(ch2Direct(dir), allRooms[(allRooms.size()-1)], ch2Direct(exitDir));
cout << nRoom.substr(4) <<" has been added!" << endl;
cout<<endl;
}
else{
cout << "This room already has another room in that direction, press 'r' to enter a different direction for the room or press any other key to return to the main menu" << endl;
cin>>response;
if(toupper(response) != 'R'){
goBack = true;
cout << "Returning to menu..." << endl;
}
}
}
}
}
// add a new connection between current room and an already existing room.
// Parameters
// current -- the current room we are in
// allRooms-- a vector of pointers to (addresses of) all the rooms in the game
// Precondition
// current refers to an existing room
// Postcondition
// if possible (both rooms must have a spare exit to link them together)
// current is now linked to another room in the game
//
void connect(Room* current, vector<Room*> allRooms)
{
char dir;
char exitDir;
int roomIndex=-1;
cout << "Connect Room in which direction (N, S, E, W): " << endl;
cin>>dir;
cout<<"ALL ROOMS"<<endl;
for(int k =0; k<allRooms.size(); k++)
cout<<k<<" " << allRooms[k]->name()<<endl;
cout << "Which room do you want to connect to? (Enter number): " << endl;
while(roomIndex > allRooms.size() || roomIndex < 0){
cin>>roomIndex;
if(roomIndex > allRooms.size() || roomIndex < 0){
cout<<"Invalid entry, choose a valid room number: "<<endl;
}
}
cout <<"Which exit of the new room leads to this room? " << endl;
cin>>exitDir;
current->connect(ch2Direct(dir), allRooms[roomIndex], ch2Direct(exitDir));
cout << (allRooms[roomIndex])->name() << " has been succesfully connected" << endl;
}
// change the name of a room
void rename(Room* current)
{
cout << "Enter Room Name: "<< endl;
getline(cin, userName);
current->set_name(userName);
}
// change the description of a room
void description(Room* current)
{
string text;
cout<<"Enter a new description for this room and hit <enter>"<<endl;
getline(cin,text);
current->set_description(text);
}
// for each exit from room r,
// show the name of the room it connects to
// or say "Nothing" if the link is null
void exits(Room* r)
{
if((r->north()) == nullptr){
cout << "North: Nothing "<< endl;
}
else
cout << "North: " << r->north()->name() << endl;
if((r->south()) == nullptr){
cout << "South: Nothing "<< endl;
}
else
cout << "South: " << r->south()->name() << endl;
//*(r->north()) returns name and description
if((r->east()) == nullptr){
cout << "East: Nothing "<< endl;
}
else
cout << "East: " << r->east()->name() << endl;
if((r->west()) == nullptr){
cout << "West: Nothing "<< endl;
}
else
cout << "West: " << r->west()->name() << endl;
}
void menu()
{
cout<<"Please choose from the following: "<<endl;
cout<<" n for north --- move north (if possible)"<<endl;
cout<<" e for east --- move east (if possible)"<<endl;
cout<<" s for south --- move south (if possible)"<<endl;
cout<<" w for west --- move at west (if possible)"<<endl;
cout<<" l for look --- look at room"<<endl;
cout<<" p for print --- print rooms list"<<endl;
cout<<" x for exits --- show room exits"<<endl;
cout<<" c for connect --- connect this room to another (already made) room"<<endl;
cout<<" r for rename --- rename this room"<<endl;
cout<<" d for desc --- change description for this room"<<endl;
cout<<" a for add --- add new room"<<endl;
cout<<" q for quit --- exit program"<<endl;
cout<<" ? --- show commands"<<endl;
}
// convert a char direction: 'N','S','E','W'
// into a Direction enum: NORTH, SOUTH, EAST, WEST
Direction ch2Direct(char c)
{
switch(c)
{
case 'N': return NORTH;
case 'n': return NORTH;
case 'S': return SOUTH;
case 's': return SOUTH;
case 'E': return EAST;
case 'e': return EAST;
case 'W': return WEST;
case 'w': return WEST;
default: return NORTH;
}
}
// Room.h: interface for the Room class.
//
//////////////////////////////////////////////////////////////////////
#ifndef ROOM_H
#define ROOM_H
#include<string>
#include<vector>
#include<iostream>
using namespace std;
enum Direction {NORTH = 0, EAST = 1, SOUTH = 2, WEST = 3};
// creates aliases, so we can say NORTH instead of 0 and so on
class Room
{
public:
// constructors
Room(string name, string desc);
Room();
// exit pointers
Room * west() const;
Room * east() const;
Room * south() const;
Room * north() const;
// inspectors for other attributes
string description() const;
string name() const;
// mutators
void set_description(string d);
void set_name(string n);
// connect this room to room r
// exit is the direction you exit this
// room from. to is the direction you enter
// the other room from.
// Theres no law that says the exits have to make sense
// The method returns true if the connection is successful
// To prevent memory leaks, you cannot disconnect an exiting
// attached exit.
// Examples:
// r1.connect(NORTH, &r2, SOUTH);
// -- exiting r1 to the north takes you to r2
// -- exiting r2 to the south takes you to r1
// -- returns true
// r1.connect(WEST, &r3, WEST); (extra credit only)
// -- exiting r1 to the west takes you to r2
// -- exiting r3 to the west takes you to r1
// -- odd but permissible
// -- returns true
// r1.connect(WEST, &r4, EAST);
// -- returns false
// -- no connections are made because there is
// -- already an exit WEST
// r1.connect(EAST, &r2, SOUTH);
// -- returns false
// -- no connections are made because there is
// -- already an exit SOUTH from r2.
bool connect(Direction exit, Room * r, Direction to);
// destructor
// the destructor disconnects itself from
// other rooms before the room itself is
// destroyed. This prevents dangling pointer
// in other rooms
virtual ~Room();
private:
// helper method for destructor
// CAUTION: dangerous
// --- may cause memroy errors!
void disconnect(Direction d);
// attributes
string description_;
string name_;
vector<Room *> exits_;
};
ostream & operator<<(ostream & out, const Room & r);
#endif // !defined(AFX_ROOM_H__7C105847_EA72_4F3E_8758_2D94DD05D583__INCLUDED_)
// Room.cpp: implementation of the Room class.
//
//////////////////////////////////////////////////////////////////////
#include "Room.h"
//////////////////////////////////////////////////////////////////////
// Construction/Destruction
//////////////////////////////////////////////////////////////////////
Room::Room()
{
name_ = "The void";
description_ = "There is nothing but blackness in every direction.";
int i;
for(i = 0; i < 4; i++) // set all exits to "closed"
exits_.push_back(NULL);
}
Room::Room(string name, string desc)
{
name_ = name;
description_ = desc;
int i;
for(i = 0; i < 4; i++) // set all exits to "closed"
exits_.push_back(NULL);
}
Room::~Room()
{
// make sure all exits to this room are
// destroyed so that no one can try to enter
// this room from another location
if(exits_[NORTH] != NULL)
disconnect(NORTH);
if(exits_[EAST] != NULL)
disconnect(EAST);
if(exits_[SOUTH] != NULL)
disconnect(SOUTH);
if(exits_[WEST] != NULL)
disconnect(WEST);
}
// --- inspectors ---
Room * Room::north() const
{
return exits_[NORTH];
}
Room * Room::south() const
{
return exits_[SOUTH];
}
Room * Room::east() const
{
return exits_[EAST];
}
Room * Room::west() const
{
return exits_[WEST];
}
string Room::name() const
{
return name_;
}
string Room::description() const
{
return description_;
}
// --- mutators ---
void Room::set_name(string n)
{
name_ = n;
}
void Room::set_description(string d)
{
description_ = d;
}
// --- facilitators ---
bool Room::connect(Direction exit, Room *r, Direction to)
{
// check that both exits are free
if (exits_[exit] != NULL or r->exits_[to] != NULL)
return false;
// make connection
exits_[exit] = r;
r->exits_[to] = this; // assign the current room (this) to the TO exit of the remote room (r)
return true;
}
// --- private methods ---
void Room::disconnect(Direction d)
{
// disconnects ALL exits from another
// room to this one. It's sloppy, but
// that's OK.
Room * other_room;
other_room = exits_[d];
int i;
for(i = 0; i < 4; i++) {
if (other_room->exits_[i] == this)
other_room->exits_[i] = NULL;
}
}
// --- operators ---
ostream & operator<<(ostream & out, const Room & r) {
out << r.name() << endl;
out << r.description() << endl;
return out;
}