Text-based game, saving progress into some file, .sav? How to?

This is a discussion on Text-based game, saving progress into some file, .sav? How to? within the C++ Programming forums, part of the General Programming Boards category; Presumably, he wants the data he has written to the file. You aren't breaking up the data to allow the ...

  1. #16
    Master Apprentice phantomotap's Avatar
    Join Date
    Jan 2008
    Posts
    4,260
    Presumably, he wants the data he has written to the file.

    You aren't breaking up the data to allow the streams to process it in text mode.

    Can you tell that the output (123123) is supposed to be parsed separately (1 2 3 1 2 3)?

    Yea, neither can the computer.

    Soma

  2. #17
    Novice programmer newn's Avatar
    Join Date
    Aug 2010
    Posts
    59
    Well, i want to write the variables somehow (I think each variable in each line would be the best thing to do) to read them. Then read them one by one. Like save HP, armor, items, quests.

    Oh, didn't noticed the second page. Hmmm, how can i break it in int mode? You cannot use "\n" in int mode...
    Last edited by newn; 09-21-2010 at 10:12 AM.

  3. #18
    a guy with long hair Xupicor's Avatar
    Join Date
    Sep 2010
    Location
    Poland
    Posts
    103
    newn, maybe you should look at this code. It saves only one player, but you should get the idea how simple writing and reading to a text file would work. Note, that saving the state of an entire game would be proportionally harder, and you probably would want to lets say input a number of players (npcs?) that are saved, and then loop the loading process, in that, probably the lists of objects would be loaded the same with their own stats. You could actually do that pretty easily with overloading operator<< for Player, Item and other classes (and using it at the "highest level" like... file << world. Surely you're doing it a bit different, but well, I still hope it'll help a bit.

    Code:
    #include <iostream>
    #include <fstream>
    #include <string>
    
    class Player {
    private:
        std::string name;
        unsigned int exp;
        int hp, mp, strength, dexterity, speed;
        double someStat;
    
    public:
        Player () : exp(0), hp(0), mp(0), strength(0), dexterity(0), speed(0),
                someStat(0.0) {}
        Player (const std::string& player_name) : name(player_name), exp(0), hp(0),
                mp(0), strength(0), dexterity(0), speed(0), someStat(0.0) {}
        ~Player() {}
    
        void save(const std::string& filename) {
            std::ofstream ofs(filename.c_str(), std::ios::trunc);
            ofs << name << "\n" << exp << " " << hp << " " << mp << " " << strength
                    << " " << dexterity << " " << speed << " " << someStat << "\n";
        }
    
        void load(const std::string& filename) {
            std::ifstream ifs(filename.c_str());
            std::getline(ifs, name);
            ifs >> exp >> hp >> mp >> strength >> dexterity >> speed >> someStat;
        }
    
        void fillExampleData() {
            exp = 1288;
            hp = 121;
            mp = 207;
            strength = 102;
            dexterity = 133;
            speed = 83;
            someStat = 45.87;
        }
    
        void print() {
            std::cout << "Player name: " << name << "\nhp: " << hp
                    << "\nmp: " << mp << "\nstrength: " << strength
                    << "\ndexterity" << dexterity << "\nspeed: " << speed
                    << "\nsomeStat: " << someStat << "\n";
        }
    };
    
    int main() {
        std::string fname = "brian.sav";
    
        Player brian("Brian the Batman Guy");
        brian.fillExampleData();
        brian.save(fname);
        brian.print();
        std::cout  << "\n\n";
    
    
        Player somebody;
        somebody.load(fname);
        somebody.print();
    
        return 0;
    }
    Last edited by Xupicor; 09-21-2010 at 01:35 PM. Reason: Got rid of the operator<<, made it into print() method.

  4. #19
    C++まいる!Cをこわせ! Elysia's Avatar
    Join Date
    Oct 2007
    Posts
    22,604
    You really should overload operator << and >> to save/load from files.
    Remember, though cout and cin may be streams, so are files! I could call << to save the object into a file, and not cout. Therefore, operator << should be overloaded to write the data to file.
    Or even better, we should be using Boost.Serialization.
    I will probably write an example of that sometime.
    Quote Originally Posted by Adak View Post
    io.h certainly IS included in some modern compilers. It is no longer part of the standard for C, but it is nevertheless, included in the very latest Pelles C versions.
    Quote Originally Posted by Salem View Post
    You mean it's included as a crutch to help ancient programmers limp along without them having to relearn too much.

    Outside of your DOS world, your header file is meaningless.

  5. #20
    Registered User
    Join Date
    Mar 2008
    Location
    Coimbra, Portugal
    Posts
    85
    Let me add that when I first learned similar things, I had quite a lot of trouble.

    The fact is that, for someone to clearly understand (I'm talking more C than C++) the methods behind saving structures and "players" to files, that someone will have to really understand what variables are -- bytes in memory. Only if you can clearly "decode" your variables, will you understand that writing data to a file can just be writing raw binary data kept in memory, which you will then read to the address of a variable, filling it up. Then there's pointers and C-strings, You can't just write the memory of the address, because that's another address (the one that it points to, which can change at runtime), so you need to write the string itself, be it using a fixed-length or another method for finding the length of a string.

    If you manage to clearly visualize how data is in memory (i.e: What memory is, what's an address, what data is stored in each of the bytes that hold the variable, etc...). Of course, that may just be my case, but I didn't really feel like I had learned it until I acquired all of these concepts. Once you do, it should be pretty damn easy -- similar (or almost identical) to sending data through sockets.

  6. #21
    C++まいる!Cをこわせ! Elysia's Avatar
    Join Date
    Oct 2007
    Posts
    22,604
    You have absolutely no need to learn all of that. That is the beauty of C++.
    We work on a object basis. And an object is self contained. That is, we don't need to know how it works internally to use it. We would expect to use the << operator to save it to a file, and the >> operator to read it from a file. The object, in turn, would do the same to all its members.
    Unfortunately, this doesn't work properly with some types which doesn't have these types defined. And in steps boost. I'll give a brief tutorial on how to use Boost.Serialization and how powerful it really is.

    Now, the first thing we have to learn are archives. These objects does the magic behind everything. They write or read data from a file.
    There are two variants: iarchive (reads data) and oarchive (writes data).
    These objects also want a file where to read or write the data. They take an istream/ostream object for this. After creating them, we can simply use the << or >> operator to read/write an object. Simple!
    Archive should support must built-in C++ objects. Example:

    Code:
            std::ifstream _File("My file.txt");
            boost::archive::text_iarchive Serializer(_File);
            Serializer >> m_TaskList;
    This would read into an object called m_TaskList.
    Similarly,

    Code:
            std::ofstream _File("My file.txt");
            boost::archive::text_oarchive Serializer(_File);
            Serializer << m_TaskList;
    This would write m_TaskList to the file.
    m_TaskList is actually an object, consisting of several members. But we don't need to know what it contains, because Boost.Serialize will do everything for us.

    Now, when we deal with user-defined types, we must naturally tell Boost how to serialize them. This isn't difficult.
    All that is basically required is that we add this to the class/struct:
    Code:
    protected:
        friend class boost::serialization::access;
    
        template<typename Archive>
        void serialize(Archive & ar, const unsigned int version)
        {
            ar & Title;
            ar & Executable;
            ar & CmdLine;
        }
    We don't want the outside to access this member, so we make it protected (private is also fine). Since boost needs access to this function, though, we declare it a friend.
    So basically we define a function that as its first argument takes a boost serialization object. We don't care what type of object it is, so we make it an arbitrary type. The next argument is the version of the library; we can ignore that.
    Next we just serialize all the members by the archive & syntax.
    And that's all!

    Taking Xupicor's example:
    EDIT: Xupicor made some fixes to the code. Recommend looking at that code now instead.
    Last edited by Elysia; 09-21-2010 at 01:37 PM.
    Quote Originally Posted by Adak View Post
    io.h certainly IS included in some modern compilers. It is no longer part of the standard for C, but it is nevertheless, included in the very latest Pelles C versions.
    Quote Originally Posted by Salem View Post
    You mean it's included as a crutch to help ancient programmers limp along without them having to relearn too much.

    Outside of your DOS world, your header file is meaningless.

  7. #22
    a guy with long hair Xupicor's Avatar
    Join Date
    Sep 2010
    Location
    Poland
    Posts
    103
    Quote Originally Posted by Elysia View Post
    You really should overload operator << and >> to save/load from files.
    Remember, though cout and cin may be streams, so are files! I could call << to save the object into a file, and not cout. Therefore, operator << should be overloaded to write the data to file.
    You are very right about that, and looking at the code, I did overload of operator<< in toString() style, just out of habit, but I could just as easily remake the save()/load() with overloaded operator<</>> and it would work the same with files as load/save methods do.

    Now, why I did load and save as methods instead? For clarity (my mistake that I used operator<< in all this, like I said, out of habit...) - because I have no idea if newn even knows enough about operator overloading, classes and methods. And if he doesn't, I felt it would be much easier to understand the code with save/load methods, instead of overloaded operators.

    edit:
    Elysia, I'd argue if it makes sense to print it or not - in an "test/example environment" it only makes sense to see by yourself what the players stats are, just to see if it really works. You sure could also use debugger to achieve this. It's nothing to do with actual logic of the game, it's just to test the very situation we have here, i.e. loading the player data back from a file correctly.
    Now, that said, you posted a great example here, I just cleaned it of one leftover mistake and #included needed files (at least I need them to compile correctly). One should also be aware of the need to link it with "boost_serialization" (libboost_serialization.a) library.
    Now it's a proper example, which will compile (remember about linking!) and show you that it works properly.

    Code:
    #include <iostream>
    #include <fstream>
    #include <string>
    #include <boost/archive/text_iarchive.hpp>
    #include <boost/archive/text_oarchive.hpp>
    
    class Player {
    protected:
        std::string name;
        unsigned int exp;
        int hp, mp, strength, dexterity, speed;
        double some_stat;
    
    public:
        Player () : exp(0), hp(0), mp(0), strength(0), dexterity(0), speed(0),
                some_stat(0.0) {}
        Player (const std::string& player_name) : name(player_name), exp(0), hp(0),
                mp(0), strength(0), dexterity(0), speed(0), some_stat(0.0) {}
        ~Player() {}
    
        template<typename Archive>
        void serialize(Archive & ar, unsigned int /* Don't need this */)
        {
            ar & name;
            ar & exp;
            ar & hp;
            ar & mp;
            ar & strength;
            ar & dexterity;
            ar & speed;
            ar & some_stat;
        }
    
        void FillExampleData()
        {
            exp = 1288;
            hp = 121;
            mp = 207;
            strength = 102;
            dexterity = 133;
            speed = 83;
            some_stat = 45.87;
        }
    
        void print () {
            std::cout << "Player name: " << name << "\n exp: " << exp 
                    << "\n hp: " << hp << "\n mp: " << mp << "\n strength: "
                    << strength << "\n dexterity: " << dexterity << "\n speed: "
                    << speed << "\n someStat: " << someStat << "\n";
        }
    };
    
    int main() {
        std::string fname = "brian.sav";
    
        Player brian("Brian the Batman Guy");
        brian.FillExampleData();
    
        std::ofstream file(fname.c_str());
        boost::archive::text_oarchive serializer(file);
        serializer << brian;
        file.close(); //explicitly close the file, just a preference, not to open the same file second time with another stream.
    
        brian.print();
        std::cout << "\n\n";
    
    
        std::ifstream file2(fname.c_str());
        Player somebody;
        boost::archive::text_iarchive serializer2(file2);
        serializer2 >> somebody;
        somebody.print();
    
        return 0;
    }
    Last edited by Xupicor; 09-21-2010 at 05:10 PM.

  8. #23
    C++まいる!Cをこわせ! Elysia's Avatar
    Join Date
    Oct 2007
    Posts
    22,604
    Quote Originally Posted by Xupicor View Post
    Now, why I did load and save as methods instead? For clarity (my mistake that I used operator<< in all this, like I said, out of habit...) - because I have no idea if newn even knows enough about operator overloading, classes and methods. And if he doesn't, I felt it would be much easier to understand the code with save/load methods, instead of overloaded operators.
    True, but then one can argue to you shouldn't have put your << operator at all in the class
    You should have made a ToString method.
    Quote Originally Posted by Adak View Post
    io.h certainly IS included in some modern compilers. It is no longer part of the standard for C, but it is nevertheless, included in the very latest Pelles C versions.
    Quote Originally Posted by Salem View Post
    You mean it's included as a crutch to help ancient programmers limp along without them having to relearn too much.

    Outside of your DOS world, your header file is meaningless.

  9. #24
    a guy with long hair Xupicor's Avatar
    Join Date
    Sep 2010
    Location
    Poland
    Posts
    103
    Quote Originally Posted by Elysia View Post
    True, but then one can argue to you shouldn't have put your << operator at all in the class
    You should have made a ToString method.
    Yeah, I wrote that too, mea culpa (sorry, not thinking that clearly these days, the flu got me). I'll probably clean that out, even though your example is what newn should follow.

  10. #25
    C++まいる!Cをこわせ! Elysia's Avatar
    Join Date
    Oct 2007
    Posts
    22,604
    Quote Originally Posted by Xupicor View Post
    Elysia, I'd argue if it makes sense to print it or not - in an "test/example environment" it only makes sense to see by yourself what the players stats are, just to see if it really works. You sure could also use debugger to achieve this. It's nothing to do with actual logic of the game, it's just to test the very situation we have here, i.e. loading the player data back from a file correctly.
    Yeah, probably should just have named it appropriately instead of using the operators.

    Now, that said, you posted a great example here, I just cleaned it of one leftover mistake and #included needed files (at least I need them to compile correctly). One should also be aware of the need to link it with "boost_serialization" (libboost_serialization.a) library.
    Now it's a proper example, which will compile (remember about linking!) and show you that it works properly.
    Good work
    I'll just refer to your example instead of my slightly incorrect. I didn't compile/run it, of course, so there was probably some problems that you corrected.
    Also, you're right that you need to link against the library file (which unfortunately also means compiling boost or using an outdated version), but the filename of the library file may vary. Mine is called "libboost_serialization-vc100-mt.lib", for example. You're probably referring to a Linux-style library file.
    Quote Originally Posted by Adak View Post
    io.h certainly IS included in some modern compilers. It is no longer part of the standard for C, but it is nevertheless, included in the very latest Pelles C versions.
    Quote Originally Posted by Salem View Post
    You mean it's included as a crutch to help ancient programmers limp along without them having to relearn too much.

    Outside of your DOS world, your header file is meaningless.

  11. #26
    Registered User
    Join Date
    Mar 2008
    Location
    Coimbra, Portugal
    Posts
    85
    Quote Originally Posted by Elysia View Post
    You have absolutely no need to learn all of that. That is the beauty of C++.
    Yes, indeed, hence why I said I was talking more about C than about C++ and, specifically, about my particular learning case. C++ makes all that transparent, like you said, it makes it beautiful.

    Now if you're left with plain C...things aren't that easy...and I think it's helpful to understand what happens / exists "behind the scenes".
    Last edited by Jorl17; 09-21-2010 at 01:59 PM.

  12. #27
    C++まいる!Cをこわせ! Elysia's Avatar
    Join Date
    Oct 2007
    Posts
    22,604
    Quote Originally Posted by Jorl17 View Post
    ...and I think it's helpful to understand what happens / exists "behind the scenes".
    Perhaps. But certainly not to a newbie.
    Only in later stages of one's exploration of the language will that become helpful to you.
    But even then, it is never as needed/helpful as in C.
    Quote Originally Posted by Adak View Post
    io.h certainly IS included in some modern compilers. It is no longer part of the standard for C, but it is nevertheless, included in the very latest Pelles C versions.
    Quote Originally Posted by Salem View Post
    You mean it's included as a crutch to help ancient programmers limp along without them having to relearn too much.

    Outside of your DOS world, your header file is meaningless.

  13. #28
    a guy with long hair Xupicor's Avatar
    Join Date
    Sep 2010
    Location
    Poland
    Posts
    103
    Quote Originally Posted by Elysia View Post
    Yeah, probably should just have named it appropriately instead of using the operators.
    Aye, the very root of the misunderstanding. My fault entirely. But worry not, I'm fighting the darn flu, and soon enough, I'll get my reasoning straight once more.

    Quote Originally Posted by Elysia View Post
    [...]you're right that you need to link against the library file (which unfortunately also means compiling boost or using an outdated version), but the filename of the library file may vary. Mine is called "libboost_serialization-vc100-mt.lib", for example. You're probably referring to a Linux-style library file.
    I'm on Windows at the moment, and I use Nuwen MinGW "distro":
    Quote Originally Posted by http://nuwen.net/mingw.html
    My MinGW distribution ("distro") currently contains GCC 4.5.1 and Boost 1.44.0.
    I figure that's the main reason for the difference, since you're using MSVC. And yes, I'd guess it would be very much like on Linux.

  14. #29
    Master Apprentice phantomotap's Avatar
    Join Date
    Jan 2008
    Posts
    4,260
    You have absolutely no need to learn all of that. That is the beauty of C++.
    But even then, it is never as needed/helpful as in C.
    O_o

    The situation is exactly the same in all languages.

    You will need to know how to handle any data stream not managed by an available library if you want to work with that data.

    If a library that manages a data stream is available, you can safely ignore the details.

    If a library that manages a data stream is not available, you must learn the details.

    And you have missed the obvious case of creating your own data stream.

    Soma

  15. #30
    Bored Programmer
    Join Date
    Jul 2009
    Location
    Tomball, TX
    Posts
    407
    Wow your solution is soo different than the one I've been using. I just saved data as strings and then converted the ones I wanted to be ints to ints. Is my method bad?

    Code:
    void Sudoku::SaveGame(string Filename)
    { 
      int a, b; 
      ofstream myfile (Filename.c_str());
      if (myfile.is_open())
      {
        // save the solution
        for(a = 0; a < 9; a++)
        {
          for(b = 0; b < 9; b++)
          {
            myfile << GameBoard[9].Read(a, b);
          }
          myfile <<endl;
        }   
        // save the user's game
        for(a = 0; a < 9; a++)
        {
          for(b = 0; b < 9; b++)
          {
            myfile<< GameBoard[8].Read(a, b);
          }
          myfile << endl;
        }
        myfile.close();
      }
    }
    
    void Sudoku::LoadGame(string Filename)
    {
      // saves the current line in the file 
      string line;
      // an int to track what line we are on.. file is known to have 18 lines 9  
      // lines for sultion then 9 lines for the displayed board
      int linenumber = 0;  
      // assign it 0 instead of one to be compatible with array index row
      ifstream myfile (Filename.c_str());
      // so we can change both boards with one loop
      int boardindex = 9;
      if(myfile.is_open())
      {
          // while its not the end of the file
          while(!myfile.eof())
          {
            getline(myfile,line);
              // change the board to 8 and make rows compatible again
              if(linenumber == 9 && boardindex != 8)
              {
                linenumber = 0;
                boardindex = 8;
              }
            // to prevent the loops from being run on the first space of the last line
            if(linenumber != 9)
            {
              for(int c = 0; c < 9; c++) // runs for 9x for every row.. 
              {
                int temp = -1; // becomes the integar read saved as -1 in case of error
                char ctemp; // a character of the current point in the string
                ctemp = line[c];
                if(ctemp == '0')
                  temp = 0;          
                if(ctemp == '1')
                  temp = 1;
                if(ctemp == '2')
                  temp = 2;
                if(ctemp == '3')
                  temp = 3;
                if(ctemp == '4')
                  temp = 4;
                if(ctemp == '5')
                  temp = 5;
                if(ctemp == '6')
                  temp = 6;
                if(ctemp == '7')
                  temp = 7;
                if(ctemp == '8')
                  temp = 8;
                if(ctemp == '9')
                  temp = 9;
                if(temp < 10 && temp > -1)
                  GameBoard[boardindex].Fill(temp, linenumber, c); 
              }
            }
              linenumber++;        
          }
          myfile.close();
      }
    }
    Stores a current sudoku and its solution then loads a current and its solution. Converts the strings to its individual char and then into a int. I just read about fstreams and this was the solution I came up with. I'm sure its flawed if you feel like pointing out why I'd appreciate it.

Page 2 of 3 FirstFirst 123 LastLast
Popular pages Recent additions subscribe to a feed

Similar Threads

  1. Formatting the contents of a text file
    By dagorsul in forum C++ Programming
    Replies: 2
    Last Post: 04-29-2008, 12:36 PM
  2. C Programming 2d Array Question
    By jeev2005 in forum C Programming
    Replies: 3
    Last Post: 04-26-2006, 03:18 PM
  3. A bunch of Linker Errors...
    By Junior89 in forum Windows Programming
    Replies: 4
    Last Post: 01-06-2006, 01:59 PM
  4. Unknown Memory Leak in Init() Function
    By CodeHacker in forum Windows Programming
    Replies: 3
    Last Post: 07-09-2004, 09:54 AM
  5. Outputting String arrays in windows
    By Xterria in forum Game Programming
    Replies: 11
    Last Post: 11-13-2001, 06:35 PM

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21