I have made revisions to my program. I gave up on the idea of using functions that return arrays. That was far too complicated for the expected benefit. This latest version compiles and runs correctly with all of the provisions required by the exercise.

What remains is feedback on the efficiency and elegance of the program. What I ask is for constructive comments on how the code for this game could have been written with fewer lines, and making better use of C++ features.

Please bear in mind that I am self-teaching C++ and started in June of this year. This is my first code solving a semi-complex problem. I am not (yet) a C++ code master. (LOL)

#include "../../std_lib_facilities.h"

class Random {
public:
Random() {srand((unsigned)time(0));}
};

int rooms[4][4] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 100, 0, 0, 0};                // array of room characterics; four for each of 3 rooms (0-2) and 1 current room (3).
string hazards[3] = {"I smell the wumpus.", "I feel a breeze.", "I hear a bat."};    //  array of room hazards.

double upplimit() {                                                                  // set upper limit for probability range.
double limu = 40 + 40 * rand()/RAND_MAX;
return limu;
}

double lowlimit() {                                                                  // set lower limit for probability range.
double liml = 60 * rand()/RAND_MAX;
return liml;
}

int room_num() {                                                                     // randomize room numbers of adjacent rooms.
int rm = rand() % 1000;
return rm;
}

int player() {                                                                       // validate play made by player.
int play_room = 0;
int play = 0;
cin >> play;
if (play < 1000 || play > 3000) {
cout << "You have entered an invalid play.  Please try again." << endl;
cin >> play;
}
play_room = play - 1000;
if (play > 1000 && play < 2000 && play_room != rooms[0][0] && play_room != rooms[1][0] && play_room != rooms[2][0]) {
cout << "You have not chosen a valid room to which to move.  Please try again." << endl;
cin >> play;
}
play_room = play - 2000;
if (play > 2000 && play < 3000 && play_room != rooms[0][0] && play_room != rooms[1][0] && play_room != rooms[2][0]) {
cout << "You have not chosen a valid room into which to shoot.  Please try again." << endl;
cin >> play;
}
return play;
}

int shoot(int play) {
double prob_wumpus = rand()/RAND_MAX;
int flag = 0;

for (int i = 0; i < 3; i++) {                   // outcome of shooting at the wumpus.
if (play == 2000 + rooms[i][0]) {
if (rooms[i][1] == 1) {
cout << "You shot the wumpus!  YOU WIN!!!" << endl;
flag = 1;
}
if (rooms[i][1] == 0 && prob_wumpus > 0.70) {
cout << "You missed the wumpus.  It has come into your room and eaten you!" << endl;
flag = 1;
} else if (rooms[i][1] == 0 && prob_wumpus <= 0.70) {
cout << "You missed the wumpus.  Play again." << endl;
flag = 0;
}
}
}
return flag;
}

int move(int play) {
int flag = 0;
for (int i = 0; i < 3; i++) {                  // outcome of moving to another room.
for (int j = 0; j < 4; j++) {
if (play == 1000 + rooms[i][0]) {
rooms[3][j] = rooms[i][j];
}
}
}

if (rooms[3][1] == 1) {
cout << "The wumpus is in the room.  You are eaten!" << endl;
flag = 1;
}

if (rooms[3][2] == 1 && rooms[3][1] == 0) {
cout << "You have fallen into a pit and died!" << endl;
flag = 1;
}

if (rooms[3][3] == 1 && rooms[3][2] == 0 && rooms[3][1] == 0) {
cout << "A bat has taken you to another room!" << endl;
rooms[3][0] = room_num();
cout << "You are now in room " << rooms[3][0] <<"!" << endl;
flag = 0;
}
return flag;
}

int main() {

int flag = 0;
int play = 0;
int shots = 5;
int shot = 0;

cout << "You are safe and in room 100!" << endl;

while (flag == 0) {

if (shot == 0) {
for (int i = 0; i < 3; i++) {                     // loop for the rooms.
rooms[i][0] = room_num();                     // randomizing of room numbers.
if (rooms[i][0] == rooms[3][0]) {i--;}        // to prevent the current room from being selected for an adjacent room.
}

for (int i = 0; i < 3; i++) {                     // loop for the rooms.
for (int j = 1; j < 4; j++) {                 // loop for the wumpus, pit, and bat.
double prob = 100.0 * rand()/RAND_MAX;
if ((prob > lowlimit() && prob < upplimit()) && (rooms[0][j] == 0 && rooms[1][j] == 0 && rooms[2][j] == 0)) {     // randomizing of wumpus, pit, and bat.
rooms[i][j] = 1;                                            // True => 1.
} else {
rooms[i][j] = 0;                                            //  False => 0.
}
}
}
}

cout << "There are passage ways to rooms " << rooms[0][0] <<", " << rooms[1][0] <<", and " << rooms[2][0] <<"." << endl;

for (int j = 1; j < 4; j++) {                                           // existence of room hazards.
if (rooms[0][j] == 1 || rooms[1][j] == 1 || rooms[2][j] == 1) {
cout << hazards[j-1] << endl;
}
}

cout << endl;
cout << "Do you wish to move or shoot?" << endl;
cout << "Play 1,000 + the room number for moving, or 2,000 + the room number for shooting." << endl;
cout << "You have " << shots << " shots remaining." << endl;              // there is a limit of 5 shots.  The game ends if a player runs out of shots.

play = player();

shot = 0;
if (play > 2000) {
flag = shoot(play);
shot = 1;
shots -= 1;
if (shots == 0) {
cout << "You have no more shots!" << endl;
flag = 1;
}
}

if (play < 2000) {
flag = move(play);
if (rooms[3][1] == 0 && rooms[3][2] == 0 && rooms[3][3] == 0) {
cout << "You are safe and in room " << rooms[3][0] <<"!" << endl;
}
}
}

cout << "Game Over." << endl;

keep_window_open();
return 0;
}

3
Contributors
6
Replies
7
Views
7 Years
Discussion Span
Last Post by Nathaniel10

You can check the efficiency of your program by checking its execution time.I am very sure there are some Run time checks you can do online for your program. Secondly the program is well structured, but only one class???

Having more Classes and internal Classes will certainly make your code look professional.

Hope this helps

Edited by Software guy: n/a

Thanks for the comment. I was using classes in earlier versions but found I was able to consolidate them by using arrays. I would not have used any classes for this version except that the compiler wouldn't accept the random number seed above the main() section. I found a suggestion on the Web that worked, which was to create a class just for the seed and initialize it in a constructor.

What other classes do you suggest? I got a tongue lashing from a poster on another forum for poorly using classes. His point, while harsh, was not without merit. There is judgment involved in deciding whether to use classes, structs, both, or neither. Judgment that I have not yet fully developed.

>>Secondly the program is well structured, but only one class???

I beg to differ. Its hard to read. Global variables, overly complicated, and definitely not well structured.

@ firstPerson,

What areas of the program/code can be made less complex and how?

@ firstPerson,

What areas of the program/code can be made less complex and how?

I'll just touch on some few points, in no particular order:

• Random class is useless
• You need to encapsulate the room[] and hazard[] and functions like uppLimit, lowLimit into classes
• Name your identifiers better. For example, upperLimit is better than uppLimit
• You main function is too complicated. Again encapsulate the logic in an appropriate class
• You have couple of "magic numbers" there
• You functions are too complicated. It could be broken into simpler functions
• rand() returns an int. RAND_MAX is a integer, therefore by the law of computer programming, at least in C++, and rand()/RAND_MAX = 0, unless in the rare case rand() = RAND_MAX, then its equal to 1.

So your main problem, is that you need to encapsulate it more. Use more classes. Hide the logic from the user. Make main simple. Simpler the better.

Edited by firstPerson: n/a

I have the Random class in order to use srand() outside the main() section. This was recommended by a poster on another site, as I explained in reply to Software Guy. I was under the impression that srand() needed to be called before calling rand(). As I call rand() in the first 3 function I thought I needed to call srand() before then. Is it possible for rand() above the main() to be seeded by srand() called in the main() section? If so, then you would be correct that the random class is not needed.

I had rooms[] in a class in the first versions of this program. I can still see how a class for it can be appropriate in that a constructor can initialize it and hazards[] to the values I give. I get stumped as to what objects to give them. I initially had wumpus, pit, and bat as objects for a room, but main() was even more complicated than it is now because there are 4 rooms and I was trying to loop over them. (You can take a look at a thread titled "Wumpus Hunt" from Monday or Tuesday.) How can I make classes for rooms[] and hazards[] giving them objects that don't complicate main() even more?

I tried to make main() simpler by making functions for the randomization of the room numbers and the room hazards. But those are arrays so the function would have to return an array (a 2D array). I looked into that and found it to be EXTREMELY complicated. (See the thread titled "Return an Array from a Function" from Thursday or Friday.)

Your comment about rand() and RAND_MAX surprised me. It contradicts the dozen or so sources I used to learn how to generate random numbers within a range: random_number = lower_limit + rand()/RAND_MAX * (upper_limit - lower_limit). Still, I double checked things by running my program with a print out of the value for rand()/RAND_MAX. It does in fact compute a decimal value between 0.0 and 1.0 value to 6 places after the decimal point.

Though I don't see how I can implement all your suggestions for this program, I agree that they are good ideals for which to strive. I will remember them for my next project.

This topic has been dead for over six months. Start a new discussion instead.
Have something to contribute to this discussion? Please be thoughtful, detailed and courteous, and be sure to adhere to our posting rules.