Moving a monster in a 2D array

Hello fellow programmers,
I am trying to figure out how to move a monster within a 2D array. The monster is supposed to move closer and closer to the player and take the shortest route possible. I have been stuck on this for a while so I would appreciate some input on what I can do to make this work. Currently, I can print the level but the monster will not move. I have tried many different ways as to try and make him move but nothing has worked. You can ignore the 'getCost' function, there is also a bug in that function I have to figure 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
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
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
#include <iostream>
#include <cmath>
#include <fstream>
#include <string>
#include <iomanip>
using namespace std;

const int ROWS = 20, COLUMNS = 60;

unsigned const int EMPTY = 0, ROCKY = 1, ROUGH = 2, WALL = 3, PLAYER_START = 4, PLAYER_GOAL = 5,
					MONSTER_START = 6, ATTACKER_START = 7, DRONE_START = 8;

typedef unsigned int Level[ROWS][COLUMNS];

//Load in a level that the user enters
void loadLevel(Level level, std::string filename);

//finds the position of the monster and saves the row & column number
void findMonsterStart(const Level level, int& row, int& column);

//finds the position of the player and saves the rows & column number
void findPlayerStart(const Level level, int& row, int& column);

//find how much it costs to move to a certain position in the array
unsigned int getCost(const Level level, int row, int column);

//calculate the straight line distance between the player and the monster
double calculateDistance(int row1, int row2, int col1, int col2);

//print the level
void printLevel(const Level level, int monster_row, int monster_column, int target_row, int target_column);

int main()
{
	Level level;
	string filename;
	int row, column, mrow, mcolumn;
	double mrowplus, mrowneg, mcolplus, mcolneg;

	loadLevel(level, filename);
	findMonsterStart(level, mrow, mcolumn);
	findPlayerStart(level, row, column);
	printLevel(level, mrow, mcolumn, row, column);

	while ((mrow != row) && (mcolumn != column))
	{
		mrowplus = calculateDistance(row, mrow + 1, column, mcolumn);
		mrowneg = calculateDistance(row, mrow - 1, column, mcolumn);
		mcolplus = calculateDistance(row, mrow, column, mcolumn + 1);
		mcolneg = calculateDistance(row, mrow, column, mcolumn - 1);

		if ((mrowplus < mrowneg) && (mrowplus < mcolplus) && (mrowplus < mcolneg))
		{
			cout << "Moving East" << endl;
			++mrow;
			printLevel(level, mrow, mcolumn, row, column);
		}
		else if ((mcolplus < mrowplus) && (mcolplus < mrowneg) && (mcolplus < mcolneg))
		{
			cout << "Moving South" << endl;
			++mcolumn;
			printLevel(level, mrow, mcolumn, row, column);
		}
		else if ((mcolneg < mcolplus) && (mcolneg < mrowneg) && (mcolneg < mrowplus))
		{
			cout << "Moving North" << endl;
			--mcolumn;
			printLevel(level, mrow, mcolumn, row, column);
		}
		else
		{
			cout << "Moving East" << endl;
			--mrow;
			printLevel(level, mrow, mcolumn, row, column);
		}
		do
		{
			cout << "Continue?" << endl;
		} while (cin.get() != '\n');
	}

	return 0;
}

void loadLevel(Level level, std::string filename)
{
        ifstream input;
	cout << "Enter the level you want to open with .txt: ";
	getline(cin, filename);
	input.open(filename);

	char letter;
	for (int i = 0; i < ROWS; i++)
		for (int j = 0; j < COLUMNS; j++)
		{
			input >> letter;
			if (letter == '.')
				level[i][j] = EMPTY;
			else if (letter == '^')
				level[i][j] = ROCKY;
			else if (letter == ':')
				level[i][j] = ROUGH;
			else if (letter == '#')
				level[i][j] = WALL;
			else if (letter == 'P')
				level[i][j] = PLAYER_START;
			else if (letter == '*')
				level[i][j] = PLAYER_GOAL;
			else if (letter == 'S')
				level[i][j] = MONSTER_START;
			else if (letter == 'A')
				level[i][j] = ATTACKER_START;
			else if (letter == 'D')
				level[i][j] = DRONE_START;
		}
}

void findMonsterStart(const Level level, int& row, int& column)
{
	for(int i = 0; i < ROWS; i++)
		for (int j = 0; j < COLUMNS; j++)
		{
			if (level[i][j] == MONSTER_START)
			{
				row = i;
				column = j;
				return;
			}
		}
}

void findPlayerStart(const Level level, int& row, int& column)
{
	for (int i = 0; i < ROWS; i++)
		for (int j = 0; j < COLUMNS; j++)
		{
			if (level[i][j] == PLAYER_START)
			{
				row = i;
				column = j;
				return;
			}
		}
}

unsigned int getCost(const Level level, int row, int column)
{
	int traversalcost[9] = { 1, 2, 4, 1000, 1, 1, 1, 1, 1 };
	unsigned int cost = 0;
	
	for (int i = 0; i < 9; i++)
	{
		if (traversalcost[i] == level[row][column])
		{
			cost = traversalcost[i];
			cout << cost << endl;
			return cost;
		}
	}
}

double calculateDistance(int row1, int row2, int col1, int col2)
{
	double distance;
	distance = sqrt(pow(col2 - col1, 2.0) + pow(row2 - row1, 2.0));
	return distance;
}

void printLevel(const Level level, int monster_row, int monster_column, int target_row, int target_column)
{
	char printchar[9] = { ' ', '^', ':', '#', '@', '*', 'M', ' ', ' ', };

	cout << "+------------------------------------------------------------+" << endl;
	for (int i = 0; i < ROWS; i++)
	{
		cout << "|";

		for (int j = 0; j < COLUMNS; j++)
		{
			if (level[i][j] == EMPTY)
				cout << printchar[0];
			else if (level[i][j] == ROCKY)
				cout << printchar[1];
			else if (level[i][j] == ROUGH)
				cout << printchar[2];
			else if (level[i][j] == WALL)
				cout << printchar[3];
			else if (level[i][j] == PLAYER_START)
			{
				cout << printchar[4];
				target_row = i;
				target_column = j;
			}
			else if (level[i][j] == PLAYER_GOAL)
				cout << printchar[5];
			else if (level[i][j] == MONSTER_START)
			{
				monster_row = i;
				monster_column = j;
				cout << printchar[6];
			}
			else if (level[i][j] == ATTACKER_START)
				cout << printchar[7];
			else if (level[i][j] == DRONE_START)
				cout << printchar[8];
		}

		cout << "|" << endl;
	}

	cout << "+------------------------------------------------------------+" << endl; 
}





for a level, i have a file called messy.txt which I will also include.
The 'S' is the starting point for the monster.
............................................................
........:::::::::::::::::...................................
............................................................
.............*...^^.........................................
..:::::::...................................................
.................^^.........................................
............................................................
............................................................
........................................................:...
..............................:........................::...
......................................................::....
.............S.......................................::.....
................:::::::.............................::......
....................^^^^^^^^^^^^^^^^^^^^^^^.................
.........::::...........:::::::::::::::::::.................
............................................................
.................................................^^^^^^^^^^^
....................................................P.......
............................................................
............................................................


Thank you for your help in advance!
Last edited on
Sorry for the messy.txt, it is supposed to be 20 by 60 but i did not know how to give it those dimensions.
Wrap the map in [output] tags to preserve spacing.

Why is input global? It should be local to loadLevel. And you should check if the file opens and give the user another chance.

Why is filename a parameter of loadLevel? You are using it like a local variable.

It might be better to use the character values themselves instead of converting them to integers. That way you don't need to do so much conversion for I/O. You can of course still name them.

I don't have time right now to help with your movement problem. I'm not even sure what you are talking about. Maybe you should describe some of the things you've tried.

And there's lots of warnings you should fix. Variables set but not used, and used uninitialized, etc. Set the max warning level and fix them all.
Last edited on
I fixed the input so it is no longer global, that was an error on my part.
This is an assignment for my class and the professor wanted us to convert them to integers then print the corresponding char.

So the goal of this program is to move the monster( which is 'S' in the map to the 'P' which is the player.)The player cannot move yet as that will come later in my course. The monster moves one space at a time, it can be either north, east, south, or west. Before the monster moves one space, you want to calculate the straight line distance to the player using the distance function. Which ever one has the shortest distance, the monster will move to that spot. Once the monster reaches the player, the program should finish.

I am fairly new to programming as I just started in September, I expect that I'll have little errors everywhere, I appreciate anything I can do to improve the performance of my program.
Last edited on
> Sorry for the messy.txt, it is supposed to be 20 by 60
Here's a tip.
The game logic works the same on a 5x5 map as it would on a 20x60 or a 1000x1000 map.

But a really small map means you're not looking at 100's of lines of debug output every time you want to inspect what is going on.
Topic archived. No new replies allowed.