How to move player object in 2d array using struct - c++

I'm making a maze game that uses a player structure and takes user input. The program runs, but nothing changes when I input commands to move my player. Any advice on whats going wrong?
// The function for user input
void getMove()
{
Player player1;
cout << "\n\nWhich direction would you like to go? ----- Treasure: " << numTreasure << "\n\n";
cout << "Up: 8\n";
cout << "Down: 2\n";
cout << "Left: 4\n";
cout << "Right: 6\n";
cin >> direction;
switch(direction)
{
case 8 :
if (currentBoard[player1.playerX - 1][player1.playerY] != '#'){
player1.playerX--;
}
break;
case 2 :
if (currentBoard[player1.playerX + 1][player1.playerY] != '#'){
player1.playerX++;
break;
}
case 4 :
if (currentBoard[player1.playerX][player1.playerY - 1] != '#'){
player1.playerY--;
break;
}
case 6 :
if (currentBoard[player1.playerX][player1.playerY + 1] != '#'){
player1.playerY++;
break;
}
}
switch(currentBoard[player1.playerX][player1.playerY]){
case '*':
cout << "You picked up a gold nugget!" << endl;
board[player1.playerX][player1.playerY] = treasureSpace;
numTreasure++;
break;
}
}
`

Your direction variable that is read in with cin >> is of type char*. In your switch-case you are comparing this direction variable against integers, so you will never get any of these cases AND you do not have a default case. I would switch the direction that is brought in from the user to an int with a type cast
`int_direction = (int)direction`
and then change your switch cases to compare against int_direction

Related

How to check if input is valid and keep asking for input if it's not

Can anybody please explain why this while loop is not working properly?
#include <iostream>
using namespace std;
void ask_user(int a, int b){
char choice = ' ';
while(choice != 'q' && choice != 'a' && choice != 's' && choice != 'm'){
cout << "choose operation" << endl;
cout << "a to add, s to subtract, m to multiply and q to quit" << endl;
cout << "----------------------------" << endl;
cin >> choice;
switch(choice){
case 'a' : cout << "a + b = " << a + b;
break;
case 's' : cout << "a - b = " << a + b;
break;
case 'm' : cout << "a * b = " << a + b;
break;
case 'q' : break;
default: cout << "please Enter a valid choice " << endl;
}
}
}
int main(){
ask_user(7, 9);
return 0;
}
If I enter p for exemple which is not valid then it works fine and asks for valid input again,
but if I enter pp that's when it starts bugging and prints the message twice. If I enter ppp it
prints three times etc...
First thing, you have a misunderstanding of how switch works. Each case must end with break statement so that the following one won't get executed.
Which means that a break will break the switch, not the while.
But the main issue is that the logic of your program is wrong.
You should not loop over the validity of the given input, let the switch statement handle that in the default clause.
Instead you should loop over a flag that will be set when the user press the q key.
So considering you have the following functions defined to respectively display the menu and ask for the operands to operate on (defined for code readability):
void display_menu(char & choice)
{
std::cout << "Operation:\na: Addition\nm: Multiplication\ns: Substraction\nq: Quit\n";
std::cin >> choice;
}
void ask_operands(int & a, int & b)
{
std::cout << "\na ?";
std::cin >> a;
std::cout << "\nb ?";
std::cin >> b;
std::cout << '\n';
}
The logic of your code can be then rewritten as:
int main()
{
bool quit = false;
char choice;
int a, b;
ask_operands(a, b); // Ask the user which operands to use
while(!quit) // loop over the flag
{
display_menu(choice);
switch(choice)
{
case 'a': std::cout << (a+b);
break;
case 'm': std::cout << (a*b);
break;
case 's': std::cout << (a-b);
break;
case 'q': std::cout << "Exiting...";
quit = true; // Set the flag to false
break;
default: std::cout << "Invalid choice, try again."; //Here you handle the invalid choices (i.e. let the loop iterate again)
}
std::cout << '\n';
}
return 0;
}
Live example
Note: If you want the user to be able to change the value of the operands at each iteration, just move the ask_operands(a, b); call inside the loop.

Total amount of games not displaying at end of switch loop cycle

so for one of my projects I am supposed to give the user multiple games to choose from, which can be played however many times they would like. As soon as they exit, the program should display the total amount of games played.
I have the code for the games done, I'm just working on the menu separately. For some reason when I call for the total at the end, it doesn't output anything. Not even the initial value that I place for the integer.
Any help is much appreciated!
#include <iostream>
using namespace std;
int main() {
int totalGames = 0;
while (true) {
int gameChoice;
cout << "Which game would you like to play?\n\n";
cin >> gameChoice;
switch (gameChoice)
{
case 1 :
cout << "You chose option 1";
totalGames++;
break;
case 2 :
cout << "You chose option 2";
totalGames++;
break;
case 3 :
cout << "You chose option 3";
totalGames++;
break;
case 4 :
return false;
break;
default:
cout << "Invalid Option";
break;
}
}
cout << "Total games: " << totalGames << endl;
return 0;
}
As already suggested in comment and #MichaelVeksler, case 4 exits the program and thus it doesn't output anything.
For instance, you can output it terminating while-loop using a boolean flag as follows:
DEMO
bool doContinue = true; // flag
while (doContinue)
{
int gameChoice;
cout << "Which game would you like to play?\n\n";
cin >> gameChoice;
switch (gameChoice)
{
case 1 :
cout << "You chose option 1";
totalGames++;
break;
case 2 :
cout << "You chose option 2";
totalGames++;
break;
case 3 :
cout << "You chose option 3";
totalGames++;
break;
case 4 :
doContinue = false;
break;
default:
cout << "Invalid Option";
break;
}
}
The issue is with:
case 4 :
return false;
Which exits the program, before reaching the printing statement.

Alternative to goto in nested loops?

This code is working fine, however this whole time I've tried avoiding using the goto statements that you will see in the switch (dice_total) statement.
Without the goto statements, the program will not loop back to the beginning of while (again=='y' || again=='Y'), and instead it keeps looping itself when it reaches the do-while loop.
However, I believe that it is also important to say, that if dice_total is = to the point_total the first time around then the program will function properly, and loop back to the beginning. For example, when the program starts, the first round will generate the point_total, which we will say its 10. Which is a value that will allow the program to continue to the next round, and if the dice_total also gets the same number, 10, the program will say you win, and the loop will work properly. However, if the program reaches the do while loop, and generates a number that isn't 10, but generates a 10 after a few loops, then the program will not loop to the beginning. So what I want to ask, what is wrong with my switch(dice_total) statement, and how can I fix it, to give the program the same effect without using the goto statements?
#include "stdafx.h"
#include <iostream>
#include <random>
#include <string>
using namespace std;
int main()
{
//Declared Variables***********************************
char again = 'y';
int point1;
int point2;
int point_total;
int round_1=1;
int dice1;
int dice2;
int dice_total;
//*****************************************************
//RANDOM SEED******************************************
random_device rd;
mt19937 mt(rd());
uniform_int_distribution<int>dist(1, 6);
//*****************************************************
start://TEMPORARY
while (again == 'y'||again=='Y')
{
int round_1 = 1;
system("CLS");
cout << "WELCOME TO THE CRAPS GAME" << endl;
cout << "THROWING ROUND:" << round_1 << " DICES.............." << endl;
point1 = dist(mt);
point2 = dist(mt);
point_total = point1 + point2;
cout << "ROUND: " << round_1 << " First dice is: " << point1 << " and second dice is: " << point2 <<" and the total is:"<<point_total<< endl;
switch (point_total)
{
case 7:
case 11:
cout << "YOU WON CONGRATS PRESS Y TO PLAY AGAIN!!" << endl;
cin >> again;
break;
case 2:
case 3:
case 12:
cout << "YOU LOST, PRESS Y TO TRY AGAIN" << endl;
cin >> again;
break;
default:
do
{
++round_1;
cout << "ROUND " << round_1 << endl;
dice1 = dist(mt);
dice2 = dist(mt);
dice_total = dice1 + dice2;
cout << "THROWING ROUND: " << round_1 << " DICES.............." << endl;
cout << "ROUND 1 DICE TOTAL IS: " << point_total << endl;
cout << "ROUND: " << round_1 << " First dice is: " << dice1 << " and second dice is: " << dice2 << " and the total is:" << dice_total << endl;
switch (dice_total)
{
case 11:
cout << "YOU WON CONGRATS PRESS Y TO PLAY AGAIN!!" << endl;
cin >> again;
goto start;
case 2:
case 3:
case 7:
case 12:
cout << "YOU LOST, PRESS Y TO TRY AGAIN" << endl;
cin >> again;
goto start;
default:
if (dice_total == point_total)
{
cout << "YOU WON CONGRATS PRESS Y TO PLAY AGAIN!!<<endl;
cin >> again;
break;
}//if
else
{
cout << "Going to next round" << endl;
}
}//dice_total
}//do
while (dice_total != point_total);
break;
}//switch point
}//again while
}//main
The problem you're facing is usual when you have too many nested loops in the same function, and is an indicator that you need to refactor parts of your code to be in their own functions.
If you do this, then you have more possibilities to control the flow of your code: in each function you have break and return, and as you can return a custom value, you can use it to determine in the surrounding function if you need to break or return again.
Besides, this gives you the opportunity to put self-explanatory names to your functions, which makes your code clearer for people that look at it for the first time (as it's written, it's so dense that I can't understand it unless I stare at it for some minutes).
An example of what I mean in code:
Before
int main() {
start:
while (a) {
b1();
switch(c) {
case 1:
do {
d();
if (cond) goto start;
} while(e);
break;
}
b2();
}
}
After
int main() {
while (a) {
if (!doStuff1())
break;
}
...
}
bool doStuff1() {
b1();
while (a) {
bool res = doStuff2();
if (res) return true;
}
b2();
...
}
bool doStuff2() {
switch(c) {
case 1:
if (doStuff3()) return true;
}
return false;
}
bool doStuff3() {
do {
d();
if (cond) return true;
} while (e);
return false;
}
How about this design?
bool stop=false;
while(!stop && (again == 'y'||again=='Y'))
{
while(again == 'y'||again=='Y')
{
// ...
break; /* breaks inner while*/
// ...
stop=true;
break; /* breaks inner while, and prevents running outer loop*/
}
}

Is there a proper way to close program from within function?

I am currently making a program that has menu and sub menus and i'd like to have an opportunity to close entire thing from within any sub menu (which is inside function). I know i could do it different way (both way i have it now and way i know it could be done are below) but for future use (i could prove useful) i would like to know:
Is there a way to properly close the program from within a function ?
I've read a few answers here and here and from what i've gotten out of it is:
I should not simply terminate the code
I should not use any system specific code as to avoid compatibilty issues
A bit of clarifiacation - that is program for my personal educational purposes so it is kind of unnecessary to worry about it but i'd rather learn propper ways of dealing with those situations at the beginning than have to learn them anew once i discover how to do them later and have to go back and fix it.
As for code samples (using visual studio 2017):
//skipping unrelevant to question bits of code
void sub_menu()
{
char a=0;
system("cls"); //yet to get changed when i'll find other way of clearing screen
std::cout << "Pick function:\n"
<< "---------------------------------------------------------\n"
<< "1.Foobar_1\n"
<<"---------------------------------------------------------\n"
<< "ESC to go back to menu menu\n"
<< "x to close";
while (a != 27)
{
a = _getch();
switch (a)
{
case 49:foobar_1(); break;
case 120:
case 88: system("exit"); break; //i'd like to replace that part
default: break;
};
};
return;
}
void main()
{
char a=0;
system("cls"); //yet to get changed when i'll find other way of clearing screen
std::cout << "Pick what you want to do:\n"
<< "---------------------------------------------------------\n"
<< "1.Sub_menu\n"
<< "2.foo\n"
<< "3.bar\n"
<<"---------------------------------------------------------\n"
<< "ESC to close\n"
while (a != 27)
{
a = _getch();
switch (a)
{
case 49:sub_menu(); break;
case 50:foo(); break;
case 51:bar(); break;
case 120:
case 88: system("exit"); break; //i'd like to replace that part
default: break;
};
};
return;
}
The way i could implement it (i think it is merely byapssing the issue):
//skipping unrelevant to question bits of code
void main()
{
char a=0;
system("cls"); //yet to get changed when i'll find other way of clearing screen
std::cout << "Pick what you want to do:\n"
<< "---------------------------------------------------------\n"
<< "1.Sub_menu\n"
<< "2.foo\n"
<< "3.bar\n"
<<"---------------------------------------------------------\n"
<< "ESC to close\n"
while (a != 27)
{
a = _getch();
switch (a)
{
case 49:
{
{
char b=0;
system("cls");
std::cout << "Pick function:\n"
<< "---------------------------------------------------------\n"
<< "1.Foobar_1\n"
<<"---------------------------------------------------------\n"
<< "ESC to go back to menu menu\n"
<< "x to close";
while (b != 27)
{
b = _getch();
switch (b)
{
case 49:foobar_1(); break;
case 120:
case 88: a=27; break;
default: break;
};
};
return;
}
}
; break;
case 50:foo(); break;
case 51:bar(); break;
case 120:
case 88: system("exit"); break; //i'd like to replace that part
default: break;
};
};
return;
}
This Code will work as you mentioned.
int main()
{
int a;
while (true)
{
system("cls"); //yet to get changed when i'll find other way of clearing screen
cout << "Pick what you want to do:\n"
<< "---------------------------------------------------------\n"
<< "1.Sub_menu\n"
<< "2.foo\n"
<< "3.bar\n"
<< "---------------------------------------------------------\n"
<< "0. to close\n";
cin >> a ;
if (a == 0)
{
return 0 ;
}
else if (a == 1)
{
char b;
while (true)
{
system("cls");
cout << "Pick function:\n"
<< "---------------------------------------------------------\n"
<< "1.Foobar_1\n"
<< "---------------------------------------------------------\n"
<< "b to go back to menu menu\n"
<< "x to close\n";
cin >> b;
if (b == '1')
{
foobar_1();
}
else if (b == 'B' || b == 'b')
{
break;
}
else if (b == 'x' || b == 'X')
{
return 0;
}
else
{
cout << "invalid input";
}
}
}
else if (a == 2)
{
foo();
}
else if (a == 3)
{
bar();
}
else
{
cout << "invalid input";
}
}
return 0;
}

Is there any way to make a C++ Switch Statement loop back to the first case?

OK, here is a simple code example:
char answer;
cin >> answer;
switch(answer)
{
case 'y':
case 'Y':
inventory[0] = "Short Sword";
cout << "\nYou place the Rusty Battle Axe in the chest.";
break;
case 'n':
case 'N':
inventory[0] = "Rusty Battle Axe";
cout << "\nYou leave the Short Sword in the chest.";
break;
default :
cout << "\nThat was an invalid response.";
}
Obviously I could pull my hair out with a while(answer != 'Y' || answer !=...) But is there a more elegant way of simply returning to the first case after executing the default case? So if a user enters the wrong letter, I simply ask them the question again until they type an acceptable response?
No this isn't homework or anything. I'm working through Dawson's C++ Game Programming book, and I wanted to jazz up the program example a little by allowing the user to keep or trade an item. I got all that working beautifully, but if a wrong response is entered it just shows the contents of the inventory and exits. I wanted to get that right. Force the user to enter a correct response, then show the updated inventory afterwards.
Appreciate the help!
UPDATE!
You have all given me so many different approaches to this - I really appreciate it! I admit I probably did not design this switch statement correctly and I apologize for the contradiction. I will try each of your suggestions and post back here, choosing one as answer. Thank you!
OK, I have just gone through all of your answers, trying most of them with my code. I have chosen the simplest, most elegant solution as the answer to my question. But you all have helped me to see different ways of looking at this, and I understand so much more about switch statements now. Using it in fact in place of a while loop in a tutorial I am following right now at YouTube by user What's A Creel?
I really appreciate all your help! I feel that I have really accomplished a lot in my programming practice today. You guys (and gals) are all awesome!
UPDATED AND COMPLETE CODE:
#include <iostream>
#include <string>
using namespace std;
// This program displays a hero's inventory
int main()
{
const int MAX_ITEMS = 4;
string inventory[MAX_ITEMS];
int numItems = 0;
inventory[numItems++] = "Rusty Battle Axe";
inventory[numItems++] = "Leather Armor";
inventory[numItems++] = "Wooden Shield";
cout << "Inventory:\n";
for(int i = 0; i < numItems; ++i)
{
cout << inventory[i] << endl;
}
cout << "\nYou open a chest and find a Lesser Healing Potion.";
inventory[numItems++] = "Lesser Healing Potion";
cout << "\nInventory\n";
for(int i = 0; i < numItems; ++i)
{
cout << inventory[i] << endl;
}
cout << "\nYou also find a Short Sword.";
if(numItems < MAX_ITEMS)
{
inventory[numItems++] = "Short Sword";
}
else
{
cout << "\nYou have too many items and can't carry another.";
cout << "\nWould you like to trade the " << inventory[0] << " for the Short Sword? ";
}
while (true)
{
char answer;
cin >> answer;
switch(answer)
{
case 'y':
case 'Y':
inventory[0] = "Short Sword";
cout << "\nYou place the Rusty Battle Axe in the chest." << endl;
break;
case 'n':
case 'N':
inventory[0] = "Rusty Battle Axe";
cout << "\nYou leave the Short Sword in the chest." << endl;
break;
default:
cout << "\nThat was an invalid response!";
cout << "\nWould you like to trade the " << inventory[0] << " for the Short Sword? ";
continue;
}
break;
}
cout << "\nInventory:\n";
for(int i = 0; i < numItems; ++i)
{
cout << inventory[i] << endl;
}
return 0;
}
You can use a one-shot loop that breaks at the end and use continue to jump back to the top:
while(true)
{
switch(...) {
//...
default:
continue;
}
break;
};
Perhaps a nicer way is to define a set of valid letters, especially if you'll do this kind of thing everywhere in your code:
char GetChoice( const string & prompt, const string & valid_choices )
{
while( cin.good() )
{
cout << prompt << " " << flush;
char c;
if( !cin.get(c) ) break;
size_t pos = valid_choices.find(toupper(c));
if( pos != string::npos ) return valid_choices[pos];
}
return 0; // Error condition.
}
And use like this:
switch( GetChoice("Do you want cake?", "YN") )
{
case 'Y':
cout << "Cake for you.\n";
break;
case 'N':
cout << "No cake for you.\n";
break;
case 0:
exit(1); // Error occurred
}
bool valid;
do
{
char answer;
cin >> answer;
switch (answer)
{
case 'y':
case 'Y':
inventory[0] = "Short Sword";
cout << "\nYou place the Rusty Battle Axe in the chest.";
valid = true;
break;
case 'n':
case 'N':
inventory[0] = "Rusty Battle Axe";
cout << "\nYou leave the Short Sword in the chest.";
valid = true;
break;
default :
cout << "\nThat was an invalid response.";
valid = false;
break;
}
}
while (!valid);
Well, add a loop and it will "loop back" wherever you want.
Note that the entire body of switch is just one long statement with labels in it. It works as any other statement, once you entered it through one of the labels. Just like an ordinary C++ statement will not "loop back" for you by itself unless you make it a cycle or use goto, neither will the body of switch "loop back" for you by itself.
So, if you want to transfer control back - use the appropriate language construct. You can inject goto right into the body of that statement and it will work as usual.
switch(answer)
{
case 'y':
case 'Y':
FIRST_OPTION:
...
break;
default :
...;
goto FIRST_OPTION; // Jump to first option
}
You might also want to take a look at Duff's device for a more intricate example of control transfer inside switch statement.
However, your question seems to contradict itself. You state that you want to ask the user for input again, if the answer was invalid. But the user input is requested and accepted outside of switch. Why do you say then that you want to return to the first option of switch???
Use a goto statement in the default section to go back to the input part
Here is one approach:
bool done = false;
while (!done) {
char answer;
cin >> answer;
done = true;
switch(answer)
{
case 'y':
case 'Y':
inventory[0] = "Short Sword";
cout << "\nYou place the Rusty Battle Axe in the chest.";
break;
case 'n':
case 'N':
inventory[0] = "Rusty Battle Axe";
cout << "\nYou leave the Short Sword in the chest.";
break;
default :
cout << "\nThat was an invalid response.";
done = false;
}
}
Use a while or do while loop.
Eg:
char answer;
bool loopback = true;
do
{
cin >> answer;
switch(answer)
{
case 'y':
case 'Y':
inventory[0] = "Short Sword";
cout << "\nYou place the Rusty Battle Axe in the chest.";
loopback = false;
break;
case 'n':
case 'N':
inventory[0] = "Rusty Battle Axe";
cout << "\nYou leave the Short Sword in the chest.";
loopback = false;
break;
default :
cout << "\nThat was an invalid response.";
loopback = true;
}
}
while (loopback);
You can use label and goto statement. Label the statement where you are asking the user to input and add a goto statement in default case.
Ex::
AskQuestion:
cout << "Press 'Y' for Short Sword Or 'N' for Rusty Battle Axe" << endl;
char answer;
cin >> answer;
switch(answer)
{
case 'y':
case 'Y':
inventory[0] = "Short Sword";
cout << "\nYou place the Rusty Battle Axe in the chest.";
break;
case 'n':
case 'N':
inventory[0] = "Rusty Battle Axe";
cout << "\nYou leave the Short Sword in the chest.";
break;
default :
cout << "\nThat was an invalid response.";
goto AskQuestion ;
}
Alternative way is to use do-while loop with condition while(answer != 'Y' || answer !=...) as you have already commented in the question. Ex::
do{
cout << "Press 'Y' for Short Sword Or 'N' for Rusty Battle Axe" << endl;
char answer;
cin >> answer;
switch(answer)
{
case 'y':
case 'Y':
inventory[0] = "Short Sword";
cout << "\nYou place the Rusty Battle Axe in the chest.";
break;
case 'n':
case 'N':
inventory[0] = "Rusty Battle Axe";
cout << "\nYou leave the Short Sword in the chest.";
break;
default :
cout << "\nThat was an invalid response.";
}
}while( answer != 'Y' || answer != 'y' || answer != 'N' || answer != 'n' ) ;