0

So I am making what will basically be a game engine for text adventures like the classic Zork. I have a network of room objects with an array 10 pointers to other rooms (N,NE,E,SE,S,SW,W,NW,up,down). Currently there is just a select case statement to check for the correct direction substring, then make sure the associated pointer for that direction isn't NULL. Is there a way I could set up an enumerated array for these pointers that could accept the substring as an index and just catch any substrings that don't map to an index? To where I could have:

//user enters "go north"
//input is parsed into a vector called words "go" and "north"
player.location = player.location->path[words[1]];
FinnJ
  • 1
  • 3
  • Not really sure what you are asking for. But it should not be difficult to just use a bunch of `if..else` statements, or a `std::(unordered_)map`, to convert a string input into an integer/enum value that you can then use as an index into an array of pointers – Remy Lebeau Jul 19 '21 at 20:37
  • 1
    It sounds like you're looking for `unordered_map` – Nathan Pierson Jul 19 '21 at 20:37
  • [This answer](https://stackoverflow.com/questions/5093460/how-to-convert-an-enum-type-variable-to-a-string) is possibly relevant because it explains setting up an array of strings corresponding to the enum names, which is also the first step in setting up a parser that can parse a user string and turn it into an enum value. Beware of how this impacts internationalization or localization (the ability to make your program work in other languages.) – Wyck Jul 19 '21 at 20:48
  • @RemyLebeau I am aware I could use a an if..else, as stated in my question I currently use have a select case setup for it. I just want to try and make it more efficient, if only slightly, so I could take a substring from the user that _should_ be a direction (north, south, etc) then pass that into the array as you would pass an integer for the index. I will look into an unordered map though. – FinnJ Jul 21 '21 at 21:07
  • @NathanPierson I think you are correct, this looks like it will work fine and hopefully faster than just having a bunch of if else's – FinnJ Jul 21 '21 at 21:23

1 Answers1

0

You could add a conversion function to your enum such as this:

enum direction_t
{
    dir_n    = 0,
    dir_ne   = 1,
    dir_e    = 2,
    dir_se   = 3,
    dir_s    = 4,
    dir_sw   = 5,
    dir_w    = 6,
    dir_nw   = 7,
    dir_up   = 8,
    dir_down = 9,
    dir_invalid = 10
    
    bool str_to_dir (std::string dir, direction_t &out_dir) // do not use const reference here!
    {
        std::for_each(data.begin(), data.end(), [](char & c) {
            c = ::tolower(c);
        });
        
        if (dir == "north" || dir == "n") // add whatever here!
        {
            out_dir = dir_n;
        }
        else if (dir == "northeast" || dir == "ne")
        {
            out_dir = dir_ne;
        }
        ...
        else
        {
            out_dir = dir_invalid;
            return false;
        }
        return true;
    }
};

void do_stuff (const std::string &input)
{
    std::vector split;
    // split string using your function
    
    if (split.size() == 2 && split[0] == "go")
    {
        direction_t dir;
        if (direction_t::str_to_dir(split[1], dir))
        {
            uint8_t index = (uint8_t)dir; // cast your direction to an index between 0 and 9, see direction_t
            some_array[index]->function_call();
        }
        else
        {
            // dir_invalid returned...
        }
    }
}

You can add functions to enum and struct just as in class (but without a keyword, everything is marked public instead of private). This way you can add all the parsing to your enum routine and get a direction_t from it and as you have predefined the values, if the function returns true your can convert your enum type to in integer type and use it as an array as you know by returning true that it is a valid direction.

Also note that its important that C++ is case sensitive, hence converting the whole string to lowercase to mitigate that and only having to check agains lowercase strings.

If you only want to check against a single string instead of multiple per direction, you can do something like this:

enum direction_t
{
    dir_n    = 0,
    dir_ne   = 1,
    dir_e    = 2,
    dir_se   = 3,
    dir_s    = 4,
    dir_sw   = 5,
    dir_w    = 6,
    dir_nw   = 7,
    dir_up   = 8,
    dir_down = 9,
    dir_invalid = 10
};

int convert_str_to_index(std::string dir)
{

    static const std::pair<std::string, uint32_t> dir_conversion_array[] = {
    std::make_pair("north", dir_n),
    std::make_pair("northeast", dir_ne),
    std::make_pair("east", dir_e),
    std::make_pair("southeast", dir_se),
    std::make_pair("south", dir_s),
    std::make_pair("southwest", dir_sw),
    ... // add everything here...
    };

    std::for_each(data.begin(), data.end(), [](char & c) {
        c = ::tolower(c);
    });
    
    for (int i = 0; i < 10; ++i)
    {
        if (dir_conversion_array[i].first == dir)
        {
            return i;
        }
    }
    return -1;
}

void do_stuff (const std::string &input)
{
    std::vector split;
    // split string using your function
    
    if (split.size() == 2 && split[0] == "go")
    {
        int index = convert_str_to_index(split[1]);
        if (index >= 0)
        {
            some_array[index]->function_call();
        }
        else
        {
            // dir_invalid returned...
        }
    }
}
Nidhoegger
  • 4,973
  • 4
  • 36
  • 81
  • By default, the first enumerator has the value 0, and all the subsequent enumerators have succeeding values. So none of those explicit values is needed. Further, unless the actual values matter, those explicit values are just noise. – Pete Becker Jul 19 '21 at 20:48
  • depends. i like it organzied like this. for you its noise, for me it isnt, so I guess its just what you prefer. – Nidhoegger Jul 19 '21 at 20:51
  • It's more than a preference. When you write all those initializers you force other people who read your code to read them all to figure out that they're doing nothing. – Pete Becker Jul 19 '21 at 21:38