Loop Skips User Input

My displayMenu function is stuck in a continuously loop (keeps outputting) after the second iteration when I call the addPlayer function(4 calls it). Any suggestions on what may be causing this? Thanks in advanced :p

I have a file called "playerdata.txt" which reads in the following:
102 Bob 345 76 34
45 Sue 300 78 21
24 David 200 50 12
76 Pam 210 34 44

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
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
//Dfurball RPG
#include <iostream>
#include <fstream>
#include <string>
#include <iomanip>
#include <ctime>
using namespace std;

struct sPlayer
{
	string name;
	int id, gold, health, exp;
};

void getData(ifstream& inp, sPlayer PlayerAr[], int &numPlayers);
void sortData(sPlayer playerAr[], int numPlayers);
int binarySearch(sPlayer playerAr[], int searchid, int numPlayers);
int displayMenu();
void displayReport(sPlayer playerAr[], int numPlayers);
int addNewplayer(sPlayer playerAr[], int numPlayers);
void attack(sPlayer playerAr[], int playerIdx);
void buyHealthpoints(sPlayer playerAr[], int playerIdx);
int deletePlayer(sPlayer playerAr[], int playerIdx, int numPlayers);
void saveData(sPlayer playerAr[], int numPlayers);
int playerSelect(sPlayer playerAr[], int numPlayers);

void main()
{
	sPlayer playerAr[100];
	int menu;
	bool quit = false;
	ifstream inp;
	int playerIdx = 0;
	int numPlayers = 0;
	
	getData(inp, playerAr, numPlayers);	
	playerIdx = playerSelect(playerAr, numPlayers); // current player
	
	while(!quit)
	{
		menu = displayMenu();

		switch(menu)
		{
		case 1: // select player
			playerIdx = playerSelect(playerAr, numPlayers);
			break;
		case 2: // attack
			attack(playerAr, playerIdx);
			break;
		case 3: // buy health
			buyHealthpoints(playerAr, playerIdx);
			break;
		case 4: // add player
			numPlayers = addNewplayer(playerAr, numPlayers);
			break;
		case 5: // delete player
			numPlayers = deletePlayer(playerAr, playerIdx, numPlayers);
			break;
		case 6: // display report
			displayReport(playerAr, numPlayers);
			break;
		case 0: // exit
			quit = true;
			cout << "You have quit" << endl;
			cout << menu;
			break;
		default:
			break;
			cout << "Invalid menu selection" << endl;
		
		} // switch
	} // while
}

void getData(ifstream& inp, sPlayer playerAr[], int &numPlayers)
{
	int i = 0;
	inp.open("playerdata.txt");
	// how do I make it loop until end of file?
	if(inp.is_open())
	{
		inp >> playerAr[i].id;

		while(inp.eof() == false) //stolen from Matt
		{
			//inp.ignore(1, ' '); //stolen from Matt
			inp >> playerAr[i].name;
			inp >> playerAr[i].gold;
			inp >> playerAr[i].health;
			inp >> playerAr[i].exp;
			i++;
			inp >> playerAr[i].id;
			numPlayers++;
		} // end while
		//numPlayers--;
	}
	else
	{
		cout << "File Error: file not found" << endl;
	}
	inp.close(); 
	sortData(playerAr, numPlayers);
}

void sortData(sPlayer playerAr[], int numPlayers)
{
	bool swapped = true;
	int j = 0;
	sPlayer tmp;

		while (swapped) 
		{
			swapped = false;
			j++;

            for (int i = 0; i < numPlayers - j; i++) 
			{
                  if (playerAr[i].id > playerAr[i + 1].id) 
				  {
					tmp = playerAr[i];
					playerAr[i] = playerAr[i + 1];
					playerAr[i + 1] = tmp;
					swapped = true;
                  }
            }
      }
}

int binarySearch(sPlayer playerAr[], int searchid, int numPlayers)
{
	int mid;
	int first = 0;
	int last = numPlayers; 
	bool found = false;

	while(first <= last && !found)
	{
		mid = (first + last) / 2;
		if(playerAr[mid].id == searchid)
		{
			found = true;
		}
		else if (playerAr[mid].id > searchid)
		{
			last = mid - 1;
		}
		else
		{
			first = mid + 1;
		}
	} //while
	if (found)
	{
		return mid; // position of player in array (playerIdx)
	}
	else
	{
		return -1; // id not found
	}
}

int displayMenu()
{
	int answer;

	cout << "1: Select player" << endl;
	cout << "2: Attack" << endl;
	cout << "3: Purchase health" << endl;
	cout << "4: Add player" << endl;
	cout << "5: Delete player" << endl;
	cout << "6: Player report" << endl;
	cout << "0: Exit" << endl;
	cin >> answer;
	
	return answer;
}

void displayReport(sPlayer playerAr[], int numPlayers)
{
	cout << "Player Info" << endl;
	cout << left << setw(10) << "ID" << setw(20) << "Player Name" << setw(20) << "Health points" << setw(20) << "Gold" << setw(20) << "Experience" << endl;
	for (int i = 0; i < numPlayers; i++)
	{
		cout << setw(10) << playerAr[i].id;
		cout << setw(20) << playerAr[i].name;
		cout << setw(20) << playerAr[i].health;
		cout << setw(20) << playerAr[i].gold;
		cout << setw(20) << playerAr[i].exp;
		cout << endl;
	}
}

int addNewplayer(sPlayer playerAr[], int numPlayers)
{
	bool found = false;
	string name;
	int id, gold, hp, exp;
	int bin;
	
	while(found == false)
	{
		cout << "Enter ID: ";
		cin >> id; 
	
		// call binary search
		bin =  binarySearch(playerAr, id, numPlayers);
		if(bin == -1) //ID is not in use therefor create new player
		{
			cout << "Enter player name: " << endl;
			getline(cin, name);
			cin.ignore(1);
			cout << endl;
			// set default values
			gold = 200;
			hp = 50; 
			exp = 0;
			playerAr[numPlayers].id = id;
			playerAr[numPlayers].name = name;
			playerAr[numPlayers].gold = gold;
			playerAr[numPlayers].health = hp;
			playerAr[numPlayers].exp = exp;
			found = true;
			numPlayers++;
			break;
		}
		else
		{
			cout <<"ID is in use." << endl;
			numPlayers--; // player is not created
			break;
		}
		
	} // while
	return numPlayers; //update numPlayers
}

void attack(sPlayer playerAr[], int playerIdx)
{
	srand((unsigned int) time(NULL)); //usigned int prevents data loss warning 
	int roll = rand() % 2;

	if (playerAr[playerIdx].health >= 5)
	{
		if (roll == 0)
		{	
			playerAr[playerIdx].gold = playerAr[playerIdx].gold + 10;
			playerAr[playerIdx].exp = playerAr[playerIdx].exp + 2;
			cout << "Registered hit!" << endl;  
		}
		else if (roll == 1)
		{
			playerAr[playerIdx].health = playerAr[playerIdx].health - 5;
			playerAr[playerIdx].exp = playerAr[playerIdx].exp + 1;
			cout << "You've been hit!" << endl;  
		}
		else if (roll == 2)
		{
			cout << "You missed!" << endl;
		}
	}
}

void buyHealthpoints(sPlayer playerAr[], int playerIdx)
{
	int num; //quantity

	if(playerAr[playerIdx].gold >= 2)
	{
		cout << "A health potion cost 2 gold. How many would you like to purchase?" << endl;
		cout << "Quantity: ";
		cin >> num;
		cout << endl;
		if(num * 2 < playerAr[playerIdx].gold)
		{
			num = num * 2 ; // hp gained
			cout << "You gained: " << num << " health points!" << endl;
			playerAr[playerIdx].health = playerAr[playerIdx].health + num;
			playerAr[playerIdx].gold =  playerAr[playerIdx].gold - num; 
		}
		else 
		{
			cout << "Not enough gold... poor bastard" << endl;
		}
	}
}

int deletePlayer(sPlayer playerAr[], int playerIdx, int numPlayers)
{
	bool found = false;
	char confirm = ' ';
	int idd = 999; 
	int bin = 2;
	
	while(numPlayers > 1 && found == false) //don't delete last player
	{
		cout << "Select ID for deletion: ";\
		cin >> idd;
		
		//call binary search
		bin = binarySearch(playerAr, idd, numPlayers);
		
		if (bin == -1)
		{
			cout << "ID not found! :( " << endl; // continue loop
		}
		else
		{
			found = true; // break loop
		}
		
	} // while
	while (found == true)
	{
		cout << "ID found. Delete info? (y/n): "; 
		cin >> confirm;
		cout << endl;
		if (confirm == 'Y' || confirm == 'y')
		{
			for (int i = bin; i < numPlayers - 1; i++)
			{
				playerAr[i] = playerAr[i + 1]; // copy players to new location
			} // for
			numPlayers--; // update number of players
			found = false; // exit while loop
			break;
		}
		else if (confirm == 'N' || confirm == 'n')
		{
			found = false;
			break; 
		}
	} // while
	return numPlayers; // update players
}

void saveData(sPlayer playerAr[], int numPlayers)
{
	ofstream outp;
	outp.open("playerdata.txt");
	
	for(int i = 0; i < numPlayers; i++)
	{
		outp << playerAr[i].id;
		outp << playerAr[i].name;
		outp << playerAr[i].gold;
		outp << playerAr[i].health;
		outp << playerAr[i].exp;
	}
}

int playerSelect(sPlayer playerAr[], int numPlayers)
{
	int playerIdx = 0;
	int id = -1;
	int bin = 2; 
	displayReport(playerAr, numPlayers);
	cout << endl << endl;
	cout << "Enter a player ID: ";
	cin >> id;

	bin = binarySearch(playerAr, id, numPlayers);

	if(bin == -1)
	{
		cout << "Binary Search function failed =(" << endl;
	}
	else
	{
		playerIdx = bin;
		cout << "Player selected" << endl;
	}

	return playerIdx;
}
Does it keep spitting out the menu over and over? Or does it ignore user input into addplayer?
It looks to me that the menu will continue to be displayed until the user enters 0. If you want it to do something else after adding a player then call the appropriate function from the addplayer function.

Main should always return an int:

1
2
3
4
5
int main() {
//your code here

return 0; //if all is well
}


Hope all goes well.
Last edited on
Another thing - you can build up the cout in parts - no need to have one big long statement. Try this:


1
2
3
4
cout << left << setw(10) << "ID" << setw(20) << "Player Name" ;
cout << setw(20) << "Health points" << setw(20) << "Gold" ;
cout << setw(20) << "Experience" << endl;


There is a bit of a rule that code should not exceed 80 chars per line.




Last edited on
Thanks for the input.

@TheIdeasMan
Why should main always return an int?
I've never heard of do not exceed 80 chars per line. Is this just for readability?

For clarification: the addPlayer function is called, it asks for the player id and name, and then afterwards it spams displayMenu. It should wait for the user to input a menu selection after its displays, but instead it just keeps outputting the menu:

1
2
3
4
5
6
7
8
9
10
int answer;
cout << "1: Select player" << endl;
cout << "2: Attack" << endl;
cout << "3: Purchase health" << endl;
cout << "4: Add player" << endl;
cout << "5: Delete player" << endl;
cout << "6: Player report" << endl;
cout << "0: Exit" << endl;
cin >> answer;
return answer;
Why should main always return an int?
Because the operating system may use the returned value to determine success or failure, for example if the prgram is run from within a script.

I've never heard of do not exceed 80 chars per line. Is this just for readability?
Legibility and Printability.

Also, online it is considered poor form for any webpage to require horizontal scrolling. The same might be said during editing of source code. Although individual users may have screens wide enough to accommodate the full width, it is generally accepted that shorter lines are more legible.

That's the reason why newspapers divide the page into columns. Although a headline extending the full page width is easy to read, the same could not be said for the body text.

Actually, you don't need to end the line with a semicolon and begin a new statement. Just add a line-break where convenient, and indent the code so it's clear that it is a continuation of the previous line. Remember the compiler ignores whitespace.
Last edited on
Why should main always return an int?


A modern compiler should complain about void main(). You can get away with not explicitly returning an int (the compiler will do it implicitly) but you do need to specify int main()

The reason is the OS makes use of the return value, and if you are writing a script that calls you program, you can test the return value to see if your program behaved as expected, and take action otherwise.

It is good practice to do it the way I mentioned earlier.

I've never heard of do not exceed 80 chars per line. Is this just for readability?


Yes. I am not fond of having to scroll sideways all the time, also if someone needs to print the code on paper, it is easier.

One small thing:
if (confirm == 'Y' || confirm == 'y')

If you make use of std::toupper (include <locale> to use it) you won't need to test the variable twice, because it converts the variable to uppercase.

As for the displaymenu function, I don't know why it does not stop for input. As far as I can see, it breaks out of the switch, then the displaymenu is called again - i don't know it doesn't stop for input.

Sorry, I still haven't answered your original question, at least we have fixed a couple of other things.

Hope all goes well - I am looking forward to the answer as well.
Thanks for the help guys! I discovered the problem was the cin.ignore that I used in my addPlayer function. It ignores the next character, which happens to be the input for the displayMenu, hence an infinite loop. *facepalm*

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
if(bin == -1) //ID is not in use therefor create new player
		{
			cout << "Enter player name: " << endl;
			getline(cin, name);
			cin.ignore(1);
			cout << endl;
			// set default values
			gold = 200;
			hp = 50; 
			exp = 0;
			playerAr[numPlayers].id = id;
			playerAr[numPlayers].name = name;
			playerAr[numPlayers].gold = gold;
			playerAr[numPlayers].health = hp;
			playerAr[numPlayers].exp = exp;
			found = true;
			numPlayers++;
			break;
		}
Oh good - pleased you have figured it out - did you use the debugger to find the problem?

The debugger is often the best way to discover answers.

Hope all goes well :)
Lol! What's the actual use for cin.ignore()? Is it a user input formatting thing?
Topic archived. No new replies allowed.