OOD: Fetch available actions from objects?

I'm trying out Object Oriented Design to make a very simple text-based adventure game where the user is in a room and interacts with the objects in that room. In this universe there is only one single room. Instead of using one of many registered verbs (use, push, wear etc.) by trial-and-error with each objects, I want the objects to present the actions that are currently available/valid and have them presented like this..


Available actions:
Cupboard: Open (1), Push (2)
Carpet: Pick up (3)
Ceiling light: Turn off (4)
Enter a number [1-4] to make your choice>


If the cupboard is opened, that action should not be available the next time around. Instead it would say


Available actions:
Cupboard: Close (1), Push (2)
...


I find it difficult to determine where to put this listing functionality. Since the actions are mostly unique to each different item, it seems logical to put a container of some sort in each item object that holds pointers to member functions or something along with a short description of each action "Open", "Move". A container that changes its content based on the current state of the object. I plan to use a common member function getAvailableActions() and run(actionNumber) for all item objects. And then have an object Menu or Game which is responsible for keeping all the actions together and presenting them visually. The idea just doesn't feel quite right. Is there some known design pattern to deal with a situation like this?
Here's an idea:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
class Item{
	static action_t actions[ACTION_COUNT];
public:
	typedef bool (Item::*action_t)(bool);
	virtual bool open(bool probing){
		return 0;
	}
	virtual bool close(bool probing){
		return 0;
	}
	virtual bool push(bool probing){
		return 0;
	}
	virtual bool shove(bool probing){
		return 0;
	}
	virtual bool nudge(bool probing){
		return 0;
	}
	// etc
	size_t probe(action_t actions[ACTION_COUNT]){
		size_t ret = 0;
		for (auto p : this->actions)
			if ((this->*p)(true))
				actions[ret++] = p;
		return ret;
	}
};
Note that you'll need something entirely different for transitive (i.e. binary) verbs.
Last edited on
Thanks. Let me try to decipher that... I'm a beginner after all.

We have a base class Item.

ACTION_COUNT is the number of actions defined in one particular item?

action_t is a pointer to a function that takes a bool parameter and returns bool. (But doesn't the typedef need to happen before the array declaration? Nevermind.)

We declare an array of these pointers called actions.

A number of polymorphic member functions; open, close, ... are introduced.

We also define a member function probe, that takes an array of action_t's and returns a size_t (basically an unsigned integer).

In the probe function we go through a range for-loop. p is initially (in the first loop cycle) a pointer to the first action_t (pointer to function) of the actions array.

If that specific function returns true, then... I'm lost here. A pointer is assigned to itself? In the first iteration p is that same as actions[0], is it not?

After going through the entire actions array, we return the index to the last element of the actions array.

How can I make use of that index?
How do I invoke the probe function from main?

1
2
3
4
5
6
7
int main()
{
    Item rock;
    rock.probe(???) // What do I put as argument?

    return 0;
}

main does not know what functions are available to begin with. Can I somehow return an array of pointers to member functions, from a getActions() method in the Item class?
closed account (j3Rz8vqX)
Can I somehow return an array of pointers to member functions, from a getActions() method in the Item class?

Maybe...
An example of accessing class methods from function pointers:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
#include <iostream>
#include <functional>
#include <vector>
class Actions{
    public:
    std::string open(){
        return "You opened something...\n";
    }
    std::string close(){
        return "You closed something...\n";
    }
    std::string pickup(){
        return "You picked something up...\n";
    }
    std::string putdown(){
        return "You put something down...\n";
    }
}myActions;
bool prompt(int &choice)
{
    std::cout<<"Function: 1, 2, 3, 4, \nor 5 to Exit\nChoice: ";
    std::cin>>choice;
    std::cin.clear();
    std::cin.ignore(1000,'\n');
    return true;
}
int main()
{
    int choice;
    std::function<std::string()> *Fun;
    std::vector<std::function<std::string()>> Commands =
    {
        std::bind(&Actions::open, myActions),
        std::bind(&Actions::close, myActions),
        std::bind(&Actions::pickup, myActions),
        std::bind(&Actions::putdown, myActions)
    };
    while(true){
        while(prompt(choice)&&(choice<1||choice>Commands.size()+1))
            std::cout<<"Invalid choice...\n\n";
        if(choice==Commands.size()+1)
            break;
        Fun=&Commands[choice-1];
        std::cout<<(*Fun)()<<'\n';
    }
    return 0;
}
Function: 1, 2, 3, 4,
or 5 to Exit
Choice: 1
You opened something...

Function: 1, 2, 3, 4,
or 5 to Exit
Choice: 2
You closed something...

Function: 1, 2, 3, 4,
or 5 to Exit
Choice: 3
You picked something up...

Function: 1, 2, 3, 4,
or 5 to Exit
Choice: 4
You put something down...

Function: 1, 2, 3, 4,
or 5 to Exit
Choice: 5

Process returned 0 (0x0)   execution time : 9.417 s
Press any key to continue.

Not what you wanted, with the flip switch mechanism from previous attempts, but something to digest.

Edit: c++11
Last edited on
ACTION_COUNT is the number of actions defined in one particular item?
It's the number of actions any item could possibly have.

If that specific function returns true, then... I'm lost here. A pointer is assigned to itself? In the first iteration p is that same as actions[0], is it not?
Note that the parameter to probe() has the same name as a class member. In those cases, this-> is not optional if you want to refer to the class member.

After going through the entire actions array, we return the index to the last element of the actions array.
The number of items that were written to the array is returned.

How can I make use of that index?
How do I invoke the probe function from main?
1
2
3
4
5
6
7
8
9
10
11
//class Rock : public Item{ ... };

int main(){
    Item::action_t possible_actions[Item::ACTION_COUNT];
    Rock rock;
    size_t action_count = rock.probe(possible_actions);
    for (size_t i = 0; i < action_count; i++){
        //(rock.*possible_actions[i])(false) should return true.
    }
    return 0;
}

To get the name of each action you could add an array of ACTION_COUNT 'const char *'s to Item and pass an array of the same size and type to probe.
Topic archived. No new replies allowed.