Text Adventure Program - Advice/Critic

Hello everyone, I am a beginner C++ student. I am taking it upon myself to create a text adventure program with the intention of expanding my C++ knowledge and learning how to properly structure a large program. This is what I have thus far, and as far as I can tell ( again, i'm a beginner ) everything is kosher, except that I should be loading in the map from a seperate file, and I will get to that eventually, but this was easier for the time being. Please offer any advice/critics that you would find helpful! Thanks for your time.

A single game tile
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
#include "cboardtile.h"
#include <iostream>
cboardtile::cboardtile()
{
}

bool cboardtile::getExit(int direction)
{
    return exit[direction];
}

std::string cboardtile::getExitDescription(int direction)
{
    return exitDescription[direction];
}

std::string cboardtile::getTileName()
{
    return tileName;
}

std::string cboardtile::getTileExamine()
{
    return tileExamine;
}

std::string cboardtile::getBlockReason(int direction)
{
    return blockReason[direction];
}

void cboardtile::setExits(bool N, bool E, bool S, bool W)
{
    exit[0] = N;
    exit[1] = E;
    exit[2] = S;
    exit[3] = W;
}

void cboardtile::setExitDescription(int direction, std::string description)
{
    exitDescription[direction] = description;
}

void cboardtile::setBlockReason(int direction, std::string reason)
{
    blockReason[direction] = reason;
}

void cboardtile::setTileName(std::string setName)
{
    tileName = setName;
}

void cboardtile::setTileExamine(std::string setExamine)
{
    tileExamine = setExamine;
}


header for game world
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
#ifndef CWORLD_H
#define CWORLD_H
#include <iostream>
#include <cboardtile.h>

class cworld : public cboardtile
{
    public:

        cworld();

        static const int boundary = 5;
        static const int lowerBoundary = -1;
        cboardtile gameWorld[boundary][boundary];

       char userPrompt();
        void choiceCheck(char choice);

    private:

        int playerX, playerY;


};

#endif 


game world cpp

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
#include "cworld.h"
#include <iostream>

cworld::cworld()
{
    // 0 is North, 1 is East, 2 is South, 3 is West

    gameWorld[0][0].setTileName("");
    gameWorld[0][0].setExits(true, false, true, false);
    gameWorld[0][0].setTileExamine("");
    gameWorld[0][0].setExitDescription(0, "");
    gameWorld[0][0].setExitDescription(1, "");
    gameWorld[0][0].setExitDescription(2, "");
    gameWorld[0][0].setExitDescription(3, "");

    gameWorld[0][0].setTileName("");
    gameWorld[0][0].setExits(true, false, true, false);
    gameWorld[0][0].setTileExamine("");
    gameWorld[0][0].setExitDescription(0, "");
    gameWorld[0][0].setExitDescription(1, "");
    gameWorld[0][0].setExitDescription(2, "");
    gameWorld[0][0].setExitDescription(3, "");

    gameWorld[0][0].setTileName("");
    gameWorld[0][0].setExits(false, false, false, false);
    gameWorld[0][0].setTileExamine("");
    gameWorld[0][0].setExitDescription(0, "");
    gameWorld[0][0].setExitDescription(1, "");
    gameWorld[0][0].setExitDescription(2, "");
    gameWorld[0][0].setExitDescription(3, "");

    gameWorld[0][0].setTileName("");
    gameWorld[0][0].setExits(true, false, true, false);
    gameWorld[0][0].setTileExamine("");
    gameWorld[0][0].setExitDescription(0, "");
    gameWorld[0][0].setExitDescription(1, "");
    gameWorld[0][0].setExitDescription(2, "");
    gameWorld[0][0].setExitDescription(3, "");

    gameWorld[0][0].setTileName("");
    gameWorld[0][0].setExits(false, true, true, true);
    gameWorld[0][0].setTileExamine("");
    gameWorld[0][0].setExitDescription(0, "");
    gameWorld[0][0].setExitDescription(1, "");
    gameWorld[0][0].setExitDescription(2, "");
    gameWorld[0][0].setExitDescription(3, "");

    gameWorld[1][0].setTileName("");
    gameWorld[1][0].setExits(false, false, false, false);
    gameWorld[1][0].setTileExamine("");
    gameWorld[1][0].setExitDescription(0, "");
    gameWorld[1][0].setExitDescription(1, "");
    gameWorld[1][0].setExitDescription(2, "");
    gameWorld[1][0].setExitDescription(3, "");

//THIS PART CONTINUES UNTIL the 25 GAME TILES of a 5 by 5 array for filled!
//I REMOVED A LOT OF IT TO SHORTEN THE POST :)


    playerX = 0, playerY = 0;
}

char cworld::userPrompt()
{// Displays valid moves to user and takes string input but only uses first character
    const int options = 4;
    const std::string choices[options] = {"[N]orth", "[E]ast", "[S]outh", "[W]est"};
    std::string takeUserInput;
    char extractInput;

    std::cout << "\n\n" << std::endl;

    for (int x = 0; x < options; x++)
    {
        if (gameWorld[playerX][playerY].getExit(x))
        {
            std::cout << choices[x] << std::endl;
        }
    }

    std::cout << std::endl << ">";

    std::cin >> takeUserInput;
    extractInput = toupper(takeUserInput[0]);
    return extractInput;
}

void cworld::choiceCheck(char choice)
{
    switch (choice){
        case 'N': if (gameWorld[playerX][playerY].getExit(0))
                    {
                        std::cout << "Test successful" << std::endl;
                    }
                    else
                    {
                        userPrompt();
                    }
                    break;
        case 'E': if (gameWorld[playerX][playerY].getExit(1))
                    {
                        std::cout << "Test successful" << std::endl;
                    }
                    else
                    {
                        userPrompt();
                    }
                    break;
        case 'S': if (gameWorld[playerX][playerY].getExit(2))
                    {
                        std::cout << "Test successful" << std::endl;
                    }
                    else
                    {
                        userPrompt();
                    }
                    break;
        case 'W': if (gameWorld[playerX][playerY].getExit(3))
                    {
                        std::cout << "Test successful" << std::endl;
                    }
                    else
                    {
                        userPrompt();
                    }
                    break;
        default: std::cout << "Unrecognized command" << std::endl;
                      userPrompt();
    }
}
Last edited on
Why does cworld inherit cboardtile?
cworld doesn't pass the "cworld is a cboardtile" test.

You haven't shown the cboardtile header, but it seems to me that Exit should be a struct since each Exit has a bool and a description.

1
2
3
4
5
6
7
8
9
  struct ExitPath 
  {  string description;
      bool allowed;
  };

//  Then in cboardtile
{  ExitPath   path[4];
...
};


I would define your directions as an enum and use those names instead of hard coded values as subscripts.
1
2
3
4
5
6
  enum direction
  { North,
    East, 
    South, 
    West 
  }; 

Last edited on
Ah i thought it had to inherit tile to use it, i see now it's useless.

Good idea on defining enum!

And... Can you have structs inside of classes?


The keywords struct and class are the same except for the default privacy setting. They can be infinitely nested, you can even nest them inside functions. Be aware though that it is uncommon to see more than 2 levels of nesting.
Last edited on
I see, thank you! Other than those few things out look good? It's just a shell this far
I would enhance userPrompt so that it only returns a valid direction. In fact, I would have it return an enum value.

I'd avoid calling choiceCheck from within userPrompt, since that would create a recursive call situation.
Well i have other choices the player can eventually choose from to navigate inventory and stats and such
I kinda see where you are going though
How would you return an enum?
1
2
3
4
5
6
direction get_direction () 
{
...
    if (extractInput == 'N')
        return North;
}

Oh, great! Thank you.
Topic archived. No new replies allowed.