2

Background of the program: the user is able to input a string of two words only - a verb and a noun. I tokenize this string into a vector and compare tokens[0] with a vector of allowed verbs, and tokens[1] with a vector of allowed nouns.

Now, I'm trying to find a way to allow only certain verbs to be performed on certain nouns. For example, writing "take book" will give a message (or whatever) saying it's allowed, but writing "take door" would not be. I have so far created a class Object with bool values for each possible verb (eg. within the class Object, I can create an Object book for which m_take = true, or false for an Object door).

However, I'm having trouble associating these objects with the user input. For example, I would like to be able to do something like this:
1) User inputs "verb noun", which go into the tokens vector as tokens[0] and tokens[1].
2) Program checks if the input contains acceptable words (individually).
3) Considering getstat() to be the function to retreive the bool value of the possible action doable on an object, the program retrieves tokens[1].getstat(tokens[0]) and, if true, executes tokens[0].tokens[1]() (eg. book.take()). This way I could have only one if cycle in my main(), which can be used by all legal verbs and nouns, without making an infinite list of if, else if, etc, considering every single option manually.

Sorry if this is at all confusing. I know it is not possible to use a variable as an object name, but I'm sure there's a better way to do this than doing cycles within cycles of considering every single mix and match of verb and noun. I'm experimenting with like 3 each at the moment, but once I get this working I plan on expanding it and it would be a nightmare to keep track of every change if I have to hard-code every possible verb and noun multiple times within the source code. (Also, sorry for not posting the whole source - it's a really long file just now!) Thanks for any help/hint in the right direction!

1
  • You may want to read up on the concept of pointer to member (maybe also on virtual functions). Commented Sep 29, 2013 at 14:42

3 Answers 3

2

You could use runtime polymorphism for this kind of stuff, either with virtual methods or C++11 std::function and lambdas.

You will obviously have to redesign your "token" system.


Virtual methods example:

struct Object
{ 
    virtual void onTake() { }
    virtual void onOpen() { }
};

struct Door : public Object 
{
    bool open{false};
    void onTake() override { say("I can't take the door!"); }
    void onOpen() override { say("The door is now open."); open = true; }
};

struct Book : public Object
{
    void onTake() override { say("I put the book in my backpack."); }
    void onOpen() override { say("I open the book. All the pages are blank."); }
};

C++11 lambdas example:

struct Object
{ 
    std::function<void()> onTake, onOpen;
};

struct Door : public Object 
{
    bool open{false};
    Door() 
    {
        onTake = []{ say("I can't take the door!"); };
        onOpen = []{ say("The door is now open."); open = true; };
    }
};

struct Book : public Object
{
    Book() 
    {
        onTake = []{ say("I put the book in my backpack."); };
        onOpen = []{ say("I open the book. All the pages are blank."); };
    }
};

// You can also avoid creating new classes
Object bananaPrototype; 
bool eaten{false};
bananaPrototype.onTake = []{ say("I put the banana in my backpack."); };
bananaPrototype.onOpen = [eaten] mutable 
{ say("I eat the banana. Yum."); eaten = true; };
Sign up to request clarification or add additional context in comments.

4 Comments

This is incredibly helpful, thank you! I have never used any of this before (haven't used structs before either) but it seems like it would do what I would need it to, so I will look into it. Thanks! Just one question though, how would I link this to the user input? How can I make the program call struct Door from the string "door", or call onTake from string "take"? Would I have to create a list of ifs to assign one to the other for all possible objects or is there a simpler way?
Ok, I've been looking at this to try and make it work for what I'm doing, and it might be a really stupid question, but what do you mean by "say", as in void onTake() override { say("I can't take the door!"); } ? I've tried to google it to see if it was part of something I have not included, but can't find it anywhere. Thanks :)
It's all pseudocode. say is an imaginary function that says something. Use cout<< instead or whatever you have.
Ah, that makes sense - had a feeling it was a stupid question :) Thank you!
0

It's hard to give an advice in such a non trivial case not seeing the code, but, as far as I understand, you'd better consider dropping the hardcode approach, i.e. book.take(). Try writing more generic code, at least something like book.action(actions::kTake).

Comments

0

As you say, tokens[0].tokens[1]() does not do what you want it to - the names of functions and variables are not available when the program is being run.

You could try using maps. objects could be a map with keys of the object names. The values (objects[token[0]]) would in turn be other maps which would be functions to do what you want (objects[token[0]][token[1]]).

Here is an example:

#include <unordered_map>
#include <string>
#include <iostream>

using namespace std;

void read_fn()
{
    cout << "You read the book";
}

int main()
{
    unordered_map <string, unordered_map <string, void (*)()>> lookup;

    unordered_map <string, void (*)()> book_lookup;

    book_lookup["read"] = read_fn;
    lookup["book"] = book_lookup;

    lookup["book"]["read"]();
}

1 Comment

Thank you! I hadn't thought I could use maps. I will try pairing verbs and nouns in a map and then looking up the input words in the map to see if a relevant pair is found.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.