# getting certain data from a text file

This topic is 4726 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

## Recommended Posts

Hi guys, currently making a rpg type game and most of its working but i need a way of getting random monster names and values of that monster into the constructor so its a bit more random. Im trying to use the fstream from a txt file like so:
string monstername;
int monsterhealth;
int monsterstr;
int monsterexp;
int monstergold;

ifstream fin("monsters.txt");
fin >> monstername >> monsterhealth >> monsterstr >> monsterexp >> monstergold;
Monster mons(monstername,monsterhealth,monsterstr,monsterexp,monstergold);


all works well with one line of the text which is formated like so: Goblin 20 2 100 100 now lets say i wanted to use a random number to pick a random line out of the text file. i prefix my monsters in my text file so i can search for something like so: 1.Goblin 20 2 100 100 2.bunny 20 4 100 100 3.foo 20 20 100 100 would there be a way to search for "2." then start reading from the file? cheers lone.

##### Share on other sites
There are various (more or less efficient) ways of doing this directly from a file. But in this case it's probably a better idea to parse the file on startup and save the lines into a list of monster structures instead.

##### Share on other sites
umm.. by monster structures do you mean an array of monster instances? :| what exactly is a structure and how do i declare one?

any help appreciated
lone

##### Share on other sites
Quote:
 Original post by Lonefox1umm.. by monster structures do you mean an array of monster instances? :| what exactly is a structure and how do i declare one?
Yes, a list of monster instances. But in this case it'd probably be less confusing to refer to them as monster templates or types instead.

A structure is basically just a collection of variables.
struct monster { const char *name; int health; int strength; int experience; int gold;};
Then you can use store a bunch of them in an array (or some other datastructure) and retrieve the right one by its index.

Here's an example using a static array:
const monster monsterTypes[] = { { "first", 100, 50, 10, 250 }, { "second", 200, 100, 20, 500 }};enum { monsterCount = sizeof(monsterTypes) / sizeof(monsterTypes[0])};const monster *randomMonster() { return &monsterTypes[rand() % monsterCount];}
In your case you'd probably want to use a dynamic array, std::vector for example, instead. That way you can simply parse the file line-by-line and add the monsters to your list.

##### Share on other sites
a few questions, where would i declare a struct? i do have a monster class which has functions in it aswell. would i declare it in main, or would i change my monster class to a monster struct? also what would happen to its functions? would it store them in each instance too?

any help appreciated im rather confused with this one!

lone

##### Share on other sites
Your monster class, when written to a file, will just contain the fields, none of the functions, so it should behave just like a struct.

##### Share on other sites
In C++, a struct is the same as a class, just with default public visibility. In fact, structs can have member functions as well as variables. It's just that most people use classes because it makes things look nicer, and struct looks more C-like.

You would declare structs and classes in a header file.

##### Share on other sites
argh!! this is driving me nuts ive been trying to impliment this for the past 3 hours and i havnt a clue how to do it, can someone give me some hints or sumthing? i need to read the values into a structure from a text file containing a name and a few integers for each line as mentioned above. or any other suggestions how to obtain a similar sort of thing would be great too!

any help really appreciated!!!

lone

##### Share on other sites
You don't need to use a structure if you don't want to (especially if you've never worked with them).

Here's one trivial way you could do it:

//inside the text file:

#FILE1 Monster 20 34 20
#FILE2 Bunny 23 32 43
#FILE3 Goblin 32 43 54

//

What you do is make a function that'll read in a character at a time from the file and once it encounters '#', the function then reads in 'F''I''L''E' (as a string or character by character) and saves it into a buffer/array etc., Then you call a function to compare ( strcmp() ) "#FILE1" with the string you just took in and if they're both the same, then you offset however many bytes (characters) there is following " Monster " , in this case, it'll be 9 (7 for monster and 2 for the space before and after the name monster. You then you read in the value 20, 34, 20 etc... If the two strings being compared are'nt the same, then you just continue reading in the next character following "#FILE1". This way, you don't have to read in the whole file into your program [wink]

I hope you get what I'm trying to say. I did it this way once when I build my first databes entry program a long time ago and it worked very good.

##### Share on other sites
i had a brain wave :P finally got it working after much frustration.. or atleast the reading it in part. just wanted to run it past you guys to see if im missing any huge mistakes which will bite me on the bum in the future

//monster header file for struct//monster.h header file#ifndef MONSTER_H#define MONSTER_H#include <fstream>#include <vector>#include <iostream>#include <string>struct monster { char name[20]; int health; int strength; int experience; int gold; }monsters[10];#endif

//using it#include <iostream>#include <string>#include <vector>#include <fstream>#include "monster.h"using namespace std;int main(){//Creates a load of monsters-----------------   monster monsterTypes; //new monster structifstream getit("iotest.txt"); //new ifstreamif (getit.bad()) //this doesnt work?{                cerr << "couldnt find file\n";              }for (int i = 0; i < 6; i++) //for get first 6 in files{    getit >> monsters.name;       getit >> monsters.health;        getit >> monsters.strength;        getit >> monsters.experience;       getit >> monsters.gold;}for (int i = 0; i < 6; i++) //output to screen {    cout << monsters.name << "\n";    cout << monsters.health << "\n";    cout << monsters.strength << "\n";    cout << monsters.experience << "\n";    cout << monsters.gold << "\n";} //---------------------------------------------return 0;}

one thing i havnt figured out yet is how to change the array size depending on how many entrys are in the txt file, any suggestions for this would be great

cheers
lone

##### Share on other sites
For that, you would probably want to go with dynamic memory allocation. In C, you use malloc for allocation, and realloc to re size the memory returned from malloc. I think the C++ way for dynamic memory allocation is using the 'new' keyword.

using malloc in C:

char * arr;
int amt_of_entries;

arr = (char*)malloc(amt_of_entries * sizeof(char));

and then you use realloc to change the size.

##### Share on other sites
Quote:
 Original post by Lonefox1i had a brain wave :P finally got it working after much frustration.. or atleast the reading it in part. just wanted to run it past you guys to see if im missing any huge mistakes which will bite me on the bum in the future *** Source Snippet Removed ****** Source Snippet Removed ***one thing i havnt figured out yet is how to change the array size depending on how many entrys are in the txt file, any suggestions for this would be greatcheerslone

Since we are using C++, we are going to use the available facilities, and write stuff with proper C++ style. You actually already have a hint about "changing the array size" - look through your header includes, notice anything you're not actually using? That's right, "string" and "vector". We're going to fix that by using a std::string to represent the "name", and by reading into a std::vector of Monster's instead of an array of them:

Monster.h:
#ifndef MONSTER_H#define MONSTER_H#include <string>// Within the .h file, only #include the stuff that's needed for the .h file.// In our case, that's just the 'string'. It won't cause a problem, but it may// confuse you later to have extra stuff there.// It is usual C++ style to capitalize class names; I do the same with struct// names since in C++, structs and classes are really the same thing (there is// just a bit of syntactic sugar: structs expose data by default while classes// hide it).// It is bad form to actually instantiate anything in your header file, and we// can't use that syntax "struct Name { stuff } thing[10];" with a vector// anyway. (The reason it is bad form is that header guards won't protect you// from getting "multiple definition" errors when you do linking; read// http://www.gamedev.net/reference/articles/article1798.asp for details.)struct Monster {  std::string name; // now we make use of std::string  int health;  int strength;  int experience;  int gold;}; // no Monsters exist yet, we've just said what they look like.#endif

Monster.cpp:
#include <iostream>#include <fstream>#include <vector>#include "monster.h"// I'm not including string here because it's already provided by monster.h;// however, if we were actually to refer to the std::string type explicitly// here, I would include it - don't rely on one header to include another, but// don't include things when you don't need their definitions locally.using namespace std;int main() {  // Now we make use of the 'vector' container to hold our Monsters. For now  // you can just read the angle brackets as "of".  vector<Monster> monsters;  monster current; // a temporary Monster to read into.  ifstream data("iotest.txt");  if (!data.good()) {    // Failed to load file. We should exit the program in this case.    cerr << "couldnt find file\n";    exit(1);    // If this weren't in the main() function of the program, we might throw    // an exception or return an error code instead.             }  // For the entire length of the input file, read in a monster.  // The operator>> can be "chained" as shown: the operation returns the  // stream again. The stream can also be compared like a boolean to see if  // it's still possible to read. So this statement means "while (it is possible  // to) read in all these values into current,".  while (data >> current.name >> current.health >> current.strength >>                  current.experience >> current.gold) {    // And for as long as it is possible to read stuff into current, we should    // then copy the monster into the vector, like this:    monsters.push_back(current);  }  // Now we will output all the vector contents, in a way that should look  // familiar to you. (There are more advanced ways that let you write things  // more neatly and do some cool tricks, but I won't get into that now.)  for (int i = 0; i < monsters.length(); i++) {    // And now we do the same thing as we would have before: the vector    // overloads the operator[] so that it can behave like an array. The    // "length" method simply tells us how many things there are, so that we    // know how far to count up to with i.    cout << monsters.name << "\n";    cout << monsters.health << "\n";    cout << monsters.strength << "\n";    cout << monsters.experience << "\n";    cout << monsters.gold << "\n";  } }

Now, the next trick would be to make the Monster into a "real" object, giving it the ability to be read and written from a stream just like plain numbers or bits of text are (instead of having to read all its fields manually). But - another time :)

##### Share on other sites
nice one Zahlman!! worked like a charm, noticed one thing tho:

"for (int i = 0; i < monsters.length(); i++)"

length() wasnt working for me so i used size(). that all helped alot thanks for that :)

lone

##### Share on other sites
Oops, my mistake :) 'length' is provided as a synonym for 'size' in strings, but not in vectors.