I've got the following enum declared in code.cpp
and im using a switch statement that depends on the what the enum is set as.
enum State { HighMoral, PoorMoral, EndGame };
State CurrentState = HighMoral;
switch (CurrentState)
{
case HighMoral: random = rand()%3+1;
switch (random)
{
case 1: CurrentState = g_Solider.KillCommander(&CurrentState, random = rand()%2+1);
break;
case 2: CurrentState = g_Solider.KillSeniorCommander(&CurrentState,random = rand()%2+1);
break;
case 3: CurrentState = g_Solider.LessHalfStrength(&CurrentState);
break;
};
break;
case PoorMoral: CurrentState = g_Solider.JoinSeniorCommander();
break;
};
I want to pass this enum to a function in a class and then have it return either HighMoral, PoorMoral or EndGame and change the current state for my switch statement.
However I'm rather clueless when it comes to passing this and returning it.
I've looked around and have had no luck in finding how to do this.
I've got 3 files. code.cpp (contains void main() and the enum), solider.h (contains solider class does not know the state enum exists (how to do this?)), solider.cpp (contains all solider code but needs to take the current state and return a new state)
Here is an example of what I'm trying to do.
Solider.h
#include <time.h>
#include <iostream>
using namespace std;
extern enum State;
class Solider
{
private:
public:
void KillSeniorCommander(State& currentState, int random); // Kill the Senior Commander or random event
void JoinSeniorCommander(State& currentState); // Have the Commander join the group
void DefunctGroup(State& currentState); // Disband the group
};
Solider.cpp
void Solider::KillSeniorCommander(State& currentState, int random)
{
if (SeniorCommander==1) // If The SeniorCommander is Active
{
cout << "The Senior Commander has died!\n";
SeniorCommander--; // Kill the SeniorCommander
Groupsize--; // Reduce the Groupsize
Strength = Strength - (5*2.5); // Remove SeniorCommanders impact on Strength
SquadMoral = SquadMoral - (5*2.5);// Remove SeniorCommanders impact on SquadMoral
CurrentState = PoorMoral;
}
else // Otherwise do something random
{
switch (random)
{
case 1: cout << "Your group survives a ambush!\n";
break;
case 2: random = rand()%5+1; // Give random a new value
if (random>1)
{
cout << random << " group members have died!\n"; // Kill x Aamount of members
}
else
{
cout << "A group member has died!\n"; // Kill a member
}
Groupsize = Groupsize - random; // Remove the members from the group
Strength = Strength - (random*2.5); // Remove there effect Strength
SquadMoral = SquadMoral - (random*2.5); // Remove there effect on GroupMoral
break;
}
CurrentState = CurrentState;
}
} // KillSeniorCommander(int random)
void Solider::JoinSeniorCommander(State& currentState)
{
if (SeniorCommander==2 && Commander == 0) // Check to see if the Commander is dead and a
{ // SeniorCommander is not in service
cout << "The Senior Commander has joined!\n";
SeniorCommander--; // Change their status to active
Groupsize++; // Add them to the group
Strength = Strength - (5*2.5); // Add their impact to Strength
SquadMoral = SquadMoral - (5*2.5); // Add their impact to GroupMoral
CurrentState = HighMoral;
}
else // He isn't available to join
{
cout << "You fail to recruit new command!\n";
CurrentState = CurrentState;
}
} // JoinSeniorCommander()
void Solider::DefunctGroup(State& currentState)
{
cout << "Your group has been disbanded as it is not fit for duty.";
CurrentState = EndGame;
} // DefunctGroup()
code.cpp
Define the enum in a header and include that header in both files.
For instance:
#ifndef SOLDIERSTATE_H
#define SOLDIERSTATE_H
enum SoldierState
{
HighMorale,
PoorMorale,
EndGame
};
#endif
Enums can be treated as integers in interfaces. You can use on of two approaches: Pass by reference and have the function change it intenally, or pass by value and return the next State by value:
// one or the other
void nextState( State& currentState );
State nextState( State currentState );
As with everything else in C++, you need to see the declaration of something you want to use. In your case, this means the definition of State must be moved to a header file and this file then be included both in main.cpp and soldier.h. Then, you will be able to use the type State in declarations of Soldier member functions normally.
class Game
{
public:
enum State { HighMoral, PoorMoral, EndGame };
aMethod(State::PoorMoral);
};
Game::aMethod(State aState)
{
return State::HighMoral;
}
Related
I have a player class where I am storing the player's current position, the number of players in the game and a static variable to store the total number of players like so:
#ifndef PLAYER_H
#define PLAYER_H
#include <ctime>
#include <random>
#include <iostream>
using std::time;
using std::cout;
class Player
{
private:
int m_Player_currentPosition, m_Player_number;
static int m_Player_numberOfPlayers;
public:
Player::Player():m_Player_currentPosition(1) {
m_Player_number = m_Player_numberOfPlayers;
++m_Player_numberOfPlayers;
}
void m_Player_SetPosition();
int m_Player_GetPosition();
int m_Player_GetPlayerNumber() { return m_Player_number; }
void m_Player_SetNumberOfPlayers() { m_Player_numberOfPlayers = 1; }
~Player() { --m_Player_numberOfPlayers; }
};
int Player::m_Player_numberOfPlayers = 1;
#endif
I also have a game class that creates a certain number of player instances using a vector. In my game class, the plan is to create players depending on user input (between 2-4 number of players) using m_Game_SetPlayers() member function and also printing the details of the players using the m_Game_PrintPlayers() member function.
#ifndef GAME_H
#define GAME_H
#include <iostream>
#include "Board.h"
#include "Player.h"
using std::cout;
using std::cin;
using std::vector;
class Game {
private:
bool m_Game_quit;
int m_Game_choice;
Board board;
vector<Player> m_Game_players;
public:
Game();
const bool &m_Game_GetQuit() const;
void m_Game_SetPlayers()
{
int numberOfPlayers = 2;
cout << "How many players (2-4)? ";
cin >> numberOfPlayers;
if (numberOfPlayers < 2 || numberOfPlayers > 4) {
numberOfPlayers = 2;
}
m_Game_players.resize(numberOfPlayers);
}
void m_Game_PrintMenu();
void m_Game_PrintInstructions();
void m_Game_GetChoice();
void m_Game_PrintPlayers()
{
cout << '\n';
vector<Player>::iterator iter;
for (iter = m_Game_players.begin(); iter != m_Game_players.end(); ++ iter) {
cout << "Player " << iter->m_Player_GetPlayerNumber() << "'s position: " << iter-
>m_Player_GetPosition() << '\n';
}
}
void Update();
};
#endif // !GAME_H
However, in my main class, I am calling the Game class's update function under a while loop. Here is my game update member function declared in a separate implementation file that decides the control flow of the game.
void Game::Update()
{
m_Game_GetChoice();
switch (m_Game_choice) {
case 0: cout << "---Bye---\n";
m_Game_quit = true;
break;
case 1:
system("cls");
m_Game_PrintInstructions();
break;
case 2:
system("cls");
m_Game_SetPlayers();
system("cls");
board.m_Board_PrintBoard();
m_Game_PrintPlayers();
m_Game_players[0].m_Player_SetNumberOfPlayers();
break;
default:
cout << "--Invalid Option---\n";
break;
}
}
Here is my while loop in the main function:
#include "Game.h"
int main() {
Game game;
while (!game.m_Game_GetQuit()) {
system("cls");
game.m_Game_PrintMenu();
game.Update();
system("pause");
}
}
When I ran this program the first time, it worked as expected. However, imagine if I choose the play option from the menu and I enter 2 players, it creates 2 instances of the player class. On the next while loop iteration, I increase the size to 4 players which also works perfectly sometimes. Then, when I reduce the size and then again increase the size, the player number does not match. Here are the following images to help understand the problem:
Input 1: https://i.stack.imgur.com/reHjE.png
Output 1: https://i.stack.imgur.com/Dt68V.png
Input 2: https://i.stack.imgur.com/Xo83c.png
Output 2: https://i.stack.imgur.com/2Qso6.png
The expected output is:
Player's position 1: 1
Player's position 2: 1
Player's position 3: 1
So, I thought that I need to delete my instances, but since I cannot delete instances on a stack memory as long as I am in a while loop (How do I manually delete an instance of a class?, http://www.cplusplus.com/forum/beginner/107822/). I thought that I will resize the vector. It did resize the vector, but then it does not delete the instances of the player class but instead created a new instance of that class. Is there a way to destroy all the instances of the class on a stack memory even when it is inside the scope? If not, how do I solve this problem?
I may/may not have provided the code needed to debug this problem. So, I have attached my entire code on https://github.com/F3INTH34RTED/Cpp/tree/master/Beginner/16SnakesAndLadder if need be.
When you increase the size of the vector, say from 2 to 3, it only needs to create one new instance of Player, so it will create a single player with the next number.
The line
m_Game_players[0].m_Player_SetNumberOfPlayers();
on the previous loop iteration sets the global counter to 1. So this single new player gets number 1, not number 3 like you expect. You should be able to remove the above line and things will work as expected.
On a design note, it would probably be wiser to recreate the vector entirely when the number of players is changed and explicitly give each player a number via the constructor, like this:
void m_Game_SetPlayers()
{
int numberOfPlayers = 2;
cout << "How many players (2-4)? ";
cin >> numberOfPlayers;
if (numberOfPlayers < 2 || numberOfPlayers > 4) {
numberOfPlayers = 2;
}
m_Game_players.clear();
for (int i = 1; i < numberOfPlayers; i++) {
m_Game_players.push_back(Player(i));
}
}
Updating the Player constructor to match, of course.
Your issue is that std::vector::push_back will do copy/move when it needs to resize internal buffer, and your (auto generated default) copy/move constructors doesn't handle that, you might do for example:
class Player
{
private:
int m_currentPosition;
std::optional<int> m_number;
static int m_numberOfPlayers;
public:
Player() : m_currentPosition(1), m_number(++m_numberOfPlayer) {}
Player(const Player&) = delete;
Player(Player&& rhs) : m_currentPosition(rhs.m_currentPosition), m_number(rhs.m_number) { rhs.m_number = std::nullopt; }
Player& operator = (const Player&) = delete;
Player& operator = (Player&& rhs) { std::swap(m_currentPosition, rhs.m_currentPosition); std::swap(m_number, rhs.m_number); }
int GetPlayerNumber() const { return *m_number; }
~Player() { if (m_number) --m_numberOfPlayers; }
};
i am trying to add a developer mode in my program. since duty of car defers every month,i want give my user permission to change every single variables in my program alike duty lccost yen2taka freight
#include <iostream>
using namespace std;
class A
{
public:
int carbid,duty;
void Input()
{
cout<<"please insert the car price you want to bid for(in yen): ";
cin>>carbid;
cout<<"duty of the car: ";
cin>>duty;
}
int Exportcost()
{
int exportcost;
int servicechrg=10;
int freight=20;
exportcost=servicechrg+freight+carbid;
return exportcost;
}
int Yen2taka()
{
int yen2taka;
int taka2dollarrate=10;
int dollar2yen=1;
yen2taka=((Exportcost())/dollar2yen)*taka2dollarrate;
return yen2taka;
}
int Importcost()
{
int importcost;
int lccost=10;
int cnfcost=20;
importcost=lccost+cnfcost;
return importcost;
}
int Totalcosting()
{
int total;
int myprofit=10; //80000
total=myprofit+Importcost()+Yen2taka();
cout<<total;
return total;
}
void summary()
{
cout<<
}
};
int main()
{
x:
A ob;
ob.Input();
ob.Exportcost();
ob.Yen2taka();
ob.Importcost();
ob.Totalcosting();
int ch;
cout<<"press 1 to see the summery of the costing or 2 to restart costing again"<<endl;
cin>>ch;
switch(ch)
{
case 1:
ob.summary();
break;
case 2:
goto x;
}
}
At first, you should collect these parameters in a separate class:
class Configuration // maybe you find a better name...
{
int m_servicechrg = 10; // default
int m_freight = 20;
// ...
public:
int servicechrg() { return m_servicechrg; }
void servicechrg(int value); { /* check some limits? */ m_servicechrg = value; }
int freight() { return m_freight; }
void freight(int value); { /* check some limits? */ m_freight = value; }
// ...
};
// will allow you to do:
// C c; std::cout << c;
ostream& operator<<(ostream& s, Configuration const& c)
{
// which ever formatting is appropriate...
s << c.servicechrg() << ' ' << c.freight();
return s;
}
The setters could alternatively return bool to indicate invalid values.
Now you can use this class within main:
Configuration c;
A a;
int cost = a.exportCost(c); // you'd have to adjust signatures...
int value;
switch(ch)
{
case 4:
if(stc::cin >> freight) // catches invalid user input!
// one ALWAYS should do, otherwise you might end up in
// your program not working any more
{
c.freight(value);
// or, if you have:
if(!c.freight(value))
{
// some appropriate error message
// (it's better not to output in the setter, you are more flexible this
// way – maybe you want different messages at different occasions?)
}
}
else
{
// appropriate error handling
}
break;
default:
// handling invalid user input
// again, you always should; but stream state is not in error state,
// so you just can print appropriate error message
break;
}
See this answer for how to correctly handle stream errors.
If you wonder about the differences in error handling: First case is met if user enters non-numerical input, such as ss, second case, if input is numerical, but out of valid range (77).
Now if you don't want to pass the configuration as parameter all the time, you could make a global variable from (but careful, there are some dangers with global variables, use them as sparely as possible) or implement the singleton pattern.
Side notes: goto can be a fine tool sometimes, but it is a dangerous one (and the label's name x isn't a good one, prefer a name that clearly shows intention, such as REENTRY_POINT, LOOP_START, ...). If you can get along without unreasonable effort, prefer such variants:
bool isRunning = true;
do
{
// ...
case 2:
isRunning = false;
break;
}
while(isRunning);
Sure, an additional variable, an additional check; unfortunately, you cannot use break to exit a (pseudo-) endless loop (for(;;)) (but don't apply this pattern for nested loops, then it gets more and more unreadabla – and ineffcient: bool isExit = false; for(int i = 0; !isExit && i < n; ++i) { for(j = 0; j < n; ++j) { isExit = true; break; } } – see what I mean?). A variant might be:
for(;;)
{
switch(ch)
case 1:
// ...
//break; <- replace
continue;
case 2:
//
break;
} // end of switch
break; // break the surrounding for(;;) loop
}
But that's not really nice either.
A pretty nice variant allowing to exit the loop in the given case, as there isn't anyhting to do afterwards:
for(;;)
{
switch(ch)
{
case 2:
// maybe yet some cleaning up here
return 0;
default:
// ...
break;
}
}
Drawback: The function's exit point possibly is deeply nested inside the code.
There are yet other tricks to allow this pattern, like packing sub-sections of code in a lambda having a return inside and call that one directly. But that now really starts going beyond the scope...
Finally, if you insist on goto, my variant would rather be:
for(;;)
{
switch(ch)
{
case 2:
// ...
goto LOOP_EXIT;
default:
// ...
break;
}
}
LOOP_EXIT:
return 0; // e. g. main
(void)0; // if there isn't anything to do in the function any more
// (labels require an instruction afterwards!)
There won't be a hidden loop now and it is more obvious what you actually are doing. Currently, not really an issue, but if your code grows, the hidden loop gets more and more difficult to spot.
In such cases, I clearly mark the gotos so that another coder can immediately spot the critical code points:
///////////////////////////////////////////////////
// possibly some comment why applying this pattern
goto SOME_LABEL;
///////////////////////////////////////////////////
One could do the same with deeply nested function exit points (return).
std::cout prints extra characters in my keyPressed string, probably because of "\r", for example, if keyPressed = "Right arrow", when I press the up arrow, it prints "keyPressed = Up arrowoww", then, when I press right arrow again, it prints "keyPressed = Right arrow" normally again, but if I press any arrow key except "Right arrow" it prints some unwanted extra characters at the end
Error example
Source code:
game.cpp
#include "engine.h"
#include <iomanip>
Engine eng;
int main() {
while (eng.isRunning) {
eng.getInput();
std::cout << std::setw(5);
std::cout << "\r X = " << eng.playerX;
std::cout << "| Y = " << eng.playerY;
std::cout << "| KEY = " << eng.keyPressed;
Sleep(100);
}
return 0;
}
engine.h
#ifndef ENGINE_H
#define ENGINE_H
#include <iostream>
#include <Windows.h>
#include <string>
class Engine {
public:
// Game
bool isRunning = true;
bool gettingInput = true;
// Player
int playerX = 1;
int playerY = 1;
char playerModel = 'P';
// Test / Debug
std::string keyPressed;
// Functions
char getInput() {
// Gets arrow keys states
while (this->gettingInput) {
this->keyPressed = "";
if (GetAsyncKeyState(VK_RIGHT)) {
// Right arrow key
this->playerX++;
this->keyPressed = "Right arrow";
break;
}
else if (GetAsyncKeyState(VK_LEFT)) {
// Left arrow key
this->playerX--;
this->keyPressed = "Left arrow";
break;
}
else if (GetAsyncKeyState(VK_UP)) {
// Up arrow key
this->playerY++;
this->keyPressed = "Up arrow";
break;
}
else if (GetAsyncKeyState(VK_DOWN)) {
// Down arrow key
this->playerY--;
this->keyPressed = "Down arrow";
break;
}
else if (GetAsyncKeyState(VK_END)) {
exit(0);
}
Sleep(255);
}
}
};
#endif
Best / easiest way to fix this?
I searched and tested for 3 days but didn't find anything, please, help me.
Since you're overwriting the previous output, when you print a shorter string the extra characters from the previous output are still displayed. Replace the \r with a \n to see what's actually being output.
You can output some spaces after your key name to overwrite those extra characters with spaces and erase them.
After looking over your provided code I do see a few issues or concerns with the code design: I'll break it down and explain some of the things that I see that could improve the quality of your code. I will start with your main.cpp then move on to your Engine class.
You initially have this:
#include "engine.h"
#include <iomanip>
Engine eng;
int main() {
while (eng.isRunning) {
eng.getInput();
std::cout << std::setw(5);
std::cout << "\r X = " << eng.playerX;
std::cout << "| Y = " << eng.playerY;
std::cout << "| KEY = " << eng.keyPressed;
Sleep(100);
}
return 0;
}
The first main issue that I see is that you have declared Engine eng at the global level. We can fix this by
#include "engine.h"
#include <iostream>
#include <iomanip>
int main() {
Engine eng; // declare it here as the first object in main; now it has local
// scope within main's function and is now in Automatic Storage
// instead of Global Storage.
while( ... ) {
// ....
}
return 0;
};
The next issue starts with while loop's conditional expression in the main function.
You currently have:
while( engine.isRunning ) { //... }
This is okay but this is more of an issue with your Engine class's design. Here you are providing a public member that anyone can access. So let's look at your class declaration/definition; you currently have:
#ifndef ENGINE_H
#define ENGINE_H
#include <iostream>
#include <Windows.h>
#include <string>
class Engine {
public:
// Game
bool isRunning = true;
bool gettingInput = true;
// Player
int playerX = 1;
int playerY = 1;
char playerModel = 'P';
// Test / Debug
std::string keyPressed;
// Functions
char getInput() { // ... }
};
#endif
Here you should protect your data members and have access modifiers functions to them:
#ifndef ENGINE_H
#define ENGINE_H
#include <iostream>
#include <Windows.h>
#include <string>
class Engine {
private:
bool isRunning;
bool gettingInput;
// Player
int playerX;
int playerY;
char playerModel;
// Test / Debug
std::string keyPressed;
public:
Engine() :
isRunning( false ),
isGettingInput( false ),
playerX( 1 ),
playerY( 1 ),
playerModel( 'P' )
{}
void run() { isRunning = true; // set or call other things here... }
// Since we protected our members variables by making them private,
// we now need some access functions to retrieve and modify them.
bool isActive() const { return isRunning; } // make this const so it doesn't change anything
void toggleIsActive() { isRunning = !isRunning; }
bool retrievingInput() const { return isGettingInput; }
void toggleRetrievingInput() { isGettingInput = !isGettingInput; }
int getPlayerX() const { return playerX; }
void setPlayerX( int newX ) { playerX = newX; }
int getPlayerY() const { return playerY; }
void setPlayerY( int newY ) { playerY = newY; }
// set both in one function call
void setPlayerPosition( int newX, int newY ) {
playerX = newX;
playerY = newY;
}
char getPlayerModel() const { return playerModel; }
// don't know if you want to change this: uncomment if you do
// void setPlayerModel( char c ) { playerModel = c; }
std::string& getPressedKey() const { return keyPressed; }
char getInput() { // ... }
};
This should fix the interface design of your class. The only major difference here is that I had set your Boolean member variables to false by default because typically when you first start an Engine it is currently not already running. So to fix this we can call a public run function that will trigger this. So main would look like this instead:
int main () {
Engine eng;
eng.run(); // this now starts the engine sets the flag to true
while (...) { //... }
return 0;
}
However, I have also seen few concerns in your Engine's getInput() function, so let's take a look at it.
char getInput() {
// Gets arrow keys states
while (this->gettingInput) {
this->keyPressed = "";
if (GetAsyncKeyState(VK_RIGHT)) {
// Right arrow key
this->playerX++;
this->keyPressed = "Right arrow";
break;
}
else if (GetAsyncKeyState(VK_LEFT)) {
// Left arrow key
this->playerX--;
this->keyPressed = "Left arrow";
break;
}
else if (GetAsyncKeyState(VK_UP)) {
// Up arrow key
this->playerY++;
this->keyPressed = "Up arrow";
break;
}
else if (GetAsyncKeyState(VK_DOWN)) {
// Down arrow key
this->playerY--;
this->keyPressed = "Down arrow";
break;
}
else if (GetAsyncKeyState(VK_END)) {
exit(0);
}
Sleep(255);
}
}
The first part is the while loop's condition statement and your class's member. Originally you have this set to true by default, yet no where in the code did I see this value being updated. We don't need to change this but the fix is simple now that we have a way to change this member through a public interface call. Since I have made your isGettingInput false by default; you can now set this within this function before you enter the while loop. The only last issue that I see is that when this function is called back in main's while loop; this function never return's a value and the return value is never being used.
As to your actual problem with your bug for cout user : 1201programalarm has pretty much already answered that for you. Just thought I'd help you out a little bit more with your code.
I am coding for the NDS in c++ with libnds, but this question is not NDS-Specific. I currently have a text-based game in which the top screen just displays a logo, and you play on the bottom screen.
So I want to add a type of single-DS multiplayer in which one player plays on the top screen, and the other on the bottom. I dont have a problem with setting up the text engine with both screens, I just need to find a method of efficiently coding in multiplayer. Below I wrote a summary or simplified version of it.
Note: consoleClear() clears the screen and the only spot where the game stops is att the pause function.
//Headers
void display(int x,int y,const char* output))
{
printf("\x1b[%d;%dH%s", y, x,output);
}
void pause(KEYPAD_BITS key) //KEYPAD_BITS is an ENUM for a key on the NDS
{
scanKeys();
while (keysHeld() & key)
{
scanKeys();
swiWaitForVBlank();
}
while (!(keysHeld() & key))
{
scanKeys();
swiWaitForVBlank();
}
return;
}
void pause() //Only used to simplify coding
{
pause(KEY_A);
return;
}
int main(void)
{
//Initializations/Setup
while (1)
{
if (rand()%2==1) //Say Hello
{
if (rand()%3!=1) //To Friend (greater chance of friend than enemy)
{
display(6,7,"Hello Friend!");
display(6,8,"Good greetings to you.");
pause();
consoleClear(); //Clears text
display(6,7,"Would you like to come in?");
pause();
//Normally more complex complex code (such as interactions with inventories) would go here
}
else //To enemy
{
display(6,7,"Hello enemy!");
display(6,8,"I hate you!");
pause();
consoleClear();
display(6,7,"Leave my house right now!!!");
pause();
}
}
else //Say goodbye
{
if (rand()%4==1) //To Friend (lesser chance of friend than enemy)
{
display(6,7,"Goodbye Friend!");
display(6,8,"Good wishes to you.");
pause();
consoleClear();
display(6,7,"I'll see you tomorrow.");
pause();
consoleClear();
display(6,7,"Wait, I forgot to give you this present.");
pause();
}
else //To enemy
{
display(6,7,"Goodbye enemy!");
display(6,8,"I hate you!");
pause();
consoleClear();
display(6,7,"Never come back!!");
pause();
consoleClear();
display(6,7,"Good riddance!"); //I think I spelt that wrong...
pause();
}
}
}
}
I know gotos are confusing and can be considered a bad habit, but I cant think of a better way. My version of integrating multiplayer:
//Headers and same functions
int game(int location)
{
switch (location)
{
case 1: goto one; break;
case 2: goto two; break;
case 3: goto three; break;
case 4: goto four; break;
case 5: goto five; break;
case 6: goto six; break;
case 7: goto seven; break;
case 8: goto eight; break;
case 9: goto nine; break;
case 10: goto ten; break;
default: break;
}
if (rand()%2==1) //Say Hello
{
if (rand()%3!=1) //To Friend (greater chance of friend than enemy)
{
display(6,7,"Hello Friend!");
display(6,8,"Good greetings to you.");
return 1;
one:;
consoleClear(); //Clears text
display(6,7,"Would you like to come in?");
return 2;
two:;
//Normally more complex complex code (such as interactions with inventories) would go here
}
else //To enemy
{
display(6,7,"Hello enemy!");
display(6,8,"I hate you!");
return 3;
three:;
consoleClear();
display(6,7,"Leave my house right now!!!");
return 4;
four:;
}
}
else //Say goodbye
{
if (rand()%4==1) //To Friend (lesser chance of friend than enemy)
{
display(6,7,"Goodbye Friend!");
display(6,8,"Good wishes to you.");
return 5;
five:;
consoleClear();
display(6,7,"I'll see you tomorrow.");
return 6;
six:;
consoleClear();
display(6,7,"Wait, I forgot to give you this present.");
return 7;
seven:;
}
else //To enemy
{
display(6,7,"Goodbye enemy!");
display(6,8,"I hate you!");
return 8;
eight:;
consoleClear();
display(6,7,"Never come back!!");
return 9;
nine:;
consoleClear();
display(6,7,"Good riddance!"); //I think I spelt that wrong...
return 10;
ten:;
}
return -1;
}
}
int main(void)
{
//Initializations/Setup
int location1 = -1, location2 = -1;
location1 = game(location1);
location2 = game(location2);
while (1)
{
scanKeys(); //Whenever checking key state this must be called
if (keysDown() & KEY_A) //A key is used to continue for player1
location1 = game(location1);
if (keysDown() & KEY_DOWN) //Down key is used to continue for player2
location2 = game(location2);
}
}
Aside from this method being a bad practice, in the actual source code, I have hundreds of gotos I would need to add which would be too time consuming.
Any help is appreciated. If anyone has the slightest of a question, or answer, please ask/reply.
Edit: Though it is not preferred to do so, I am willing to rewrite the game from scratch if someone has a method to do so.
Using if-else conditional statements for each case is a simple solution that comes first to mind.
For example:
int game(int i){
if(i == 1){
//first case code here.
}
else if(i == 2){
//second case code here.
}
//....
return 0;
}
The code in each case can even be put in other functions that will be invoked depending on each condition.
This will probably be enough for your case.
A more flexible solution (but much more complex) is a dispatch table.
The idea is to have separate functions with each desired functionality, and put pointers of them in an array. Then, you can call them by indexing the table, using those function pointers. This can be extremely helpful if you have a sequence of executions (function invokes) to be done and you want to set it done easily, or you want to have different results depending on your input, without changing your program.
There is an example below.
This code can be used in C too, if you replace std::cout with printf and iostream with stdio library.
#include <iostream>
using namespace std;
// Arrays start from 0.
// This is used for code
// readability reasons.
#define CASE(X) X-1
typedef void (*chooseCase)();
// Functions to execute each case.
// Here, I am just printing
// different strings.
void case1(){
cout<< "case1" << endl;
}
void case2(){
cout<< "case2" << endl;
}
void case3(){
cout<< "case3" << endl;
}
void case4(){
cout<< "case4" << endl;
}
//Put all the cases in an array.
chooseCase cases[] = {
case1, case2, case3, case4
};
int main()
{
//You can call each scenario
//by hand easily this way:
cases[CASE(1)]();
cout << endl;
//Idea: You can even set in another
// array a sequence of function executions desired.
int casesSequence[] = {
CASE(1), CASE(2), CASE(3), CASE(4),CASE(3),CASE(2),CASE(1)
};
//Execute the functions in the sequence set.
for(int i = 0; i < (sizeof(casesSequence)/sizeof(int)); ++i){
cases[casesSequence[i]]();
}
return 0;
}
This will print at the output:
case1
case1
case2
case3
case4
case3
case2
case1
I have a piece of code pretty similar to this:
class someclass
{
public:
enum Section{START,MID,END};
vector<Section> Full;
void ex(){
for(int i=0;i<Full.size();i++)
{
switch (Full[i])
{
case START :
cout<<"S";
break;
case MID :
cout<<"M";
break;
case END:
cout<<"E";
break;
}
}
}
};
Now imagine I have much more enum types and their names are longer....
well what i get is not a very good looking code and i was wondering if it possible to bind a specific char to an enum type and maybe do something like this:
for(int i=0;i<Full.size();i++)
{
cout<(Full[i]).MyChar();
}
Or any other method that could make this code "prettier".
Is this possible?
Unfortunately there is not much you can do to clean this up. If you have access to the C++11 strongly typed enumerator feature, then you could do something like the following:
enum class Section : char {
START = 'S',
MID = 'M',
END = 'E',
};
And then you could do something like:
std::cout << static_cast<char>(Full[i]) << std::endl;
However, if you do not have access to this feature then there's not much you can do, my advice would be to have either a global map std::map<Section, char>, which relates each enum section to a character, or a helper function with the prototype:
inline char SectionToChar( Section section );
Which just implements the switch() statement in a more accessible way, e.g:
inline char SectionToChar( Section section ) {
switch( section )
{
default:
{
throw std::invalid_argument( "Invalid Section value" );
break;
}
case START:
{
return 'S';
break;
}
case MID:
{
return 'M';
break;
}
case END:
{
return 'E';
break;
}
}
}
In a situation like this you could be tricky and cast your chars.
enum Section{
START = (int)'S',
MID = (int)'M',
END = (int)'E'
};
...
inline char getChar(Section section)
{
return (char)section;
}
I think the best solution in this case would be to use a map:
#include <iostream>
#include <map>
class someclass
{
public:
enum Section{START = 0,MID,END};
map<Section,string> Full;
// set using Full[START] = "S", etc
void ex(){
for(int i=0;i<Full.size();i++)
{
cout << Full[i];
}
}
};