Importing int multi-array from .txt

Jan 5, 2011 at 1:45pm
I am currently working on a big game project, a platform game that uses a tilebased system to load the maps. But the text to load all the (currently) 40*160 tiles is quite large and it's annoying to scroll down. I am also planning on having more maps (I only got 1 currently) and possibly larger maps.

I was thinking that if I write the tiles to a .txt file instead and then use a function to load the tiles from that file. But I got problem with how to load the integers one by one.

I feel like a beginner and that I have taken water above my head. But I still managed to create the platform game (using allegro library), but now I am just confused I got no code that I have tried because I don't know where to start or how to think.

I use a program that writes the tiles (not made by me) they look like this when I load them:
0, 1, 2, 3,
4, 4, 4, 4,
2, 1, 3, 0,

and then I have to add all those {}
{0, 1, 2, 3},
{4, 4, 4, 4},
{2, 1, 3, 0}}:

Now I have searched for a few way of loading from a file, and then how to convert from string to an int. But I am really confused how I take the precise number without the ", " and saving them into my "double-array". I only know a way to save the whole "getline".

I guess it looks just about this way:
*string line;
ifstream myfile ("example.txt");
if (myfile.is_open())
{
while ( myfile.eof() )
{
getline (myfile,line); //(loads 0, 1, 2, 3)


cout << line << endl;

/*convert the string to numbers and save to myInt[i][x], (i is the row and x should increase per each number (it could be good if it is also possible to store numbers with more then 1 digits, ex 13.*/
i++
}
myfile.close();
}

else cout << "Unable to open file";
Jan 5, 2011 at 2:26pm
One way is to treat ',' as white space. Then you can just read the values as normal.

For example:
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
#include <string>
#include <sstream>
#include <fstream>
#include <locale>
#include <vector>

// From:
// http://groups.google.com/group/alt.comp.lang.learn.c-c++/msg/db55ffea728c5cf9?dmode=source
class local_ctype : public std::ctype<char>
{
	// VC++ 7 doesn't make table_size a const, so we use UCHAR_MAX+1
	// instead -- this is kind of a hack, but works well enough for now.
	mask m_table[UCHAR_MAX+1];
public:
	local_ctype(const char* delimiters, size_t refs = 0)
		:	std::ctype<char>(m_table, false, refs)
	{
		// copy the original character classification table.
		std::copy(classic_table(), classic_table() + table_size, m_table);

		// specify white space chars.
		for (const char* p = delimiters; *p; ++p)
			m_table[*p] = (mask)space;
	}
};

struct Row
{
	std::vector<int> values;
};

int main()
{
	std::vector<Row> rows;

	std::locale custom_whitespace(std::locale::classic(), new local_ctype("{},"));
	std::ifstream infile("example.txt");
	infile.imbue(custom_whitespace);

	std::string line;
	while (std::getline(infile, line))
	{
		Row row;
		int value;
		std::istringstream instr(line);
		while (instr >> value)
			row.values.push_back(value);

		rows.push_back(row);
	}

	return 0;
}
Last edited on Jan 5, 2011 at 2:27pm
Jan 5, 2011 at 10:54pm
I got no idea what those std::vector, struct Row does.

To be honest I don't think I understand most of it. I think it's mostly because I have 0 to very little experience with loading from files. (I've only used it once where I stored a string and then loading the stored string. I could then delete those strings via a linked list system. If I remember correctly)

I have also pretty little experience with string types.

Is there a way where you only load each row as a string, and then afterwards splitting it up into int variables and then storing them in the array?
Jan 5, 2011 at 11:21pm
A vector is a dynamicly sized array: http://www.cplusplus.com/reference/stl/vector/

The top part of the page explains it pretty well but I didn't understand it until I tried to use it in code.

EDIT: If you have used linked lists then vectors will feel like a Birthday present.

Is there a way where you only load each row as a string, and then afterwards splitting it up into int variables and then storing them in the array?


A string is and array, so is a vector as I mentioned above. Also yes you can do that, you would declare an array of strings, or a string type vector would be better, then load the data into the array and access each piece by the index number.
Last edited on Jan 5, 2011 at 11:26pm
Jan 6, 2011 at 1:04am
Hm, we learned the linked list in class. And we worked pretty linear with first using a class etc. I just remember we spend a lot of time on this.

Maybe it will be hard to learn on my own. We will see, since I am planning on continuing with this I will try to learn. Will try this tomorrow if I get time. Might take a while for another reply.

*When trying to learn things by yourself, do you got any tips in doing so?

EDIT: I took a quick look at it, and I realized I had no idea what it means with "template". Is this something I need to know more about, or can I just "write it" and then use vectors?
Last edited on Jan 6, 2011 at 1:06am
Jan 6, 2011 at 1:46am
Hi Twilice I think there are two major component in your project. You have a clear idea of the first component and that is the "tile loading" conceptually. The second component is to implement in C++ code based on your first component concept.

It seem you may need to learn more on C++ in particular Standard C++ container, algorithm, iterator etc classes. It is only when you clear this hurdle can you comfortably undertake your second component.

It is the classic program design -> coding -> testing -> release cycle.

You should be at stage 2 coding.
Jan 6, 2011 at 11:06am
To be honest I don't think I understand most of it.
Ok, here we go. I hope this isn't too basic.

A data stream is a sequence of bytes. These can come from memory, from disk, from a terminal, from a network interface and so on. In C++ it's common to treat file operations as streams to/from disk.

C++ provides a family of classes to deal with streams in the I/O Stream Library. The idea is you create the appropriate kind of stream, then read/write to them in a common way. The idea is a powerful one and starts with Multics, but that's another story.

So you use stringstream to deal with streams on memory, fstream to deal with streams on files, and there are a few predefined instances of streams that deal with terminals called cin, cout, cerr, clog.

So to read a number from a terminal you do:
 
    std::cin >> number;

And to read a number from a file:
1
2
    std::iftream in("data.txt");  // create file stream instance
    in >> number;

And to read a number that's in a string:
1
2
3
    std::string str = "77";  // a string with a number
    std::istringstream in(str);  // create a string stream instance
    in >> number;

Enough of that.

As you know, arrays hold sequences of things:
1
2
    std::string string_array[10];  // an array of 10 strings
    int number_array[5];  // an array of 5 ints 

But what if you don't know how many elements you need before hand? That's what std::vector is. It's like an array, but it can grow. It's like arrays because you can use [] to get to each element, and it's like array because it knows what type it is storing. So vector equivalents of the declarations above are:
1
2
    std::vector<std::string> string_vector(10);  // a vector of strings with intial size 10
    std::vector<int> int_vector(5);  // vector of int with initial size 5 

But you add to the end of a vector with push_back. For example:
 
    int_vector.push_back(3);  // add 3 to the end, int_vector now has size 6 

I'll assume you know what struct is.

If you want to read three numbers from a stream that has
 
    1  2  3  4

you can do so with:
1
2
    int n[4];
    std::cin >> n[0] >> n[1] >> n[2] >> n[3];

But what if you want to read:
 
    0, 1, 2, 3,

You have to tell the stream that the comma character as well as the space and tab characters is white space. And that's what lines 7- 25, 36, and 38 do. But I won't explain them.

The rest should be straight forward.
line 37: create an input file instance
line 41: read a line from the input file stream to a string
lines 43-47: read the values from the string into a Row, a vector of ints.
line 49: add the row you just read to a vector of rows.

At the end you're left with a 2D grid of your data that you can access as:
1
2
    rows[3][0];  // row 3, col 0
    unsigned nrows = rows.size(); // I have this many rows 

Jan 6, 2011 at 7:09pm
Thanks, now it's a bit easier to understand. (I will try to use it when/if I have the time)
Topic archived. No new replies allowed.