Tilemap array of unknown size - c++

I want the users to pick there map size so I do not know the size of the map at run time. I have been looking around how I can implement this with little success. Closest to something that is working is with the vector variant but while it runs it still does not work properly.
I want a 3 dimensional array so in my header i declare the tilemap like this.
std::vector<std::vector<std::vector<Tile>>> tileMap;
and test it in the class like this:
World::World(int width, int height, int depth)
{
tileMap.resize(width);
tileMap[0].resize(height);
tileMap[0][0].resize(depth);
tileMap.resize(width);
for (int i = 0;i<width;i++)
{
tileMap[i].resize(height);
}
for (int y = 0; y < height;y++)
{
for (int x = 0; x < width; x++)
{
tileMap[x,y].resize(depth);
}
}
std::cout << sizeof tileMap / sizeof tileMap[0][0][0] << std::endl;
}
I am aware that not all the dimensions of the array are resized properly but the final line just outputs "0".
Is there i better way to create my tilemap of unknown size? I need a lot of sizes like 64*64, 256*256, 64*1024, etc (the z levels will be determined after generating the level). so creating an array for each size seems inefficient. But maybe there is a better way of declaring my array or i am doing something wrong somewhere.

You want tileMap.size() * tileMap[0].size() * tileMap[0][0].size() to get the number of tiles.

Related

Implementing a 2d array for an object

Creating a crossword puzzle generator. The grid size is chosen by input and the grid will be generated. I'd like the grid to be an object with rows and columns but also a 2d array which will allow me to divide the grid into smaller sections for randomising between blank and numbered squares. I am not sure where to implement it.
It has to be a 2d array as I will do dividing and inverting the layout.
Here is my Grid class with some methods. (And the rest)
class Grid
{
int rows; //x
int columns; //y
Square field;
public:
void SetXY(int x, int y)
{
rows = x;
columns = y;
return;
}
public:
void DisplaySize()
{
cout << "Rows = ", rows, "Columns = ", columns;
}
};
The simplest way to implement a 2D array is to use a std::array<std::array<>> or std::vector<std::vector<>> - depending on whether it needs to be a static or dynamically sized array.
But, you can also just use a one dimensional std::array or std::vector and then just get the second dimension by indexing like row*size_of_row+column.

Write 2D array to PGM grayscale image

I'm creating various 2D arrays of sizes from 100x100 to 2000x2000 elements. The values within the arrays can be clamped down to 0 - 255 gray scale and then need to be written to a PGM image in order to visually represent the data.
For example, I'm declaring the arrays globally as:
element case1[100][100];
element is a structure of double pixelValue and a Boolean value (that won't be used when actually writing to the file but is necessary in the program).
In writing to the PGM image, I am having errors considering the FILE *fp in this area of the code when writing after the header:
int *p
for (int x = 0; x < dimension; x++)
{
for (int y = 0; y < dimension; y++)
{ //also doesn't work as: fp << (unsigned char)case1[x][y].pix;
int pix = case1[x][y].pixelValue;
*p = pix;
fp << (unsigned char)*p;
}
}
fclose(fp);
I'm unsure of how to work with the pointer in order to get the pixelValue from each location within the 2D array. I need to be able to iterate through each pixelValue to get the visual representation of the data.
Thank you for your help!
Used fputc() instead so that I could directly insert values instead of using pointers.

passing several boost multi_array from function

I have a bunch of 3d arrays generated using boost::multi_array in a function. I would not want to use all these arrays in another code of mine is there any way to do this?
When I had a 2d case what I did was
typedef boost::numeric::ublas::matrix<double> fils;
boost::array<fils,5> filter1(unsigned width, unsigned height)
{
matrix<double>l,m,n,o,p;
//perform other steps//
boost::array<fils,5> t={l,m,n,o,p};
return t;
}
main.cpp
int main()
{
boost::array<fils,5> z;
z= t(w,h);
}
for the 2d case this method works fine. I now want to do the same with a 3D case where
typedef boost::multi_array<double,3>x;
boost::array<x,12>x1(unsigned w,unsigned h,unsigned s)
{
typedef boost::multi_array<double,3>M;
typedef M::index Mi;
m l(boost::extents[w][h][s]),m(boost::extents[w][h][s]),n(boost::extents[w][h][s]),o(boost::extents[w][h][s]);
//perform steps//
}
how do I get the matrices l,m,n,o,p so that I can use them as source in other bits of code.
In my opinion the most elegant solution is to declare a 4-D multi_array like so :
typedef boost::multi_array<double,4> FloatArray4D;
typedef M::index Mi;
function create4dArray()
{
FloatArray4D returnValue(boost::extents[w][h][s][4]);
// Populate the array as you please here is an example.
for (int i = 0; i < 4; i++) {
for (int j = 0; j < w; j++) {
for (int k = 0; k < h; k++) {
for (int x = 0; x < s; x++) {
returnValue[j][k][x][i] = i+j*10+k*100+x*1000;
}
}
}
}
return returnValue;
}
Then you can access the subarray by indexing on the last coordinate. It might be more efficient to index them by the first coordinate (in terms of localization of the data) but I don't know the implementation details of boost::multi_array (can someone weight in on this in comments ?)
To extract a view (no-copy) of your 3-D data from the 4-D multi_array created you can use this :
typedef boost::multi_array_types::index_range range;
FloatArray4D::index_gen indices;
FloatArray4D my4DArray = create4dArray();
// Create a new view with 3 dimentions (corresponding to your l) fixing the 4th dimention to 0
FloatArray4D::array_view<3>::type l = [indices[range()][range()][range()][0];
then you can use l as if it was your 3-D array.
PS: NEVER name something x or M, especially not a type. Yes long names are a pain to type, but get a decent text editor with auto-completion and it won't be a problem.
Knowing what an object is by its name however, will always be great. It improves readability, for you and for anyone else who has to read your code.
Also do not typedef inside a function. If you want to define a custom type do it in a header file that is shared.
You don't want to have to declare that type everywhere.
And actually don't overuse typedef, only use it if it improves readability.

Add 1 to vector<unsigned char> value - Histogram in C++

I guess it's such an easy question (I'm coming from Java), but I can't figure out how it works.
I simply want to increment an vector element by one. The reason for this is, that I want to compute a histogram out of image values. But whatever I try I just can accomplish to assign a value to the vector. But not to increment it by one!
This is my histogram function:
void histogram(unsigned char** image, int height,
int width, vector<unsigned char>& histogramArray) {
for (int i = 0; i < width; i++) {
for (int j = 0; j < height; j++) {
// histogramArray[1] = (int)histogramArray[1] + (int)1;
// add histogram position by one if greylevel occured
histogramArray[(int)image[i][j]]++;
}
}
// display output
for (int i = 0; i < 256; i++) {
cout << "Position: " << i << endl;
cout << "Histogram Value: " << (int)histogramArray[i] << endl;
}
}
But whatever I try to add one to the histogramArray position, it leads to just 0 in the output. I'm only allowed to assign concrete values like:
histogramArray[1] = 2;
Is there any simple and easy way? I though iterators are hopefully not necesarry at this point, because I know the exakt index position where I want to increment something.
EDIT:
I'm so sorry, I should have been more precise with my question, thank you for your help so far! The code above is working, but it shows a different mean value out of the histogram (difference of around 90) than it should. Also the histogram values are way different than in a graphic program - even though the image values are exactly the same! Thats why I investigated the function and found out if I set the histogram to zeros and then just try to increase one element, nothing happens! This is the commented code above:
for (int i = 0; i < width; i++) {
for (int j = 0; j < height; j++) {
histogramArray[1]++;
// add histogram position by one if greylevel occured
// histogramArray[(int)image[i][j]]++;
}
}
So the position 1 remains 0, instead of having the value height*width. Because of this, I think the correct calculation histogramArray[image[i][j]]++; is also not working properly.
Do you have any explanation for this? This was my main question, I'm sorry.
Just for completeness, this is my mean function for the histogram:
unsigned char meanHistogram(vector<unsigned char>& histogram) {
int allOccurences = 0;
int allValues = 0;
for (int i = 0; i < 256; i++) {
allOccurences += histogram[i] * i;
allValues += histogram[i];
}
return (allOccurences / (float) allValues) + 0.5f;
}
And I initialize the image like this:
unsigned char** image= new unsigned char*[width];
for (int i = 0; i < width; i++) {
image[i] = new unsigned char[height];
}
But there shouldn't be any problem with the initialization code, since all other computations work perfectly and I am able to manipulate and safe the original image. But it's true, that I should change width and height - since I had only square images it didn't matter so far.
The Histogram is created like this and then the function is called like that:
vector<unsigned char> histogramArray(256);
histogram(array, adaptedHeight, adaptedWidth, histogramArray);
So do you have any clue why this part histogramArray[1]++; don't increases my histogram? histogramArray[1] remains 0 all the time! histogramArray[1] = 2; is working perfectly. Also histogramArray[(int)image[i][j]]++; seems to calculate something, but as I said, I think it's wrongly calculating.
I appreciate any help very much! The reason why I used a 2D Array is simply because it is asked for. I like the 1D version also much more, because it's way simpler!
You see, the current problem in your code is not incrementing a value versus assigning to it; it's the way you index your image. The way you've written your histogram function and the image access part puts very fine restrictions on how you need to allocate your images for this code to work.
For example, assuming your histogram function is as you've written it above, none of these image allocation strategies will work: (I've used char instead of unsigned char for brevity.)
char image [width * height]; // Obvious; "char[]" != "char **"
char * image = new char [width * height]; // "char*" != "char **"
char image [height][width]; // Most surprisingly, this won't work either.
The reason why the third case won't work is tough to explain simply. Suffice it to say that a 2D array like this will not implicitly decay into a pointer to pointer, and if it did, it would be meaningless. Contrary to what you might read in some books or hear from some people, in C/C++, arrays and pointers are not the same thing!
Anyway, for your histogram function to work correctly, you have to allocate your image like this:
char** image = new char* [height];
for (int i = 0; i < height; ++i)
image[i] = new char [width];
Now you can fill the image, for example:
for (int i = 0; i < height; ++i)
for (int j = 0; j < width; ++j)
image[i][j] = rand() % 256; // Or whatever...
On an image allocated like this, you can call your histogram function and it will work. After you're done with this image, you have to free it like this:
for (int i = 0; i < height; ++i)
delete[] image[i];
delete[] image;
For now, that's enough about allocation. I'll come back to it later.
In addition to the above, it is vital to note the order of iteration over your image. The way you've written it, you iterate over your columns on the outside, and your inner loop walks over the rows. Most (all?) image file formats and many (most?) image processing applications I've seen do it the other way around. The memory allocations I've shown above also assume that the first index is for the row, and the second is for the column. I suggest you do this too, unless you've very good reasons not to.
No matter which layout you choose for your images (the recommended row-major, or your current column-major,) it is in issue that you should always keep in your mind and take notice of.
Now, on to my recommended way of allocating and accessing images and calculating histograms.
I suggest that you allocate and free images like this:
// Allocate:
char * image = new char [height * width];
// Free:
delete[] image;
That's it; no nasty (de)allocation loops, and every image is one contiguous block of memory. When you want to access row i and column j (note which is which) you do it like this:
image[i * width + j] = 42;
char x = image[i * width + j];
And you'd calculate the histogram like this:
void histogram (
unsigned char * image, int height, int width,
// Note that the elements here are pixel-counts, not colors!
vector<unsigned> & histogram
) {
// Make sure histogram has enough room; you can do this outside as well.
if (histogram.size() < 256)
histogram.resize (256, 0);
int pixels = height * width;
for (int i = 0; i < pixels; ++i)
histogram[image[i]]++;
}
I've eliminated the printing code, which should not be there anyway. Note that I've used a single loop to go through the whole image; this is another advantage of allocating a 1D array. Also, for this particular function, it doesn't matter whether your images are row-major or column major, since it doesn't matter in what order we go through the pixels; it only matters that we go through all the pixels and nothing more.
UPDATE: After the question update, I think all of the above discussion is moot and notwithstanding! I believe the problem could be in the declaration of the histogram vector. It should be a vector of unsigned ints, not single bytes. Your problem seems to be that the value of the vector elements seem to stay at zero when your simplify the code and increment just one element, and are off from the values they need to be when you run the actual code. Well, this could be a symptom of numeric wrap-around. If the number of pixels in your image are a a multiple of 256 (e.g. 32x32 or 1024x1024 image) then it is natural that the sum of their number would be 0 mod 256.
I've already alluded to this point in my original answer. If you read my implementation of the histogram function, you see in the signature that I've declared my vector as vector<unsigned> and have put a comment above it that says this victor counts pixels, so its data type should be suitable.
I guess I should have made it bolder and clearer! I hope this solves your problem.

Dynamically allocating 2D int array

Can someone please point out what I am doing wrong in the following code?
int* a = NULL;
int* b = NULL;
a = new int[map->mapSize.width];
b = new int[map->mapSize.height];
layer->tileGids = new int[a][b];
Here's what the code uses:
typedef struct _size {
int width, height;
} size;
class Map {
size mapSize;
}
class Layer {
int * tileGids;
}
EDIT: Compiler-Errors (in line 6 of the first bit of code):
error: expression in new-declarator must have integral or enumeration type|
error: 'b' cannot appear in a constant-expression|
Solution:
I have decided to accept lightalchemist's answer. In essence, what works for me is use a vector instead of the array. Vector manages the memory for you and hence is a lot easier to deal with.
You can't pass a pointer for initializing the size of an array. Others have now mentioned this.
This post (it's not mine) seems like it might help you: http://eli.thegreenplace.net/2003/07/23/allocating-multi-dimensional-arrays-in-c/
You should also consider doing the allocation in the class Layer's constructor and then deleting the memory in it's destructor (i.e. RAII - resource acquisition is initialization). This is considered good style.
Finally, you might consider using continuous memory and a custom indexing scheme, which you could easily use Layer to encapsulate. This of course depends upon how big things will get. The bigger they get the better the case for continuous memory becomes.
This should give you a flavor.
#include <iostream>
#include <cstdlib>
int main()
{
const size_t ROWS = 5;
const size_t COLS = 2;
const size_t size = ROWS*COLS;
int* arr = new int[size];
int i = 0;
for ( size_t r = 0 ; r < ROWS; ++r )
{
for (size_t c = 0; c < COLS; ++c )
{
arr[r*COLS+c] = i++;
}
}
for ( int j = 0; j < i; ++j)
{
std::cout << arr[j] << std::endl;
}
delete [] arr;
}
Firstly, your variables "a" and "b" are pointers. Your code:
layer->tileGids = new int[a][b]
is the root cause of the problem.
I'm trying to guess your intention here and I think what you are trying to do is make layer.tileGids a 2 dimension array to reference a "grid" of size (mapSize.Width, mapSize.height) so that you can refer to each "cell" in the grid using layer.tileGids[x][y].
If you are indeed trying to create a 2 dimension array, there are 2 methods to do it.
Method 1:
class Layer {
int ** tileGids; // NOTE the "**" to indicate tileGids is a pointer to pointer i.e. 2D array.
}
To initialize it:
int width = map->mapSize.width;
int height = map->mapSize.height;
layer.tileGids = new int*[width]; // NOTE the "int*" to indicate tileGids is a new array of pointers to int.
for (int i = 0; i < width; i++) // Initialize each element in layer.tileGids[] to be a pointer to int.
{
layer.tileGids[i] = new int[height];
}
Now you can access the items in layer.tileGids using:
int value = layer.tileGids[x][y] // where 0 <= x < width and 0 <= y < height
To deallocate this data structure, similar to how you allocate it, you need to deallocate each dynamically allocated array in each "row":
for (int i = 0; i < width; i++)
{
delete [] layer.tileGids[i]; // Deallocate each row.
}
delete [] layer.tileGids; // Deallocate "array" to the pointers itself.
Method 2:
Now another easier, less messy method (avoid pointers) is to use the C++ vector class. You need to make the following changes:
#include <vector>
class Layer {
vector<vector<int> > tileGids; // Note the space at "<int> >".
}
To initialize:
int width = map->mapSize.width;
int height = map->mapSize.height;
layer.tileGids = vector<vector<int> >(width, vector<int>(height, 0)); // Initialize all entries to 0.
To access the elements:
int value = layer.tileGids[x][y]; // Where 0 <= x < width and 0 <= y < height
Note that for the second method using vectors, you do not have to do any memory cleanup as is required in the first method because the vector will automatically take care of it. However, because a vector can grow dynamically i.e. you can add items to it, you lose the safety of having a fixed size array i.e. someone could accidentally increase the size of your grid if you use the vector method but if he tries to do that when you intialized it using the first method above an error will occur and you will immediately know that something is wrong.
Can someone please point out what I am doing wrong in the following code?
A lot. You're allocating two single arrays (a "row array" and a "column array", not what you need), and then you try to do something strange.
Generally you can't (strictly speaking) dynamically allocate a 2D array in C++ (because the type system would still need the type, along with the dimensions, to be known at compile time). You can emulate it with an array of arrays or so, but the best way is to allocate an 1D array:
int width=5;
std::vector<int> tab(width*height);
and then access the element by calculating the coordinates manually:
// access the element (1,2)
tab[1 + 2*width] = 10;
This way you're essentially interpreting a 1D array as a 2D array (with performance equal to static 2D arrays).
Then it's best to wrap the indexing with a class for convenience; boost::multi_array also has this done for you already.
a and b are int* here:
layer->tileGids = new int[a][b];
Perhaps you meant to say this?
layer->tileGids = new int[*a][*b];