Allegro.cc - Online Community

Allegro.cc Forums » Programming Questions » Is there a way to use CSV files within a tile game?

This thread is locked; no one can reply to it. rss feed Print
 1   2   3 
Is there a way to use CSV files within a tile game?
Ryan Rees-Williams
Member #13,825
December 2011

[SOLVED]
I have been busy making some simple games for a while now, all completed bar a start and end screen but now I want to take the leap into tile based code and am looking for a way to implement CSV files in my code as I find these the most easy to understand in a text editor.

I.E. a level file could be something like:

0,0,0,0,0,0,0,0,0,0,0,0,0,0,9
0,0,0,1,1,1,1,1,1,1,1,0,0,0,9
0,0,0,0,0,0,0,0,0,0,0,0,0,0,9
1,1,1,1,1,0,0,0,0,1,1,1,1,1,9
0,0,0,0,0,0,0,0,0,0,0,0,0,0,9
1,1,1,1,1,1,1,1,1,1,1,1,1,1,9

ones indicating a solid surface, zeros indication nothing and nines indicating the end of a line.

Are there any libraries capable of handling a CSV file that anyone could point me in the direction of? Thanks!

CursedTyrant
Member #7,080
April 2006
avatar

Eh? Why not just read the file directly and store the tile value in a Tile class object (or even a 2D integer array if you want something really simple)?

I hear Mappy is quite good. It even generates C++ code IIRC.

---------
Signature.
----
[My Website] | [My YouTube Channel]

Ryan Rees-Williams
Member #13,825
December 2011

Not quite what I'm after, I've tried using fstream.h (the standard file handling header for C++) with a CSV file and it will simply not work, it even BSOD'd me once which is a clear indication to me that it's not designed to work with CSV files (unless I'm doing something very wrong)

CursedTyrant
Member #7,080
April 2006
avatar

If it's a .csv file saved in some other program, I suppose you would have to know the exact file format info to know how to handle said file. Failing that, there is nothing preventing you from just using .txt files containing comma separated tile values like in the first post.

If all you want is to use a text editor and have data in a CSV-like format, there is no reason not to use a .txt file if it's the easier alternative, especially while using a monospaced type font in your text editor of choice.

---------
Signature.
----
[My Website] | [My YouTube Channel]

gnolam
Member #2,030
March 2002
avatar

CursedTyrant: CSV is plain text. Containing comma-separated values. The extension does not matter.

I've tried using fstream.h (the standard file handling header for C++) with a CSV file and it will simply not work, it even BSOD'd me once which is a clear indication to me that it's not designed to work with CSV files

That... makes no sense whatsoever, I'm afraid. First off, file streams simply read/write data. File formats do not concern them - that's for you to handle.
Second, if you're on a reasonably modern OS (XP era or later), you just should not be able to cause a BSOD with a regular program. If you can, something is broken with your system (cue the Linux trolls in 5... 4... 3... :P).

--
Move to the Democratic People's Republic of Vivendi Universal (formerly known as Sweden) - officially democracy- and privacy-free since 2008-06-18!

Ryan Rees-Williams
Member #13,825
December 2011

guess the BSOD was just a coincidence then, I know Windows 7 is not a crash prone OS so I'll have to look into that.
Should I be reading the data the same way that I would read some return separated variables like

read item[0].qty
read item[0].name
read item[0].price
read item[1].qty
read item[1].name
read item[1].price
read item[2].qty
read item[2].name
read item[2].price
read item[3].qty
read item[3].name
read item[3].price

and trust fstream.h to understand how the information is to be read differently?

Edgar Reynaldo
Major Reynaldo
May 2007
avatar

I've tried using fstream.h (the standard file handling header for C++) with a CSV file and it will simply not work, it even BSOD'd me once which is a clear indication to me that it's not designed to work with CSV files (unless I'm doing something very wrong)

You're doing something very wrong. fstream will NEVER, I repeat NEVER give you a BSOD. Something else is causing that.

Your best bet is to use std::string::getline(istream& is) and then create a vector of values (or use an array is the size is predetermined) by using sscanf on the c_str().

Example :

#SelectExpand
1std::vector<std::vector<int> > ReadCSV(const char* csvfile) { 2 std::ifstream in(csvfile); 3 if (!in) {throw -1;} 4 string line; 5 int value; 6 int charcount = 0; 7 int n = 0; 8 int nitems = 0; 9 std::vector<std::vector<int> > map; 10 while (!in.eof()) { 11 std::vector<int> row; 12 line.getline(in); 13 const char* cstr = line.c_str(); 14 charcount = 0; 15 while (charcount < line.size()) { 16 nitems = sscanf(cstr , "%i%n" , &value , &n); 17 if (nitems != 1) {throw -2;} 18 row.push_back(value); 19 cstr += n + 1;// number of characters in the number + 1 to skip the comma; 20 charcount += n + 1; 21 } 22 map.push_back(row); 23 } 24 return map; 25}

Use :

vector<vector<int> > map;
try {
   map = ReadCSV("map.txt");
}
catch (int i) {
   cout << "Error " << i << " occurred during ReadCSV." << endl;
   return -1;
}

Ryan Rees-Williams
Member #13,825
December 2011

wow that just threw me right off, I have absolutely no idea what's going on in that code, is there any chance you could break down what's there at all? for example, I see your returning 'map', should I be using this as an int function?

james_lohr
Member #1,947
February 2002

I don't understand how you could have a nearly complete game but be incapable of parsing a CSV using regular C/C++. :P

Ryan Rees-Williams
Member #13,825
December 2011

so far I've been hard coding the levels in my games :P I know, I'm a naughty and messy programmer hangs head in shame

Edgar Reynaldo
Major Reynaldo
May 2007
avatar

wow that just threw me right off, I have absolutely no idea what's going on in that code, is there any chance you could break down what's there at all? for example, I see your returning 'map', should I be using this as an int function?

Well, since you asked :

#SelectExpand
1// The ReadCSV function takes a file name string and returns a vector of integer vectors 2std::vector<std::vector<int> > ReadCSV(const char* csvfile) { 3 std::ifstream in(csvfile);// create our input file stream 4 if (!in) {throw -1;}// test to make sure the stream is working 5 string line;// for reading each line in the file 6 int value;// for storing each integer read from the string 7 int charcount = 0;// to keep track of how many characters have been read 8 int n = 0;// temp variable storing how many characters were read this time 9 int nitems = 0;// number of items successfully read by sscanf 10 std::vector<std::vector<int> > map;// declare our vector of integer vectors 11 while (!in.eof()) {// while not at the end of the input file stream 12 std::vector<int> row;// create an empty vector of integers 13 line.getline(in);// read a line from the input stream into the string 14 const char* cstr = line.c_str();// get access to the c string 15 charcount = 0;// reset character count to 0 16 while (charcount < line.size()) {// while we're not past the end of the string 17 nitems = sscanf(cstr , "%i%n" , &value , &n);// scan an integer and record the number of characters read 18 if (nitems != 1) {throw -2;}// if we didn't read one integer, we failed 19 row.push_back(value);// add the integer to the vector 20 cstr += n + 1;// number of characters in the number + 1 to skip the comma;// advance the char pointer by n + 1 chars 21 charcount += n + 1;// increase the character count by n + 1 22 } 23 map.push_back(row);// add the vector of integers to our map vector 24 } 25 return map;// return the vector of integer vectors 26}

Quote:

Should I be using this as an int function?

Your question suggests you don't know what a return type is, or you don't know what a vector is. The function returns a 2d array of integers stored in vectors, and you access it with [] notation.

bamccaig
Member #7,536
July 2006
avatar

0,0,0,0,0,0,0,0,0,0,0,0,0,0,9
0,0,0,1,1,1,1,1,1,1,1,0,0,0,9
0,0,0,0,0,0,0,0,0,0,0,0,0,0,9
1,1,1,1,1,0,0,0,0,1,1,1,1,1,9
0,0,0,0,0,0,0,0,0,0,0,0,0,0,9
1,1,1,1,1,1,1,1,1,1,1,1,1,1,9

ones indicating a solid surface, zeros indication nothing and nines indicating the end of a line.

Levels generally don't have "lines" (at least, not in the sense of a newline..). Additionally, the file already has newlines, so I see no need for the special meaning given to the '9'. I also don't really see much need for the commas. You might need the commas if you're going to have enough tiles to require more than one digit per tile (i.e., 0-9 as a single digit is obviously only 10 tiles). If instead you use a single printable ASCII character per tile, for example, then that's 95 tiles. I think that there are relatively few tile-based games that require more than 95 tiles for a single level.

That is easier to parse because each character is either a tile, or a control character (e.g., newline to trigger the y coordinate incrementing). It's easy to read and write in plain text, meaning that you can easily edit the levels with a plain text editor. I think I made a similar suggestion here that you may or may not find useful.

If you do opt to use a delimited list then you might still prefer not to call them CSV files. There are many 'standards' for CSV files and you may get people trying to use incompatible formats with your software if you call them CSV files. For example, sometimes the data fields are quoted, sometimes quoting is optional, sometimes white-space (outside of quotes) is ignored, etc.

CursedTyrant
Member #7,080
April 2006
avatar

gnolam said:

CursedTyrant: CSV is plain text. Containing comma-separated values. The extension does not matter.

I thought MS Excel saved CVS files a little bit differently, with some sort of additional data, but I guess not :). I suppose that wouldn't make any sense.

---------
Signature.
----
[My Website] | [My YouTube Channel]

torhu
Member #2,727
September 2002
avatar

Are there any libraries capable of handling a CSV file that anyone could point me in the direction of? Thanks!

C++ makes it easy to read whitespace-separated values, you could just replace the commas with spaces or tabs.

Here's roughly how to do it:

  1. Read one line from the file using ifstream's getline() function.

  2. Put the line into an istringstream object.

  3. Read the values one at a time with istringstreams's operator>>. You can read into an int variable directly (iss >> someint).

  4. GOTO 1

Add some error checking and a test for when you should exit the loop, and you're good to go :)

Ryan Rees-Williams
Member #13,825
December 2011

Thanks for the replies guys, I'm going to have a go at using white space instead of commas and try out the getline() function that torhu suggested and give csv reading a go once I'm back at college (seems just a tad complicated for someone with my level of experience right now), thanks again :)

torhu
Member #2,727
September 2002
avatar

By the way, if you just need one (or a fixed number of) character(s) per tile, it would be easier to do what bamccaig suggested.

Your data would then look like this:

00000000000000
00011111111000
00000000000000
11111000011111
00000000000000
11111111111111

You could read one line at a time with getline, check that the length is correct, that all values are valid, etc. But you wouldn't need to parse it using istringstream or anything else, you can just use the values directly.

Ryan Rees-Williams
Member #13,825
December 2011

Thanks, I'm learning getline from the links you posted although I'm running into brick walls, I feel I'm so close to reading a line but I just can't seem to get rid of one error without causing another

#SelectExpand
1 2#include <iostream> 3#include <fstream> 4 5using namespace std; 6 7int main() 8{ 9 ofstream out_stream; 10 ifstream in_stream; 11 12 int coord[100][100], currentx, currenty, numtiles, line; 13 14 in_stream.open("test.txt"); 15 16 getline(in_stream,line); 17 cout << line; 18 19 in_stream.close(); 20 21 /*cout << coord[0][0] << " "; 22 cout << coord[1][0] << " "; 23 cout << coord[2][0] << " "; 24 cout << coord[3][0] << " "; 25 cout << coord[4][0] << " "; 26 cout << coord[5][0] << endl; 27 cout << coord[0][1] << " "; 28 cout << coord[1][1] << " "; 29 cout << coord[2][1] << " "; 30 cout << coord[3][1] << " "; 31 cout << coord[4][1] << " "; 32 cout << coord[5][1] << endl; 33 cout << coord[0][2] << " "; 34 cout << coord[1][2] << " "; 35 cout << coord[2][2] << " "; 36 cout << coord[3][2] << " "; 37 cout << coord[4][2] << " "; 38 cout << coord[5][2] << endl;*/ 39}

I'm possibly making more silly "noob" mistakes again that will be a very conspicuous and obvious error to you :P
btw the error for the code as it is now is: error: no matching function for call to 'getline(std::ifstream&, int&)' I have searched solutions for it online but everybody else seems to be using strings instead of integers

gnolam
Member #2,030
March 2002
avatar

I have searched solutions for it online but everybody else seems to be using strings instead of integers

Exactly. Therefore, the error is..?

You're passing an integer where the function expects a string reference.
This is what your error message is saying: error: no matching function for call to 'getline(std::ifstream&, int&)
In plain English: "no function called getline() exists that takes an std::ifstream reference and an int reference". This is what actually exists.


You can't just treat the language like magic. If a function takes one type as an argument, you can't pass it a completely different one and expect it to magically make whatever you intended work.
You need to read a book on C++. There are free ones.

--
Move to the Democratic People's Republic of Vivendi Universal (formerly known as Sweden) - officially democracy- and privacy-free since 2008-06-18!

Ryan Rees-Williams
Member #13,825
December 2011

Right, I changed it to a string and it's reading from the file just fine now :) as the number is a string will I have to convert them to integers for them to work with mathematical stuff like if statements to determine which tile is what kind?
EDIT
I have read lots of books on C++ and found them for the most part useless as they give you code and explain what it does in very technical terms without even including pages at the back explaining say, what an array actually means.
It was all nonsense while I was reading it and I only started understanding C++ properly once I had somebody (my college tutor in my case) telling me what my goal was and what headers and functions I had to use, I would get a basic explanation of what was what and then expected to figure out how it fits together.
If I ran into a long-term bug I would ask and be pushed in the right direction and sort the bug out myself.
Books in my experience are written by people with a false notion of self-superiority and rarely understand that new-comers simply won't understand what they are talking about if they don't explain it in more simple terms

Specter Phoenix
Member #1,425
July 2001
avatar

what an array actually means.

What do you mean? Single arrays are just lists and 2D+ are tables (the higher the dimensions the more tables in tables you have).

Ryan Rees-Williams
Member #13,825
December 2011

yes but to somebody learning a new bit of C++ that will mean nothing but nonsense, people learning can't just have a load of technical terms thrown at them and be expected to know how they work without explaining what each term is and how the interact with code, books I find are very bad at this

An update on what my code is like right now:

#SelectExpand
1#include <iostream> 2#include <fstream> 3#include <sstream> 4 5using namespace std; 6 7int main() 8{ 9 ofstream out_stream; 10 ifstream in_stream; 11 12 int coord[1][1], currentx, currenty, numtiles, howtall; 13 string stuff[3], gettall; 14 15 in_stream.open("test.txt"); 16 17 getline(in_stream,gettall); 18 stringstream convert(gettall); 19 if (!(convert >> howtall)) 20 { 21 howtall = 0; 22 } 23 24 getline(in_stream,stuff[0]); 25 getline(in_stream,stuff[1]); 26 getline(in_stream,stuff[2]); 27 28 cout << howtall << endl; 29 cout << stuff[0] << endl; 30 cout << stuff[1] << endl; 31 cout << stuff[2] << endl; 32 33 in_stream.close(); 34}

Reading from the file is now fine, and I am able to convert the first variable (the one that determines how high the level is), finally some progress has been made ^^ now ill have a go at converting the other lines to integers and separating each number to different variables :)

CursedTyrant
Member #7,080
April 2006
avatar

yes but to somebody learning a new bit of C++ that will mean nothing but nonsense, people learning can't just have a load of technical terms thrown at them and be expected to know how they work without explaining what each term is and how the interact with code, books I find are very bad at this

Why not look it up, then? http://cplusplus.com/doc/tutorial/arrays/

Also, you can find almost anything you want to know about C++ on those two sites, and most of it is explained clearly:

http://en.cppreference.com/w/cpp
http://cplusplus.com/

---------
Signature.
----
[My Website] | [My YouTube Channel]

Ryan Rees-Williams
Member #13,825
December 2011

I meant that as a generalisation, and by going into websites I am no longer learning form a book, and it's very unlikely that a book will have links to a website, it could have been any kind of term I used but my point is books are terrible for teaching completely new people C++ as they are full of technical mumbo jumbo.
I personally know exactly what an array is don't worry about that but any new term I come across in a book might as well be written in Japanese until I find out what it does to code, and more often than not books will not give you simplified terminology or any hints to what something does

Anyway this has gone a bit off-topic, lets bring it back onto rails for a bit yes? :P

Specter Phoenix
Member #1,425
July 2001
avatar

yes but to somebody learning a new bit of C++ that will mean nothing but nonsense, people learning can't just have a load of technical terms thrown at them and be expected to know how they work without explaining what each term is and how the interact with code, books I find are very bad at this

What? Arrays is an easy concept compared to the rest of the concepts in C++. If your books didn't explain that clear enough you need to start investing money in a Computer Science course book (pricey but worth it). Computer programming is technical. Most technical terms are self explanatory, and those that aren't normally are defined. Most books introduce the terminology in early chapters and build on it while using them throughout the book they stay in your head. What books are you reading? I've read and own tons of books and the ones I have read have never just thrown technical terms in without explaining them.

Lastly, like CursedTyrant pointed out, if you run into a term you don't know then ask or look it up online to get an understanding of it. Actually, term really isn't the proper word, array is more a feature that goes with a concept (lists and tables, data tables, etc).

Anyway this has gone a bit off-topic, lets bring it back onto rails for a bit yes?

After you have been here a while you will realize we seldom stay on topic in any thread :P.

torhu
Member #2,727
September 2002
avatar

now ill have a go at converting the other lines to integers and separating each number to different variables :)

You don't really need to do that. This will work:

if (stuff[linenum][tilenum] == '1')
    cout << "it's a one!\n";
else if (stuff[linenum][tilenum] == '0')
    cout << "it's a zero!\n";

Each element in a string is a value of type char, which you can compare to a character literal.

 1   2   3 


Go to: