Thread: A Tale of Two Classes: The Conundrum of Choosing More Modularity or Fewer Definitions

  1. #16
    C++まいる!Cをこわせ!
    Join Date
    Oct 2007
    Location
    Inside my computer
    Posts
    24,654
    You can use switches for these purposes... Even better is to make a function that simply returns the desired string, so you can call it to check peoples' opinions, because they are sure to be such checks in many places.
    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.

  2. #17
    C++ Witch laserlight's Avatar
    Join Date
    Oct 2003
    Location
    Singapore
    Posts
    28,413
    Quote Originally Posted by chaucer345
    Oh, then what did you mean by a vector when you were talking about keeping a master list before?
    You know about std::vector, don't you? And the other standard containers?
    Quote Originally Posted by Bjarne Stroustrup (2000-10-14)
    I get maybe two dozen requests for help with some sort of programming or design problem every day. Most have more sense than to send me hundreds of lines of code. If they do, I ask them to find the smallest example that exhibits the problem and send me that. Mostly, they then find the error themselves. "Finding the smallest program that demonstrates the error" is a powerful debugging tool.
    Look up a C++ Reference and learn How To Ask Questions The Smart Way

  3. #18
    Registered User
    Join Date
    Jul 2012
    Posts
    36
    Quote Originally Posted by laserlight View Post
    You know about std::vector, don't you? And the other standard containers?
    Actually no... would you be kind enough to link to a page explaining that? I found this: vector - C++ Reference , but that doesn't tell me how a storage array could be useful for making a large series of integers more easily transferable between classes.

    You know, I have to say, I've been learning C++ from this site's tutorials mostly and I'm starting to think that those are focused primarily on concepts that easily translate from C. There are some large gaps in my knowledge, especially when it comes to all the useful functions in the std library.

  4. #19
    Lurking whiteflags's Avatar
    Join Date
    Apr 2006
    Location
    United States
    Posts
    9,612
    It has been a long time since I actually visited the sister site. I could swear the site had some information on vector, map and friends when I used the site, but that appears to be gone. Anyway, even when I first started, I carefully selected a book. Since you're being pressured into using the STL, Accelerated C++ comes to mind. It talks about vector as early as chapter 5.

    You may just be taking on more than you can chew at this point but in the spirit of being helpful I will try to turn one of laserlight's suggestions into simple English.

    Quote Originally Posted by laserlight
    a) Keep a master list of Room objects, then each Room will have a list (e.g., a vector) of pointers to the next Room.
    The word list in this statement is just a list and not a data structure as far as I can tell. In fact, vector is recommended. I think I know why vector is recommended: because in the absence of a better idea, vector is one of the simplest data structures. (Simplicity in computing does not always mean poor, by the way.)

    There has to be a direct connection between the simple fact of where the player is and these pointers to other places contained in the individual rooms. One of your game's most basic jobs is to track movement to keep the game going. So, in your mind's eye, if it's possible travel in four directions from the middle room of the game board, you would have the nearest north, south, east and west rooms in the list pertaining to the middle room. If then you went into the south room you would have a different list of options pertaining to that room, including one option to go back.

    It will be important for the rooms to take on responsibilities if you want the game to be organized. Room objects will have to spawn characters and items that belong there, etc, as much as "spawn" can mean in a p&p adventure. That is how you cut down on massive data migration.
    Last edited by whiteflags; 08-03-2012 at 10:00 AM.

  5. #20
    - - - - - - - - oogabooga's Avatar
    Join Date
    Jan 2008
    Posts
    2,808
    Maybe this kind of thing is in order. This is just an example. I've used strings instead of pointers to "link" things.

    Code:
    typedef map<string,Item>      ItemMap;
    typedef map<string,Room>      RoomMap;
    typedef map<string,Character> CharacterMap;
    
    ItemMap      items;
    RoomMap      rooms;
    CharacterMap characters;
    
    class Thing
    {
      string       name;
      string       description;
      string       location;    // room or character name
      list<string> history;
    };
    
    class Room : public Thing
    {
      list<string>  objects;
      list<string>  characters;
      list<string>  connected_rooms; // E.g.  south=Bathroom
    };
    
    class Character : public Thing
    {
      list<string>  objects;
    };
    
    class Item : public Thing
    {
      // anything needed here?
    };
    
    
    Item(
        "wrench",
        "a very large wrench",
        "The Spider's Lair"
    );
    
    Room(
        "The Spider's Lair",
        "A dark, dusty room with a large table ...",
        "map1", // could be unused for a room, or could be multiple maps/levels
        "wrench:big_table",
        "Joe:The Cat",
        "south=Kitchen:up=Cellar"
    );
    
    Character(
        "Joe",
        "A big dumb guy.",
        "The Spider's Lair",
        "harmonica:comb"   // Items
    );
    The best would be if all that string data could be read in from a data file.
    The cost of software maintenance increases with the square of the programmer's creativity. - Robert D. Bliss

  6. #21
    Registered User
    Join Date
    Jul 2012
    Posts
    36
    Quote Originally Posted by whiteflags View Post
    It has been a long time since I actually visited the sister site. I could swear the site had some information on vector, map and friends when I used the site, but that appears to be gone. Anyway, even when I first started, I carefully selected a book. Since you're being pressured into using the STL, Accelerated C++ comes to mind. It talks about vector as early as chapter 5.

    You may just be taking on more than you can chew at this point but in the spirit of being helpful I will try to turn one of laserlight's suggestions into simple English.



    The word list in this statement is just a list and not a data structure as far as I can tell. In fact, vector is recommended. I think I know why vector is recommended: because in the absence of a better idea, vector is one of the simplest data structures. (Simplicity in computing does not always mean poor, by the way.)

    There has to be a direct connection between the simple fact of where the player is and these pointers to other places contained in the individual rooms. One of your game's most basic jobs is to track movement to keep the game going. So, in your mind's eye, if it's possible travel in four directions from the middle room of the game board, you would have the nearest north, south, east and west rooms in the list pertaining to the middle room. If then you went into the south room you would have a different list of options pertaining to that room, including one option to go back.

    It will be important for the rooms to take on responsibilities if you want the game to be organized. Room objects will have to spawn characters and items that belong there, etc, as much as "spawn" can mean in a p&p adventure. That is how you cut down on massive data migration.

    Okay, now for a question that has been bothering me a long time...

    What's an object?

    I get that if I define a structure, or a class, or whatever in main I'm creating a copy of that specifically for main, and that I can even create multiple copies of the same structure/class if the variables of that structure/class applied to two different things I wanted to program about (say I wanted to make two different monsters appear in the game and one monster was just the same as an earlier version with stronger stats so I'd code:
    Code:
    struct  monster {
    int claws;
    int teeth;
    int tentacles;
    };
    
    int main()
    {
    monster little_monster;
    monster big_monster;
    
    little_monster.claws = 1;
    little_monster.teeth = 1;
    little_monster.tentacles = 1;
    big_monster.claws = 5;
    big_monster.teeth =5;
    big_monster.tentacles =5;
    }
    )

    But are those two structures in main objects? And what's so special about them being objects?

    I'm sorry if it's an impossibly stupid question, but it just seems like everything I've bumped into is an object and it's very hard to determine what that means, especially when everyone keeps referring to my game rooms as objects when I've been using functions for that, like this:

    Code:
    void rooms::training_room (int& player_race_reference, int hard_knock_conversation_choice_one, int examine_locker, int spiked_horse_shoes, int first_visit, int group_conversation_choice_one, int group_conversation_choice_two, char*& player_name_reference)
    {
     if (first_visit=1)
    {cout <<"TRAINING ROOM\n";
    
    cout <<"0000000000000000000000000000000000000000000000\n";
    cout <<"0            ()  ()  ()  ()                  0\n";
    cout <<"0              KICKING BAGS                  0\n";
    cout <<"0                                            0\n";
    cout <<"0-------      ______________________  -------0\n";
    cout <<"0       |    |                      | |      0\n";
    cout <<"0 WEAPON|    |                      | |      0\n";
    cout <<"0 LOCKER|    |   EXERCISE MAT       | | COT  0\n";
    cout <<"0       |    |                      | |      0\n";
    cout <<"0       |    |   (STALLION)         | |      0\n";
    cout <<"0       |    |                      | -------0\n";
    cout <<"0-------     |______________________|        |\n";
    cout <<"0                                        DOOR|\n";
    cout <<"0                      (ZEBRA)               |\n";
    cout <<"0                       (STALLION)           0\n";
    cout <<"0        DOOR                                0\n";
    cout <<"00000000_____000000000000000000000000000000000\n\n";
        cout << "You find yourself in what looks like a gym or training room, there is a row of kicking bags and practice dummies along one wall and much of the floor is covered in mats. There is also a heavy wire mesh case filled with various implements of destruction sitting along a wall. A muscle bound gray earth pony with a steely look in his eyes resides here.\n\n";
        cout << "However, he isn't the only one in the room. A startlingly handsome white earth pony stands there talking to a zebra stallion with a perplexing ribbon in his hair. \nThey turn to face you as you enter. The mare nods to the white pony.\n\nThe white pony walks up and holds out his hoof, \"Organizer Blueblood at your service. I have to say, that was pretty impressive. You saved a lot of lives out there and we are definitely grateful\"\n\n The gray earth pony nods. \"Definitely a good show, but we should really get him back home. We can't keep him here.\"\n\n1. He's right.\n2. Don't do that! After what I pulled they'd take my head off!\n\n";
        while (group_conversation_choice_one != 1 && group_conversation_choice_one !=2)
        {
            cout << "Choose an option: ";
            cin >> group_conversation_choice_one;
            switch (group_conversation_choice_one)
            {
                case 1:
                cout << "Blueblood shakes his head. \"That's probably not a good idea... I think you've already figured this out, but your army days are over.\" \nWind nodded, \"You did the right thing, but... you won't like what'll happens if you go back there.\" \nYou knod. She's proabaly right. \nBlueblood sighs and turns back to you. \"Don't worry, we'll find a way to help you out.\" \n\n";
                break;
                case 2:
                cout << "The muscular stallion narrows his eyes. \"We still can't afford to keep you ar-.\" \n\"Hard Knock, what's wrong with you?\" Blueblood cuts in. \"This pony saved all of our lives.\" \nThe gray pony (Hard Knock you suppose) shakes his head. \"Boss, this pony is an obvious security risk. If he ain't a plant he's at the very least someone they'll be looking for real hard.\" \nBlueblood tilts his head and raises an eyebrow, \"First of all, they're probably looking for all of us pretty hard. Secondly... you really think it's more likely that this stallion's a spy so devoted to Seasons that he's willing to throw away his body parts than it is that he's just some pony who made a decent split decision to help us?\" \nHard knock leans back against the weapons locker and folds his hooves. The zebre looks at the floor uncertainly.
                if (wind_opinion >= 2)
                {
                    cout << "Wind speaks up. \"I don't know much about him, but he's a good patient at least. I think we should give him the benefit of the doubt.\" \nThe gray pony and the zebra still look uncertain.\n\n"
                }
                cout << "Blueblood sighs and turns back to you. \"Don't worry, we'll find a way to help you out.\" \n\n";
                break;
            }
            cout << "\"Anyway,\" He continued \"nopony, or zebra...\" The zebra stallion with the ribbon blushed. \"is going to be able to go anywhere untill Archer gets back from foraging at the very least, so we might as well get to know our new friend. What's your name?\" \n\n";
            cout << "\"" << player_name_reference << "\" you reply. \n\n";
            cout << "\"Well," << player_name_reference << ", this is Hard Knock,\" he says gesturing to the grey earth pony,\"and this is Ura, you've allready met Wind.\" \n\n";
            // You need to continue writing the above cout statement
        }
    
    }
    }
    ((Note: I'm fully aware that this code is incomplete, and also that that weird pointer-reference hybrid monstrosity thing will give you nightmares. I'm sorry about that, I have no Idea what horrors I've unleashed upon the world.))

    So basically what my assumption had been was that I would set up if statements within the functions such that different things would be occurring in the rooms depending on how the players actions would modify global variables.

    Does that make my room an object? Or are functions automatically not objects?

    Note: I thank you guys for your advice. Seriously, you are an awesome and incredibly helpful community and I'm sorry if I just don't get it sometimes

  7. #22
    Lurking whiteflags's Avatar
    Join Date
    Apr 2006
    Location
    United States
    Posts
    9,612
    An object is a variable of some type, an instance of some class. A function like main() or anything similar is not object.

  8. #23
    Registered User
    Join Date
    Jul 2012
    Posts
    36
    Quote Originally Posted by whiteflags View Post
    An object is a variable of some type, an instance of some class. A function like main() or anything similar is not object.
    Oh! Okay, I get it now... huh.

    Honestly when all is said and done, it seems like the answer to my original question is pretty clear. I'm going to have to merge my two classes so that all of the global variables can be read by each individual room function, it will lead to a long list of definitions in public:, but it will at the end of the day make all of those variables available to me for each function in the class, and I should be able to define the changing global variables that affect all rooms using references.

    I know several people have suggested that I define a generic room class and then differentiate it with variables from main, but honestly the rooms are sufficiently unique that I'm not convinced that that would help cut down on duplicate code all that much.

    Thank you all for your help! Especially you whiteflags.

  9. #24
    C++ Witch laserlight's Avatar
    Join Date
    Oct 2003
    Location
    Singapore
    Posts
    28,413
    Quote Originally Posted by chaucer345
    it seems like the answer to my original question is pretty clear. I'm going to have to merge my two classes so that all of the global variables can be read by each individual room function, it will lead to a long list of definitions in public:, but it will at the end of the day make all of those variables available to me for each function in the class, and I should be able to define the changing global variables that affect all rooms using references.
    Generally, global variables should be avoided, unless they are actually constants.

    If you say, have a long list of dialogue (possibly read from file) such that the strings are const, fine. But if you have global variables that can be modified by different functions, then look before you leap, otherwise you will find that it will be harder to reason about your program because a global variable could be changed without you realising it, causing it to be more difficult to maintain your program. Furthermore, it will be harder for you to reuse parts of your program, because you depend on global variables that might not exist (with those names) elsewhere.

    Quote Originally Posted by chaucer345
    I know several people have suggested that I define a generic room class and then differentiate it with variables from main, but honestly the rooms are sufficiently unique that I'm not convinced that that would help cut down on duplicate code all that much.
    Eliminating duplicate code is one thing, but it is not the only thing. A class is a mechanism for abstraction. You create Room objects and reason about them.
    Quote Originally Posted by Bjarne Stroustrup (2000-10-14)
    I get maybe two dozen requests for help with some sort of programming or design problem every day. Most have more sense than to send me hundreds of lines of code. If they do, I ask them to find the smallest example that exhibits the problem and send me that. Mostly, they then find the error themselves. "Finding the smallest program that demonstrates the error" is a powerful debugging tool.
    Look up a C++ Reference and learn How To Ask Questions The Smart Way

  10. #25
    Registered User
    Join Date
    Jul 2012
    Posts
    36
    Quote Originally Posted by laserlight View Post
    Generally, global variables should be avoided, unless they are actually constants.

    If you say, have a long list of dialogue (possibly read from file) such that the strings are const, fine. But if you have global variables that can be modified by different functions, then look before you leap, otherwise you will find that it will be harder to reason about your program because a global variable could be changed without you realising it, causing it to be more difficult to maintain your program. Furthermore, it will be harder for you to reuse parts of your program, because you depend on global variables that might not exist (with those names) elsewhere.


    Eliminating duplicate code is one thing, but it is not the only thing. A class is a mechanism for abstraction. You create Room objects and reason about them.
    I understand that having global variables that multiple functions modify is a complicated thing to program around, but it's kind of the entire point of my program. The whole idea of this game is that your past actions come back to haunt you. If I can't create a variable or something that tracks what the player's previous decisions were so that they can affect future game play... well, then I can't write the program at all.

    Tight control over when and how my variables change would truly be ideal.

  11. #26
    C++まいる!Cをこわせ!
    Join Date
    Oct 2007
    Location
    Inside my computer
    Posts
    24,654
    Quote Originally Posted by chaucer345 View Post
    Tight control over when and how my variables change would truly be ideal.
    Put them into a class or struct. Ideally you should control access to your variables for future compatibility.
    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.

  12. #27
    C++ Witch laserlight's Avatar
    Join Date
    Oct 2003
    Location
    Singapore
    Posts
    28,413
    Quote Originally Posted by chaucer345
    I understand that having global variables that multiple functions modify is a complicated thing to program around, but it's kind of the entire point of my program. The whole idea of this game is that your past actions come back to haunt you. If I can't create a variable or something that tracks what the player's previous decisions were so that they can affect future game play... well, then I can't write the program at all.
    Let's see... if you are tracking based on certain "player attributes", then these can be member variables of a Player object. Or maybe you want to actually track actions rather than some score that is the result of those actions, in which case maybe you have an Action class then store an archive of past actions in the player object.
    Quote Originally Posted by Bjarne Stroustrup (2000-10-14)
    I get maybe two dozen requests for help with some sort of programming or design problem every day. Most have more sense than to send me hundreds of lines of code. If they do, I ask them to find the smallest example that exhibits the problem and send me that. Mostly, they then find the error themselves. "Finding the smallest program that demonstrates the error" is a powerful debugging tool.
    Look up a C++ Reference and learn How To Ask Questions The Smart Way

  13. #28
    Frequently Quite Prolix dwks's Avatar
    Join Date
    Apr 2005
    Location
    Canada
    Posts
    8,057
    Here's one idea, an elaboration of laserlight's thoughts. You could use an Action or Decision to represent the choices the player has made. Then store a map from strings to Decision pointers somewhere that's pretty much globally accessible (e.g. in a Player object). This would allow you to add new Decisions without modifying a giant WhatIHaveDone class, and yet query exactly the ones you need...
    Code:
    #include <string>
    #include <map>
    
    class Decision {
    private:
        bool boolDecision;
    public:
        Decision(bool yes = false) : boolDecision(yes) {}
        bool getBool() const { return boolDecision; }
    };
    
    std::map<std::string, Decision> decisions;
    decisions["fellIntoHole"] = Decision(false);
    
    // ...
    if(decisions["fellIntoHole"].getBool()) {
        std::cout << "You already used your rope getting out of the hole, remember?\n";
    }
    You could have a Decision hierarchy, inherit BoolDecision from there etc (maybe even have a templated decision class so you could store whatever type you wanted). However, that would mean you'd probably have to downcast the Decisions to the correct type. I'd be more inclined to have a Decision that stores bool, int, string, whatever you need, and then different getter functions. You'd assign default values to the int/bool/whatever. This way you can randomly query a decision -- the object doesn't even have to be registered in the map, it will be automatically created -- and you'll get the default value. If you query the wrong type, you'll get something sensible. Of course you could also have a "type" associated with each Decision, and maybe it asserts if you do a query of the wrong type... it's up to you how much work you want to put into it.

    P.S. Great title, by the way. It was the best of code, it was the worst of code... it was the best design, it was the worst design....
    Last edited by dwks; 08-14-2012 at 04:24 PM.
    dwk

    Seek and ye shall find. quaere et invenies.

    "Simplicity does not precede complexity, but follows it." -- Alan Perlis
    "Testing can only prove the presence of bugs, not their absence." -- Edsger Dijkstra
    "The only real mistake is the one from which we learn nothing." -- John Powell


    Other boards: DaniWeb, TPS
    Unofficial Wiki FAQ: cpwiki.sf.net

    My website: http://dwks.theprogrammingsite.com/
    Projects: codeform, xuni, atlantis, nort, etc.

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. Replies: 23
    Last Post: 03-07-2011, 05:28 PM
  2. Sending fewer parameters then arguments
    By gar35 in forum C++ Programming
    Replies: 1
    Last Post: 05-01-2010, 09:20 PM
  3. Best journalism...saddest tale.
    By Sebastiani in forum General Discussions
    Replies: 4
    Last Post: 06-18-2009, 05:55 AM
  4. A tale of two systems.
    By sean in forum Linux Programming
    Replies: 8
    Last Post: 05-25-2002, 12:12 AM
  5. classes and definitions
    By scott27349 in forum C++ Programming
    Replies: 6
    Last Post: 05-15-2002, 10:11 PM