mackesmilian
mackesmilian

Reputation: 123

How do I check a string for a range of strings in C?

I have to create a Solitaire Program in C. I have the data structure set up but I have a question about comparing strings.

The user input has to look like "move [colour] [value] to [stack]".

Now my plan was to use strncmp to see if the string contained "move" "color", etc. But with "value" I have a range of 13 acceptable inputs (Ace to King), which means I would need 13 different if-statements. Is there a more elegant way to check which "value" the input holds?

Examples: "move red 4 to 3" or "move black K to 6"

After I determined what the user specified, I have to find the given card in 7 double linked lists and move it to another list as specified by the user.

Thanks!

Upvotes: 1

Views: 1462

Answers (1)

Arkku
Arkku

Reputation: 42139

If your input for value is a single character, you can simply check that the character exists in the list of valid characters:

const char valid_values[] = "A23456789TJQK";
if (strchr(valid_values, input_value[0])) {
    // valid
} else {
    // invalid
}

You can even use the character itself internally as-is as the representation of the value (since it is both unique and optimally small at 1 char). Or you can convert to the numerical value by taking the index (such as by subtracting valid_values from the non-NULL return value of strchr) and adding 1.

If you wish to allow multiple alternatives (such as "A", "ace" or "two", "2", "deuce"), a simple alternative is to make an array of string-value pairs and iterate over them until a match is found or the end is reached:

struct value_string {
    const char *string;
    int value;
};
const struct value_string valid_values[] = {
    { .string = "A", .value = 1 },
    { .string = "ace", .value = 1 },
    { .string = "2", .value = 2 },
    { .string = "two", .value = 2 },
    // …
    { .string = "K", .value = 13 },
    { .string = NULL, .value = 0 } // terminator
};

int card_value = 0;
for (const struct value_string *p = valid_values; p->string; ++p) {
    if (strcmp(p->string, input_value) == 0) {
        // found match
        card_value = p->value;
        break;
    }
}
if (card_value) {
    // valid
} else {
    // invalid
}

The benefits of this kind of a solution are in the clarity and expandability of code, rather than on improving performance or reducing the total number of lines. For the best performance I would expect a look-up table (or simply a switch) by first character and then manual character-by-character validation (of the remaining possibilities, only) to be hard to beat.

Upvotes: 1

Related Questions