Command translator.

hi,
i was writing some sort of a game, it's a console application.
every game needs input,
i thought to implement the input as follows:
the player writes a string, and the game should execute the command.
the way my program handles the command is, it does a calculation on the string to convert it into a unique int, then compare the int against some enumeration values.
up until now every thing is ok, i made the translation function, and it looks like fine.

the problem is, it's really hard to write the enum values by hand, as the int returned is unique for every string, so i thought i could automate the process.
like, create a class that contains static members ,a function that initializes those members with the right value to each command, and i want those members to be public for read access, but private for write access.
maybe some code can illustrate the idea, here's what i have:
you can skip translate() as the problem isn't in it.
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
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
typedef unsigned int CommandID;
// translation constants, took the idea from the MD5 algorithm.
const CommandID TC1 = CommandID(0x0d);
const CommandID TC2 = CommandID(0x01);
const CommandID TC3 = CommandID(0x01);
const CommandID TC4 = CommandID(0x01);

CommandID translate(string& message)
{
    CommandID com = NULL; //   will hold the result.
    unsigned int i = 0;
    size_t tempSize = message.size();
    for( i=0 ; i<tempSize ; i++) // preliminary process.
    {
        message[i] = std::tolower(message[i]); // ignore letter case.

        if( i > sizeof(com) )
            message [ i % sizeof(com) ] ^= message[i]; // reduce message to be of size = sizeof(com).
    }
    message.erase( sizeof(com) , tempSize ); // erase the un-needed characters.
    tempSize *= tempSize;	// enlarge tempSize to prepare it to be merged into the translation equation.
    com ^= tempSize;	//merge tempSize into the equation, this lets the string length affect its translation.
    for( i=0 ; i<sizeof(com) ; i++)
    {
        com ^= ( static_cast<CommandID>( message[i] << 8*i ) );	//merge the message letters, each in its corresponding byte.
    }
//    merge the translation constants into com.
    com *= TC1 ;
    com *= TC2 ;
    com *= TC3 ;
    com *= TC4 ;

    return com;
}

void processCommand(string& message)
{
    CommandID a = translate(message);
    switch(a)
    {
    case command::EXIT :  //this is how i want to use it.
        std::exit(0);
            break;
    default:
        std::cerr<<"Unknown command recieved ("<<a<<"), ignoring.\n";
        return;
        break;
    }
}

class command abstract
{
public:
    static CommandID EXIT ;


//    static methods.
    static void Initialize();
    command(void)
    {
    }

    ~command(void)
    {
    }
};
CommandID command::EXIT;
void command::Initialize()
{
	command::EXIT = translate( std::string ("exit") ); // this is the automation process i want.
}


in the code above, i want command::EXIT to be accessible publicly for read operations, but private for write operations.

before you ask, i used typdef to provide an easy platform for possible future upgrades on the project.

i read a previous thread to do so, it demonstrated it using const references, but looks like this method can be exhausting in my project because i might define lots of commands.
on the other hand, it needs an object to be created, i want the class abstract (the class represents an enumeration).
if there's another approach to do so, it'd be better.

thanks in advance.
Hmm I don't see why these values would ever be changing, so why not just make them all const?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
class command abstract
{
public:
    static const CommandID EXIT ;

    command(void)
    {
    }

    ~command(void)
    {
    }
};
const CommandID command::EXIT = translate("exit") ;


Have you considered using a container like std::unordered_map?
@ResidentBiscuit:
later on in the project i made them const.

@cire:
this way is fine, but i'm making a game, and eventually it will contain so many commands, i can't hard code all this translation process, a 2D char that contains the commands, and a loop to translate them is much easier.
and no, i don't know what is an unordered_map, i'll check on that.

this post is somewhat outdated, i figured another way:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
const char* commandList = { "EXIT" , "NEW_GAME" /*. . .*/};
void command::Initialize()
{
	std::ofstream commandFile("Commands.inf", std::ios::out | std::ios::trunc );

	commandFile<<"[Currently_Available_Commands]"<<std::endl;
	for(unsigned i=0 ; i<command::numberOfCommands ; i++)
	{
		commandFile<<"\tstatic const CommandID "<<commandList[i]<<" = ";
		commandFile<<translate( std::string(commandList[i]) );
		commandFile<<";"<<std::endl;
	}
	commandFile.close();
}


if i pass a specific argument to main() it will re-initialize the command list, then i go to that file and copy its contents into my code.
even this is hard.

if i could make public-read private-write, i can make the game initialize the commands each time it is started, and it will provide an even easier way to add new commands.
Topic archived. No new replies allowed.