Rand function

Hi folks. I started teaching myself C++ this month, and I have just completed my first program. It's a simple music theory quiz. It's supposed to randomly generate a key and scale, and then the user guesses how many sharps/flats are in the given scale.

Everything works the way it's supposed to, except that when the user selects "Play again," the program generates the same key and scale as the first time. The only way to get a new, randomly selected key/scale is to quit and restart the program.

I'm sure I must be making a very simple mistake, but, like I said, I'm very new to C++, and I've got a lot to learn about the rand function (along with every other function!).

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
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
#include <iostream>
#include <cstdlib>
#include <ctime>
#include <string>

using namespace std;

int main ()
{
srand(static_cast<unsigned int>(time(0)));
	
short int key=1;
short int mode=1;
short int guess, assess, correctA, correctB;
char keyLtr;
char again='y';
string modeName;
	
while (again=='y')
{
	// Generate random key
	while (key==1 || key==3 || key==6 || key==8 || key==10)
	{
		key=rand()%12;
	}

	// Generate random mode
	while (mode==1 || mode==3 || mode==6 || mode==8 || mode==10)
	{
		mode=rand()%12;
	}

	// Generate key name
	switch (key)
	{
		case 0:
			keyLtr='C';
			break;
		case 2:
			keyLtr='D';
			break;
		case 4:
			keyLtr='E';
			break;
		case 5:
			keyLtr='F';
			break;
		case 7:
			keyLtr='G';
			break;
		case 9:
			keyLtr='A';
			break;
		case 11:
			keyLtr='B';
			break;
		default:
			cout << "\nUh oh, key=" << key << endl;		
	}
	
	// Generate mode name
	switch (mode)
	{
		case 0:
			modeName="Ionian";
			break;
		case 2:
			modeName="Dorian";
			break;
		case 4:
			modeName="Phrygian";
			break;
		case 5:
			modeName="Lydian";
			break;
		case 7:
			modeName="Mixolydian";
			break;
		case 9:
			modeName="Aeolian";
			break;
		case 11:
			modeName="Locrian";
			break;
		default:
			cout << "\nUh oh, modeName=" << modeName << endl;
	}
	cout << "\nHow many sharps/flats are in " << keyLtr << " " << modeName << "?\n(Use negative numbers for flats)\n";
	cin >> guess;
	
	// Generate correct answer
	assess=key + (12-mode);
	if (assess>11)
	{
		assess-=12;
	}

	switch (assess)
	{
		case 0:
			correctA=0;
			correctB=0;
			break;
		case 1:
			correctA=7;
			correctB=-5;
			break;
		case 2:
			correctA=2;
			correctB=2;
			break;
		case 3:
			correctA=-3;
			correctB=-3;
			break;
		case 4:
			correctA=4;
			correctB=4;
			break;
		case 5:
			correctA=-1;
			correctB=-1;
			break;
		case 6:
			correctA=6;
			correctB=-6;
			break;
		case 7:
			correctA=1;
			correctB=1;
			break;
		case 8:
			correctA=-4;
			correctB=-4;
			break;
		case 9:
			correctA=3;
			correctB=3;
			break;
		case 10:
			correctA=-2;
			correctB=-2;
			break;
		case 11:
			correctA=5;
			correctB=-7;
			break;
		default:
			cout << "\nUh oh, assess=" << assess << endl;
	}
	
	// Compare user response to correct answer
	if (guess==correctA || guess==correctB)
	{
		cout << "\nYou are correct, sir!\n";
	}
	else
	{
		cout << "\nNope, the correct answer is " << correctA;
		if (correctB != correctA)
		{
			cout << " or " << correctB;
		}
		cout << ".\n";
	}
	cout << "\nShall we give it another go? (y/n)\n";
	cin >> again;
}
cout << "\nOkay, later tater.\n";


return 0;
}
in while (again=='y')
add:
1
2
	key=1;
	mode=1;

at the beginning (before while (key==1 || key==3 || key==6 || key==8 || key==10)).
meanwhile ... Your first time has found a valid number according to the while loop condition. It is still valid on next iteration, so there is no need to call rand again.

Consider this:
1
2
3
4
std::string keys( "CDEFGAB" );
int key = rand() % 7;
cout << keys[ key ];
std::vector<std::string> modes = { "Ionian", ...

Ah, of course. I knew it would be something simple. Thanks for your help, tath and keskiverto!

Incidentally, the reason I don't just use a random number between 1 and 7 is because I need a number that represents the note's position on the piano, so that the "assess" expression will work properly. Anyway, thanks again.
I need a number that represents the note's position on the piano

But, what if you could compute the position?
1
2
3
const int position[] = { 0, 2, 4, 5, 7, 9, 11 };
...
int keyvalue = position[key];

The array 'position' is a simple "(math) function" that maps values from [0..6] into [0..11]. Your switch statements perform similar mappings.
Ahh.. I see. Good to know, thanks! Looks like I've got a lot to learn!
in this case you could also use structures to hold the data:
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
#include <iostream>
#include <cstdlib>
#include <ctime>
#include <string>

using namespace std;

struct note_t
{
	char letter;
	int	position;
	string modeName;
};

int main ()
{
srand(static_cast<unsigned int>(time(0)));
	
short int key;
short int mode;
short int assess;

note_t notes[7] = { {'C',0,"Ionian"},
		{'D',2,"Dorian"},
		{'E',4,"Phrygian"},
		{'F',5,"Lydian"},
		{'G',7,"Mixolydian"},
		{'A',9,"Aeolian"},
		{'B',11,"Locrian"}};

	key=rand()%7;

	cout << "Letter: " << notes[key].letter << endl;
	cout << "Position: " << notes[key].position << endl;

	cout << "-------------------------" << endl;

	mode=rand()%7;

	cout << "Mode name: " << notes[mode].modeName << endl;
	cout << "Position: " << notes[mode].position << endl << endl;

	system ("pause");

	return 0;
}


read more here: http://www.cplusplus.com/doc/tutorial/structures/
Last edited on
Topic archived. No new replies allowed.