std::thread communication issue - c++

I am building a multithreaded application, but I've got a problem.
In the application I'm using a variable to communicate between the threads but it does not work. So when you type in exit the application does not stop executing.
The code:
//Program that controls an cadrocopter with the use of a
//Raspberry Pi, MPU 6050, an ultrasonic sensor, an HMC5883L and Arduino Leonardo
//to compile use "g++ ./quad.cpp -o ./quad -std=c++0x -pthread"
//
//Copyright Jan Hendrik Farr
#include <iostream> //used to input data
#include <string> //used to procces the userdata
#include <stdlib.h> //used to convert strings into floats
#include "./serial/serial.h" //used to communicate with the Arduino
#include <thread> //used to do multithreating
using namespace std;
//userinterface thread
void userInterface(int cmdPos1, float cmdPos[]){
string cmd = "";
cout << "************************" << endl;
cout << "* Quadrocopter control *" << endl;
cout << "* software *" << endl;
cout << "* *" << endl;
cout << "* version 0.1 *" << endl;
cout << "* *" << endl;
cout << "* Copyright J.H. Farr *" << endl;
cout << "************************" << endl << endl << endl;
while(cmdPos1 != 4){
cin >> cmd;
if(cmd == "move"){
cin >> cmdPos[0] >> cmdPos[1] >> cmdPos[2] >> cmdPos[3];
cmdPos1 = 1;
cout << endl << endl;
} else if(cmd == "move+"){
cin >> cmdPos[0] >> cmdPos[1] >> cmdPos[2] >> cmdPos[3];
cmdPos1 = 2;
cout << endl << endl;
} else if(cmd == "land"){
cmdPos1 = 3;
cout << endl << endl;
} else if(cmd == "exit"){
cmdPos1 = 4;
cout << endl;
} else {
cout << "invalid argument!!" << endl << endl;
}
}
}
//algorithm
void algorithm(float tele[], int cmdPos1, float cmdPos[]){
while(cmdPos1 != 4){
switch (cmdPos1){
case 2:
cout << "works!!";
break;
case 1:
break;
case 3:
break;
}
}
}
//gets telemetrydata from mpu
void gettelempu(float tele[], int cmdPos1){
while(cmdPos1 != 4){
}
}
//gets height from ultrasonic sensor
void getheight(float tele[], int cmdPos1){
while(cmdPos1 != 4){
}
}
//main function
int main(){
//telemetry data
float tele[12] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
//what to do
int cmdPos1 = 0;
//where to go
float cmdPos[4] = {0, 0, 0, 0};
thread t1(userInterface, cmdPos1, cmdPos);
thread t2(algorithm, tele, cmdPos1, cmdPos);
thread t3(gettelempu, tele, cmdPos1);
thread t4(getheight, tele, cmdPos1);
t1.join();
t2.join();
t3.join();
t4.join();
return 0;
}

void gettelempu(float tele[], int cmdPos1)
This function gets its own copy of cmdPos; at the time when it's called, the value passed to it is 0, and the function never changes that value, so the loop never terminates. Same thing in algorithm and getheight.
In order to change the value of this argument in one place and have other functions see that change the functions have to take the value by reference:
void gettelempu(float tele[], int& cmdPos1)
and when the thread is created you have to pass a reference:
thread t3(gettelempu, tele, std::ref(cmdPos1));
But wait, there's more! There's no guarantee that changes to cmdPos1 that are made in one thread will be visible to other threads. To ensure this, make it atomic. In main, change
int cmdPos1 = 0;
to
std::atomic<int> cmdPos1 = 0;
and change the function signatures to take an std::atomic<int> instead of an int:
void gettelempu(float tele[], std::atomic<int>& cmdPos1)

Related

Two codes; same logic and line of code, one works but other doesn't

I asked this question a couple of hours ago; I want to see if someone can now explain the problem.
One code is about separating items in a grocery; in the end you'll have two(2) bags; a fragileBag and a normalBag.
Other code separates passengers depending on the office they go for pickup; in the end you'll have three(3) types of passengers; ones that go to rio, ones that go to maya, and ones that request elsewhere.
Both codes use the same logic but the passenger code gives an error on a line that works perfectly on the grocery code.
Just to be clear, BOTH CODES RETURN VALUES OF STRING.
ERROR FROM THE PASSENGER CODE:
Error (active) E0304 no instance of overloaded function "std::vector<_Ty,_Alloc>::push_back [with _Ty=trans, _Alloc=std::allocator<trans>]" matches the argument list dataPractice2 C:\Users\javye\source\repos\dataPractice2\dataPractice2\main.cpp 82
and also:
Error C2664 'void std::vector<trans,std::allocator<_Ty>>::push_back(_Ty &&)': cannot convert argument 1 from 'std::string' to 'const _Ty &' dataPractice2 c:\users\javye\source\repos\datapractice2\datapractice2\main.cpp 82
//GROCERY FUNCTION
//separate function
void separateItems(vector<myBag>& newMyVector) {
for (int x = newMyVector.size() - 1; x >= 0; --x) {
if (newMyVector[x].getItem() == "eggs" || newMyVector[x].getItem() == "bread") {
fragileBag.push_back(newMyVector[x].getItem()); //NO PROBLEM HERE
newMyVector.pop_back();
}
else {
normalBag.push_back(newMyVector[x].getItem()); //OR HERE
newMyVector.pop_back();
}
}
}
//PASSENGER FUNCTION
//separate function
void separateP(vector<trans>& newMyVector) {
for (int x = newMyVector.size() - 1; x >= 0; --x) {
if (newMyVector[x].getXoLoc() == "rio") {
rioLoc.push_back(newMyVector[x].getXoLoc()); //PROBLEM HERE
newMyVector.pop_back();
}
else
if (newMyVector[x].getXoLoc() == "maya") {
mayaLoc.push_back(newMyVector[x].getXoLoc()); //HERE
newMyVector.pop_back();
}
else
elseLoc.push_back(newMyVector[x].getXoLoc()); //HERE
newMyVector.pop_back();
}
}
//GROCERY FULL CODE
//HEADER
#pragma once
#include<iostream>
#include<vector>
#include<string>
using namespace std;
#ifndef BAG_H
#define BAG_H
class myBag {
public:
myBag(); //default constructor
myBag(string anItemName); //overload constructor
void addItem(string anItemName); //mutator
string getItem();//accessor
private:
string itemName;
};
#endif
//SOURCE
#include"bag.h"
myBag::myBag() {
addItem("");
}
myBag::myBag(string anItemName) {
addItem(anItemName);
}
void myBag::addItem(string anItemName) {
itemName = anItemName;
}
string myBag::getItem() {
return itemName;
}
//MAIN
#include"bag.h"
void inputItems(vector<myBag>&); //input data function prototype
void displayQuantity(vector<myBag>&); //display data function prototype
void separateItems(vector<myBag>&); //function that separates items; func prototype
void fragBag(vector<myBag>&); //fragile bag function prototype
void norBag(vector<myBag>&); //normal bag function prototype
vector<myBag> myVector; //main vector
vector<myBag> fragileBag, normalBag; //seconday vectors
string item; //global item variable
int main() {
int option;
try {
do {
cout << "\tMENU"
<< endl << "1) Input Items"
<< endl << "2) Display Quantity"
<< endl << "3) Separate (IMPORTANT)"
<< endl << "4) Display Items in Fragile Bag"
<< endl << "5) Display Items in Normal Bag"
<< endl << "6) Exit Program"
<< endl << endl << "Choose: ";
cin >> option;
if (option > 6) {
throw 404;
}
switch (option) {
case 1: //input
system("cls");
inputItems(myVector);
system("pause");
system("cls");
break;
case 2://display
system("cls");
displayQuantity(myVector);
system("pause");
system("cls");
break;
case 3: //separate
system("cls");
separateItems(myVector);
system("pause");
system("cls");
break;
case 4: //fragile
system("cls");
fragBag(myVector);
system("pause");
system("cls");
break;
case 5: //normal
system("cls");
norBag(myVector);
system("pause");
system("cls");
break;
case 6: //exit
exit(0);
}
} while (option != 6);
}
catch(int x){
cout << "ERROR, OPTION DOESN'T EXITS" << endl;
system("pause");
}
}
//input function
void inputItems(vector<myBag>& newMyVector) {
do {
cout << "Enter grocery items || enter letter X to stop: ";
cin >> item;
if (item != "x")
newMyVector.push_back(myBag(item));
} while (item != "x");
}
//display function
void displayQuantity(vector<myBag>& newMyVector) {
try {
for (int x = 0; x < newMyVector.size(); ++x) {
if (x == 0) {
cout << "Store bag has " << newMyVector.size() << " items in it. These are: " << endl;
}
cout << newMyVector[x].getItem() << endl;
}
if (newMyVector.empty())
throw 404;
}
catch (int x) {
cout << "ERROR " << x << " ,QUANTITY NOT FOUND" << endl;
}
}
//separate function
void separateItems(vector<myBag>& newMyVector) {
for (int x = newMyVector.size() - 1; x >= 0; --x) {
if (newMyVector[x].getItem() == "eggs" || newMyVector[x].getItem() == "bread") {
fragileBag.push_back(newMyVector[x].getItem()); //PROBLEM WOULD APPEAR HERE, BUT DOESN'T, UNLIKE THE OTHER CODE
newMyVector.pop_back();
}
else {
normalBag.push_back(newMyVector[x].getItem());
newMyVector.pop_back();
}
}
}
//fragile bag function
void fragBag(vector<myBag>& newMyVector) {
try {
for (int x = 0; x < fragileBag.size(); ++x) {
if (x == 0) {
cout << "The fragile bag has " << fragileBag.size() << " items in it. These are: " << endl;
}
cout << fragileBag[x].getItem() << endl;
}
if (fragileBag.empty()) {
throw 404;
}
}
catch (int x) {
cout << "ERROR " << x << " ,FRAGILE BAG EMPTY" << endl;
}
}
//normal bag function
void norBag(vector<myBag>& newMyVector) {
try {
for (int x = 0; x < normalBag.size(); ++x) {
if (x == 0) {
cout << "The normal bag has " << normalBag.size() << " items in it. These are: " << endl;
}
cout << normalBag[x].getItem() << endl;
}
if (normalBag.empty()) {
throw 404;
}
}
catch (int x) {
cout << "ERROR " << x <<" , NORMAL BAG EMPTY" << endl;
}
}
//PASSENGER FULL CODE
//HEADER
#pragma once
#include<iostream>
#include<vector>
#include<string>
using namespace std;
#ifndef TRANSPORT_H
#define TRANSPORT_H
class trans {
public:
trans();
trans(string aName, string anXoLoc, string anXfLoc, string aTime, string aCellNum);
void setName(string aName);
void setXoLoc(string anXoLoc);
void setXfLoc(string anXfLoc);
void setTime(string aTime);
void setCellNum(string aCellNum);
string getName();
string getXoLoc();
string getXfLoc();
string getTime();
string getCellNum();
private:
string name;
string xoLoc; //offices
string xfLoc; //destination
string time;
string cellNum;
};
//SOURCE
#include"transport.h"
trans::trans() {
setName("");
setXoLoc("");
setXfLoc("");
setTime("");
setCellNum("");
}
trans::trans(string aName, string anXoLoc, string anXfLoc, string aTime, string aCellNum) {
setName(aName);
setXoLoc(anXoLoc);
setXfLoc(anXfLoc);
setTime(aTime);
setCellNum(aCellNum);
}
void trans::setName(string aName) {
name = aName;
}
void trans::setXoLoc(string anXoLoc) {
xoLoc = anXoLoc;
}
void trans::setXfLoc(string anXfLoc) {
xfLoc = anXfLoc;
}
void trans::setTime(string aTime) {
time = aTime;
}
void trans::setCellNum(string aCellNum) {
cellNum = aCellNum;
}
string trans::getName() {
return name;
}
string trans::getXoLoc() {
return xoLoc;
}
string trans::getXfLoc() {
return xfLoc;
}
string trans::getTime() {
return time;
}
string trans::getCellNum() {
return cellNum;
}
#endif
//MAIN
#include"transport.h"
void inputInfo(vector<trans> &);
void displayInput(vector<trans>&);
void separateP(vector<trans>&);
void rio(vector<trans>&);
void maya(vector<trans>&);
void elsewhere(vector<trans>&);
vector<trans> myVector;
vector<trans> rioLoc, mayaLoc, elseLoc;
string newName;
string newXoLoc; //offices
string newXfLoc; //destination
string newTime;
string newCellNum;
//main not ready. Creating each function one by one to them make it look nice
int main() {
int option;
do {
cout << "MENU"
<< endl << "1) input "
<< endl << "2) output "
<< endl << "3) separate"
<< endl << "4) rio passengers"
<< endl << "5) maya passengers"
<< endl << "6) elsewhere passengers";
cin >> option;
switch(option){
case 1:
inputInfo(myVector);
break;
case 2:
displayInput(myVector);
break;
case 3:
separateP(myVector);
break;
case 4:
rio(myVector);
break;
case 5:
maya(myVector);
break;
case 6:
elsewhere(myVector);
break;
case 7:
exit(0);
}
} while (option != 7);
system("pause");
}
void inputInfo(vector<trans> &newMyVector) {
int charSize;
cout << "How many passangers to register: ";
cin >> charSize;
for (int x = 0; x < charSize; ++x) {
cout << "Name of passanger: ";
cin >> newName;
cout << "Office: ";
cin >> newXoLoc;
cout << "Destination: ";
cin >> newXfLoc;
cout << "Time of pickup: ";
cin >> newTime;
cout << "Cellphone: ";
cin >> newCellNum;
if (charSize != 0)
newMyVector.push_back(trans(newName, newXoLoc, newXfLoc, newTime, newCellNum));
}
}
void displayInput(vector<trans>& newMyVector) {
for (int x = 0; x < newMyVector.size(); ++x) {
if (x == 0) {
cout << "There are " << newMyVector.size() << " passengers. These are: " << endl;
}
cout << "-----------------------------Passenger #" << x + 1 << endl;
cout << newMyVector[x].getName() << endl;
cout << newMyVector[x].getXoLoc() << endl;
cout << newMyVector[x].getXfLoc() << endl;
cout << newMyVector[x].getTime() << endl;
cout << newMyVector[x].getCellNum() << endl;
}
}
void separateP(vector<trans>& newMyVector) {
for (int x = newMyVector.size() - 1; x >= 0; --x) {
if (newMyVector[x].getXoLoc() == "rio") {
rioLoc.push_back(newMyVector[x]);
newMyVector.pop_back();
}
else
if (newMyVector[x].getXoLoc() == "maya") {
mayaLoc.push_back(newMyVector[x]);
newMyVector.pop_back();
}
else
elseLoc.push_back(newMyVector[x]);
newMyVector.pop_back();
}
}
void rio(vector<trans>& newMyVector) {
for (int x = 0; x < rioLoc.size(); ++x) {
if (x == 0) {
cout << "Num. of passangers to pickup in Rio Piedras is " << rioLoc.size() << " , these are: " << endl;
}
cout << rioLoc[x].getName() << endl;
cout << rioLoc[x].getXoLoc() << endl;
cout << rioLoc[x].getXfLoc() << endl;
cout << rioLoc[x].getTime() << endl;
cout << rioLoc[x].getCellNum() << endl;
}
}
void maya(vector<trans>& newMyVector) {
for (int x = 0; x < mayaLoc.size(); ++x) {
if (x == 0) {
cout << "Num. of passangers to pickup in Mayaguez is " << mayaLoc.size() << " , these are: " << endl;
}
cout << mayaLoc[x].getName() << endl;
cout << mayaLoc[x].getXoLoc() << endl;
cout << mayaLoc[x].getXfLoc() << endl;
cout << mayaLoc[x].getTime() << endl;
cout << mayaLoc[x].getCellNum() << endl;
}
}
void elsewhere(vector<trans>& newMyVector) {
for (int x = 0; x < elseLoc.size(); ++x) {
if (x == 0) {
cout << "Num. of passangers to pickup in elsewhere is " << elseLoc.size() << " , these are: " << endl;
}
cout << elseLoc[x].getName() << endl;
cout << elseLoc[x].getXoLoc() << endl;
cout << elseLoc[x].getXfLoc() << endl;
cout << elseLoc[x].getTime() << endl;
cout << elseLoc[x].getCellNum() << endl;
}
}
To explain why the second code does not work I first have to explain why the first code appears to work.
myBag::myBag(string anItemName)
can make a bag out of a string. It is a Conversion Constructor. So when
fragileBag.push_back(newMyVector[x].getItem());
is compiled, the compiler quietly inserts a call to the myBag(string) constructor and you get something more like
fragileBag.push_back(myBag(newMyVector[x].getItem()));
which makes no sense logically. It says turn an item in a bag into a bag with one item and insert this new bag into still another bag, fragileBag.
When you look more closely at myBag, you see that it isn't a bag at all. It is a single item and should be renamed to myItem or discarded all together in favour of an all-new all-different myBag that is a wrapper around a vector of string where the strings represent items. This makes
myBag fragileBag;
the real bag.
In other words, the only reason the working code works is it doesn't actually do what the naming implies it does. The code compiles and produces the expected result, but is semantically troubled.
This leads to the confusion with
rioLoc.push_back(newMyVector[x].getXoLoc());
rioLoc is a vector<trans> and can only hold trans. There is no trans::trans(string) to convert a string to a trans so the faulty logic of the grocery code is exposed. As bag and item have been intertwined in grocery, passenger and transport are combined here.
The fix for grocery described above is relatively straight forward. Passenger will need a slightly different solution with both a passenger class to describe the passengers and a transport class to describe the means of transport. transport will have a vector<passenger> member to contain its passengers as well as methods to add and remove the passengers and possibly book-keeping to track the location of the transport, details incompletely specified by the question.
Both codes are pushing string values into a vector that does not hold string values.
Your grocery code uses a vector of myBag objects. The code works because myBag has a non-explicit constructor that takes a single string as input, so the compiler is able to implicitly construct a temporary myBag object to push into the vector.
Your passenger code uses a vector of trans objects. The code fails because trans does not have a constructor that takes a single string as input, so the compiler cannot construct a temporary trans to push into the vector.

Error Variable is Protected

#include <iostream>
#include <string>
#include <cstdlib>
#include <ctime>
using namespace std;
void armySkirmish();
void battleOutcome();
string commander = "";
int numberOfHumans = 0;
int numberOfZombies = 0;
class ArmyValues
{
protected:
double attackPower;
double defensePower;
double healthPoints;
public:
void setAttackPower(double a)
{
attackPower = a;
}
void setDefensePower(double d)
{
defensePower = d;
}
void setHealthPoints(double h)
{
healthPoints = h * (defensePower * .1);
}
};
class Zombies: public ArmyValues
{
};
class Humans: public ArmyValues
{
};
int main(int argc, char ** argv)
{
cout << "Input Commander's Name: " << endl;
cin >> commander;
cout << "Enter Number of Human Warriors: " << endl;
cin >> numberOfHumans;
cout << "Enter Number of Zombie Warriors: " << endl;
cin >> numberOfZombies;
armySkirmish();
battleOutcome();
return 0;
}
void armySkirmish()
{
cout << "\nThe Humans tense as the sound of the undead shuffle towards them." << endl;
cout << commander << " shuffles forward with a determined look." << endl;
cout << "The undead form up into ranks and growl a war chant!" << endl;
cout << commander <<" shouts, CHARGE!!!" << endl;
cout << endl;
cout << "Warriors from both sides blitz across the field!" << endl;
cout << endl;
cout << "*The Carnage has begun!*" << endl;
cout << "*Steal, Sparks, and Flesh flies" << endl;
}
void battleOutcome()
{
int zombieLives = numberOfZombies;
int humanLives = numberOfHumans;
int randomNumber = 0;
int humanDeath = 0;
int zombieDeath = 0;
double newHumanLife = 0;
double newZombieLife = 0;
Zombies zombieBattleData;
Humans humanBattleData;
srand(time(NULL));
zombieBattleData.setAttackPower(20.0);
humanBattleData.setAttackPower(35.0);
zombieBattleData.setDefensePower(15.0);
humanBattleData.setDefensePower(20.0);
zombieBattleData.setHealthPoints(150.0);
humanBattleData.setHealthPoints(300.0);
while(zombieLives && humanLives > 0)
{
randomNumber = 1+(rand()%10);
if(randomNumber < 6)
{
newHumanLife = humanBattleData.healthPoints - zombieBattleData.attackPower;
if(newHumanLife <= 0)
{
humanLives--;
humanDeath++;
}
}else
{
newZombieLife = zombieBattleData.healthPoints - humanBattleData.attackPower;
if(newZombieLife <= 0)
{
zombieLives--;
zombieDeath++;
}
}
}
if(zombieLives <= 0)
{
cout << "Humans have emerged victorious!" << endl;
cout << "Human Deaths: " << humanDeath << "Zombie Deaths: " << zombieDeath << endl;
}else if(humanLives <= 0)
{
cout << "Zombies have emerges victorious!" << endl;
cout << "Human Deaths: " << humanDeath << "Zombie Deaths: " << zombieDeath << endl;
}
I know the code wont run properly as of now. What I was doing was a test run to make sure I was receiving no errors. The two errors I'm getting are:
armySimulatorMain.cpp:25:10: error: 'double ArmyValues::healthPoints' is protected
armySimulatorMain.cpp:115:67: error: within this context.
newHumanLife = humanBattleData.healthPoints - zombieBattleData.attackPower;
This is the case for Attack Power and Health Power however, Defense power is clearing the errors. i don't understand why they are getting flagged. I'm changing the variable through the public function so shouldn't this be allowed?
Also, I'm calling three variables outside of all functions because they are being used by multiple functions. How can I plug those variables somewhere I don't like that they are floating freely above everything?
Thanks guys I can't believe I forgot about getters... Anyway the code runs now much appreciated I'll make sure to remember this time xD
It's not complaining about the line where you set the values; as you say, that uses a public function. But here, you try to read the protected member variables:
newHumanLife = humanBattleData.healthPoints - zombieBattleData.attackPower;
You only try to read two variables, and those are the ones it complains about.
You'll need a public getter function to read the values.
You need to do something like:
public:
double gethealthPoints()
{
return healthPoints;
}
because attackPower, defensePower, healthPoints are all protected, so if you want to access to any of them you need a getter, otherwise you will always receive an protect error

Console game not working properly

I am making a simple game for learning purposes mostly and I recently ran into this problem. Keep in mind that I'm still a huge beginner. When I go into the game from the menu and write anything in the "Command Line" I instantly starve and dehydrate. I haven't been able to connect to the internet for a couple of days and I've read through the entire program but I can't find anything wrong.
menu.h
#include <iostream>
#include <stdlib.h>
#include <string>
#include <time.h>
#include <dos.h>
#include <windows.h>
#include <WinBase.h>
//-------------//
#include "tutorial.h"
#include "game.h"
void menu() {
std::cout << "-------MENU------- \n";
std::cout << " 1.Play \n";
std::cout << " 2.Tutorial \n";
std::cout << " 3.Exit \n";
std::cout << " \n";
std::cout << " \n";
std::cout << " \n";
std::cout << "Choose Option: ";
int menuOption;
std::cin >> menuOption;
int menuLoop = 0;
while (menuLoop != 1) {
if (menuOption == 1) {
menuLoop = 1;
play();
}
if (menuOption == 2) {
menuLoop = 1;
system("CLS");
tutorial();
}
if (menuOption == 3) {
menuLoop = 1;
std::cout << "Bye!";
Sleep(1000);
}
if (menuOption > 3)
std::cout << "\"" << menuOption << "\"" << " is not a valid option.\n";
}
}
game.h
#include <iostream>
#include <string>
#include <windows.h>
#include <WinBase.h>
//initiating functions
void step();
void run();
void theme();
void starve();
void die();
void dehydrate();
void b();
//globals
std::string name;
std::string commandLine;
int onRoad = 1; // 1 = True, 0 = False
int steps = 0;
double hunger = 0.0;
double thirst = 0.0;
int energy = 5;
void play() {
system("CLS");
std::cout << "Enter your name: \n";
std::cin >> name;
system("CLS");
theme();
Sleep(350);
std::cout << " " << name << "'s Roadtrip\n";
std::cout << "Type \"/help\" for help\n";
std::cout << "---------Command Line---------\n";
std::cin >> commandLine;
while (onRoad != 0){
//------------------Conditions start------------------
// Hunger Conditions
if (hunger = 0){
if (hunger < 0){
std::cout << "You can't eat that, you're not hungry.\n";
b();
}
}
if (hunger > 100){
hunger = 100;
}
if (hunger < 0){
hunger = 0;
}
if (hunger = 100){
starve();
}
else if (hunger > 96){
std::cout << "You're extremely hungry! If you don't eat something quick you're going to die!\n";
b();
}
else if (hunger > 90) {
std::cout << "You're very hungry.\n";
b();
}
else if (hunger > 80) {
std::cout << "You're hungry.\n";
b();
}
// Thirst Conditions
if (thirst = 0){
if (thirst < 0){
std::cout << "You can't drink that, you're not thirsty.\n";
}
}
if (thirst < 0){
thirst = 0;
}
if (thirst > 100) {
thirst = 100;
}
if (thirst = 100){
dehydrate();
}
else if (thirst > 90){
std::cout << "You're extremely thirsty! If you don't drink something quick you're going to die!\n";
b();
}
else if (thirst > 75) {
std::cout << "You're very thirsty.\n";
b();
}
else if (thirst > 50){
std::cout << "You're thirsty.\n";
b();
}
//Energy Conditions
if (energy > 10){
energy = 10;
}
if (energy < 0){
energy = 0;
}
//-------------------Conditions end-------------------
if (commandLine == "/commands"){
std::cout << "-Command- -Action-\n";
std::cout << " /help Displays this menu.\n";
std::cout << " /commands Displays list of commands.\n";
std::cout << " /step Take a step and display total amount of steps.\n";
std::cout << " /run Take 5 steps and consume 5 energy.\n";
std::cout << " Doesn't increase hunger or thirst.\n";
std::cout << " /inventory Displays inventory.\n";
std::cout << " /info Displays stats.\n";
b();
}
if (commandLine == "/step") {
step();
b();
}
if (commandLine == "/info") {
std::cout << name << "'s stats\n";
std::cout << "Hunger: " << hunger << std::endl;
std::cout << "Thirst: " << thirst << std::endl;
std::cout << "Energy: " << energy << std::endl;
b();
}
else {
std::cout << commandLine << " is not a valid command. Type /commands to display commands.\n";
b();
}
}
}
void step(){
steps += 1;
std::cout << steps;
hunger += 5;
thirst += 5;
}
void run() {
steps += 5;
std::cout << steps;
}
void starve(){
std::cout << "You starved to death!\n";
die();
}
void dehydrate(){
std::cout << "You dehydrated!\n";
die();
}
void die(){
std::cout << "Steps taken: " << steps << std::endl;
onRoad = 0;
}
void theme(){
Beep(600, 200);
Beep(500, 200);
Beep(800, 400);
}
// b takes you back to the command line
void b(){
std::cin >> commandLine;
}
main.cpp
#include <iostream>
#include "menu.h"
#include <WinBase.h>
#include <windows.h>
int main(){
menu();
system("PAUSE");
return 0;
}
**EDIT: ** Pic: http://i.imgur.com/yu1V1pq.png (need 10 rep to post picture)
This is really weird. I entered /step and it worked, and then i entered /run and it also worked. I don't understand...
Some of your if statements do assignment instead of comparison
if (hunger = 100){
starve();
}
You probably need to change = to ==
Enable warnings while compiling, if you have not already done so.
Because
// b takes you back to the command line
void b(){
std::cin >> commandLine;
}
b doesn't take you back to the command line just wait for a character to be read and then it returns. If you want to go back, you should follow the way you came from. For example exiting play will return you to the menu loop, obviously with menuLoop = 1 so it will exit the whole program but with modifications this is not a bad looping system.
Edit: I've seen what you do mean in the "command line".
Like others said, you have a load of conditions accidentally spelled as assignments.
Also, indeed, the b() function is eating subsequent commands.
Maybe you should
use std::getline() to read a command one line at a time
or use std::cin.ignore() inside b() to actually consume until the end of the line
PS. Due to the use of globals I have a hard time verifying the game loop logic. I just know that /step after /step gets ignored without effect right now. Separate your input from the loop control and try to remove the global variables.
INFO
Instead of writing std::cout every single time you can just write using namespace std; on the beginning after that you dont need to write std::cout just write cout << "" ;

C++ How to declare my array and other integers in a different cpp file from where they are filled?

So heres what im trying to do with my text based rpg now. I want to clean up my main.cpp so that it isnt so long and cluttered, so I am creating a few different cpp files that will hold related items.
I have a maketoon.cpp file that will go through some switch statements that will set all the modifiers(str, int, agl, maxhp) based on the class they choose(class being like lumberjack doctor etc not classes in the object sense of things).
when setting the variables in the maketoon.cpp(within a function called makeMainPlayer() ) i use setters that i made within my createcharacter.h file.
So before you look at my code below, i have a few questions.
1)Where should i create the object(main.cpp, maketoon.cpp). Currently i was creating the object Player in the maketoon.cpp file but im getting these errors:
||=== Build: Debug in 6_days_to_escape (compiler: GNU GCC Compiler) ===|
C:\...\maketoon.cpp||In function 'int makeMainPlayer()':|
C:\...\maketoon.cpp|5|error: 'startChoices' was not declared in this scope|
C:\...\maketoon.cpp|6|error: 'name' was not declared in this scope|
C:\...\main.cpp||In function 'int main()':|
C:\...\main.cpp|39|error: 'Player' was not declared in this scope|
||=== Build failed: 3 error(s), 0 warning(s) (0 minute(s), 0 second(s)) ===|
2)Should i capitalize the first letting in my object name?
3)how do i call makeMainPlayer in my main.cpp so set that specific objects values to then start the game?
4)Lastly, when i was testing to see if the setters and getters were working, i was getting another Player not declared in this scope error, so i tried just banging out another CreateCharacter Player;at the start of my int main, but i feel that will overwrite all the values set in the later functions, with the default null values.
Also. I know nothing about pointers, but if that is the best way to go(some google searches popped up with this as a fix to similar scenarios)
Seriosly thanks a ton! Im trying to teach myself OOc++ and it is proving difficult. Getting lost in the online tuts and youtube tuts.
//main.cpp
//game rpg
#include <iostream>
#include <ctime>
#include <cstdlib>
#include <conio.h>
#include "createcharacter.h"
#include "maketoon.cpp"
using namespace std;
//is running check
bool running = 1;
//int healedHP(int x, int y);
//int attackedHP(int x, int y);
//user input var+
int userInput = 0;
int startChoices[4] = {0, 0, 0, 0};
string name;
//function declarations
void theStart();
void newGame();
int main (){
void makeMainPlayer();
cout << "Enter your name." << endl;
cin >> name;
cout << "Welcome " << name << "." << endl;
cout << "Strike any key....if you dare......";
getch();
system("cls");
theStart();
makeMainPlayer();
cout << "Name: " << Player.getplayerName() << endl;
cout << "Health: " << Player.getplayerHealth() << endl;
cout << "Strength: " << Player.getStr() << endl;
cout << "Int: " << Player.getInt() << endl;
cout << "Agility: " << Player.getAgl() << endl;
cout << "Difficulty: " << Player.getDifficulty() << endl;
system("pause");
return EXIT_SUCCESS;
}
void theStart()
{
cout << "\n\n";
cout << "\t6 Days to Escape!\n"; //title
cout << "\t\t 1: Play\n"; //main menu options. The first thing the user sees.
cout << "\t\t\t 2: Exit\n";
cin >> userInput;
system("cls");
if(userInput == 1)
{
// Create a new game
newGame();
}
else
{
//bool then false causeing program to exit
running = 0;
}
return;
}
void newGame(){
// there are 4 addresses in this array for the following:
//0. Difficulty
//1. Class
//2. Starting Wep
//3. Boost not implimented yet TODO
//enum class difficulty{simple, easy, hard, impossible};
do{
cout << "Choose Your difficulty: " << endl;
cout << "\t1. Simple - Game practically plays itself." << endl;
cout << "\t2. Easy - Not that easy." << endl;
cout << "\t3. Hard - Zombies do more than crave flesh." << endl;
cout << "\t4. Impossible - You will not make it." << endl;
cin >> startChoices[0];
cout << endl;
system("cls");
if(startChoices[0] < 1 || startChoices[0] > 4){
cout << "Invalid Difficulty Choice. Try again." << endl;}
}while(startChoices[0] < 1 || startChoices[0] > 4);
do{
cout << "Choose your class:" << endl;
cout << "\t1. Lumber Jack - Stong, hard to kill, but slow." << endl;
cout << "\t2. Doctor - Healer, weak but fast. Favors health." << endl;
cout << "\t3. Theif - FAST, Cunning but weak attacks." << endl;
cout << "\t4. Everydayer - Balenced everything." << endl;
cin >> startChoices[1];
cout << endl;
system("cls");
if(startChoices[1] < 1 || startChoices[1] > 4){
cout << "Invalid Class Choice. Try again." << endl;}
}while(startChoices[1] < 1 || startChoices[1] > 4);
do{
cout << "Choose your starting Weapon:" << endl;
cout << "\t1. Axe" << endl;
cout << "\t2. Crowbar" << endl;
cout << "\t3. Swiss army knife" << endl;
cout << "\t4. Ice pick" << endl;
cin >> startChoices[2];
cout << endl;
if(startChoices[0] < 1 || startChoices[0] > 4){
cout << "Invalid Weapon Choice. Try again." << endl;}
}while(startChoices[2] < 1 || startChoices[2] > 4);
}
//----------------------------------------------------------------------------------------
//createcharacter.h
#ifndef CREATECHARACTER_H
#define CREATECHARACTER_H
class CreateCharacter{
public:
//setter
void setplayerName(std::string x){
playerName = x;}
void setwepSpeed(int v){
wepSpeed = v;}
void setplayerHealth(int h){
playerHealth = h;}
void setplayerMaxHealth(int mh){
playerMaxHealth = mh;}
void setplayerStr(int s){
playerStr = s;}
void setplayerAgl(int a){
playerAgl = a;}
void setplayerInt(int i){
playerInt = i;}
void setplayerDifficulty(int d){
playerDifficulty = d;}
void setwepbaseDmg(int j){
wepbaseDmg = j;}
//getters
std::string getplayerName(){
return playerName;}
int getplayerHealth(){
return playerHealth;}
int getMaxHealth(){
return playerMaxHealth;}
int getStr(){
return playerStr;}
int getAgl(){
return playerAgl;}
int getInt(){
return playerInt;}
int getDifficulty(){
return playerDifficulty;}
private:
std::string playerName;
int playerHealth;
int playerMaxHealth; //absolute max = 200
int playerStr; // absolute max = 20
int playerAgl;// absolute max = 20
int playerInt;// absolute max = 20
int playerDifficulty; // absolute max = 4
//items
int wepbaseDmg;
int wepSpeed;
};
#endif
//------------------------------------------------------------------------------
//maketoon.cpp
//This was my attempt based off google....
//int* startChoices[4]={getDifficulty(), get};
int makeMainPlayer(){
CreateCharacter Player;
Player.setplayerDifficulty(startChoices[0]);
Player.setplayerName(name);
switch(startChoices[1]){
case 1:
Player.setplayerMaxHealth(175);
Player.setplayerStr(18);
Player.setplayerAgl(10);
Player.setplayerInt(6);
break;
case 2:
Player.setplayerMaxHealth(200);
Player.setplayerStr(9);
Player.setplayerAgl(13);
Player.setplayerInt(15);
break;
case 3:
Player.setplayerMaxHealth(100);
Player.setplayerStr(11);
Player.setplayerAgl(20);
Player.setplayerInt(10);
break;
case 4:
Player.setplayerMaxHealth(150);
Player.setplayerStr(12);
Player.setplayerAgl(12);
Player.setplayerInt(13);
break;
}
switch(startChoices[2]){
case 1:
Player.setwepbaseDmg(40);
Player.setwepSpeed(4);
break;
case 2:
Player.setwepbaseDmg(30);
Player.setwepSpeed(5);
break;
case 3:
Player.setwepbaseDmg(25);
Player.setwepSpeed(8);
break;
case 4:
Player.setwepbaseDmg(20);
Player.setwepSpeed(10);
break;
}
return 0;
}

C++ Why is my loop breaking?

I'm following a tutorial for making a MUD (text-based RPG), and I am having issues with my main function. If you'll look at the code, you'll see that when the player moves it will check for a random encounter, and if monster != 0, it will go into the combat loop. When I execute this in the command prompt, it will allow me to attack the monster, but it never makes it to the monster->attack(mainPlayer) function. It just goes back to the screen that states whether I want to move, rest, view stats, or quit. Any help with this would be greatly appreciated!
#include "stdafx.h"
#include "Map.h"
#include "Player.h"
#include <cstdlib>
#include <ctime>
#include <iostream>
using namespace std;
int main()
{
srand( time(0) );
Map gameMap;
Player mainPlayer;
mainPlayer.createClass();
// Begin adventure
bool done = false;
while( !done )
{
// Each loop cycle we output the player position and
// a selection menu.
gameMap.printPlayerPos();
int selection = 1;
cout << "1) Move 2) Rest 3) View Stats 4) Quit: ";
cin >> selection;
Monster* monster = 0;
switch( selection )
{
case 1:
// Move the player
gameMap.movePlayer();
// Check for a random encounter. This function
// returns a null pointer if no monsters are
// encountered.
monster = gameMap.checkRandomEncounter();
// 'monster' not null, run combat simulation.
if( monster != 0)
{
// Loop until 'break' statement.
while( true )
{
// Display hitpoints
mainPlayer.displayHitPoints();
monster->displayHitPoints();
cout << endl;
// Player's turn to attack first.
bool runAway = mainPlayer.attack(*monster);
if( runAway )
{
break;
}
if( monster->isDead() )
{
mainPlayer.victory(monster->getXPReward());
mainPlayer.levelUp();
break;
}
monster->attack(mainPlayer);
if( mainPlayer.isDead() )
{
mainPlayer.gameover();
done = true;
break;
}
}
// The pointer to a monster returned from
// checkRandomEncounter was allocated with
// 'new', so we must delete it to avoid
// memeory leaks.
delete monster;
monster = 0;
}
break;
case 2:
mainPlayer.rest();
break;
case 3:
mainPlayer.viewStats();
break;
case 4:
done = true;
break;
} // End switch statement
} // End While statement
} // End main function
Here is the Player::attack function:
bool Player::attack(Monster& monster)
{
int selection = 1;
std::cout << "1) Attack 2) Run: ";
std::cin >> selection;
std::cout << std::endl;
switch( selection )
{
case 1:
std::cout << "You attack the " << monster.getName()
<< " with a " << mWeapon.mName << std::endl;
if( Random(0, 20) < mAccuracy )
{
int damage = Random(mWeapon.mDamageRange);
int totalDamage = damage - monster.getArmor();
if( totalDamage <= 0)
{
std::cout << "Your attack failed to penetrate the "
<< monster.getName() << "'s armor." << std::endl;
}
else
{
std::cout << "You attack for " << totalDamage
<< " damage!" << std::endl;
// Subtract from monster's hitpoints.
monster.takeDamage(totalDamage);
}
}
else
{
std::cout << "You miss!" << std::endl;
}
std::cout << std::endl;
break;
case 2:
// 25% chance of being able to run.
int roll = Random(1, 4);
if( roll == 1 )
{
std::cout << "You run away!" << std::endl;
return true; //<-- Return out of the function.
}
else
{
std::cout << "You could not escape!" << std::endl;
break;
}
}
}
And here is the Monster::attack function:
void Monster::attack(Player& player)
{
cout << "A " <<mName << " attacks you "
<< "with a " << mWeapon.mName << std::endl;
if( Random(0,20) < mAccuracy )
{
int damage = Random(mWeapon.mDamageRange);
int totalDamage = damage - player.getArmor();
if( totalDamage <= 0 )
{
cout << "The " << mName << "'s attack failed to "
<< "penetrate your armor." << endl;
}
else
{
cout << "You are hit for " << totalDamage
<< " damage!" << endl;
player.takeDamage(totalDamage);
}
}
else
{
cout << "The " << mName << " missed!" << endl;
}
cout << endl;
}
Your Player::attack() method has only one return-statement: return true;. You forgot to add the final line return false; to your method.
This could have easily been prevented if you enable warnings (and pay attention to them!)
Your Player::attack doesn't return in all cases (specifically when it needs to return false). When the calling function tries to access the return value of Player::Attack it will get junk and so you enter the if(ranAway) block and break out of your while loop