How to Map-Associating Strings with Integers

So, I have this function to code called int GetGuess ( ). The idea for me is to map out each possible string to an integer. The various strings I need to associate with an integer are:

1
2
3
4
5
	int const CARDS=18;
	std::string deck [CARDS]={"red circle","red square","red triangle","blue circle","blue square",
	 "blue triangle","yellow circle","yellow square","yellow triangle","orange circle",
	 "orange square" ,"orange triangle","purple circle","purple square",
     "purple triangle","green circle","green square","green triangle"};


Now, I really do not know how to begin mapping to be honest. If anyone can point me in the right direction I will be eternally grateful!
If the integers are positions in the array, std::find() could be used.
http://en.cppreference.com/w/cpp/algorithm/find

With a std::map<std::string,int> or std::unordered_map<std::string,int>, the association is more flexible and lookups are faster.
https://stdcxx.apache.org/doc/stdlibug/9.html
Last edited on
This is for my programming one class, and I initially began using std::map and she said she won't accept it. Why? Because she is ignorant lol. I have these instructions and they have to be followed for me to get the credit:

From the spec:□ Declare an array to be used to map each card description (shape/color) to its unique integer (1-18)

You have the choice of:

1. using a "lookup array" as specified below

If you use the lookup array, you will need to access it from at least two functions.

Therefore,you are allowed to make just this lookup array global, (not the other arrays!)

or, better yet,create a global pointer to this array. (not to the other arrays!)

OR:

2. using if and switch statements to do your mapping from string to integer, and from integer to string.
(Your code does not have to contain the lookup array if you choose the if/switch method.)

There are other possible solutions, but these are the most common.





I was thinking of doing the if statements, but I really just don't know where to begin. I appreciate your input JLBorges!
I was thinking of doing something like this...


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
int const CARDS=18;
	std::string deck [CARDS]={"red circle","red square","red triangle","blue circle","blue square",
	 "blue triangle","yellow circle","yellow square","yellow triangle","orange circle",
	 "orange square" ,"orange triangle","purple circle","purple square",
     "purple triangle","green circle","green square","green triangle"};
     

int i;

	
	std::string color, shape,combo;

 for (int i=0;i<CARDS;i++)
    {
    	cout<<"Please choose a card with a color first, and then a shape.";
	cin>>color>>shape;
	combo= color + " " +shape;
	
    }
    


if(combo == "RED CIRCLE")
       
                return 1;
            else
combo == "RED SQUARE"
                return 2;
        else.....


Would this be efficient?
Anybody have some input? I'm desperate here lol
in line 25 and 28, which function are you in and what are you returning to?
Oh sorry, I am in function int GetGuess ( ). I am returning the strings converted to integers, because I have to use these integers to see if their are matches to the computer. This is the assignment below, to give you a little bit of background on what the program as a whole is to do. I have 6 functions to code in total:

void DisplayInstructions ( );
void GenerateCorrectCards (int *);
int GetGuess ( );
bool CheckMatch (int , int *);
void DisplayCards (int *, int *);
void DisplayESP (int);





The rules of ESP are:
There is a deck of 18 cards that looks like this:
Each card has a color and a shape.
There are 3 shapes: CIRCLE, SQUARE, TRIANGLE
There are 6 colors: RED, BLUE, YELLOW, PURPLE, GREEN, ORANGE
For example: one card is BLUE SQUARE

The program allows the player to play as many rounds as they'd like.
The program gives the player the opportunity to quit after each round, by entering 'Q' or 'q'.

One round consists of:
The computer will randomly choose 5 cards from this deck (these are the 'correct' cards).
The player will guess 5 cards by entering a color and a shape for each. (Give them exactly 5 chances to guess in one round (see below for duplicate guesses).)
For each guess, display whether or not it matches one of the 'correct' cards. Cards do not have to be in the same order as the correct cards to win. Display whether or not it is a duplicate guess, which is not allowed.
After the player has made 5 guesses, the round is over, at which point
the program will display that round's information (see below) and ask if they want to play again.
At the end of each round, display the following:
the five cards the computer selected (correct cards) (color/shape of each card)
the five cards the player guessed (color/shape of each card)
the player’s ESP Level (you must have these 4 exact levels, but you can make up your own messages!)
0 matches: “Level 1: No ESP at all!”
1-2 matches: “Level 2: Some ESP, keep working on it!”
3-4 matches: “Level 3: Lots of ESP, try Powerball!”
5 matches: “Level 4: ESP expert! Host a TV show!”

Here are some tricky parts: (Plan to devote a good amount of time to solving these problems.)
make sure there are no duplicate cards generated for the computer (i.e. no duplicates in 'correct' cards)
make sure there are no false positives, i.e.
RED CIRCLE should not be a match if the computer chose RED SQUARE and GREEN CIRCLE.
Do not let the player choose a duplicate card (i.e. one already guessed before in that round). If they choose a duplicate, you must allow them to choose again. (i.e. always 5 non-duplicate guesses.)
Don’t let the player get duplicate matches for guessing the same correct card several times!
(similar to #3 above)
Remember that the cards do not have to be in the same order to match.
Have two arrays, one for the six colours, another for the three shapes?

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
72
73
#include <iostream>
#include <string>
#include <cctype>

const int NCOLOURS = 6 ;
const std::string colours[NCOLOURS] = { "red", "blue", "yellow", "orange", "purple", "green" } ;

const int NSHAPES = 3 ;
const std::string shapes[NSHAPES] = { "circle", "triangle", "square" } ;

const int NCARDS = NCOLOURS * NSHAPES ;

std::string to_lower( std::string str ) // make everything lower case
{
    for( char& c : str ) c = std::tolower(c) ;
    return str ;
}

int colour_to_int( std::string colour ) // return 1-6 if valid colour, 0 if not found
{
    colour = to_lower(colour) ;
    for( int i = 0; i < NCOLOURS ; ++i ) if( colours[i] == colour ) return i+1 ;
    return 0 ; // not found
}

std::string int_to_colour( int colour_number ) // colour_number 1-6
{
    if( colour_number > 0 && colour_number <= NCOLOURS ) return colours[colour_number-1] ;
    return "" ; // not found
}

int shape_to_int( std::string shape ) // return 1-3 if valid shape, 0 if not found
{
    shape = to_lower(shape) ;
    for( int i = 0; i < NSHAPES ; ++i ) if( shapes[i] == shape ) return i+1 ;
    return 0 ; // not found
}

std::string int_to_shape( int shape_number ) // shape_number 1-3
{
    if( shape_number > 0 && shape_number <= NSHAPES ) return shapes[shape_number-1] ;
    return "" ; // not found
}

int card_number( std::string colour, std::string shape ) // numbers 1-18, 0 if not found
{
    return colour_to_int(colour) * NSHAPES + shape_to_int(shape) - NSHAPES ;
}

std::string card_description( int card_number ) // 1-18
{
    if( card_number > 0 && card_number <= NCARDS )
    {
        const int colour_number = (card_number-1) / NSHAPES  + 1 ;
        const int shape_number = (card_number-1) %  NSHAPES + 1 ;
        return int_to_colour(colour_number) + ' ' + int_to_shape(shape_number) ;
    }
    else return "" ; // not found
}

int main()
{
    std::string colour, shape ;
    std::cout << "enter colour and shape: " ;
    std::cin >> colour >> shape ; // validate input
    std::cout << "your guess is: " << colour << ' ' << shape << '\n' ;

    int random_card = 5 ;
    std::cout << "the random card is: " << card_description(random_card) << '\n' ;

    if( card_number( colour, shape ) == random_card ) std::cout << "your guess is correct\n" ;
    else std::cout << "your guess is wrong\n" ;
}

http://coliru.stacked-crooked.com/a/f51255d60838f918
Wow, thank you JL! That's a hugee help man.


For this line
for( char& c : str ) c = std::tolower(c) ;

I'm getting the error [Error] range-based 'for' loops are not allowed in C++98 mode



I'm using dev to compile.
Set your compiler options to: -std=c++11 -Wall -Wextra -pedantic-errors

The classic for-loop:
1
2
// for( char& c : str ) c = std::tolower(c) ;
for( std::size_t i = 0 ; i < str.size() ; ++i ) c[i] = std::tolower( c[i] ) ; // legacy C++ 
Hm, the problem is this is for my class and it wouldn't compile on my professors computer either. I'll have to play around with the code, thanks a lot for your help. I'll check back in after I mess around with it a bit.
I'm getting the error [Error] range-based 'for' loops are not allowed in C++98 mode



I'm using dev to compile.


Your professor seems like one of those that is stuck way back in the old C++ days. The reason it won't compile is probably because you are using a severly outdated compiler to compile the code.

For example by your error code we know that you are following the 1998 C++ standard which is about almost 17 years old now and there have already been 2 new standards C++03 and C++11 (Think how much stuff has happened technology wise in 17 years). To put it more in perspective Windows XP was released in 2001. So you really need to update your compiler to a modern compiler that supports C++11 (Which will allows you to use ranged based for loops).

Also since you noticed that you are using "dev" to compile I am going to assume you mean Dev-C++ from Bloodshed which is a no longer supported (At least by bloodshed) IDE which comes with a outdated compiler (The last version of Dev-C++ from bloodshed was around 10 years ago which was version 4.9.9.2). Again 10 years is a long long time in the software world. So you should also grab a new IDE with more modern features (Every IDE should come with a C++11 enabled compiler also now days).

If of course your professor is forcing you to use your compiler and IDE I would seriously complain to a CS department head or the dean if possible because they really need to be replaced or get with the times.

Anyways just wanted to point out why you were having troubles with JLBorges code. And of course go on a little rant about weird professors that still think we are back in the 90's and are either forcing or suggesting their students use outdated software. ;p
Last edited on
OMG, 17 years old?! Ffs, no wonder I'm having such a difficult time. Thank you for pointing that out! I am absolutely going to meet with the dean of CS with this knowledge.
> OMG, 17 years old?!

It is not more than a few years old.

You couldn't have got this diagnostic from a pre-2010 compiler:
range-based 'for' loops are not allowed in C++98 mode

Compile with -std=c++11 and your compiler would become fairly current.


> I am absolutely going to meet with the dean of CS with this knowledge.

That is a good idea; demand that you be taught C++ as it is today; not as it used to be sometime back.

Last edited on
Oooh I see, JL, how long have you been programming? You seem very knowledgeable, considering you coded the whole function for me this ease, if my compiler was up to date lol.

So this is the route I decided to go, I'm not getting any compiler errors, so I think! I got 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
72
73
74
75
int const CARDS=18;
const int NCOLOURS = 6 ;
const std::string colours[NCOLOURS] = { "red", "blue", "yellow", "orange", "purple", "green" } ;

const int NSHAPES = 3 ;
const std::string shapes[NSHAPES] = { "circle", "triangle", "square" } ;

const int NCARDS = NCOLOURS * NSHAPES ;



std::string to_lower( std::string str ); // make everything lower case
 for (int i=0;i<CARDS;i++)
    {
    	std::string color,shape,combo,userSelect;
    	
    	
    	cout<<"Please choose a card with a color first, and then a shape.";
	cin>>color>>shape;
	combo= color + " " +shape;
	combo=userSelect;
  if (userSelect=="red circle")
  		return 1;
  	else if	(userSelect=="red triangle")
  		return 2;
  	else if(userSelect=="red square")
  		return 3;
  	else if(userSelect=="blue circle")
  	
  	return 4;
  	else if (userSelect=="blue triangle")
  	
  	return 5;
  	else if(userSelect=="blue square")
  	
  	return 6;
  	else if(userSelect=="yellow circle")
  	
  	return 7;
  	else if(userSelect=="yellow triangle")
  	
  	return 8;
  	else if(userSelect=="yellow square")
  	
  	return 9;
  	else if (userSelect=="orange circle")
  	
  	return 10;
  	else if (userSelect=="orange triangle")
  	
  	return 11;
  	else if(userSelect=="orange square")
  	
  	return 12;
  	else if (userSelect=="purple circle")
  	
  	return 13;
  	else if (userSelect=="purple triangle")
  	
  	return 14;
  	else if (userSelect=="purple square")
  	
  	return 15;
  	else if(userSelect=="green circle")
  	
  	return 16;
  	else if ( 	userSelect=="green triangle")
 
  	return 17;
  	else if  (userSelect=="green square")
  	
  	return 18;
}
    }
    
> OMG, 17 years old?!

It is not more than a few years old.

You couldn't have got this diagnostic from a pre-2010 compiler:


True you are right, I guess a better wording would be you are currently compiling under a standard that is 17 years old.

I shouldn't have implied that your compiler itself is that outdated (Though if you are using bloodshed Dev-C++ is it quite outdated if you haven't upgraded to a newer compiler).
Here's a slightly different way to do it. It creates a class to map an array of strings to/from the numbers and then instantiates two of them, one for shapes and the other for colors. An advantage is that there are no globals whatsoever.

We use a similar class at work quite a lot. In that version we have [] operators so it's very natural to use.

My compiler at work is very old so this could be improved.
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
#include <iostream>
#include <string>
#include <cstring>
#include <stack>
#include <vector>

using namespace std;

// maps an array of cstrings to numbers. Note that the first one maps
// to number 1, not 0.
class StringMap {
public:
    StringMap(const char **src, unsigned sz) :
	data(src),
	size(sz)
        {;}

    // map int to alpha. Returns "INVALID" if i is out of range.
    string itoa(int i);

    // map s to integer. The comparison is case insensitive. Returns
    // -1 if s isn't one of the strings.
    int atoi(const string &s);
private:
    const char **data;
    unsigned size;
};

string StringMap::itoa(int i)
{
    if (i<1 || i > size) return "INVALID";
    return data[i-1];
}

int StringMap::atoi(const string &s)
{
    for (size_t i=0; i<size; ++i) {
	// case insensitive comparison
	if (strcasecmp(s.c_str(), data[i]) == 0) {
	    return i+1;
	}
    }
    return -1;
}

int main(int argc, char **argv)
{
    static const char *shapeData[] = {"circle", "triangle", "square"};
    StringMap shapes(shapeData, 3);

    static const char *colorData[] = {"red", "blue", "yellow", "orange", "purple", "green"};
    StringMap colors(colorData, 6);

    cout << "red is " << colors.atoi("red") << '\n';
    cout << "BLUE is " << colors.atoi("BLUE") << '\n';
    cout << "Chartruse is " << colors.atoi("Chartruse") << '\n';

    for (int i=-3; i < 5; ++i) {
	cout << "shape " << i << " is " << shapes.itoa(i) << '\n';
    }
    return 0;
}


Hmm, thats very interesting. I began doing it in a way kind of like that, and she said nope not allowed. She's so strict in how she wants this done(it is the final project). I'm a CS major taking programming I, and we didn't even cover vectors or classes (go figure). Thank you for your input, i'll use that code to self educate myself.
Topic archived. No new replies allowed.