Sign in to follow this  
GamerCon

MUD commands

Recommended Posts

I dont know how to explain it so ill just do my best in commenting.
#include <iostream>

#define NUM_COMMANDS 2

void (*function)(char*); // This holds a pointer of the function to be called. It's global because I dont know how to get a function to return a pointer to a function (if it is possible, can someone explain how?)

struct CMD // The magic structure
{
    char *cmd; // this will hold the actual command to be compaired with a players input
    void (*fun)(char*); // If players input and cmd are equal this is the function  address that will be set into (*function)(char*)
};

//The below functions are called when the proper command was input
void say(char *str)
{
    //just so i know this function was called successfully
    std::cout << "This is the \"say\" function accesed by " << str << std::endl;
}

void get(char *str)
{
    //just so i know this function was called successfull
    std::cout << "This is the \"get\" function accesed by " << str << std::endl;
}

//Now that there are a couple command functions, create the CMD structure array
CMD commands[NUM_COMMANDS] = //an array NUM_COMMANDS wide
{
    {"say ",say},  //first part is the command that must be input, second part is the pointer the the function
    {"get ",get}
};

// this next function compares player input to the current command being looked at by "i"
bool compare_command(char *str,int i) //str is the player input, "i" is the element of the command array to look at
{
    if(strncmp(str,commands[i].cmd,strlen(commands[i].cmd))==0) // If the players input matches the current, looked at, command
    {
        function = command[i].fun // function is the global void (*function)(char*) variable
                                 // command[i].fun is address of the command function
        return true; // so we know to call function(char *str)
    }
    return false; //meanse that player input didnt match the looked at command
}

int main() // where it all happens
{
    char *input = "say ";  // this is the player input, since im not wrapping any socket programming around this source, it'l have to do

    for(int i=0; i < NUM_COMMANDS; i++) //loop through all the commands comparing them to the player input
    {
        if(compare_command(input,i)) //if this function returns true
        {
            function(input); // call function() which holds the address say() so it technically calls say()
        }
    }
    system("pause"); //I need to see the output before the console closes
    return 0; //all went well
}




Am I doing this correctly? does this method make any sense to anyone? Know any better methods to accomplish the same thing? Thanks -GamerCon

Share this post


Link to post
Share on other sites
Seems like it would work. I personally would use a std::map mapping strings to function pointers or better yet functors.

I haven't checked this so it may (and will) contain small errors, but you get the general gist of it. As for a good resource on function pointers - you should check out http://www.function-pointer.org/




#include <string>
#include <map>
#include <iostream>
#include <pair>

using namespace std;
typedef void (*fnPtr)(string);
map<string,fnPtr> gFunctionMap;

void say(string params)
{
cout << "You say: \"" << params << "\"\n";
}

int main()
{
gFunctionMap.insert(pair<"say",say);

string command = "say";
string params = "I am awesome!";
fnPtr f = gFunctionMap(command);
f(params);
}


Share this post


Link to post
Share on other sites
The illustrated typedef is a good idea, it will keep things clearer since the syntax for function-pointer types is pretty messy.

The map is a good idea too; the map lookup will automatically use a good algorithm for managing your list of command names and looking them up (it will basically do a binary search, except you can change the list without major problems, and it will do all the management for you - take an algorithms class, or [google] "red-black tree" to see how this is done).

Using functors is a really good idea; it will let you change the behaviour of commands over time (by associating state with them - since they are objects), and avoid those messy typedefs. Basically in C++, all you need is an object that implements the operator():


#include <string>
#include <map>
#include <iostream>
#include <pair>
#include <algorithm>

using namespace std;

class Functor {
// This is my weird Java-influenced organization of things at work...
// You might prefer to put the function map in a namespace, or leave it global.
public:
static map<string, Functor> commands; // note "static".
virtual void operator()(vector<string> words) = 0;
// Assumes you will tokenize your input later...

static void insert(string& name, Functor& cmd) {
// Just for convenience.
commands.insert(std::pair<string, Functor>(name, cmd));
}
protected:
static void output_word(string& word) {
cout << word;
} // definitely note "static" here. Otherwise we're looking at a
// "member function pointer" and things get a lot harder.
}

class Say: public Functor {
public:
void operator()(vector<string>& words) {
cout << "You say: \"";
std::for_each(words.begin(), words.end(), output_word);
cout << "\"" << endl;
}
}

// Similarly for other commands... notice you can do anything with them you
// could with a normal object

int main() {
// initialization
Functor.insert("say",say);

// Get a command and arguments from user input
string command = "say";
vector<string> params = // get the words of input here

// Respond to user input
Functor.commands[command](params);
}

Share this post


Link to post
Share on other sites
In C, rather than having a constant to indicate the number of commands in the array, it is much, much simpler to have a sentry in the array itself, like a NULL pointer for your command string.


#include <string.h>

typedef void command_func(char*);

struct command_table_entry
{
char *command;
command_func* function;
};

command_table_entry command_table[] = // No need to specify the array size
{
"say", say,
"get", get,
NULL, NULL, // Handy for cut/paste: a trailing comma is not an error
};

void execute(char* command, char* args)
{
int cmd_len = strlen(command);

command_table_entry* ptr;
for(ptr = command_table; ptr->command != NULL; ++ptr)
if( !strncmp(command, ptr->command, cmd_len) )
break;

if(ptr->command == NULL || ptr->function == NULL)
{
// Error - no matching command
}
else
{
ptr->function(args);
}
}





Variations are of course possible, including, in C++, std::map.

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

Sign in to follow this