Console game missues

Im trying to implement some of the stuff i learned into a program and I am having an issue getting it to work correctly for some reason. I put the issues at the top of the program, everything is in one file for now to make it easier to post questions.

I tried stepping through it with the debugger, and i was able to solve a few issues using it, but i cant seem to figure these two out.

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
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
#include <iostream>
#include <vector>

/*ISSUES
//
// 1. Map cannot have different size values, x cannot b 10 and y be 15 for example, or else it will crash
// 2. Player leaves a trail when going up for some reason
*/

void DirectionalError();

class Map
{
    public:
        Map
        (
            const std::string& mapName, 
            int mapRows, 
            int mapColumns, 
            char mapTile
        ): 
            mMapName(mapName), 
            mMapRows(mapRows), 
            mMapColumns(mapColumns), 
            mMapTile(mapTile)
        {}

        void InitializeMap()
        {
            for (int row = 0; row < mMapRows; row++)
            {
                std::vector<char> v1;

                for (int col = 0; col < mMapColumns; col++)
                {
                    v1.push_back(mMapTile);
                }

                mGameMap.push_back(v1);
            }
        }

        void DrawMap(int posX, int posY, char player)
        {
            if (posX >= mGameMap.size() || posY >= mGameMap.size())
            {
                std::cout << "Critical error drawing map! Map size is too small, please resize it!\n\n";
            }
            else 
            {
                for (int row = 0; row < mMapRows; ++row)
                {
                    for (int col = 0; col < mMapColumns; ++col)
                    {
                        mGameMap[col][row] = mMapTile;
                        mGameMap[posX][posY] = player;

                        std::cout << mGameMap[row][col];
                    }
                    std::cout << '\n';
                }
            }
        }

    private:
        std::string mMapName{ "Map Name" };
        int mMapRows{ 5 };
        int mMapColumns{ 5 };
        const char mMapTile{ '+' };
        const char mMapTransition{ 'Z' }; //UNUSED: Transition from one map to another whn player touches this
        std::vector<std::vector<char>> mGameMap;
};

//Can promote to a character class when i learn virtual, then inherit from there.
class Player
{
    public:
        Player(char player, int posX, int posY): mPlayer(player), mPosX(posX), mPosY(posY)
        {}

        int GetPositionX() const
        {
            return mPosX;
        }

        int GetPositionY() const
        {
            return mPosY;
        }

        char GetPlayerSprite() const
        {
            return mPlayer;
        }

        int Movement(int choice);

    private:
        const char mPlayer{ 'O' };
        int mPosX{ 0 };
        int mPosY{ 0 };
};

int main()
{
    Player Hero('O', 5, 5);
    Map Courtyard("Courtyard", 20, 20, '-');

    Courtyard.InitializeMap();

    while (true)
    {
        Courtyard.DrawMap(Hero.GetPositionX(), Hero.GetPositionY(), Hero.GetPlayerSprite());

        std::cout << "X: " << Hero.GetPositionX() << " Y: " << Hero.GetPositionY() << "\n\n";

        std::cout << "What do you want to do?\n\n";

        std::cout << "1) Move Up\n";
        std::cout << "2) Move Down\n";
        std::cout << "3) Move Left\n";
        std::cout << "4) Move Right\n";

        int choice{ 0 };
        std::cin >> choice;

        Hero.Movement(choice);
    }
}

//No error Handling Yet.
int Player::Movement(int choice)
{
    enum class Direction {UP = 1, DOWN = 2, LEFT = 3, RIGHT = 4};

    switch (choice)
    {
        case static_cast<int>(Direction::UP):
                return mPosX--;
            break;

        case static_cast<int>(Direction::DOWN):
                return mPosX++;
            break;

        case static_cast<int>(Direction::LEFT):
                return mPosY--;
            break;

        case static_cast<int>(Direction::RIGHT):
                return mPosY++;
            break;

        default:
            std::cout << "Invalid Input\n";
    }
}

void DirectionalError()
{
    std::cout << "Cannot go any further in this direction\n";
}
Last edited on
> if (posX >= mGameMap.size() || posY >= mGameMap.size())
1. You should be checking against mapRows and mapColumns. This test assumes the map is square.
2. You also need to check for <0 in each direction, otherwise you step off the grid.

> mGameMap[col][row] = mMapTile;
> mGameMap[posX][posY] = player;
You need some sense of where the player was previously, in order to restore the map with mGameMap[col][row] = mMapTile;

Maybe
mGameMap[oldX][OldY] = mMapTile;
mGameMap[posX][posY] = player;


Be careful about which way round the indices are
rows increase in the Y axis
cols increase in the X axis


This should be in a separate function called drawMap()
> std::cout << mGameMap[row][col];
You're confusing x, y row and col. Row is y and col is x. As a first refactor consider something like:

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
131
132
133
134
135
136
137
138
139
#include <iostream>
#include <vector>

void DirectionalError();

class Map {
public:
	Map ( const std::string& mapName, size_t mapRows, size_t mapColumns, char mapTile ) :
		mMapName(mapName), mMapRows(mapRows), mMapColumns(mapColumns), mMapTile(mapTile) {}

	void InitializeMap() {
		mGameMap.assign(mMapRows, std::vector<char>(mMapColumns, mMapTile));
	}

	void DrawMap(size_t posX, size_t posY, char player) {
		for (size_t row {}; row < mMapRows; ++row) {
			for (size_t col {}; col < mMapColumns; ++col) {
				mGameMap[row][col] = mMapTile;
				mGameMap[posY][posX] = player;

				std::cout << mGameMap[row][col];
			}
			std::cout << '\n';
		}
	}

	size_t maxRow() const {
		return mGameMap.size();
	}

	size_t maxCol() const {
		return !mGameMap.empty() ? mGameMap[0].size() : 0;
	}

private:
	const std::string mMapName { "Map Name" };
	size_t mMapRows { 5 };
	size_t mMapColumns { 5 };
	const char mMapTile { '+' };
	const char mMapTransition { 'Z' }; //UNUSED: Transition from one map to another whn player touches this
	std::vector<std::vector<char>> mGameMap;
};

//Can promote to a character class when i learn virtual, then inherit from there.
class Player {
public:
	Player(char player, size_t posX, size_t posY) : mPlayer(player), mPosX(posX), mPosY(posY) {}

	size_t GetPositionX() const {
		return mPosX;
	}

	size_t GetPositionY() const {
		return mPosY;
	}

	char GetPlayerSprite() const {
		return mPlayer;
	}

	void Movement(int choice, Map);

private:
	const char mPlayer { 'O' };
	size_t mPosX { };
	size_t mPosY { };
};

int main() {
	Player Hero('O', 7, 5);
	Map Courtyard("Courtyard", 25, 20, '-');

	Courtyard.InitializeMap();

	while (true) {
		Courtyard.DrawMap(Hero.GetPositionX(), Hero.GetPositionY(), Hero.GetPlayerSprite());

		std::cout << "X: " << Hero.GetPositionX() << " Y: " << Hero.GetPositionY() << "\n\n";

		std::cout << "What do you want to do?\n\n";

		std::cout << "1) Move Up\n";
		std::cout << "2) Move Down\n";
		std::cout << "3) Move Left\n";
		std::cout << "4) Move Right\n";

		int choice { };

		std::cin >> choice;
		Hero.Movement(choice, Courtyard);
	}
}

//No error Handling Yet.
void Player::Movement(int choice, Map map) {
	enum class Direction {
		UP = 1, DOWN = 2, LEFT = 3, RIGHT = 4
	};

	switch (choice) {
		case static_cast<int>(Direction::UP):
			if (mPosY) {
				--mPosY;
				return;
			}
			break;

		case static_cast<int>(Direction::DOWN):
			if (mPosY < map.maxRow() - 1) {
				++mPosY;
				return;
			}
			break;

		case static_cast<int>(Direction::LEFT):
			if (mPosX) {
				--mPosX;
				return;
			}
			break;

		case static_cast<int>(Direction::RIGHT):
			if (mPosX < map.maxCol() - 1) {
				++mPosX;
				return;
			}
			break;

		default:
			std::cout << "Invalid Input\n";
			return;
	}

	DirectionalError();
}

void DirectionalError() {
	std::cout << "Cannot go any further in this direction\n";
}

Last edited on
Ok thank you so much, that helped!
What if i wanted to add all my maps to a list and then output them with a map transition and when the player touches the transition, the map changes? Ive been sitting here thinking of how to do this and at first i tried to use an std::map, but idk, it didnt seem to work out. maybe a vector? I tried a little test and got the map transitioning working, i just did it in main just to test it out but i deleted it.

I'm just looking for advice on what would be the best way to go about implementing something like that. Im also wondering how to implement the map transition system, should it be part of draw map? or its own function? I was trying some stuff earlier but it just didnt seem right and didnt work.

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
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
//============================================================================
// Name             : Console Game
// Author           : Chay Hawk
// Version          : 0.1.6
// Version Date     : March 25th 2023 @ 2:11 PM
// Date Created     : 
// Lines of Code    : 195
// Description      : 
//============================================================================

#include <iostream>
#include <vector>
#include <string>
#include <map>
#include <random>
#include <utility>

void DirectionalError();

class Map
{
public:
	Map(const std::string& mapName, int mapRows, int mapColumns, char mapTile) :
		mMapName(mapName), mMapRows(mapRows), mMapColumns(mapColumns), mMapTile(mapTile) {}

	//Comment this out for now so we dont mess up the working code while testing
	void InitializeMap() 
	{
		mGameMap.assign(mMapRows, std::vector<char>(mMapColumns, mMapTile));
	}

	void DrawMap(int posX, int posY, char player)
	{
		for (int row{}; row < mMapRows; ++row) 
		{
			for (int col{}; col < mMapColumns; ++col)
			{

				mGameMap[row][col] = mMapTile;
				mGameMap[posY][posX] = player;

				std::cout << mGameMap[row][col];
			}
			std::cout << '\n';
		}
	}


	int MaxRows() const
	{
		return mGameMap.size();
	}

	int MaxColumns() const
	{
		return !mGameMap.empty() ? mGameMap[0].size() : 0;
	}

private:
	const std::string mMapName{ "Map Name" };
	int mMapRows{ 5 };
	int mMapColumns{ 5 };
	const char mMapTile{ '+' };
	std::vector<std::vector<char>> mGameMap;
};

//Can promote to a character class when i learn virtual, then inherit from there.
class Player
{
public:
	Player(char player, int posX, int posY) : mPlayer(player), mPosX(posX), mPosY(posY) {}

	int GetPositionX() const
	{
		return mPosX;
	}

	int GetPositionY() const
	{
		return mPosY;
	}

	char GetPlayer() const
	{
		return mPlayer;
	}

	void Movement(int choice, Map);

private:
	const char mPlayer{ 'O' };
	int mPosX{ };
	int mPosY{ };
};

int main()
{
	Player Hero('O', 7, 5);
	Map Courtyard("Courtyard", 10, 20, '-');
	Map Field("Field", 20, 50, '-');

	Courtyard.InitializeMap();
	Field.InitializeMap();

	while (true)
	{
		//Map transition code, need to figure out how to put this in member functions
		if (Hero.GetPositionX() == 7 && Hero.GetPositionY() == 5)
		{
			Field.DrawMap(Hero.GetPositionX(), Hero.GetPositionY(), Hero.GetPlayer());
		}
		else if (Hero.GetPositionX() == 7 && Hero.GetPositionY() == 6)
		{
			Courtyard.DrawMap(Hero.GetPositionX(), Hero.GetPositionY(), Hero.GetPlayer());
		}
		else
		{
			Courtyard.DrawMap(Hero.GetPositionX(), Hero.GetPositionY(), Hero.GetPlayer());
		}

		std::cout << "X: " << Hero.GetPositionX() << " Y: " << Hero.GetPositionY() << "\n\n";

		std::cout << "What do you want to do?\n\n";

		std::cout << "1) Move Up\n";
		std::cout << "2) Move Down\n";
		std::cout << "3) Move Left\n";
		std::cout << "4) Move Right\n";

		int choice{ };

		std::cin >> choice;
		Hero.Movement(choice, Courtyard);
	}
}

void Player::Movement(int choice, Map map)
{
	enum class Direction
	{
		UP = 1, DOWN = 2, LEFT = 3, RIGHT = 4
	};

	switch (choice)
	{
	case static_cast<int>(Direction::UP):
		if (mPosY)
		{
			--mPosY;
			return;
		}
		break;

	case static_cast<int>(Direction::DOWN):
		if (mPosY < map.MaxRows() - 1)
		{
			++mPosY;
			return;
		}
		break;

	case static_cast<int>(Direction::LEFT):
		if (mPosX)
		{
			--mPosX;
			return;
		}
		break;

	case static_cast<int>(Direction::RIGHT):
		if (mPosX < map.MaxColumns() - 1)
		{
			++mPosX;
			return;
		}
		break;

	default:
		std::cout << "Invalid Input\n";
		return;
	}

	DirectionalError();
}

void DirectionalError()
{
	std::cout << "Cannot go any further in this direction\n";
}
Last edited on
1
2
3
Player Hero('O', 7, 5);
...
if (Hero.GetPositionX() == 7 && Hero.GetPositionY() == 5)


It's good practice to name a const for a value that doesn't change and then use that name in the program. eg (which may have the wrong names!):

1
2
3
4
5
6
7
constexpr int fieldX {7};
constexpr int fieldY {5};
constexpr char playSym {'o'};

Player Hero(playSym, fieldX, fieldY);
...
if (Hero.GetPositionX() == fieldX && Hero.GetPositionY() == fieldY)


Then if these change, you only have to change them once in one place. Also it makes reading the code easier if you're not trying to work out what all these numbers mean.

Also note that the if statement on L112 has no effect. Courtyard is drawn in either case.

PS. In .Movement(), Map should be passed by ref to prevent an unnecessary copy. If the param isn't going to be changed, then as a const ref.

Also, why not pass type DIRECTION to .Movement() rather than an int. Yu then only need do a cast once (on the call) - rather than for every case.
Last edited on
With name like DrawMap, it could be assumed that that function just drew the map - and not update it as well! I'd suggest that the update is separated from the display. Why do you want multiple maps? If you want a courtyard and a field can't that be represented using only 1 map?

As a refactor using 1 map, consider:

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
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
#include <iostream>
#include <vector>
#include <string>
#include <map>

void DirectionalError();

class Map;

//Can promote to a character class when i learn virtual, then inherit from there.
class Player {
public:
	enum class Direction { UP = 1, DOWN = 2, LEFT = 3, RIGHT = 4 };

	Player(char player, size_t posX, size_t posY) : mPlayer(player), mPosX(posX), mPosY(posY) {}

	size_t GetPositionX() const {
		return mPosX;
	}

	size_t GetPositionY() const {
		return mPosY;
	}

	char GetPlayer() const {
		return mPlayer;
	}

	void Movement(Player::Direction, Map& m);

private:
	const char mPlayer { 'O' };
	size_t mPosX { };
	size_t mPosY { };
};

class Map {
public:
	Map(const std::string& mapName, size_t mapRows, size_t mapColumns, char mapTile) :
		mMapName(mapName), mMapRows(mapRows), mMapColumns(mapColumns), mMapTile(mapTile) {}

	//Comment this out for now so we don't mess up the working code while testing
	void InitializeMap(const Player& p) {
		mGameMap.assign(mMapRows, std::vector<char>(mMapColumns, mMapTile));
		mGameMap[p.GetPositionY()][p.GetPositionX()] = p.GetPlayer();
	}

	void update(size_t oldx, size_t oldy, size_t newx, size_t newy, char player) {
		mGameMap[oldy][oldx] = mMapTile;
		mGameMap[newy][newx] = player;
	}

	void DrawMap() const {
		for (const auto& cl : mGameMap) {
			for (const auto& el : cl)
				std::cout << el;

			std::cout << '\n';
		}
	}

	size_t MaxRows() const {
		return mGameMap.size();
	}

	size_t MaxColumns() const {
		return !mGameMap.empty() ? mGameMap[0].size() : 0;
	}

private:
	const std::string mMapName { "Map Name" };
	size_t mMapRows { 5 };
	size_t mMapColumns { 5 };
	const char mMapTile { '+' };
	std::vector<std::vector<char>> mGameMap;
};

void Player::Movement(Player::Direction choice, Map& map) {
	switch (choice) {
		case Direction::UP:
			if (mPosY) {
				const auto oldy { mPosY-- };

				map.update(mPosX, oldy, mPosX, mPosY, mPlayer);
				return;
			}
			break;

		case Direction::DOWN:
			if (mPosY < map.MaxRows() - 1) {
				const auto oldy { mPosY++ };

				map.update(mPosX, oldy, mPosX, mPosY, mPlayer);
				return;
			}
			break;

		case Direction::LEFT:
			if (mPosX) {
				const auto oldx { mPosX-- };

				map.update(oldx, mPosY, mPosX, mPosY, mPlayer);
				return;
			}
			break;

		case Direction::RIGHT:
			if (mPosX < map.MaxColumns() - 1) {
				const auto oldx { mPosX++ };

				map.update(oldx, mPosY, mPosX, mPosY, mPlayer);
				return;
			}
			break;

		default:
			std::cout << "Invalid Input\n";
			return;
	}

	DirectionalError();
}

void DirectionalError() {
	std::cout << "Cannot go any further in this direction\n";
}

int main() {
	Player Hero('O', 7, 5);
	Map Field("Field", 20, 50, '-');

	//Courtyard.InitializeMap();
	Field.InitializeMap(Hero);

	while (true) {
		Field.DrawMap();

		std::cout << "X: " << Hero.GetPositionX() << " Y: " << Hero.GetPositionY() << "\n\n";
		std::cout << "What do you want to do?\n\n";
		std::cout << "1) Move Up\n";
		std::cout << "2) Move Down\n";
		std::cout << "3) Move Left\n";
		std::cout << "4) Move Right\n";
		std::cout << "Enter choice: ";

		int choice { };

		std::cin >> choice;
		Hero.Movement(static_cast<Player::Direction>(choice), Field);
	}
}

Last edited on
Registered users can post here. Sign in or register to post.