I am working on a little text based adventure game, the first project I've ever worked on for my own enjoyment, and have ran into a problem. I have got it to ask if you want to play, what your name will be and then the problem starts when you try to choose a race. It works just fine when the user types the first character but when they type the string it will skip past the gender, and class cin. Do I have to clear the cin? Or is my code just wrong?? Thanks for any help you can provide.
#include "pch.h"
#include <iostream>
#include <string>
#include <cctype>
#include <map>
using namespace std;
enum races { Human, Orc, Elf, Dwarf};
enum classes { Warrior, Mage, Archer, Assassin};
const std::map< char, string > race_map =
{ {'H', "human"}, {'O', "orc"}, {'E', "elf"}, {'D', "dwarf"} };
const std::map< char, string > class_map =
{ {'W', "warrior"}, {'M', "mage"}, {'Ar', "archer"}, {'A', "assassin"}
};
void gameIntro();
void gameStart();
void raceFunc(char race);
void playerClassFunc(char playerClass);
void gameIntro()
{
string playerName;
char race;
char sex;
char playerClass;
cout << "Enter your name: \n";
cin >> playerName;
cout << "\n";
cout << "Select a race (Human, Orc, Elf, Dwarf): \n";
cin >> race;
cout << "\n";
raceFunc(race);
cout << "Select Gender (M or F): \n";
cin >> sex;
cout << "\n";
cout << "Select a class (Warrior, Mage, Archer, Assassin): \n";
cin >> playerClass;
cout << "\n";
playerClassFunc(playerClass);
gameStart();
}
void raceFunc(char race)
{
race = toupper(race);
switch (race)
{
case 'H':
cout << "You chose Human!\n\n";
break;
case 'O':
cout << "You chose Orc!\n\n";
break;
case 'E':
cout << "You chose Elf!\n\n";
break;
case 'D':
cout << "You chose Dwarf!\n\n";
break;
default:
cout << "Please choose from the following. Program closing.\n";
system("pause");
exit(0);
}
}
void playerClassFunc(char playerClass)
{
playerClass = toupper(playerClass);
switch (playerClass)
{
case 'W':
cout << "You chose Warrior!\n";
break;
case 'M':
cout << "You chose Mage!\n";
break;
case 'Ar':
cout << "You chose Archer!\n";
break;
case 'A':
cout << "You chose Assassin!\n";
break;
default:
cout << "Please choose from the following. Program closing.\n";
system("pause");
exit(0);
}
}
void gameStart()
{
}
int main()
{
char answer;
cout << "Welcome to Dark Horse\n\n";
cout << "This is my fisrt ever actual program I made out of my own free
will lol.\n";
cout << "It is a Text-Based Adventure game. In this game you will make a
character,\n";
cout << "and explore the land of Spelet, battling enemies, leveling up,
getting loot,\n";
cout << "and learning skills! You do not need to capitalize anything but
your character\n";
cout << "name. If a question has (something like this) if you don't
enter whats inside\n";
cout << "the program will CLOSE, so please pay attention! Thank you for
trying it out!\n";
cout << "I really hope y'all enjoy it!\n\n";
do
{
cout << "Would you like to play?\n";
cin >> answer;
if (answer == 'Y')
{
gameIntro();
}
else if (answer == 'N')
{
system("pause");
return 0;
}
else if (answer != 'N' || 'Y' || 'exit')
{
cout << "Come on dog it's Y or N...yes or no...\n\n";
}
} while (answer == 'N' || 'Y');
system("pause");
return 0;
}
"cin, of class istream, is the standard input channel used for user input. This steam corresponds to C's stdin. Normally, this stream is connected to the keyboard by the operating system." (Josuttis, 2012, p. 745)
Josuttis, N. (2016). The C++ Standard Library: A Tutorial and Reference 2nd Edition: Addison-Wesley
The types are important.
char race;
std::cout << "Please enter your race:" << std::endl;
std::cin >> race;
If the user enters "Human", the standard input stream contains Human and the race variable now has the value H (of type char). The standard input stream now contains uman.
char gender;
std::cout << "Please enter your gender:" << std::endl;
std::cin >> gender;
Calling >> with std::cin gets another character from the standard input stream (in this case u) and stores it in gender. The standard input stream now contains man.
While it appears that the gender question was skipped, you can now see that this is not the case. The input stream still contains characters. If you look at your first screenshot you can see that "Mage" was selected. This is because the value of playerClass is m, the same m from when you entered human.
One way to remedy this is to use std::string instead of char to store the input. That way you have more flexibility in parsing what the user enters (e.g. you can allow for H or Human).
Related
void adding();
void print();
void end();
int counter = 0;
int main()
{
char choice;
cout << "What do you want to do?" << endl;
cout << "a = add a student, p = print the student list, e = exit function" << endl;
cin >> choice;
switch (choice) {
case 'a':
adding();
break;
case 'p':
print();
break;
case 'e':
end();
break;
default:
cout << "That is not a valid option.";
break;
}
}
void adding()
{
ofstream outFS;
outFS.open("myoutfile.txt", fstream::app);
int i = 0;
string name[100]; string amount[100]; string grades[100];
for (i = 0; i < 1; i++) {
cout << "What is the name of the student?";
cin >> name[i];
outFS << name[0] << ' ';
cout << "How many exercises has the student completed?";
cin >> amount[i];
outFS << amount[0] << ' ';
cout << "What grade did the student get?";
cin >> grades[i];
outFS << grades[0] << ' ';
counter++;
}
outFS.close();
main();
}
void print()
{
ifstream inFS;
inFS.open("myoutfile.txt");
string name;
inFS >> name;
int amount;
inFS >> amount;
int grades;
inFS >> grades;
inFS.close();
cout << name << ' ' << amount << ' ' << grades << endl;
main();
So when I use the "adding" function it works fine and adds it to the file. When I add the more than one student the file still shows it but when I print within the console it only prints out the first student and their info. How do I get it to show the entire array in the console? I tried to use a counter variable but it is not helping
What you are missing is the loop keywords (the various incarnations of for and while).
Making your own loop by doing this:
void a()
{
// Do stuff
b();
}
void b()
{
// Do other stuff
a();
}
Is really not a good idea since it will just throw more and more calls on the stack, and eventually make the stack run out of space (which will crash the program). Replacing one of those functions with main() is even worse, because main() is a special function that you really are not allowed to call yourself.
Instead do something like this:
int main()
{
char choice;
bool running = true;
while (running)
{
cout << "What do you want to do?" << endl;
cout << "a = add a student, p = print the student list, e = exit function" << endl;
cin >> choice;
switch (choice) {
case 'a':
adding();
break;
case 'p':
print();
break;
case 'e':
// end(); Dunno what this does. Is it just an empty function that will finally end the infinite stack of calls?
// I am replacing it with setting the loop variable to false, which will stop the loop
running = false;
break;
default:
cout << "That is not a valid option.";
break;
}
}
}
Then remove all calls to main() from the rest of your code.
As for your print() function, again your problem is the lack of loops. Your current code opens the file, reads the first line, prints the line, then closes the file and calls main. Then the next time print() is called it again opens the file, reads the first line, etc.
What you need is a loop that reads all the lines before closing the file again. Something like this should do the trick:
void print()
{
ifstream inFS;
inFS.open("myoutfile.txt");
string name;
int amount;
int grades;
while (inFS >> name >> amount >> grades)
{
cout << name << ' ' << amount << ' ' << grades << endl;
}
inFS.close();
}
However, all of this is pretty basic C++ that should have been covered in whatever book you are using to learn C++. And if you do not have a C++ book to learn from, then I strongly recommend that you get one - it will be only get harder to learn if you constantly get stuck on basic stuff.
Function 5:
The Display Sales History Function.. It is just displaying the last entry twice...
Function 1:
The 'Add Book' Feature.. It was actually working alright until I added the 'Edit Book' and 'Add Sales' Features. Now it writes something to the file("Books.txt"); that none of the other functions identify. Earlier,i.e.
when 'Edit Book' and 'Add Sales' weren't coded and structure Sale not declared,
'Search Book' could work properly with the entry done by 'Add Book'.
((This is what I found in BOOKS.txt when I only coded functions 1 and 2 and did a test run:
{{Mein Kampf ÿu)<èÿX 0# Ÿ0 :òÿ2 XThe Accidental Prime Minister Ÿ0 :òÿ< ^Quantico ental Prime Minister Ÿ0 :òÿ ÂSurely You Are Joking, Mr. Feynman X0- ô}}
If you paste this in Books.txt, all features except 'Add' work allright))
#include <fstream.h>
#include <conio.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <dos.h>
struct Sale {
char costumer[40], name[40];
int quant, pric, netprice;
};
class Book {
public:
char name[40];
int qty, code, price;
void Add()
{
cout << "\n Enter Name Of New Book\n";
gets(name);
cout << "\n Enter book code:";
cin >> code;
cout << "\n Enter book price:";
cin >> price;
cout << "\n Enter book quantity:";
cin >> qty;
}
void Display()
{
cout << "\n Name:";
puts(name);
cout << "Code:" << code;
cout << "\nPrice:" << price;
cout << "\nQuantity Available:" << qty;
}
void Modify();
Sale Sell(int q)
{
Sale sale;
sale.pric = price;
qty -= q;
sale.quant = q;
sale.netprice = q * price;
cout << "\n Enter costumer name\n";
gets(sale.costumer);
strcpy(sale.name, name);
return sale;
}
};
void Book::Modify()
{
Display();
char ch = 'n';
do {
cout << "\n Enter detail to modify \n";
cout << "1.NAME\t2.QUANTITY\t3.CODE\t4.PRICE\n";
int mod;
cin >> mod;
switch (mod) {
case 1:
cout << "\nEnter new Name\n";
gets(name);
break;
case 2:
cout << "\nEnter new available quantity\n";
cin >> qty;
break;
case 3:
cout << "\nEnter changed CODE\n";
cin >> code;
break;
case 4:
cout << "\nEnter updated PRICE\n";
cin >> price;
break;
}
Display();
cout << "\nWant to edit more? (y/n)\n";
ch = getch();
} while (ch == 'y' || ch == 'Y');
}
void Print(Sale s)
{
cout << "\nCostumer Name:\t";
puts(s.costumer);
cout << "Book Name:\t";
puts(s.name);
cout << "\nQuantity(units):" << s.quant << "\tPrice per pice:" << s.pric << "\n\t Net Sale:" << s.netprice;
}
void MScreen()
{
clrscr();
cout << "\tTHE BOOK STORE MANAGEMENT SOFTWARE\n";
cout << "\tPLEASE CHOOSE AN OPTION";
cout << "\n1.ADD NEW BOOK\n2. SEARCH FOR A BOOK\n3. EDIT BOOK DETAILS\n 4.ADD NEW SALES\n5. DISPLAY SALES HISTORY\n";
}
void main()
{
char ch = 'n';
while (ch == 'n' || ch == 'N') {
MScreen();
int i;
cin >> i;
clrscr();
switch (i) {
case 1:
Book a;
a.Add();
ofstream obj1("BOOKS.txt", ios::app);
obj1.write((char*)&a, sizeof(Book));
obj1.close();
break;
case 2:
Book b;
ifstream obj2("BOOKS.txt");
obj2.seekg(0);
cout << "Enter Book Code:";
long int x;
cin >> x;
while (!obj2.eof()) {
obj2.read((char*)&b, sizeof(Book));
if (b.code == x) {
b.Display();
obj2.close();
break;
}
}
break;
case 3:
Book c;
cout << "\n Enter Code of book to be modified\t";
int y;
cin >> y;
fstream obj3("BOOKS.txt", ios::in | ios::out | ios::ate);
long int pos;
obj3.seekg(0);
while (!obj3.eof()) {
pos = obj3.tellg();
obj3.read((char*)&c, sizeof(Book));
if (c.code == y) {
c.Modify();
obj3.seekp(pos);
obj3.write((char*)&c, sizeof(Book));
break;
}
}
cout << "\nDATA MODIFIED\n";
break;
case 4:
char ch1 = 'n';
do {
Book d;
cout << "\n Enter the book code \t";
int z;
cin >> z;
fstream obj4("BOOKS.txt", ios::in | ios::out | ios::ate);
long int pos;
obj4.seekg(0);
int found = 0;
while (!obj4.eof()) {
pos = obj4.tellg();
obj4.read((char*)&d, sizeof(Book));
if (d.code == z) {
found = 1;
break;
}
}
if (found == 0) {
cout << "\nIncorrect Code\t Aborting";
break;
}
else {
d.Display();
cout << "\nEnter Sales Quantity:\t";
int q;
cin >> q;
if (q > d.qty) {
cout << "\n Can't Sell. Aborting ";
break;
}
else {
Sale newsale;
newsale = d.Sell(q);
obj4.seekp(pos);
obj4.write((char*)&d, sizeof(Book));
obj4.close();
ofstream obj5("Sales.txt", ios::app);
obj5.write((char*)&newsale, sizeof(newsale));
obj5.close();
cout << "\nSALE SUCCESSFUL\n";
sleep(2);
}
}
cout << "\n Add more sale? (y/n)";
cin >> ch1;
} while (ch1 == 'y' || ch1 == 'Y');
break;
case 5:
cout << "\nPlease enter SALE password:";
char pass[40];
gets(pass);
if (strcmp(pass, "creationbydhruvarora\n")) {
clrscr();
ifstream obj6("Sales.txt");
obj6.seekg(0);
Sale readsale;
int net = 0;
while (!obj6.eof()) {
obj6.read((char*)&readsale, sizeof(Sale));
net += readsale.netprice;
Print(readsale);
sleep(1);
}
cout << "\n END OF SALES\n TODAY NET SALE:" << net;
break;
}
else {
cout << "\nIncorrect Password\n ABORTING";
break;
}
}
getch();
clrscr();
cout << "Press Any Key To QUIT. To Go To Main Menu Press 'n'\n";
ch = getch();
}
}
I do not understand what this is. A piece of code added to some code is disrupting working w/o being executed.
First, you are using stuff that's seriously ancient. There is free, absolutely, completely, and totally free stuff out there that's much more modern than this. If this is production code, you should be moving it to a newer platform. If it's student code, you shouldn't be learning on this platform at all. If you have at least an 80386, there are perfectly serviceable tiny Linux distributions available for free download that will run on the hardware you have. And then you'll have a modern compiler.
You clearly have access to the Internet, so you should have some ability to do this. In fact, the hardware you're using to access this site could probably run a modern, completely free to use compiler like GNU C++ or clang.
I can tell from the headers and lack of ::std namespace you have that you're using a really old MS-DOS based compiler. Turbo C++, Borland C++, Zortech C++, maybe whatever Microsoft called their thing back then. Something like that. I know because I've written C++ for that platform... in 1990.
Even given that ancient platform, your code is written poorly. You are mixing stdio and iostreams. While this isn't inherently bad, it's confusing. Additionally, you're using gets which makes it easy for bad input to crash your program. There are other problems, but I won't get into all of them because I don't think they're relevant to your question.
The reason, in general, why adding code that's never executed causes your program to crash is that it had an already existing problem that moving stuff around in memory made appear. I can't compile or run your code because it's too ancient. Additionally, I have no available input to use.
But, were I to hazard a guess, it would be because you are using gets and the input is causing a buffer overrun (you are reading more than 40 characters into your buffer). It always caused a buffer overrun, but because the new code moved stuff around in memory, it's now causing your program to crash instead of having no effect or causing some other problem you didn't see before. Buffer overruns result in undefined behavior, which means the program is allowed to do anything, even seemingly work perfectly normally.
Here is a function to replace all your gets calls with:
int fetch_line(char *s, int size)
{
fgets(s, size, stdin);
if ((size <= 0) || (s[0] == '\0') || (s[strlen(s) - 1] != '\n')) {
int c = '\0';
do {
c = getchar();
} while ((c != '\n') && (c != EOF));
return c != EOF;
} else {
s[strlen(s) - 1] = '\0'; // Drop trailing newline.
}
}
This function will return a non-zero (aka true) value if it did not encounter EOF and 0 (aka false) if it did. It will discard any characters that don't fit in your buffer but still read until the end of line (aka '\n') character. In your code, a call to it would look like fetch_line(name, sizeof(name));.
Your code may have other problems, but if it does, they aren't obvious to me. The gets one is a huge red flag though. You should never use gets. My compiler gives me scary deprecation warnings that I can't turn off if I use it because the call is going away completely in a few years.
In general, any function that works with C-style strings and doesn't have a parameter declaring the maximum size of any string being written to is a bad function to use that's prone to buffer overrun behavior.
BTW, I have no platform on which calls to getch or clrscr work anymore. Using those functions makes your program very non-portable.
I am trying to make a small operating system that takes a response from a switch...case to go to a miniature game or a simple calculator. However, no matter what input I give (even correct ones) the output is always the default.
The compiler I am using (Microsoft Visual Studio; It could be the problem) isn't giving me any errors, and I can't find or think of any mistakes. Do some of you people who are actually good at this have any answers to my problem?
#include "stdafx.h"
#include <iostream>
#include <limits>
using namespace std;
int calc() {
char op;
float num1, num2;
cout << "Enter operation:";
cin >> op;
cout << "Enter two numbers:";
cin >> num1 >> num2;
switch (op)
{
case '+':
cout << num1 + num2;
break;
case '-':
cout << num1 - num2;
break;
case '*':
cout << num1 * num2;
break;
case '/':
cout << num1 / num2;
break;
default:
cout << "That is not an operation";
break;
}
return 0;
};
int main()
{
char answer;
cout << "Welcome to the FR Operating System. \n";
cout << "If you want to go to the calculator, type in 'Calc'. \n";
cout << "If you want to go to the game, type in 'Game'. \n";
cin >> answer;
switch (answer) {
case 'Calc' || 'calc':
cout << "Welcome to the calculator. \n";
break;
case 'Game':
cout << "Welcome to our game, 'A Day in the Life'. \n";
break;
default:
cout << "That is an invalid answer. This has caused the system to crash. \n";
break;
}
atexit([] { system("PAUSE"); });
return 0;
}
'Game' is not a valid string
Even if you replace it by "Game", which is a valid string, switch doesn't work with strings.
So either use single chars in your switch or use if-else blocks where you compare std::strings via ==.
std::string answer;
cin >> answer;
if (answer == "Calc" || answer == "calc")
//...
else if (answer == "Game")
//...
else
// invalid
Use map to item callbacks
Ideally, it would be better to map item menu to it's respective actions. std::map<std::string, std::function<void()>> allows exactly that! Read the inline comments to make sense of the rest:
#include <string>
#include <map>
#include <iostream>
#include <functional>
int main()
{
std::map<std::string, std::function<void()>> menu_items;
menu_items.emplace("calc", [](){std::cout << "calculate chosen\n";}); //use lambdas to spare boilerplate
menu_items.emplace("game", [](){std::cout << "game is chosen\n";});
std::string chosen_item;
std::cin >> chosen_item;
auto item = menu_items.find(chosen_item); //search by the string
if (item == menu_items.end()) //item was not found in the list
std::cout << "invalid item is chosen\n";
else
item->second(); //execute the stored function
}
Demo.
Depending on your usage you might want to use void*() for std::function<void()>, and std::unordered_map for std::map. For your usage case it doesn't seem to matter though.
Also you might want to normalize the input, e.g. lowercase the string, or perform some other normalization. Since this is not performance sensitive part of the code, I believe overhead of std::function and std::map won't matter in this case.
You are prompting user for a string while your variable answer is a char, change your prompts to characters like c and g thus make it more convenient, thus you can use and enumerate characters in your switch / case statement:
int main()
{
char answer;
cout << "Welcome to the FR Operating System. \n";
cout << "If you want to go to the calculator, type in 'c'. \n";
cout << "If you want to go to the game, type in 'g'. \n";
cin >> answer;
switch (answer) {
case 'c':
case 'C':
cout << "Welcome to the calculator. \n";
break;
case 'g':
case 'G':
cout << "Welcome to our game, 'A Day in the Life'. \n";
break;
...
What I want to do is to have the player "select" what class they want to be, and each class has a number. A different number will print out a different string into the console, and I wanted to do that through making if statements. In other words, the player will type in a choice and their choice will end up printing something from a different if statement. However, every time I run the code, the program will just end when it asks the user what class they want to use, and won't print out the message that is for that class.
#include "stdafx.h"
#include<iostream>
#include <string>
using std::cout;
using std::cin;
using std::endl;
using std::string;
int main()
{
int Name,Class;
cout << "Welcome to the world of Jumanji!\n\n";
cout << "Please Tell me your name:";
cin >> Name;
cout << "\n\nOkay, so your name is " << Name << "? Welcome to the world of Jumanji - A game for those who seek to find a way to leave their world behind\n\n";
cout << "I am a fellow adventurer who will aid you during your journey\n\n";
cout << "Alright " << Name << "I need you to tell me what you will be playing as\n\n";
cout << "1.Archaeologist\n2.Cartographer\n3.Commando\n4.Pilot\n5.Zoologist ";
cin >> Class;
if (Class == 1) {
cout << "Are you sure that you want to be a Archaeologist?";
system("pause");
}
else if (Class == 2) {
cout << "Are you sure that you want to be a Cartographer?";
system("pause");
}
else if (Class == 3) {
cout << "Are you sure that you want to be a Commando?";
system("pause");
}
else if (Class == 4) {
cout << "Are you sure that you want to be a Pilot?";
system("pause");
}
else if (Class == 5) {
cout << "Are you sure that you want to be a Zoologist?";
system("pause");
}
return 0;
}
What am I doing wrong?
so, name should be string, not int.
string Name;
int Class;
Because the user might enter "John Doe" as the name, cin >> Name; would only get the "John", and leave "Doe", in the buffer which now ends up in Class, that causes Class to contain an arbitrary value. Thus the if else doesn't work. using getline() should fix things.
string Name;
int Class;
cout << "Welcome to the world of Jumanji!\n\n";
cout << "Please Tell me your name:";
getline(cin, Name);
I wrote a certain method on how to access my fields in a class, but my teacher told me I should use an enum.
How can I re-write this code to use an enum and not use gotos?
void SetType() {
cout << "Book SetType" << endl;
Choice: cout << "Please Select from the list: \n "
<< "1- Technical literature \n "
<< "2- Fiction literature \n "
<< "3- Textbook" << endl;
int i;
cin >> i;
switch (i) {
case 1:
Type = "Technical literature";
break;
case 2:
Type = "Fiction literature";
break;
case 3:
Type = "Textbook";
break;
default:
cout << "Erorr you entered a wrong choice" << endl;
goto Choice;
}
}
just use loops instead of gotos of it is going to be a spaghetti code.
Enums are fine to does not care about the numbers for the defines, because they are incremented automatically if you add a new one.
#include <iostream>
#include <string>
void SetType();
using namespace std;
string Type;
int main()
{
SetType();
cout << "so you choose " << Type << endl;
return 0;
}
enum select
{
Technical_literature = 1,
Fiction_literature,
Textbook
};
void SetType() {
cout<<"Book SetType"<<endl;
while(1)
{
cout<<"Please Select from the list: \n 1- Technical literature \n 2- Fiction literature \n 3- Textbook"<<endl;
int i;
cin >> i;
switch(i) {
case Technical_literature:
Type="Technical literature";
return;
case Fiction_literature:
Type="Fiction literature";
return;
case Textbook:
Type="Textbook";
return;
default:
cout << "Erorr you entered a wrong choice" << endl;
}
}
}
Your teacher meant that instead of hardcoding constants all over the place you need to declare your i as enum.
enum some_type {
type_techlit=1, type_fiction, type_textbook
};
some_type i;
And then read up on enums.