Handling decimal values in evaluating postfix using stacks in c++ - c++

I am new to posting and relatively new to coding in c++.
My question involves:
Handling decimal values in evaluating postfix using stacks in c++. This is a homework assignment, but I have already gotten my code to work for the basic requirement. I am not asking for help with my homework. My professor wants us to brute force the assignment, so I have avoided many shortcuts using special header files such as <stack>.
I have researched the question and was not satisfied with the answers given. No one else seems to have split up their code like mine. I am having an issue passing a value from the inner loop which detects the decimal values to the rest of the main function. The code compiles and runs, but my final result is gibberish. I found a post which states multiple values cannot be passed from a function with 'return', but I do need at least two values returned from the inner decimal function. I do not understand the 'tuple' or 'pair' commands.
I know this is a wordy prelude, but I do want any readers to understand I have read pre-requisite materials and did lost of research. Personally, I hate brute force methods. I understand that a response may not be in time to help with my project, but I have been working on this for weeks. I would like to get the satisfaction of seeing this method work as conceived. Suggestions and pointers are very much welcome.
Here is the link to my code:
link
Here is my code:
//*****************************************************************************
// Postfix expression evaluation
// 11/13/2012
// by DJH
//
// all applicable copyrights apply
//
// this program evaluates an input postfix string
//
// created using Dev-C++ 5.2.0.3
//*****************************************************************************
// ----------------------------------libraries---------------------------------
#include <iostream> // For cin, cout and endl
#include <string>
#include <cctype>
#include <vector>
#include <sstream>
#include <cstdlib>
#include <cmath>
#include <iomanip>
using namespace std;
// ------------------------------ Globals -------------------------------------
string postfix;
// --------------------------- stack class ------------------------------------
class Stack {
public:
enum {MaxStack = 50};
void init() {top = -1;}
void push( double p ) {
if ( isFull() ) {
cerr << "Full Stack. DON'T PUSH\n";
return;
}
else {
arr[ ++top ] = p;
cout << "Just pushed " << p << endl;
return;}
}
int pop() {
if (isEmpty() ) {
cerr << "\tEmpty Stack. Don't Pop\n\n";
return 1;
}
else
return arr[top--];
}
bool isEmpty() {return top < 0 ? 1 : 0;}
bool isFull() {return top >= MaxStack -1 ? top : 0;}
void dump_stack() {
cout << "The Stack contents, from top to bottom, from a stack dump are: " << endl;
for (int s = top; s >= 0; s--)
cout << "\t\t" << arr[s] << endl;
}
private:
int top;
double arr[MaxStack];
} pStack;
// ------------------------------ end stack class -----------------------------
// -----------------------------function prototypes----------------------------
void evalPostfix( string);
double decimalEvaluate( string, int, double);
// ----------------------------------------------------------------------------
// -----------------------------------Main()-----------------------------------
int main() {
cout << "Enter a postfix expression\n\t (without spaces - using '_' for delimiters):\n\t";
cout << "For example: 8_5_3_+_*_2_/_5_+\n" << endl;
getline(cin, postfix);
// postfix = "7_2_*_5_+_2_*";
cout << "You entered: " << postfix << endl;
int c = 0;
while (postfix[c] != '\0') {
// this loop counts the characters in the input string including
// whitespace
++c;
}
cout << "\tThe string length is:\t" << c << endl;
evalPostfix(postfix);
int result = pStack.pop();
cout << "The result of the postfix expression is: " << result << endl;
/*
stack commands:
Stack a_stack; // creates new stack
a_stack.init(); // initializes top element
a_stack.pop(); // pops top of stack
a_stack.push(n); // push element to top of stack
a_stack.dump_stack(); // displays the contents of the stack from top to bottom
*/
return 0;
cin.get();
}
// --------------------------------end of Main()-------------------------------
// ------------------------------functions follow------------------------------
void evalPostfix( string) {
double ch = 0, dc = 0, b = 0, a = 0, d = 0;
double tempDC = 0;
double tempDCD = 0;
char op;
int i = 0, j = 0, k = 0, m = 0, n = 0, q = 0;
while (postfix[i] != '\0') {
if (postfix[i] == '_') {
i++;
} else if (isdigit(postfix[i])) {
ch = postfix[i] - '0'; // for numbers only
j = i + 1;
while (postfix[j] != '_') {
if (isdigit(postfix[j])) {
ch = ch * 10 + (postfix[j] - '0');
k = j + 1;
// this accounts for decimals by skipping the '.' and
// conducting operations on trailing numbers
if (postfix[k] == '.') {
dc = 0;
decimalEvaluate(postfix, k, dc);
dc = tempDC / tempDCD;
d = ch + dc;
k++;
}
j = k - 1;
j++;
}
}
cout << "Post decimal function k: " << k << endl;
cout << "Post decimal function dc: " << setprecision(12) << dc
<< endl;
cout << "Post decimal function d: " << d << endl;
pStack.push(d);
i = j - 1;
i++;
} else if (postfix[i] == '+' || postfix[i] == '-' || postfix[i] == '*'
|| postfix[i] == '/' || postfix[i] == '^') {
b = pStack.pop();
a = pStack.pop();
op = postfix[i]; // for operators only
switch (op) {
case '+':
pStack.push(a + b);
break;
case '-':
pStack.push(a - b);
break;
case '*':
pStack.push(a * b);
break;
case '^':
pStack.push(pow(a, b));
break;
case '/':
if (b == 0) {
cout << "Division by zero not allowed!" << endl;
cin.get();
exit(0);
}
pStack.push(a / b);
default:
cout << "Invalid Operation" << endl;
}
i++;
}
}
}
// ----------------------------------------------------------------------------
double decimalEvaluate(string postfix, int k, double dc) {
dc = 0;
double tempDC = 0;
double tempDCD = 0;
int n = 0, m = 0, lenDC = 0;
n = k;
while (postfix[n] != '_') {
if ((isdigit(postfix[n])) == false) {
n++;
}
cout << "This step (1) n: " << n << endl;
if (isdigit(postfix[n])) {
m = n;
// assumes characters between a '.' and '_' are all digits
// (may need to check)
while (postfix[m] != '_') {
lenDC++;
// this loop counts the digits in the input trailing a decimal
// point
m++;
}
cout << "This step (2) m: " << m << endl;
cout << "This step (2) lenDC: " << lenDC << endl;
while ((postfix[n]) != '_') {
tempDC = tempDC * 10 + (postfix[n]) - '0';
n++;
}
cout << "This step (3) n: " << n << endl;
cout << "This step (3) tempDC: " << tempDC << endl;
}
k = n;
tempDCD = pow(10, lenDC);
dc = tempDC / tempDCD;
cout << "This step (4) k: " << k << endl;
cout << "This step (4) tempDCD: " << tempDCD << endl;
cout << "This step (4) tempDC: " << tempDC << endl;
cout << "This step (4) dc: " << dc << endl;
}
return dc, k, tempDC, tempDCD;
}

Pass the variables by reference:
void decimalEvaluate (string postfix, int& k, double& dc, double& tempDC, double& tempDCD)
{
tempDC = 0.0;
//...
}

Related

(C++) Problem with if statement ,simple == condition

I have something which outputs all the factors for an integer using a fixed loop.
in this case, int_end_int_ = 4
and middle_x_coefficient = 4
for (int i = 1; i <= int_end_int_; i++)
{
if (int_end_int_ % i == 0) // This gets the factors
{
//here
}
}
i have that inside the if loop that if i * 2 == 4, print a string. So i thought that when i = 2, it will output the string.
//inside if loop
int newi = i * 2;
//i = 2
if (newi == middle_x_coefficient) {
preroot1 = i; //ignore
cout << "prerooted";
preroot2 = i; //ignore
}
It does not output "prerooted", and i have no clue why.
Full Code:
#include <iostream>
#include <string>
using namespace std;
int main()
{
cout << "Quadratic Equation Solver ( to roots )" << endl;
cout << "Enter quadratic equation, e.x (x^2 + 4x + 4) must be in this form" << endl;
string equation;
cout << ">> ";
getline(cin, equation);
if (equation.length() < 12)
{
cout << "Please enter valid string." << endl;
while (equation.length() < 12)
{
cout << ">> ";
getline(cin, equation);
}
}
char middle_x_coefficient = equation[6]; // getting x^2 + 4(this<-)x + 4
char end_int_ = equation[11]; // getting x^2 + 4x + 4 <-- this
int preroot1 = 0;
int preroot2 = 0;
int int_end_int_ = static_cast<int>(end_int_); //convert char to int using static cast for like no reason
//nvm <- https://stackoverflow.com/questions/103512/why-use-static-castintx-instead-of-intx this says it is better bc compiler bad or smthn
int_end_int_ -= 48; //This converts the ascii value (52 for 4) to 4 (-48)
int pasti = 0;
for (int i = 1; i <= int_end_int_; i++)
{
if (int_end_int_ % i == 0)
{
cout << i << "this<- i" << endl;
cout << middle_x_coefficient << "this<- x" << endl;
int newi = i * 2;
//i = 2
if (newi == middle_x_coefficient) {
preroot1 = i;
cout << "prerooted";
preroot2 = i;
}
else if (i + pasti == middle_x_coefficient) {
preroot1 = i;
preroot2 = pasti;
}
pasti = i;
}
}
cout << preroot1 << " " << preroot2 << endl;
return 0;
}
You converted the character end_int_ to the integer int_end_int_, but you didn't convert the character middle_x_coefficient to an integer. Convert and use converted integer just as you did for end_int_.
Instead of using magic number 48, using character literal '0' is better.

Continuous x no. of A and then after (n-x) no.s of B

I am stuck in one of the problem related string in c++. My logic has worked well for some test cases, but not for all test cases. Please suggest me the actual logic of the following question::
I am given a string s of n character, comprising only of A's and B's . I can choose any index i and change s(i) to either A or B. Find the minimum no. Of changes that you must make to string S such that the resultant string is of format : AAAAA.....BBBBB. In other words, your task is to determine minimum no. of changes such that string s has x no. of A's in the beginning, followed by the remaining (n-x) no. of B's.
my code::
#include<bits/stdc++.h>
using namespace std;
int main() {
int t;
cin >> t;
while (t--) {
int n, i, flag = 0;
cin >> n;
string str;
cin >> str;
int cnt = 0, cnt1 = 0;
for (i = 0; i < str.length(); i++) {
if (str[i] == 'A') {
cnt++;
} else {
cnt1++;
}
}
int pp = 0;
//cout << cnt << " " <<cnt1;
for (i = 0; i < cnt; i++) {
if (str[i] == 'B') {
pp++;
}
}
for (i = cnt; i < n; i++) {
if (str[i] == 'A' && str[i - 1] != 'A') {
pp++;
}
}
cout << pp << endl;
}
}
For example: AAB = 0 changes, BABA= 2 changes , AABAA= 1 changes
How to approach this question. Do respond!!!
I wrote the following code to compute the number of changes needing to order a string containing unorderd A e B according to the order that shall be "A[...A]B[...B]". (function countChanges).
The algorithm (countChanges) used to count modifications acts in three steps:
Step 1: counts how much 'A' chars are in the string (cnt).
Step 2: scans how much 'B' chars are in the first cnt chars of the string increasing a counter (sum) for each encounterd 'B'.
Step 3: scans how much 'A' chars are in the remaining chars of the string after the 2nd step increasing a counter (sum) for each encountered 'A'.
At the end of the function sum is the expected result.
The code also computes and executes the minimum number of swaps needing to obtain the string ordered according to the requirement.
The code contains two evaluation functions (the code under the main):
cntChanges. It computes the needing number of changes (The code gives the result as foreseen changes).
executeSwaps. It performs swaps on the string, counts them and may or may not show the steps performed.
Code result:
Do you have a code composed of A and B? [y]es/[n]o/[I] do it/[q]uit y
Insert your code? BABA
Do you want to print swap steps? [y]es/[n]o y
Input: BABA
Step 1 BABA swap(3,0) ==> AABB
Result AABB performed with 1 swap - foreseen changes 2
--
Do you have a code composed of A and B? [y]es/[n]o/[I] do it/[q]uit n
How much codes do you want to generate? 5
What's your preferred length for all generated codes? 10
Do you want to print swap steps? [y]es/[n]o y
Input: AAAAABAABB
Step 1 AAAAABAABB swap(7,5) ==> AAAAAAABBB
Result AAAAAAABBB performed with 1 swap - foreseen changes 2
--
Input: ABBABAAABA
Step 1 ABBABAAABA swap(9,1) ==> AABABAAABB
Step 2 AABABAAABB swap(7,2) ==> AAAABAABBB
Step 3 AAAABAABBB swap(6,4) ==> AAAAAABBBB
Result AAAAAABBBB performed with 3 swaps - foreseen changes 6
--
Input: AAABBAABBB
Step 1 AAABBAABBB swap(6,3) ==> AAAABABBBB
Step 2 AAAABABBBB swap(5,4) ==> AAAAABBBBB
Result AAAAABBBBB performed with 2 swaps - foreseen changes 4
--
Input: BABAABBABB
Step 1 BABAABBABB swap(7,0) ==> AABAABBBBB
Step 2 AABAABBBBB swap(4,2) ==> AAAABBBBBB
Result AAAABBBBBB performed with 2 swaps - foreseen changes 4
--
Input: AAABAABAAA
Step 1 AAABAABAAA swap(9,3) ==> AAAAAABAAB
Step 2 AAAAAABAAB swap(8,6) ==> AAAAAAAABB
Result AAAAAAAABB performed with 2 swaps - foreseen changes 4
--
The code:
#include <iostream>
#include <ctime>
#include <cstring>
#include <vector>
#include <algorithm>
using namespace std;
unsigned int executeSwaps(string &x, bool printSteps);
unsigned int cntChanges(const string& x);
unsigned int cntChangesJarod42(string const &x);
unsigned int cntChangesDamien(string const &x);
void questionToStart(int &c, size_t &cl, char &ync, char &ynps, string &x);
string generateCode(size_t n);
const char char1='A';
const char char2='B';
int main(void)
{
srand(static_cast<unsigned int>(time(nullptr)));
int c;
size_t cl;
char ync='n';
char ynps='n';
string x;
x.clear();
do {
questionToStart(c,cl,ync,ynps,x);
if (ync == 'q')
break;
for(int i=0;i<c;i++) {
unsigned int cnt=0;
if (ync=='n') {
x=generateCode(cl)
}
/* unsigned int fc2 = cntChangesJarod42(x);
unsigned int fc1 = cntChangesDamien(x);*/
unsigned int fc3 = cntChanges(x);
cout << "Input: " << x << endl;
cnt=executeSwaps(x, (ynps=='y')?1:0);
cout << "Result " << x << " performed with "
<< ((cnt>0)?to_string(cnt):"no")
<< " swap"
<< ((cnt>1)?"s ":" ") << " - foreseen changes " << fc3 << endl << "--" << endl;
/* << "foreseen changes (#Damien) " << fc1
<< " - foreseen changes (#Jarod42) " << fc2
<< endl << endl;*/
}
} while(ync != 'q');
return 0;
}
unsigned int cntChanges(const string& x)
{
const char * s;
unsigned int cnt=0,sum=0,i;
if (x.empty())
return 0;
s=x.c_str();i=0;
// count char1
while(*(s+i))
if (*(s+i++) == char1)
cnt++;
/* verify how much elements, from start to cnt,
* are different than char1 (equal to char2).
*/
for(i=0;i<cnt;i++)
if (*(s+i)==char2)
sum++;
cnt=static_cast<unsigned int>(strlen(s));
/* verify how much of the remaining elements
* are different than char2 (equal to char1).
*/
for(;i<cnt;i++)
if (*(s+i)==char1)
sum++;
return sum;
}
// #Jarod42
unsigned int cntChangesJarod42(const string& s)
{
if (s.empty()) { return 0; }
std::vector<std::size_t> switch_count(s.size());
{ // Count 'B' before index
unsigned int sum = 0;
std::size_t i = 0;
for (auto c : s) {
switch_count[i++] += sum;
sum += c == 'B';
}
}
{ // Count 'A' after the index
unsigned int sum = 0;
std::size_t i = 0;
for (auto c : std::string(s.rbegin(), s.rend())) {
switch_count[s.size() - 1 - i++] += sum;
sum += c == 'A';
}
}
return static_cast<unsigned int>(*std::min_element(switch_count.begin(), switch_count.end()));
}
// #Damien Algorithm
unsigned int cntChangesDamien (string const &x)
{
size_t n = x.length();
int cntCh_1 = 0, cntCh_2 = 0;
// there's nothing to swap!! :p
if (n < 2)
return 0;
for (size_t i = 0; i < n; ++i) {
if (x.at(i) == char1) {
cntCh_1++;
} else {
// x.at(i) is equal to char1
cntCh_1 = min (cntCh_2, cntCh_1);
// Now the foreseen swap are equal to cntCh1
cntCh_2++;
}
}
return static_cast<unsigned int>(std::min (cntCh_2, cntCh_1));
}
unsigned int executeSwaps(string &x, bool printSteps)
{
unsigned int cnt =0;
size_t apos=0;
size_t bpos=0;
// cout << "Start: " << x << " " << apos << " " << bpos << endl;
do {
apos=x.find_last_of(char1);
if (apos == string::npos)
break;
bpos=x.find_first_of(char2);
if (bpos == string::npos)
break;
if (apos>bpos) {
++cnt;
if (printSteps) {
cout << "Step " << cnt << " " << x << " swap(" << apos << "," << bpos <<") ==> ";
}
x.at(bpos)=char1;
x.at(apos)=char2;
if (printSteps)
cout << x << endl;
}
} while(apos>bpos);
return cnt;
}
string generateCode(size_t n)
{
string x;
x.clear();
size_t i,cb=0;
char ch;
if (n==0) {
n=rand()%10;
}
for (i=0;i<n-1;i++) {
ch = ( char1 + (rand()&1) );
if (ch == char2 )
cb++;
x +=ch;
}
if (cb==n-1) {
ch=char1;
} else if (cb==0) {
ch=char2;
} else {
ch=( char1 + (rand()&1) );
}
x += ch;
return x;
}
void questionToStart(int &c, size_t &cl, char &ync, char &ynps, string &x)
{
int ex=1;
do {
ex=1;
cout << "Do you have a code composed of "<<char1 << " and " << char2 <<"? [y]es/[n]o/[I] do it/[q]uit ";
cin >> ync;
switch(ync) {
case 'n':
cout << "How much codes do you want to generate? ";
cin >> c;
cout << "What's your preferred length for all generated codes? ";
cin >> cl;
break;
case 'I':
c=10; cl=(rand()&7)+9;
cout << c <<" attempts with " << cl << " characters long strings will be executed" << endl;
break;
case 'y':
c=1;
cout << "Insert your code? ";
cin >> x;
cl = x.length();
break;
case 'q':
break;
default:
ex=0;
}
} while(!ex);
if ( ync != 'q' ) {
if ( ync != 'I' ) {
cout << "Do you want to print swap steps? [y]es/[n]o ";
cin >> ynps;
} else {
ynps = 'y';
ync = 'n';
}
cout << endl;
}
}
As state by Tfry,
you might count the number of switch needed to have
XBBB
AXBB
AAXB
AAAX
which is the number of 'B' before the index + number of 'A' after the index.
Then take the minimum:
std::size_t count_switch_for_ab(const std::string& s)
{
if (s.empty()) { return 0; }
std::vector<std::size_t> switch_count(s.size());
{ // Count 'B' before index
int sum = 0;
std::size_t i = 0;
for (auto c : s) {
switch_count[i++] += sum;
sum += c == 'B';
}
}
{ // Count 'A' after the index
int sum = 0;
std::size_t i = 0;
for (auto c : std::string(s.rbegin(), s.rend())) {
switch_count[s.size() - 1 - i++] += sum;
sum += c == 'A';
}
}
return *std::min_element(switch_count.begin(), switch_count.end());
}
Demo.
The solution can be found in a simple loop, considering a 2-state process.
A state corresponds to the fact that for the given index, we decide to be in the A part or the B part. The transition from B state to A state is not allowed.
The corresponding number of changes up to index i can then be calculated iteratively.
For index i, let us call countA[i] the number of changes to get A only until index i, and let us call countB[i] the optimal number of changes up to i, assuming that somewhere before i, or at i time, we decided that the following part of the last string will containt B only.
It the current character s[i] is equal to A, then
countA[i] = countA[i-1]
countB[i] = countB[i-1] + 1
If the current character is B, then
countA[i] = countA[i-1] + 1
countB[i] = min (countB[i-1], countA[i-1])
if the last equation, countB[i] = countB[i-1] corresponds to the case that the transition to B state already occurs, and
countB[i] = countA[i-1] corresponds to the case that the transition occurs now.
In practice, we don't need an array to update countA and countB.
Here is the code:
#include <iostream>
#include <string>
int nb_changes (const std::string &s) {
int n = s.size();
if (n < 2) return 0;
int countA = 0, countB = 0;
for (int i = 0; i < n; ++i) {
if (s[i] == 'A') {
countB++;
} else {
countB = std::min (countA, countB);
countA++;
}
}
return std::min (countA, countB);
}
int main() {
std::string s;
s = "AAB";
std::cout << "number of changes for " << s << " is " << nb_changes(s) << "\n";
s = "BABA";
std::cout << "number of changes for " << s << " is " << nb_changes(s) << "\n";
s = "AABAA";
std::cout << "number of changes for " << s << " is " << nb_changes(s) << "\n";
}

Inputting Grades with Looping C++

We're only interested in the #'s in the range [0,100]. There may be number outside the range [0, 100], but they aren't part of our calculation (i.e numbers below 0 and above 100 can be inputted but will be ignored in the calculations and counters).
Assume we assign ABCDF as
[85,100]: A
[75,85): B
[65,75): C
[55,65): D
[0,55): F
For each of the five letter grades, output the number of scores with that grade, and also, if the number of scores wasn't 0, output the average score with that grade. Also, if the number of valid scores (in [0, 100]) wasn't 0, output the average of all the scores
I am having trouble with this looping question. When I input multiple scores, it loops them incorrectly and outputs two sets of grades for each input rather than the example answer shown above. Also I am not sure if my break is placed correctly to exit the program when a word is inputted. Any help will be greatly appreciated!
Here is my code:
#include <iostream>
#include <cmath>
#include <cstdlib>
#include <string>
using namespace std;
int main(){
double scores;
unsigned countA = 0;
unsigned countB = 0;
unsigned countC = 0;
unsigned countD = 0;
unsigned countF = 0;
char grade;
double sumA = 0, sumB = 0, sumC = 0, sumD = 0, sumF = 0;
cout << "Enter scores: ";
for (scores; cin >> scores;){
if (scores > 85 && scores <= 100){
grade = 'A';
countA++;
sumA += scores;
}
else if (scores > 75){
grade = 'B';
countB++;
sumB += scores;
}
else if (scores > 65){
grade = 'C';
countC++;
sumC += scores;
}
else if (scores > 55){
grade = 'D';
countD++;
sumD += scores;
}
else{
grade = 'F';
countF++;
sumF += scores;
}
if (!cin){
break;
}
if (countA == 0){
cout << "# A's: 0 " << endl;
}
else {
cout << "# A's: " << countA << " Average = " << sumA/countA << endl;
} if (countB == 0){
cout << "# B's : 0 " << endl;
}
else{
cout << "# B's: " << countB << " Average = " << sumB /countB << endl;
} if (countC == 0){
cout << "# C's: 0 " << endl;
}
else{
cout << "# C's: " << countC << " Average = " << sumC /countC << endl;
} if (countD == 0){
cout << "# D's: 0 " << endl;
}
else {
cout << "# D's: " << countD << " Average = " << sumD /countD << endl;
} if (countF == 0){
cout << "# F's: 0 " << endl;
}
else {
cout << "# F's: " << countF << " Average = " << sumF /countF << endl;
}
}
TL;DR version: Closing brace on the for loop was missing. Loop never ended and caused OP's output code to also loop.
Long version:
Here is working code. The stuff I changed is marked with comments.
#include <iostream> //removed a bunch of unused includes.
using std::cin; // including all of namespace::std is overkill and often
using std::cout; // leads to hard-to-solve bugs. Only use what you need
using std::endl;
int main()
{
double scores;
unsigned countA = 0;
unsigned countB = 0;
unsigned countC = 0;
unsigned countD = 0;
unsigned countF = 0;
char grade;
double sumA = 0, sumB = 0, sumC = 0, sumD = 0, sumF = 0;
cout << "Enter scores: ";
// for (scores; cin >> scores;){
while (cin >> scores) // cleaner
{
if (scores > 85 && scores <= 100)
{
grade = 'A';
countA++;
sumA += scores;
}
else if (scores > 75)
{
grade = 'B';
countB++;
sumB += scores;
}
else if (scores > 65)
{
grade = 'C';
countC++;
sumC += scores;
}
else if (scores > 55)
{
grade = 'D';
countD++;
sumD += scores;
}
else
{
grade = 'F';
countF++;
sumF += scores;
}
// this test is made redundant by the loop condition
// if (!cin)
// {
// break;
// }
} // this was missing. The loop kept going and included all of
// the following code in the loop.
if (countA == 0)
{
cout << "# A's: 0 " << endl;
}
else
{
cout << "# A's: " << countA << " Average = " << sumA / countA << endl;
}
if (countB == 0)
{
cout << "# B's : 0 " << endl;
}
else
{
cout << "# B's: " << countB << " Average = " << sumB / countB << endl;
}
if (countC == 0)
{
cout << "# C's: 0 " << endl;
}
else
{
cout << "# C's: " << countC << " Average = " << sumC / countC << endl;
}
if (countD == 0)
{
cout << "# D's: 0 " << endl;
}
else
{
cout << "# D's: " << countD << " Average = " << sumD / countD << endl;
}
if (countF == 0)
{
cout << "# F's: 0 " << endl;
}
else
{
cout << "# F's: " << countF << " Average = " << sumF / countF << endl;
}
}
Your question is a bit confusing, I assume your main issue is the output part. Currently your code produces this.
As you see we get intermediate output, after every score entered. To change that the loop needs to be split into two loops: One for input, and one for output that runs after the first:
while (/* we get scores */) {
// update the counters and sums
}
for (/* every score */) {
// print count and average
}
To generate the output in a loop you need to store your data in some "loopable" way. Currently you have multiple local variables. Changing that to an array (indexed by the respective grade) allows us to loop over the data:
unsigned counter[5];
double sum [5];
// A -> 0, B -> 1, ..., F -> 4
for (std::size_t it = 0; it < 5; ++it) {
// use sum[it] and counter[it]
}
But raw arrays (as raw pointers) are evil - only use them when absolutely necessary - we use std::array from the standard library. And to ease iteration and improve logical encapsulation it's good to keep sum and count of each grade together:
struct grade_info {
unsigned count = 0;
double sum = 0;
};
// ... later in the main function
std::array<grade_info, 5> grades;
// input
for (auto const & grade : grades) { // C++11 shorthand to iterate over a collection
// use grade.count and grade.sum
}
Concerning your input:
for (scores; cin >> scores;){
This does the right thing, but is a bit strange. Since scores will only be used inside that loop instead of declaring it as local variable of main we only declare it inside the loop:
for (double score; // only a single score is in that variable at any time
cin >> score; // ends the loop on eof or failure to convert to double (when text got entered)
// no step instructions, the above check does that already
) {
Now there's also no need to test cin inside the loop. The operator>> returns (a reference to) its first argument, which is cin, so the test in the for loop already tests cin, no need for if (! cin) { break; }.
Then you have code like this
grade = 'A';
when you never use the value stored in grade. Just remove that.
Last but not least your input validation isn't working (the 101 in my test case is treated as grade B):
if (scores > 85 && scores <= 100) {
// scores between (85, 100]
}
// scores is either <= 85 OR > 100
else if (scores > 75){
// scores is in (75, 85] OR > 100
}
Ideally you should keep input validation and business logic separated:
if (not input_is_valid(score)) {
continue; // the loop
}
// business logic, assuming valid input
So, the final code could be
#include <iostream>
#include <array>
struct grade_info {
unsigned count = 0;
double sum = 0;
char const name;
grade_info(char n) : name(n) {
}
};
bool input_is_valid(double score) {
return (score >= 0) and (score <= 100);
}
std::size_t score_to_grade_index(double score) {
if (score >= 85) {
return 0;
} else if (score >= 75) {
return 1;
} else if (score >= 65) {
return 2;
} else if (score >= 55) {
return 3;
} else {
return 4;
}
}
int main(int, char**) {
std::array<grade_info, 5> grades {'A', 'B', 'C', 'D', 'F'};
for (double score; std::cin >> score;) {
if (not input_is_valid(score)) {
continue;
}
auto index = score_to_grade_index(score);
++(grades[index].count);
grades[index].sum += score;
}
for (auto const & grade : grades) {
std::cout << "# " << grade.name << ": "
<< grade.count;
if (grade.count > 0) {
std::cout << " avg: " << (grade.sum / grade.count);
}
std::cout << std::endl;
}
return 0;
}
Live here

Mastermind string cout issue

Ok I have been struggling with this code and I think I have it written out right but here is the rules from my teacher
1 = implies right Number, Right Place.
2 = implies right Number, Wrong Place.
0 = implies Wrong Number.
So the computer decides on 12345; the user guesses 11235; the computer should respond with 10221. Hint: Watch out for a double number like 11 when there is only one.
I have it where it does all of that except I can not get it to show a 0 when it is wrong can you please help me every single part is written except that part here is my code
// Programming 2
// Mastermind
#include "stdafx.h"
#include <iostream>
#include <ctime>
#include <cstdlib>
#include <string>
using namespace std;
struct fields{//the list of variables used in my program
int size = 5;;
int range = 9;
char lowest = '0';
string guess;
string answer;
int number;
int correct;
int position;
bool gameover = false;
};
void gameplay(fields & info);//declaring the function
int main()
{
fields game;
gameplay(game);//calling the function
system("pause");
return 0;
}
void gameplay(fields & info){//calling the structure into the function
srand(time(0));//to randomize number
info.answer = "";//getting the number
for (int i = 0; i < info.size; i++)
{
char ch = info.lowest + rand() % info.range;
info.answer += ch;
}
info.number = 1;
info.correct = 0;
info.position = 0;
while (!info.gameover)//using a while loop to let them go until they guess it
{
cout << "Guess #" << info.number << ": Enter 5 numbers that are '0' through '9': ";//asking them to guess
cout << info.answer;
cout << "\n";
cin >> info.guess;
if (info.guess == info.answer)//if the guess is right this will end the game
{
cout << "Right! It took you " << info.number << " move";
if (info.number != 1) cout << "s";
cout << "." << endl;
info.gameover = true;
}
int correctNumbers = 0;
for (char const &ch : info.guess) //seeing if there are numebrs in the guess that is in the answer
{
if (info.answer.find(ch) != string::npos)
{
++correctNumbers;
}
}
int const digits = 5;
int correctPositions = 0;
int correctPosition[digits];
int test = 0;
for (int i = 0; i < digits; ++i)//telling which numbers is correct and displaying the 2 or 0 for number is correct or number is wrong
{
if (info.answer[i] == info.guess[i])
{
++correctPositions;
}
if (info.answer[i] == info.guess[i]){
correctPosition[i] = 2;
cout << correctPosition[i];
}
if (correctPosition[i] != 2){
correctPosition[i] = 1;
cout << correctPosition[i];
}
if (correctPosition[i] != 2 && correctPosition[i] != 1)){
correctPosition[i] = 0;
cout << correctPosition[i];
}
}
cout << "\nYou have " << correctPositions << " numbers in the correct position " <<endl;
cout << "You have " << correctNumbers <<" correct numbers in the wrong position"<< endl;
}
cout << "GAME OVER\n\n";
}

Seg fault from attempting to access out of range array, unknown to why

I am working on a school project (I was allowed to do a simulation in C++ for my Science Fair project) and everything is going pretty ok (besides another bug that I had an issue with) until now. In order to fully understand what I am doing, I suggest that you take a quick glance at this page.
Okay. Below is my code. When you try to run it, you can clearly see that some bots' x and y cordinates are in the negatives, which shouldn't be happening. I have triple checked all the operations and everything looks fine to me. I used this to help me understand X and Y locations relative in arrays. Is there any clear issue of my mistake? I am still getting used to multidimensional arrays, so please take that into consideration. Also, I am aware that most of it is highly inefficient; cleaning it up will be a project itself. Thank you and Happy Holidays!
*My issues are coming from the moveBot functions, which are towards the bottom. It didn't seem right to have you read over unnecessary parts.
Updated Code:
// NANORG SIMULATION
// CREATED BY JACOB HARTMANN FOR THE SCIENCE FAIR (2013)
// CODED IN C++
#include <iostream>
#include <string>
#include <stdlib.h>
#include <time.h>
#include <stdio.h>
#include <stdlib.h>
#include <cstdlib>
#include "bot.h"
using namespace std;
signed int map [40][70]; //2D array x first, then y
int mapBot [40][70]; //If bot is there, 1. If not, 0 This array keeps track if there is a bot in a location
signed int currentTick = 0; //Signed just in case something goes wrong and goes into the -s
int maxTick = 1000000; //Should always stay at 1mil
signed int totalEnergy = 0; //For some reason, when I add this here, everything breaks.
Bot bots[50];
void setupMap();
void tick();
void updateTickOutput();
void outputMapValue(int x, int y);
void assignBotID();
void setupBot();
void moveBot();
void manualMoveBot(int botID);
void mutateBot(int botID, int level, int sT);
void ckLoc(int botIdent);
void reassignLoc(int botID);
void gatherEnergy(int botID);
int main() {
cout << " ----------------------" << endl;
cout << " NANORG Simulation V1.3.1" << endl;
cout << "Created in C++ by Jacob Hartmann" << endl;
cout << " ----------------------" << endl << endl;
srand (time(NULL));
cout << "Setting up map.. (Step 1)" <<endl;
setupMap();
cout << "Assigning botIDs.. (Step 2)" << endl;
assignBotID();
cout << "Setting up bots.. (Step 3)" << endl;
setupBot();
cout << "Starting ticks.. (Step 4)" << endl;
tick();
// outputMapValue(5,5);
// mutateBot(5, 2); //Just to test
/* cout << endl << "X before: " << bots[5].x_cord << " Y before: " << bots[5].y_cord << endl;
moveBot(5);
cout << "X after: " << bots[5].x_cord << " Y after: " << bots[5].y_cord << endl;
cout << "Energy before: " << bots[5].energy <<endl;
gatherEnergy(5);
cout << "Energy after: " << bots[5].energy << endl; */ //DEBUG
return 0;
}
void setupMap(){
// srand (time(NULL)); //Not a good idea to put it here
for(int i = 0; i < 40; i++){
for(int j = 0; j < 70; j++){ // We add one extra (70) so it fills the entire array. Same for above
map[i][j] = rand() % 2 + 1; // 1==normal 2==toxic
}
}
// outputMapValue(5,4); //Debugging purposes
// outputMapValue(7,9);
cout << "Map setup - \033[0;32mSuccessful" << "\033[0m" << endl;
}
void outputMapValue(int x, int y){
cout << "The chunk value at (" << x+1 << ", " << y+1 << ") is: ";
cout << map[x][y]; //Outputting the value of (x,y)
if(map[x][y]==1){ //If (x,y) is == 1, the chunk is fine to eat
cout << " | Chunk is not toxic." << endl;
}
if(map[x][y]==2){
cout << " | Chunk is toxic." << endl;
}
}
void updateTickOutput() {
//cout << "Map Size (x,y): " << " " << mapsizeX << "," << mapsizeY << endl; This function used to just refresh everything, including map size, which really isn't needed. cout << "Current Tick: " << currentTick << " " << "Max Tick: " << maxTick << endl; //Just outputting currentTick and maxTick
cout << "Score: " << totalEnergy << endl;
}
void tick() {
while(true){
if(currentTick <= maxTick){
currentTick += 1;
moveBot();
/* if(currentTick >= 900000){ //If currentTick is over 900,000: we will begin to output individual ticks. Anything less and we get a seg fault.
updateTickOutput(); //See above
}*/
// cout << "tick!"; This was for debugging, before I made the updateTickOutput() function to make sure that the program actually ticked
}
else if(currentTick == maxTick){
cout << endl << "Done!" << endl; //Report that we are finished with the simulation.
// assignBotID(); //Make sure every bot has the proper ID. Moved to main()
break; //Kill the loop
}
// updateTickOutput(); //No real need for this, anymore.
}
}
void setupBot(){
srand(time(NULL));
for(int botNumber=0;botNumber <= 50; botNumber++){
// cout << "debug (botNumber): " << botNumber << endl; //Debug feature
bots[botNumber].x_cord = rand() % 39 + 1;
// cout << "debug (bot x cord): " << bots[botNumber].x_cord << endl; //Debug feature
int bufferX = bots[botNumber].x_cord;
bots[botNumber].y_cord = rand() % 69 + 1;
// cout << "debug (bot y cord): " << bots[botNumber].y_cord << endl; //Debug feature
int bufferY = bots[botNumber].y_cord;
if(mapBot[bufferX][bufferY] == 1){
cout << endl <<"A bot already is here!" << endl;
reassignLoc(botNumber);
}
else{
mapBot[bufferX][bufferY] = 1; //Take the bot's cords and make sure everyone knows that a bot is there.
// cout<< "debug (map location):"<<mapBot[bufferX][bufferY] << endl ; Just a nice debug feature
}
// if(botNumber==5){
// cout << "bot 5 assigned"; //I broke this entire function a while back and I used this to test if I was assigning bots correctly.
// }
}
/* cout << endl << "X: " << bots[5].x_cord+1 << endl; //Just some debugging stuff below
cout << "Y: " << bots[5].y_cord+1 << endl;
// cout << "The value at " << mapBot[bots[5].x_cord]<<","<< mapBot[bots[5].y_cord]<<" is: " << mapBot[bots[5].x_cord][bots[5].y_cord]; //This is a very messed up debug feature, but it still works.
cout << endl << "X: " << bots[6].x_cord+1 << endl;
cout << "Y: " << bots[6].y_cord+1 << endl;
cout << mapBot[6][6];
*/
cout << "Bot setup - \033[0;32mSuccessful" << "\033[0m" << endl;
}
void assignBotID(){
for(int i = 0; i < 50; ++i){
bots[i].id = i + 1;
}
/* int botNumber = 0;
string botName = "Bot";
string finalName;
string buffer;
while(botNumber <50){
if(botNumber < 50){
botNumber = botNumber + 1;
buffer = to_string(botNumber);
finalName = botName + buffer;
//finalName.id = botNumber; A very very broken line.
bots[botNumber].id = botNumber;
// cout << finalName << ":"<< bots[botNumber].id << endl; A super awesome debugging output to make sure the bot's id is correct
}
else if((botNumber = 51)){ //Redundancy :)
break;
}
}*/
}
void mutateBot(int botID, int level, int sT){
if((sT=2)){
bots[botID].mutationLevel = bots[botID].mutationLevel + level;
}
else if((sT=1)){
bots[botID].mutationLevel = bots[botID].mutationLevel - level;
}
// cout << botID << ":" << bots[botID].mutationLevel << endl; //Just a quick debugging feature to make sure it worked
}
void ckLoc(int botIdent){
int bufferX;
int bufferY;
bufferX = bots[botIdent].x_cord; //Just set the buffers. Uses a bit more memory, but that is okay.
bufferY = bots[botIdent].y_cord;
// cout << bufferX << endl << bufferY;
if(mapBot[bufferX][bufferY] ==1){
cout << "Bot lives here!";
reassignLoc(botIdent);
}
}
void reassignLoc(int botID){
bots[botID].x_cord = rand() % 39 + 1;
bots[botID].y_cord = rand() % 69 + 1;
ckLoc(botID);
}
void moveBot(){
for(int botID=1;botID<=50;botID++){
int direction = 0;
// int bufX = bots[botID].x_cord;
// int bufY = bots[botID].y_cord;
direction = rand() % 4 + 1;
if(direction == 1){ //NORTH
if(bots[botID].y_cord==0 || mapBot[bots[botID].x_cord][bots[botID].y_cord=-1] == 1){
//cout << "error moving bot - N ";
manualMoveBot(botID);
}
else{
//cout << "BufferY: " << bufferY;
bots[botID].y_cord -= 1;
gatherEnergy(botID);
}
}
else if(direction == 2){ //EAST
if(bots[botID].x_cord == 39 || mapBot[bots[botID].x_cord+=1][bots[botID].y_cord] == 1){
//cout << "error moving bot - E";
manualMoveBot(botID);
}
else{
bots[botID].x_cord += 1;
gatherEnergy(botID);
}
}
else if(direction == 3){ //SOUTH
if(bots[botID].y_cord == 69 || mapBot[bots[botID].x_cord][bots[botID].y_cord+=1] == 1){
//cout << "error moving bot - S ";
manualMoveBot(botID);
}
else{
bots[botID].y_cord += 1;
gatherEnergy(botID);
}
}
else if(direction == 4){ //WEST
if(bots[botID].x_cord == 0 or mapBot[bots[botID].x_cord=-1][bots[botID].y_cord] == 1){
//cout << "error moving bot - W";
manualMoveBot(botID);
}
else{
bots[botID].x_cord -= 1;
gatherEnergy(botID);
}
}
// gatherEnergy(botID); //Moved this to indivdual (spelling) stuff above. Just in case :)
// cout << endl << "Direction: " << direction << endl; //Debug
}
}
void manualMoveBot(int botID){
int direction = 0;
// int bufX = bots[botID].x_cord;
// int bufY = bots[botID].y_cord;
direction = rand() % 4 + 1;
if(direction == 1){ //NORTH
if(bots[botID].y_cord==0 || mapBot[bots[botID].x_cord][bots[botID].y_cord-1] == 1){
//cout << "error moving bot - N ";
manualMoveBot(botID);
}
else{
//cout << "BufferY: " << bufferY;
bots[botID].y_cord -= 1;
gatherEnergy(botID);
}
}
else if(direction == 2){ //EAST
if(bots[botID].x_cord == 39 || mapBot[bots[botID].x_cord+1][bots[botID].y_cord] == 1){
//cout << "error moving bot - E";
manualMoveBot(botID);
}
else{
bots[botID].x_cord += 1;
gatherEnergy(botID);
}
}
else if(direction == 3){ //SOUTH
if(bots[botID].y_cord == 69 || mapBot[bots[botID].x_cord][bots[botID].y_cord+1] == 1){
//cout << "error moving bot - S ";
manualMoveBot(botID);
}
else{
bots[botID].y_cord -= 1;
gatherEnergy(botID);
}
}
else if(direction == 4){ //WEST
if(bots[botID].x_cord == 0 or mapBot[bots[botID].x_cord-1][bots[botID].y_cord] == 1){
//cout << "error moving bot - W";
manualMoveBot(botID);
}
else{
bots[botID].x_cord += 1;
gatherEnergy(botID);
}
}
}
void gatherEnergy(int botID){
// int mV = map[bufferX][bufferY]; //Eeeeh, doesn't work here
int x = bots[botID].x_cord;
int y = bots[botID].y_cord;
// cout << "id: " << botID << endl;
// cout << "x: " << x;
// cout << endl << "y: " << y << endl;
if(1==map[x][y]){ //Good chunk
bots[botID].energy += 2000;
totalEnergy += 2000;
// cout << totalEnergy << endl; //Debug
}
else if(2==map[x][y]){ //Bad chunk (toxic)
mutateBot(botID, 1, 2);
}
}
You have several problems.
The main one is that indices of array:
so for Bot bots[50]; valid indices are [0; 49].
For map, according to contest it should be int mapBot [40][70];
so you may access element starting from mapBot[0][0] to mapBot[39][69].
You confound = and == in some comparison.
= does an assignment when == do a comparison.
I see you add extra parenthesis to remove a warning.
You have to read/understand more carefully warning messages.
so else if((currentTick = maxTick)){ in tick for example, should be else if (currentTick == maxTick) {.
Same in mutateBot...
In AssigningBotID, you increment index before accessing the array
and do redundant checks. following is enough:
void assignBotID() {
for (int i = 0; i < 50; ++i) {
bots[i].id = i /* + 1 */; // uncomment if id should be [1; 50]
// A super awesome debugging output to make sure the bot's id is correct
//std::cout << "Bot" << i << ":"<< bots[i].id << endl;
}
}
in manualMoveBot your test may change the position, since you use +=:
mapBot[bots[botID].x_cord += 1][bots[botID].y_cord] == 1
should be mapBot[bots[botID].x_cord + 1][bots[botID].y_cord] == 1
Your logic forget to update mapBot: the old place should be set to 0,
the new place should be set to 1.
Note that during initialization, it is not always set neither...
EDIT:
You should only call srand (time(NULL)); once (the one in main())
setupBot() should be something like (and so reassignLoc and ckLoc may be removed):
void setupBot() {
for (int i = 0; i < 50; ++i) {
int x, y;
do {
x = rand() % 40; // [0; 39]
y = rand() % 70; // [0; 69]
while (mapBot[x][y] == 1);
bots[i].x_cord = x;
bots[i].y_cord = y;
mapBot[x][y] = 1;
}
cout << "Bot setup - \033[0;32mSuccessful" << "\033[0m" << endl;
}
mutateBot has not be fixed: replace = by == for comparison.
void moveBot() {
for (int i = 0; i < 50; ++i) {
manualMoveBot(botID);
}
}
void manualMoveBot(int botID) {
const int oldX = bots[botID].x_cord;
const int oldY = bots[botID].y_cord;
int newX = oldX;
int newY = oldY;
int direction = rand() % 4 + 1;
if (direction == 1) { // NORTH
newY = oldY - 1;
} else if (direction == 2) { // EAST
newX = oldX + 1;
} else if (direction == 3) { // SOUTH
newY = oldY + 1;
} else if (direction == 4) { // WEST
newX = oldX - 1;
}
if (newX < 0 || 40 <= newX
|| newY < 0 || 70 <= newY
|| mapBot[newX][newY] == 1) {
cout << "error moving bot";
#if 0
// if this code is active, we may have infinite loop
// when bot is completely surrounded.
manualMoveBot(int botID);
#endif
return;
}
bots[botID].x_cord = newX;
bots[botID].y_cord = newY;
mapBot[newX][newY] = 1;
mapBot[oldX][oldY] = 0;
gatherEnergy(botID);
}