Grid class not working [SOLVED]

I've created a simple Grid class to reuse in projects, but apparently it isn't working well, while it was before.

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
/*Grid.h*/
#ifndef GRID_H
#define GRID_H

#include <vector>
#include <iostream>

template<class T>
class Grid
{
private:
	int m_width;
	int m_height;
	std::vector< std::vector<T> > *m_grid; //pointer to a std::vector of std::vectors, constructor will initialize this
	
public:
	/*Constructor*/
	Grid(int width, int height);
	/*Destructor*/
	~Grid();
	/*Output*/
	void Print();
	
	/*Access*/
	T at(int x, int y);
	void set(int x, int y, T value);
	
};

/*Constructor*/
template<typename T>
Grid<T>::Grid(int width, int height) : 
	m_width(width),
	m_height(height),
	m_grid(new std::vector< std::vector<T> >)	
{
	/*Resize the 2D std::vector to the specified width and height*/
	m_grid->resize(m_height); //We need m_height sub-vectors
	for (int i = 0; i < m_height; ++i)
		(*m_grid)[i].resize(m_width); //each sub-vector has a size of m_width
}
/*Destructor*/
template<typename T>
Grid<T>::~Grid()
{
	//delete dynamically allocated grid
	delete m_grid;
}

template<typename T>
void Grid<T>::Print()
{
	/*This function assumes there is a valid output operator for type T*/
	for (int i = 0; i > m_height; ++i)
	{
		for (int j = 0; j < m_width; ++j)
			std::cout << at(j,i);
		std::cout << "\n";
	}
	std::cout << "\n\n";
}

template<typename T>
T Grid<T>::at(int x, int y)
{
	return (*m_grid)[y][x];
}

template<typename T>
void Grid<T>::set(int x, int y, T value)
{
	(*m_grid)[y][x] = value;
}


#endif 

But when I test this with the following main function:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
#include <iostream>

#include "Grid.h"

int main()
{
	Grid<char> *grid = new Grid<char>(5,5);
	
	grid->set(2,2,'X');
	grid->set(0,0,'Y');
	
	grid->Print();
	
	return 0;
}


It prints an empty grid.
Last edited on
Okay, first of all, I made a typo in my print function, instead of i > m_height I obviously have to write i < m_height. But this doens't solve the problem.
I have worked it out, sorry for this strange post.

Hope you all have a nice day.
@goldenchicken

I copied your program, changed line 54 in Grid.h, and the program worked great. Just don't understand how this is going to be used in a regular program. Could you tell me what it's going to be used for? Seems interesting, though.
Last edited on
I use it quite often whenever I want to make, say a game that has a board where pieces move. Or when you want to create a map of a world in the game. I find it easier to just type:
 
Grid<mapObject> *worldMap = new Grid<mapObject>(MAP_WIDTH, MAP_HEIGHT);

And then proceed to immediately use this map, instead of creating std::vectors, resizing them and especially to avoid the pain of having to do this:
1
2
/*Assumes there is a std::vector named grid*/
mapObject x = ((*grid)[i][j]).someMapObjectFunction();
Just a few of things to think about.

You might want to make at return a T&. Then you can modify grid locations in place, which might help if your T objects get large--no need to copy a large object twice to modify it. Of course you would also need a second:
const T& at(int x, int y) const;
that you can use on constant Grid objects.

Also, why are you dynamically allocating m_grid? I guess it's not hurting anything, but a vector does dynamic allocations for it contents, so you're not really saving that much space on the stack.

Last, you should have bounds checking in both your set and at functions to catch spurious array index values.
All true, I'll be working on those for now. Thanks alot for pointing that out.
About the dynamic allocation, I wrote the base code for this when I was using dynamic allocation all the time (I have no idea why actually). Back then, I wasn't using templates for it, as I only used it in one project. But then I wanted to reuse it, and quickly implemented it with templates.
Last edited on
@goldenchicken

Thanks for the explanation. I had written a grid making program also, but mine displays a grid, so I combined our two programs to come up with this. Hope you can use it. Feel free to ask questions if needed.
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
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
// Grid with Grid_Class.cpp : main project file.

#include <stdio.h>
#include <conio.h>
#include <iostream>
#include <string>
#include "Grid.h"
#include <windows.h>

using std::string;
using std::cout;
using std::cin;
using std::endl;
using System::Console;

enum {
	black,          //  0
	dark_blue,      //  1
	dark_green,     //  2
	dark_cyan,      //  3
	dark_red,       //  4
	dark_magenta,   //  5
	dark_yellow,    //  6
	light_gray,     //  7
	dark_gray,      //  8
	light_blue,     //  9
	light_green,    // 10
	light_cyan,     // 11
	light_red,      // 12
	light_magenta,  // 13
	light_yellow,   // 14
	white           // 15
};

#define on , // So I can use the function - void text(text_color on background_color)
// To more easily remember which is text color vs background color

// Movement keys
#define ENTER 13
#define UP 72
#define LEFT 75
#define RIGHT 77
#define DOWN 80

// My text color function. Use it if you wish.
void text(int text_color = 7 on int paper_color = 0)
{
	// defaults to light_gray on black
	int color_total = (text_color + (paper_color * 16));
	SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE), color_total);
}

void gotoXY(int x, int y);
void gotoXY(int x, int y, string text);
void Make_Grid(int style, int across, int down, int Single_Square_Width,
 int Single_Square_High, int Number_Squares_Wide,int Number_Squares_High,
 int f_color, int b_color, bool shadow, int shadow_fc, int shadow_bc);

int main()
{
	const int col = 38, row = 11;
	int x = 0, y = 0;
	int ch;
	bool moved = true;
	HANDLE console = GetStdHandle(STD_OUTPUT_HANDLE);
	Grid<char> *grid = new Grid<char>(col,row);

	Console::SetWindowSize(80, 27);
	gotoXY(31, 1, "\"Make Grid\" Demo");

	Make_Grid(2, 0, 0, 78, 25, 1, 1, black, light_red, 0, 0, 0);
	Make_Grid(1, 1, 1, 1,1, col, row, black, light_cyan, 1, light_red, black);
	grid->set(2,2,'A');
	grid->set(0,0,'B');
	grid->set(1,3,'C');
	grid->set(4,0,'D');
	text(black on light_red);
	gotoXY(3,15,"Let's move the letter 'B'");
	text(black on light_cyan);
	do
	{
		// Not sure how to check if grid location 
		// is filled or empty before moving
		if(moved)
		{
			grid->set(x,y,'B');
		grid->Print();
		moved = false;
		}
		ch =_getch();
		if(ch==LEFT)
			if(x-1>=0)
			{
				grid->set(x,y,' ');
				x--;
				moved = true;
			}
			if(ch==RIGHT)
				if(x+1< col)
				{
					grid->set(x,y,' ');
					x++;
					moved = true;
				}
				if(ch==DOWN)
					if(y+1 < row)
					{
						grid->set(x,y,' ');
						y++;
						moved = true;
					}
					if(ch==UP)
						if(y-1>=0)
						{
							grid->set(x,y,' ');
							y--;
							moved = true;
						}
	}while (ch != ENTER);
	Console::SetWindowSize(80, 25);
	text(black on light_red);
	gotoXY(22, 24, "\xB5 Press any key to close program.. \xC6");
	_getch();
	return 0;
}

void gotoXY(int x, int y)
{
	HANDLE console = GetStdHandle(STD_OUTPUT_HANDLE);
	COORD CursorPosition;
	CursorPosition.X = x;
	CursorPosition.Y = y;
	SetConsoleCursorPosition(console, CursorPosition);
}

void gotoXY(int x, int y, string text)
{

	HANDLE console = GetStdHandle(STD_OUTPUT_HANDLE);
	COORD CursorPosition;
	CursorPosition.X = x;
	CursorPosition.Y = y;
	SetConsoleCursorPosition(console, CursorPosition);
	cout << text;
}

void Make_Grid(int style, int across, int down, int Single_Square_Width,
 int Single_Square_High, int Number_Squares_Wide, int Number_Squares_High,
 int f_color, int b_color, bool shadow, int shadow_fc, int shadow_bc)
{
	char Shadow = '\xB1';
	char  Grid[6][14] = {
		{ ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ' },
		{ ' ', '\xDA', '\xC4', '\xC2', '\xB3', '\xBF', '\xB3', '\xC3', '\xC4', '\xC5', '\xB4', '\xC0', '\xC1', '\xD9' },
		{ ' ', '\xC9', '\xCD', '\xCB', '\xBA', '\xBB', '\xBA', '\xCC', '\xCD', '\xCE', '\xB9', '\xC8', '\xCA', '\xBC' },
		{ ' ', '\xC9', '\xCD', '\xD1', '\xBA', '\xBB', '\xB3', '\xC7', '\xC4', '\xC5', '\xB6', '\xC8', '\xCF', '\xBC' },
		{ ' ', '\xD6', '\xC4', '\xD2', '\xBA', '\xB7', '\xBA', '\xC7', '\xC4', '\xD7', '\xB6', '\xD3', '\xD0', '\xBD' },
		{ ' ', '\xD5', '\xCD', '\xD1', '\xB3', '\xB8', '\xB3', '\xC6', '\xCD', '\xD8', '\xB5', '\xD4', '\xCF', '\xBE' },

	};

	int a, b, x, y;
	string Rail(Single_Square_Width, Grid[style][2]);
	string Line(Single_Square_Width, Grid[style][8]);
	string Middle(Single_Square_Width, ' ');

	text(f_color on b_color);

	// <<----------- Top Row ------------>

	gotoXY(across, down);
	cout << Grid[style][1];

	for (x = 0; x < Number_Squares_Wide; x++)
	{
		cout << Rail;
		if (x < Number_Squares_Wide - 1)
			cout << Grid[style][3];
		else
			cout << Grid[style][5];
	}
	down++;

	// <<----------- Middle Rows ------------>

	for (x = 0; x < Number_Squares_High; x++)
	{
		gotoXY(across, down);
		for (y = 0; y < Single_Square_High; y++)
		{
			gotoXY(across, down);
			cout << Grid[style][4];
			for (a = 0; a < Number_Squares_Wide; a++)
			{
				if (a < Number_Squares_Wide - 1)
					cout << Middle << Grid[style][6];
				else
					cout << Middle << Grid[style][4];
			}
			if (shadow)
			{
				text(shadow_fc on shadow_bc);
				cout << Shadow;
				text(f_color on b_color);
			}
			down++;
		}
		gotoXY(across, down);
		cout << Grid[style][7];
		for (b = 0; b < Number_Squares_Wide; b++)
		{
			cout << Line;
			if (b < Number_Squares_Wide - 1)
				cout << Grid[style][9];
			else
				cout << Grid[style][10];
		}
		if (shadow)
		{
			text(shadow_fc on shadow_bc);
			cout << Shadow;
			text(f_color on b_color);
		}
		down++;
	}
	down--;

	// <<----------- Bottom Row ------------>

	gotoXY(across, down);
	cout << Grid[style][11];

	for (x = 0; x < Number_Squares_Wide; x++)
	{
		cout << Rail;
		if (x < Number_Squares_Wide - 1)
			cout << Grid[style][12];
		else
			cout << Grid[style][13];

	}
	if (shadow)
	{
		text(shadow_fc on shadow_bc);
		string Grid_shadow(Number_Squares_Wide*(Single_Square_Width + 1) + 1, Shadow);
		gotoXY(across + 1, down + 1, Grid_shadow);
		text(f_color on b_color);
	}
}

New Grid.h follows. Added a bit more to 'T Grid<T>::at(int x, int y)'
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
/*Grid.h*/
#ifndef GRID_H
#define GRID_H

#include <vector>
#include <windows.h>

template<class T>
class Grid
{
private:
	int m_width;
	int m_height;
	std::vector< std::vector<T> > *m_grid; //pointer to a std::vector of std::vectors, constructor will initialize this
	
public:
	/*Constructor*/
	Grid(int width, int height);
	/*Destructor*/
	~Grid();
	/*Output*/
	void Print();
	
	/*Access*/
	T at(int x, int y);
	void set(int x, int y, T value);
	
};

/*Constructor*/
template<typename T>
Grid<T>::Grid(int width, int height) : 
	m_width(width),
	m_height(height),
	m_grid(new std::vector< std::vector<T> >)	
{
	/*Resize the 2D std::vector to the specified width and height*/
	m_grid->resize(m_height); //We need m_height sub-vectors
	for (int i = 0; i < m_height; ++i)
		(*m_grid)[i].resize(m_width); //each sub-vector has a size of m_width
}
/*Destructor*/
template<typename T>
Grid<T>::~Grid()
{
	//delete dynamically allocated grid
	delete m_grid;
}

template<typename T>
void Grid<T>::Print()
{
	/*This function assumes there is a valid output operator for type T*/
	for (int i = 0; i < m_height; ++i)
	{
		for (int j = 0; j < m_width; ++j)
			std::cout << at(j,i);
	}
}

template<typename T>
T Grid<T>::at(int x, int y)
{
	 HANDLE console = GetStdHandle(STD_OUTPUT_HANDLE);
	COORD CursorPosition;
	CursorPosition.X = 2+(x*2);
	CursorPosition.Y = 2+(y*2);
	SetConsoleCursorPosition(console, CursorPosition);
	return (*m_grid)[y][x];
}

template<typename T>
void Grid<T>::set(int x, int y, T value)
{
	(*m_grid)[y][x] = value;
}
#endif  
Last edited on
That looks quite cool, but I don't understad why you are moving the cursor to a position with every time at() gets called. When there is a grid displayed at that moment, I understand why, but this isn't always the case. So when I'm using it and I call the at function in the program, and the cursor moves, it might be a bit strange. What I would do in that case is the following:

1
2
3
4
5
6
7
8
9
10
11
12
13
14

template<typename T>
T& Grid<T>::at(int x, int y, bool moveCursor = false)
{
        if (moveCursor)
        {
	        HANDLE console = GetStdHandle(STD_OUTPUT_HANDLE);
	        COORD CursorPosition;
	        CursorPosition.X = 2+(x*2);
	        CursorPosition.Y = 2+(y*2);
	        SetConsoleCursorPosition(console, CursorPosition);
        }
	return (*m_grid)[y][x];
}
Last edited on
@goldenchicken

I was just setting up the program as if you were playing a board game, like checkers, chess etc. where you move a specified piece. May add in allowing you to change which character gets moved. Still not sure, though, how to check if the Grid location is empty or filled, as when I move the 'B', I can overwrite the character present, which I don't want to do.

I don't believe that a() is called UNLESS one of the arrow keys is pressed. If I'm wrong, please show me where. Also, when does the bool moveCursor get changed to true from false and change back to false when no arrow key is pressed?

EDIT:

Added in a bool in main() [ in above program] , so that Grid.h doesn't have to be changed, nor any program already written.

After a recognized key press, the bool is changed to true, Grid can be called, then the bool is changed back to false, so Grid is NOT called again until a arrow key is pressed.
Last edited on
Okay, now I see what you're aiming for, and I like the idea. This is not how I imagined using the Grid class, but it's a good idea, so thanks for that.
Topic archived. No new replies allowed.