I am trying to get this C++ assignment aligned properly. The main goal is to properly read data from a file, which is being done, but the output is not aligned properly.
Somebody has suggested putting all the variables into one string and outputting that row by row, but that seems like I would need to re-write the majority of the program and I'm not completely sure how to do it. I have attached the code and what the output looks like below. Just wondering if there's a better way to keep everything aligned while using setwidth, or another basic alignment method if one exists. By the way, the file's input can change.
while (!PatientsFile.eof()) {
PatientsFile >> firstName;
PatientsFile >> lastName;
PatientsFile >> pulse;
PatientsFile >> respir;
PatientsFile >> oxygen;
PatientsFile >> room;
string name = firstName + ", " + lastName;
//patient info
cout << setw(4) << room << ' ';
cout << name;
//pulse
if (pulse >= 101) {
cout << setw(13) << "High=" << pulse << ' ';
dangerCount++; }
else if (pulse <= 59) {
cout << setw(16) << "Low=" << pulse << ' ';
dangerCount++; }
else {
cout << setw(19) << pulse << ' '; }
//respir
if (respir >= 21) {
cout << setw(5) << "High=" << respir << ' ';
dangerCount++; }
else if (respir <= 10) {
cout << setw(6) << "Low=" << respir << ' ';
dangerCount++; }
else {
cout << setw(7) << respir << ' '; }
//oxygen
if (oxygen >= 101) {
cout << setw(7) << "High=" << oxygen << ' ';
dangerCount++; }
else if (oxygen <= 91) {
cout << setw(5) << "Low=" << oxygen << ' ';
dangerCount++; }
else {
cout << setw(7) << oxygen << ' '; }
//dangerCount
if (dangerCount == 1) {
checkTotal++;
cout << "CHECK\n";}
else if (dangerCount == 2) {
alertTotal++;
cout << "ALERT***\n"; }
else if (dangerCount == 3) {
criticalTotal++;
cout << setw(15) << "CRITICAL****\n"; }
else {
normalTotal++;
cout << endl; }
dangerCount = 0;
}
//display totals
cout << endl << normalTotal << " Normal\n";
cout << alertTotal << " ALERT\n";
cout << checkTotal << " CHECK\n";
cout << criticalTotal << " CRITICAL\n";
Output:
Room Name Pulse Respir Oxygen
-----------------------------------------------------
111 Pete, Moss Low=59 11 Low=91 ALERT***
312 Diana, Canser High=107 Low=10 96 ALERT***
332 Willie, Makit High=123 High=30 94 ALERT***
111 Betty, Wont Low=50 Low=10 Low=90 CRITICAL****
331 Freda, Spirit High=110 High=23 Low=90 CRITICAL****
321 Wilma, Moneylast High=132 18 Low=88 ALERT***
121 Robin, Banks Low=59 20 100 CHECK
122 Charlie, Horse Low=56 15 95 CHECK
121 Eileen, Back Low=45 17 Low=88 ALERT***
222 Eaton, Buggs 79 16 97
222 Summer, Day 60 12 92
231 Bea, Sting 73 High=21 Low=91 ALERT***
311 Anita, Bath High=111 High=33 97 ALERT***
232 April, Showers 61 High=22 93 CHECK
222 Rose, Bush 100 20 100
231 Buster, Leggs 88 High=44 Low=88 ALERT***
221 Barb, Wire 60 12 Low=82 CHECK
322 Jim, Shoos High=101 19 94 CHECK
322 Kris, Mass Low=4 14 99 CHECK
222 Rich, Bright 77 16 92
4 Normal
8 ALERT
6 CHECK
2 CRITICAL
You can try using tab \t in order to align your list correctly.
Here is the link you might want to look at: How many spaces for tab character(\t)?
Otherwise you will have to do
cout << "text" << setw(#) << "text" << setw(#) << endl;
I would advise against this since it just hardcoding set numbers and its tedious because you would have to count and make sure it is matching correctly.
As Xion's answer mentioned, the process of hardcoding the correct value for the for the text to be aligned correctly, is tedious. Furthermore, it might even not be correct at all for a different data set - For example, what would happen if someone had a much larger name than anticipated?
My suggestion is the following: Iterate over the data completely once, and store the maximum width of each field in a separate variable (also storing the data retrieved).
After that, you could then loop once again over the input, and now everything would be correctly aligned, as you would now know the maximum width of each field (including not having the guess the correct spacing for the header column beforehand, which would be ideal).
You could either create objects of this information and store them in a std::vector, or do the same with each separate data field, having a vector for each one.
Related
Why is the program skipping the first line of every new deptnum?
I am trying to read from a file that looks like:
1 Suits 0300 100 092
1 Coats 0200 060 065
1 Shirts 1000 012 013
2 Dresses 0400 060 065
2 Coats 0185 184 200
2 Shoes 0600 040 030
3 Jeans 0200 040 035
3 Shoes 0200 030 034
4 Jeans 0300 042 043
The deptnum is the first column.
And when I write to the other file I get:
Blinn Discount Apparel Company
Inventory Evaluation
10/12/2018
Unit Cost Extended
Quantity Cost Market Cost Market Lower Cost
Mens Dept
Suits 300 100.00 92.00 30000.00 27600.00
Coats 200 60.00 65.00 12000.00 13000.00
Shirts 1000 12.00 13.00 12000.00 13000.00
Total $54000.00 $53600.00 $53600.00
Womens Dept
Coats 185 184.00 200.00 34040.00 37000.00
Shoes 600 40.00 30.00 24000.00 18000.00
Total $112040.00 $108600.00 $108600.00
Girls Dept
Shoes 200 30.00 34.00 6000.00 6800.00
Total $118040.00 $115400.00 $115400.00
Boys Dept
Total $118040.00 $115400.00 $115400.00
Total Inventory $393000.00
It skipped Womens Dept -> Dresses, Girls Dept -> Jeans, and Boys Dept -> Jeans.
Here is my code:
#include <iostream>
#include <iomanip>
#include <fstream>
using namespace std;
int main()
{
ifstream inFile;
ofstream outFile;
int x = 1, deptnum, quant,cost,mkt,extcost,extmkt,totalcost = 0,totalmkt = 0,
lowcost,totalInv = 0;
char item [15];
inFile.open("blinn.dat");
outFile.open("blinn.dout");
if (!inFile)
cout <<"\n\t\t Can't open data file: blinn.dat\n";
else {
outFile <<"\n\t Blinn Discount Apparel Company\n";
outFile <<"\t Inventory Evaluation\n";
outFile <<"\t 10/12/2018\n";
outFile <<"\n\t\t\t\t\t\t Unit Cost\t\t\t Extended\n";
outFile <<"\t\t Quantity Cost Market Cost Market Lower Cost";
while (x < 5)
{
if (x == 1)
outFile << "\nMens Dept";
else if (x == 2)
outFile << "\nWomens Dept";
else if (x == 3)
outFile << "\nGirls Dept";
else if (x == 4)
outFile << "\nBoys Dept";
else
break;
while (inFile >> deptnum >> item >> quant >> cost >> mkt)
{
if (deptnum == x){
extcost = quant * cost;
extmkt = quant * mkt;
outFile << left << "\n " << setw(7)<< item << " "
<< right << setw(4)<< quant << " "
<< right << setw(4) << cost << ".00 "
<< right << setw(3) << mkt << ".00 "
<< right << setw(5) << extcost<< ".00 "
<< right << setw(5) << extmkt << ".00";
totalcost += extcost;
totalmkt += extmkt;
if (totalcost > totalmkt)
lowcost = totalmkt;
else
lowcost = totalcost;
}else
break;
}
outFile << right << "\n Total\t\t\t\t\t $" << totalcost << ".00 $"
<< totalmkt << ".00 $"<< lowcost << ".00";
x += 1;
totalInv += lowcost;
}
}
outFile << "\nTotal Inventory\t\t\t\t\t\t $"<< totalInv<< ".00";
inFile.close ();
outFile.close ();
return 0;
}
What is wrong with my logic?
There is a problem with your logic:
if (deptnum == x) {
// do something
}
else {
break;
}
To achieve the else branch, you have already read a line that deptnum != x (the first line of every new deptnum) so at the next iterator, the current line is discarded by the next input line.
I'm having some issues producing this output for my code.
Apples
10 # 0.98/UNIT: $9.80
Bananas
1 # 1.29/UNIT: $1.29
Flank Steak
1 # 8.82/UNIT: $8.82
Chocolate Ice Cream
1 # 3.23/UNIT: $3.23
Gym Bag
1 # 23.12/UNIT: $23.12
ORDER TOTAL:************************************$46.26
My issue is with the alignment of the decimal places for the totals with the dollar sign attached. I'm supposed to be able to do it with raw setw() code and right, left alignment, but I'm not so sure how to go about it without getting spaces between the $ and the actual numerical value.
Here's what I've gotten so far..
void printReceipt(const int cart[], const string productName[], const double prices[], int productCount){
double orderTotal = 0;
for (int i = 0; i < productCount; i++){ //Loop for output of receipt
if (cart[i] != 0){ //Will not output for item not ordered.
cout << productName[i] << endl;
cout << fixed << setprecision(2)
<< setw(3) << left << cart[i]
<< setw(3) << " # " //Formatting for receipt print
<< setw(6) << prices[i]
<< setw(35) << left << "/UNIT:" << "$"
<< setw(6)<< right << (cart[i] * prices[i]) << endl;
orderTotal = orderTotal + (cart[i] * prices[i]);
}}
cout << fixed << setfill('*') << setw(47)<< left << "ORDER TOTAL:";
cout << setfill(' ') << "$" << setw(6) << right << setprecision(2) << orderTotal;
}
current output is as follows
Apples
5 # 0.98/UNIT: $ 4.90
Bananas
5 # 1.29/UNIT: $ 6.45
Flank Steak
5 # 8.82/UNIT: $ 44.10
Chocolate Ice Cream
5 # 3.23/UNIT: $ 16.15
Gym Bag
5 # 23.12/UNIT: $115.60
ORDER TOTAL:***********************************$187.20
You will have to do this as a two-step process.
Format the dollar amount (cart[i]*prices[i]) into a std::ostringstream, using only the setprecision manipulator. No minimum setw, so all you get is the formatted amount. Obtain the string representation from the std::ostringstream, using str().
By using the length of the string that's returned from str(), you can calculate the amount of padding needed to position the '$'.
Instead of the fixed setw(35), you will compute the padding for this field. Just as a rough estimate, this will probably be:
<< setw(42-amount.length()) << left << "/UNIT:" << "$" << amount << std::endl;
where amount is the formatted std::string you obtained in step 1. In this manner, the width here will automatically adjust to give the appropriate amount of room for the amount.
This, by itself will not adjust for the unit count at the beginning of the line, which is also variable length. But after handling the amount correctly, here, you should be able to figure out how to fix that in the same manner.
I've never posted here before but I'm really stuck so I thought i'd give it a try. I've been working on this code for a while, The aim is to input a few students with their marks and to output them into tables with averages and totals. I was given a file like this:
15
Albert Einstein 52 67 63
Steve Abrew 90 86 90 93
David Nagasake 100 85 93 89
Mike Black 81 87 81 85
Andrew Van Den 90 82 95 87
Joanne Dong Nguyen 84 80 95 91
Chris Walljasper 86 100 96 89
Fred Albert 70 68
Dennis Dudley 74 79 77 81
Leo Rice 95
Fred Flintstone 73 81 78 74
Frances Dupre 82 76 79
Dave Light 89 76 91 83
Hua Tran Du 91 81 87 94
Sarah Trapp 83 98
my problem is that when I am inputting the names the program crashes after Fred Flinstone, I know its not a problem with the formatting of the next name (Frances Dupre) because when i moved him up the list it read it fine.
I have located where the program is crashing with 'cerr' outputting at different stages of the read process and it crashes when it is trying to read in Frances's marks.
a1main.cpp
#include <iostream>
#include "student.h"
using namespace std;
int main()
{
int numStds;
cin >> numStds;
cerr << endl << "Num Stds: " << numStds << endl;
Student std[numStds+1];
for(int i = 0; i <= numStds; i++)
{
std[i].readData();
std[i].printStudent();
}
// delete [] std;
return 0;
}
student.h
#include <iostream>
using namespace std;
class Student {
private:
char* name;
int mark[4];
int num;
public:
Student();
~Student();
void readData();
void printStudent();
float getTotal();
float getAverage();
};
student.cpp
#include <iostream>
#include <cstring>
#include <cctype>
#include "student.h"
using namespace std;
Student::Student()
{
name = new char;
mark[0] = 0;
mark[1] = 0;
mark[2] = 0;
mark[3] = 0;
num = 0;
}
Student::~Student()
{
// Doesn't work?
// delete name;
}
void Student::readData()
{
int l = 0;
// Reading the Name
cin >> name; // Read in the first name
l = strlen(name); // get the strlength
name[l] = ' '; // Putting a space between the first and last name
cin >> &name[l+1]; // Read in the last name
cerr << endl << "I have read the name!" << endl;
// Checking if there is a third name
if(cin.peek() == ' ')
cin >> ws; // checking and navigating past the whitespace
char next = cin.peek();
if( isalpha(next) ) // Checking whether the next cin is a char
{
l = 0;
l = strlen(name);
name[l] = ' ';
cin >> &name[l+1];
}
cerr << "I've checked for a third name!" << endl;
// Reading in the marks
for(int i = 0; i < 4; i++)
{
// Checks if the next cin is a newline
if (cin.peek() == '\n')
break;
cin >> mark[i];
}
cerr << "I've read in the marks!" << endl;
//cerr << endl << "I have read " << name << "'s marks!" << endl << endl;
for(int m = 0; m < 4; m++)
{
if(mark[m] != 0)
{
num++;
}
}
cerr << "I've incremented num!" << endl << endl;
}
// Function for error checking
void Student::printStudent()
{
cout << endl << "Student Name: " << name << endl;
cout << "Mark 1: " << mark[0] << endl;
cout << "Mark 2: " << mark[1] << endl;
cout << "Mark 3: " << mark[2] << endl;
cout << "Mark 4: " << mark[3] << endl;
cout << "num marks: " << num << endl << endl;
}
float Student::getTotal()
{}
float Student::getAverage()
{}
Can anyone see what i'm doing wrong? thanks :)
You're never allocating memory to store the student names.
In your Student constructor, add this code:
name = new char[100]; // allows names up to 100 characters long
and uncomment this line in the destructor:
delete[] name;
You could also make the code more sophisticated and robust by measuring the name length and allocating the correct size, or use std::string as suggested below.
So i have a program that reads from a text file and outputs to another text file. Here is the file text (format included) that it reads:
Duckey Donald 85
Goof Goofy 89
Brave Balto 93
Snow Smitn 93
Alice Wonderful 89
Samina Akthar 85
Simba Green 95
Donald Egger 90
Brown Deer 86
Johny Jackson 95
Greg Gupta 75
Samuel Happy 80
Danny Arora 80
Sleepy June 70
Amy Cheng 83
Shelly Malik 95
Chelsea Tomek 95
Angela Clodfelter 95
Allison Nields 95
Lance Norman 88
In the program it adds each of these to a struct within an array; it then calculates the grade and prints.
cout << "Student Name Test Score Grade" << endl;
for (int studentNumber = 0; studentNumber < STUDENT_NUMBER; studentNumber++){
cout << students[studentNumber].studentLName << ", "
<< students[studentNumber].studentFName << " "
<< students[studentNumber].testScore << " "
<< students[studentNumber].grade << endl;
}
The desired output looks like this:
Student Name Test Score Grade
Donald, Duckey 85 B
Goofy, Goof 89 B
Balto, Brave 93 A
Smitn, Snow 93 A
Wonderful, Alice 89 B
Akthar, Samina 85 B
Green, Simba 95 A
Egger, Donald 90 A
Deer, Brown 86 B
Jackson, Johny 95 A
Gupta, Greg 75 C
Happy, Samuel 80 B
Arora, Danny 80 B
June, Sleepy 70 C
Cheng, Amy 83 B
Malik, Shelly 95 A
Tomek, Chelsea 95 A
Clodfelter, Angela 95 A
Nields, Allison 95 A
Norman, Lance 88 B
Highest Test Score: 95
Students having the highest test score:
Green, Simba
Jackson, Johny
Malik, Shelly
Tomek, Chelsea
Clodfelter, Angela
Nields, Allison
So basically my question is this... is there any way for the test score column integers to line up like they do in my above desired output?
SOLUTION
int colWidth = 20;
for (int studentNumber = 0; studentNumber < STUDENT_NUMBER; studentNumber++){
string s = students[studentNumber].studentFName + ", " + students[studentNumber].studentLName;
int size = s.size();
cout << s << std::string(colWidth - size, ' ')
<< students[studentNumber].testScore << " "
<<
You can pad the string manually with spaces like so:
#include <string>
#include <iostream>
int main()
{
std::string first("John");
std::string last("Smith");
std::string full = last + ", " + first;
int colWidth = 20;
std::cout << "12345678901234567890\n"
<< full << std::string(colWidth - full.size(), ' ')
<< "aligned after 20 characters\n";
return 0;
}
Outputs:
12345678901234567890
Smith, John aligned after 20 characters
This will work for left justifying your text, given you calculate the number of characters you print.
For right-justifying, std::setw from <iomanip> works well. Unlike other stream manipulators, std::setw is not sticky, so it will only modify your next immediate output.
#include <string>
#include <iostream>
#include <iomanip>
int main()
{
std::string s("ABCDE");
int colWidth = 20;
std::cout << "12345678901234567890\n";
std::cout << std::setw(colWidth) << s << "\n";
return 0;
}
Prints
12345678901234567890
ABCDE
Putting it all together, I would left justify the first column, and right justify the second and third columns.
#include <string>
#include <iostream>
#include <iomanip>
int main()
{
std::string first("John");
std::string last("Smith");
std::string full = last + ", " + first;
int score = 100;
std::string grade("A");
std::cout << "123456789012345678901234512345\n"
<< full << std::string(20 - full.size(), ' ')
<< std::setw(5) << score
<< std::setw(5) << grade << "\n";
return 0;
}
Prints:
123456789012345678901234512345
Smith, John 100 A
You can change your code like this:
#include <iomanip>
cout << "Student Name Test Score Grade" << endl;
for (int studentNumber = 0; studentNumber < STUDENT_NUMBER; studentNumber++){
cout << setiosflags(ios::left) << setw(29) << setfill(' ')
<< students[studentNumber].studentLName + ", " + students[studentNumber].studentFName
<< setw(8) << students[studentNumber].testScore
<< students[studentNumber].grade << endl;
}
where 29 and 8 are calculated based on your disired output format, you can change it as you needs.
I am overseeing a tech camp where one of the campers has created some code for a text based video game that he is having trouble display the results. While the program compiles and runs correctly, it will not add to the player's health when "heal" is chosen and we also get zero when the user chooses "attack". I have limited knowledge in programming and am trying to help him the best I can so that his experience here will be enjoyable and fulfilling. If you could offer any help or advice we would be so thankful. Here is the code:
// Test for hard stuff.cpp : Defines the entry point for the console application.
//
// Bigger proj
// Constructors will make characters with rolling statistics
#include "stdafx.h"
#include <iostream>
#include <string>
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
using namespace std;
// declaring function for hit power
//int power( int str, int def);
int command;
class character
{
public:
character();
//~character();
string name;
float str;
float def;
float health; // hit points
float regen; // health regen amount
float roll; // for random value
float ouch; // amount of attack damage
float getAttack(void);
float getHeal(void);
void setRegen(float reg);
//void setHeal(float healAmt);
private:
};
character::character()
{
srand(time_t(NULL));
str = rand() % 30 + 5;
def = rand() % 30 + 5;
health = 100;
//Output to check the constructor is running properly
cout<< "Character has been created.\n";
}
void character::setRegen( float reg )
{
regen = reg;
}
float character::getAttack()
{
//defines the magnitude/power of attack
//function shows how much damage is inflicted
// ouch is how much damage is done
roll = rand() % 20 + 1; // range between 1 &20
if (roll <= 11)
{
ouch = str - (def /2);
}
else if ((roll <= 17) && (roll >= 12))
{
ouch = (str * 2) - (def / 2);
}
else if ((roll <= 20) && (roll >= 18))
{
ouch = (str * 3) - (def / 2);
//cout << "CRITICAL HIT!!";
}
return ouch;
}
float character::getHeal()
{
//this is what happens when you chose to heal
regen = rand() % 20 + 3;
cout << "regen value= " << regen<< ".\n";
return regen;
}
/*character::~character()
{
str = 0;
def = 0;
health = 0;
// Output to check the destructor is running properly
cout << "Character has been destroyed\n";
} */
int _tmain(int argc, _TCHAR* argv[])
{
//Class objects
character user, computer;
//Hard code in a name for the computer's player
computer.name = "ZOID\n";
float attackDamage;
float healthAdded;
user.setRegen(void);
//Recieve data for the user's player
cout<< "Please enter a name for your character:\n";
cin>> user.name;
//Output name and stats to the user
cout<< "\nYour name is: " << user.name << endl;
cout << "here are your statistics: \n"
<< "strength: " << user.str << endl
<< "Defense: " << user.def << endl
<< "Health: " << user.health << endl;
cout<< "oh no an oppenent appeared!!!\n";
cout<< "you will have to fight him!" << endl<< endl;
cout << "opponent's health: 100" << endl
<< "what would you like to do: heal (1), attack(2), or run(3).\n";
cin>> command;
switch(command)
{
case 1 :
healthAdded = user.getHeal();
cout<< ""<<user.name <<" has regenerated " << healthAdded << " health.\n";
break;
case 2 :
attackDamage = user.getAttack();
cout << "" <<user.name <<" did " << attackDamage << " damage to the opponent!\n";
break;
case 3:
cout<< ""<<user.name<<" got away!\n";
break;
default:
cout<< "Please enter a valid choice!";
} //end switch
return 0;
}
I'll try to help as best I can a piece at a time. My line numbers might be slightly different from yours, so feel free to look around a bit.
In:
115 user.setRegen(void);
setRegen is declared to take a float:
20 class character
21 {
22 public:
.
.
.
34 void setRegen(float reg);
So you can't pass void. Incidentally, in C++ it is customary to simply pass nothing when calling a function that takes no parameters, rather than passing an explicit void. However, the explicit void is OK.
The getHeal() function computes a random ammount to heal the character with, but it doesn't actually increment the health member variable. You might implement healing in this way, see line 92:
87 float character::getHeal()
88 {
89 //this is what happens when you chose to heal
90 regen = rand() % 20 + 3;
91 cout << "regen value= " << regen<< ".\n";
92 health += regen;
93 return regen;
94 } Z
You also aren't reducing the health of the opponent when you attack. One way you might do this is by passing a reference to the opponent to getAttack() and modifying it there:
58 float character::getAttack(character& opponent)
59 {
60 //defines the magnitude/power of attack
61 //function shows how much damage is inflicted
62
63
64 // ouch is how much damage is done
65 roll = rand() % 20 + 1; // range between 1 &20
66
67 if (roll <= 11)
68 {
69 ouch = str - (def /2);
70 }
71
72 else if ((roll <= 17) && (roll >= 12))
73 {
74 ouch = (str * 2) - (def / 2);
75 }
76
77 else if ((roll <= 20) && (roll >= 18))
78 {
79 ouch = (str * 3) - (def / 2);
80 //cout << "CRITICAL HIT!!";
81 }
82
83 opponent.health -= ouch;
84
85 return ouch;
86
87 }
You'll also need to change the declaration (prototype) for getAttack():
20 class character
21 {
22 public:
.
.
.
32 float getAttack(character& opponent);
...and how it is called in main():
152 case 2 :
153
154 attackDamage = user.getAttack(computer);
155
156 cout << "" <<user.name <<" did " << attackDamage << " damage to the opponent!\n";
157
158 break;
I also noticed that the program doesn't loop at all. It just accepts one action, executes it, and terminates. The game might be more fun if it looped until one of the players was dead.
One last thing, when using random numbers, you call srand exactly one, at typically at the beginning of the program's run. You are calling it every time a character is created.
Here is a shameless plug for one of my previous answers about using rand.
I made a few modifications for you. Here is a link to ideone with the same code as below:
// Test for hard stuff.cpp : Defines the entry point for the console application.
//
// Bigger proj
// Constructors will make characters with rolling statistics
//#include "stdafx.h"
#include <iostream>
#include <string>
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
using namespace std;
// declaring function for hit power
//int power( int str, int def);
int command;
class character
{
public:
character();
//~character();
string name;
float str;
float def;
float health; // hit points
float regen; // health regen amount
float roll; // for random value
float ouch; // amount of attack damage
float getAttack(character& opponent);
float getHeal(void);
void setRegen(float reg);
bool IsAlive() const;
//void setHeal(float healAmt);
private:
};
character::character()
{
str = rand() % 30 + 5;
def = rand() % 30 + 5;
health = 100;
//Output to check the constructor is running properly
cout<< "Character has been created.\n";
}
bool character::IsAlive() const
{
return health > 0.0f;
}
void character::setRegen( float reg )
{
regen = reg;
}
float character::getAttack(character& opponent)
{
//defines the magnitude/power of attack
//function shows how much damage is inflicted
// ouch is how much damage is done
roll = rand() % 20 + 1; // range between 1 &20
if (roll <= 11)
{
ouch = str - (def /2);
}
else if ((roll <= 17) && (roll >= 12))
{
ouch = (str * 2) - (def / 2);
}
else if ((roll <= 20) && (roll >= 18))
{
ouch = (str * 3) - (def / 2);
//cout << "CRITICAL HIT!!";
}
opponent.health -= ouch;
return ouch;
}
float character::getHeal()
{
//this is what happens when you chose to heal
regen = rand() % 20 + 3;
cout << "regen value= " << regen<< ".\n";
health += regen;
return regen;
}
/*character::~character()
{
str = 0;
def = 0;
health = 0;
// Output to check the destructor is running properly
cout << "Character has been destroyed\n";
} */
int main()
{
srand(time_t(NULL));
//Class objects
character user, computer;
//Hard code in a name for the computer's player
computer.name = "ZOID\n";
float attackDamage;
float healthAdded;
user.setRegen(42.0);
//Recieve data for the user's player
cout<< "Please enter a name for your character:\n";
cin>> user.name;
//Output name and stats to the user
cout<< "\nYour name is: " << user.name << endl;
cout << "here are your statistics: \n"
<< "strength: " << user.str << endl
<< "Defense: " << user.def << endl
<< "Health: " << user.health << endl;
cout<< "oh no an oppenent appeared!!!\n";
cout<< "you will have to fight him!" << endl<< endl;
cout << "opponent's health: 100" << endl;
while (user.IsAlive() && computer.IsAlive())
{
cout << "Str: " << user.str << "\t"
<< "Def: " << user.def << "\t"
<< "Health: " << user.health << "\t"
<< "\n";
cout << "what would you like to do: heal (1), attack(2), or run(3).\n";
cin>> command;
switch(command)
{
case 1 :
healthAdded = user.getHeal();
cout<< ""<<user.name <<" has regenerated " << healthAdded << " health.\n";
break;
case 2 :
attackDamage = user.getAttack(computer);
cout << "" <<user.name <<" did " << attackDamage << " damage to the opponent!\n";
break;
case 3:
cout<< ""<<user.name<<" got away!\n";
break;
default:
cout<< "Please enter a valid choice!";
} //end switch
}
return 0;
}
In general, one of the ways to approach this kind of issue is to examine what happens line by line and determine what each line does. It's lengthy sometimes(many times, really), but also does a good job of ensuring you don't miss anything. In this particular case, lets look at the heal issue.
When you enter the switch statement and hit case 1 (healing), this first thing the code does is assign the results of user.getHeal() to healthAdded. What you do from here is "Step into" getHeal() and see what it does. getHeal() gets a regen number, and assigns it to regen. It then prints regen, and finally returns the value you stored in regen.
Now that we know what getHeal() does, we can jump back to our case 1: and fully say what the first line does. It takes the regen value built in getHeal() and assigns it to healthAdded.
case 1: then prints the value in healthAdded before the break; statement. The break; finishes case 1.
So what your code did in quick list form was:
generate heal value
print it twice
What you wanted to do was modify the user's health based on the regen value, so you have a missing step: changing the user.health value with the regen number you built in getHeal().
The issue with the attack damage is similar, try comparing what you want the code to do in goal-like terms with what you see the code is actually doing.