I appreciate the help. I am really bad at c++ and i like constructive criticism. im building a text based game and im currently setting up all the functions and systems. my problem is that i need a way for the user to be able to, at any time, type in somthing like "stats" and have them printed on the screen. currently i do not know how to do that. i dont know if this is possible but would i be able to have the stats always show. you know when your in the cmd and where it shows what directory your in, i would like it to be right there but in my game. heres the source, i know its cluttered
#include <iostream>
#include <conio.h>
#include <stdlib.h>
#include <ConsoleColor.h>
using namespace std;
//STAT VARS
int hp=100;
//Login VARS
const string USERNAME = "user";
const string PASSWORD = "123456";
string username, password;
int main()
{
login:
cout<< "================" <<endl;
cout<< "======Login=====" <<endl;
cout<< "================" <<endl;
cout<< "\n Username: ";
cin >> username;
cout<< endl;
cout<< "Enter Password : ";
cin >> password;
cout<< endl;
if(username == USERNAME && password == PASSWORD)
{
system("cls");
cout << green << "CORRECT" <<white<< endl;
Sleep(1000);
system("cls");
goto correct;
}
else
{
system("cls");
cout <<red<< "Invalid login details" <<white<< endl;\
Sleep(1000);
system("cls");
goto login;
}
correct:
char name[20];
cout <<"What do they call you boy?" << endl;
cin.getline(name, 20);
cout << "You should keep moving, " << name << ".Were running out of daylight." << endl;
cout << "\n ***** Press Any Key To Continue *****" << endl;
_getch();
return 0;
}
Remove goto
while ((username != EXPECTED_USERNAME)
&& (password != EXPECTED_PASSWORD))
{
// No need to clear the screen.
cout<< "\n Username: ";
cin >> username;
cout<< endl;
cout<< "Enter Password : ";
cin >> password;
cout<< endl;
}
You should not have your identifiers differ only by case. Although the compiler will treat username different from USERNAME, Good Coding Guidelines state that identifiers (names) should be more different. This is why I used username and EXPECTED_USERNAME in the example above. Something about better readability.
Consistency
You used the std::string type for the username, yet you use char [20] for the boy's name. Be consistent, use std::string for all the types.
Pause for Enter
Trying to detect a keypress without pressing Enter is not as portable as waiting for them to press enter.
Try this:
std::cout << "Press ENTER when ready.\n";
std::cin.ignore(100000, '\n);
Stop Clearing The Screen
Very annoying. There may be information that could be retrieved by scrolling back, but you insist on clearing the screen. Bad form.
Don't Sleep
The input will wait for the User to press the Enter key, so there is no need to sleep. The sleep is not portable.
Also, if you are going to fool people about entering bad passwords, you will need to sleep when they enter a valid password too.
Don't use non-portable console tricks
In modern times, console programs are run in a window; maybe a terminal emulator. The console windows are not standard. Don't rely on colors or clearing the screen or moving the cursor. Display what you need to each time.
If you want to use graphics, develop for a GUI application.
Edit 1: Command Driven Architecture
You will need to have a design or architect following this psuedo code:
While true
{
Input User's text
if User entered quit command, exit program.
else Execute a function based on the Users text
}
This will allow the User to enter the command "stats" at any time.
If you want the User to enter commands while you are displaying text, it is possible, but adds more complication.
The actions of the game should be quick enough that the next command prompt is displayed before the User can enter "stats".
Related
I'm working on a project where I want to have delays in the output in C++ on UNIX. Here's an example of what I'm talking about:
cout << "You walk through the darkness, no sign of life in sight" << endl;
usleep(1000000);
cout << "What would you like to do?" << endl;
cin >> userCommand;
Now, if the user types something while the usleep is ongoing, it goes into the cin statement later, which, while I can give appropriate error messages, I'd rather not deal with. Additionally, sometimes I want certain things on the screen, so I don't want the user to just hold down enter and clear the screen.
Is there any command which fully blocks user input from even interacting with the screen? Something that I could deactivate right before my cin statement and reactivate right after the cin statement?
Thanks!
you can use
#include <stdio.h>
...
cout << "You walk through the darkness, no sign of life in sight" << endl;
getch();
cout << "What would you like to do?" << endl;
cin >> userCommand;
getch() block until you press a key
I have a school assignment almost done. I need a small help in fixing a part i couldn't solve. Much help will be appreciated.
I want to allow user to press enter to return to main menu. However, i am unable to do so, may someone advise me. I wish to make it such that no matter how many/what characters the user inputs, as long as he ends with a enter, it will return to main menu.
I have already done the assignment, below is a snippet of the problem i'm facing.
//switch statement on top
string enter = " ";
case 2:
Menu2(id, gridxHighest, gridxLowest, gridyHighest, gridyLowest);
cout << "Press <enter> to go back to main menu ...";
getline(cin, enter);
cin >> enter;
cout << endl;
break;
My actual result i get is that when i press enter, a new blank line will just appear.
Remove your
getline(cin, enter);
cin >> enter;
replace it with
cin.ignore();
Ok I searched for questions but couldn't get my answer, or was not using appropriate term.
if(choice == 2){
string tempName, tempAddress; int tempNic,tempContact;
cout << "\n\t\t*\tWelcome to Our Sponsor Registeration Section\t*\n\n";
cout << "Please enter your name : "; cin>>tempName;
cout << "Please enter your National Identity Card Number : "; cin>>tempNic;
cout << "Please enter your Contact Number : "; cin>>tempContact;
cout << "Please enter your Address : "; cin>>tempAddress;
// prototype Sponsor(string n, string add, int nic_n, int phone) constructor
Sponsor (Constructor goes here) // how to make many objects now?
}
the code is pasted here https://codeshare.io/aVxl42
check line 69 where i am going to use a constructor to add the values, by this i can add 1 object, but what shall i do such that if a person who is using program wants to add more objects do it?
I know i need to encapsulate something between 61 and 70.
Please help me how i work this out.
I'm guessing you want to make it loop? I'd suggest a while-loop.
I haven't used vectors in forever(professors forbid it) so I may make some mistake, but you'll get the overall point.
bool stop = false; //This is to check after each loop if it should continue or not
char contChoice;
vector<Sponsor> sponsors;
while(!stop){
if(choice == 2){
string tempName, tempAddress; int tempNic,tempContact;
cout << "\n\t\t*\tWelcome to Our Sponsor Registeration Section\t*\n\n";
cout << "Please enter your name : "; cin>>tempName;
cout << "Please enter your National Identity Card Number : "; cin>>tempNic;
cout << "Please enter your Contact Number : "; cin>>tempContact;
cout << "Please enter your Address : "; cin>>tempAddress;
// prototype Sponsor(string n, string add, int nic_n, int phone) constructor
sponsors.push_back(Sponsor(tempName, tempAddress, tempContact, tempNic));
//Add whatever other arguments you want to pass in, in whatever order
cout << "Do you want to continue? [Y/N]: "; cin>>contChoice;
if(contChoice == 'N' || contChoice == 'n')
stop = true;
else stop = false; //This isn't really necessary since it is false by default
}
}
But I would also suggest that you make set-member functions in Sponsor at least. You can also use a dynamic array and make it expand, which is trickier than a vector, way trickier in fact.
I'm trying to check if the user has entered their name correctly, with or without space i.e. Joe Bloggs. They cannot have special characters or numbers in their name or it will pop up with an error message i.e. Jo3_Bl0ggs. What I'm trying to do is if they enter their name in the wrong format, an error message will be alerted and the program will ask the user to enter their name again, until they enter it correctly.
I'm using a while loop to do this so if it's correct, I change the value of the flag and break out of the loop, if not I'll rerun the setName() function which asks for their name.
However the problem I'm having is that if they enter for the first time and it's incorrect, it asks them to enter their name again and if the second input is correct a message will say "Welcome Joe Bloggs", but the loop will continue and ask them to enter their name in again.
The only way I can avoid this problem is if the first input is correct, but that kind of defeats the whole point of the try and catch block.
Below is the two functions I'm concerned with. If someone can point me in the right direction, then that would be great. I'm new to c++ which is why I'm a bit confused about this.
inputclass::inputclass(){//empty constructor}
void inputclass::validateName(string name){
int flag = 1;
while ( flag == 1){
try{
for (int i=0; i < name.length(); i++){
if (name[i] != ' '){
if (!isalpha(name[i])){
cout << "You have entered incorrectly. Please try again. " << endl;
cin.clear(); //I'm trying to clear input buffer but still doesn't work
cin.ignore(256, '\n');
setName();
throw 0; //do i need this?
break; //do i need breaks?
}else if(i == name.length()-1){
cout << "Welcome to the program " << name << endl;
flag = 2; //break out of while loop
break; //not sure if this does anything
}
}
}
}catch (int e){
cout << "There's been an error" << endl;
setName(); //until input is correct, this will ask the user for their name.
}
}
}
void inputclass::setName(){
string name;
cout << "Please enter your name: " << endl;
getline(cin, name);
validateName(name);
}
My honest opinion is that your algorithm logic itself is wrong. Validation should be done as a consequence of input. The input itself should be the decision point of recycling on validation failure
1. Write a simple validation function
This is easier than you may think, in particular since the standard library provides some neat algorithms for doing much of the iteration work for you.
2. Integrate your validation function exclusively in setName(); not the opposite.
Your input mechanics should take said-input, validate, and if invalid, loop on the input. The validator should exclusively be returning yea or nay. Leave the input mechanics to the input function, and don't trigger them from the validator. A validator is for just that; validating, not cycling input loops.
The first of these is fairly simple since the standard library provides you with most of the algorithms you need. The sample below uses a functor to do this, but C++11 could easily do this with a lambda instead:
struct is_not_space_or_alpha
{
bool operator()(char c) const
{
return c != ' ' && !std::isalpha(static_cast<unsigned char>(c));
}
};
static bool is_valid_name(const std::string& name)
{
return !name.empty() &&
name.end() != std::find_if(name.begin(), name.end(), is_not_space_or_alpha());
}
With that, your setName() becomes the location where validation is a consequence of input; the validation doesn't internally trigger more input. That is left to the caller (setName()) to decide:
std::string name;
while (true)
{
std::cout << "Please enter your name: ";
std::flush(std::cout);
if (std::getline(std::cin, name) && is_valid_name(name))
{
std::cout << "Welcome to the program " << name << "!\n";
break;
}
std::cout << "You have entered incorrectly. Please try again. \n";
std::cin.clear();
}
Sample Output
Please enter your name: Monkey777
You have entered incorrectly. Please try again.
Please enter your name: Wiley Coyote
Welcome to the program Wiley Coyote!
The Bottom Line: Don't trigger input from validation. Instead, trigger validation from input and act accordingly.
I am in the process of developing a console application that acts as a Diary. At this stage I am developing the login authentication and have hit a bit of a wall! As I will be dealing with text files for both my login and diary storage, I would like to encrypt these text files from prying eyes.
Now, the problem is I do not know how to go about the decrypt >> check user&&pass >> encrypt again.
Would it be along these lines?:
Program Loads
Decrypt passwords.txt
If at any point the program closes, encryptFile() is ran.
Validate user entry
Encrypt passwords.txt
If I am along the right lines how do I go about implementing this? I searched for encryption tutorials for text files using c++ and they were not very helpful.
Here is my butchered beginner password.txt code, where shall I go from here? If there is an encryption tutorial/article you recommend that I missed please post it!
void checkPasswordFile() {
string username;
string password;
string passwordAgain;
string userIn;
string passIn;
string line;
ifstream passwordFile("passwords.txt");
istringstream instream;
if (passwordFile.good()) {
cout << "\t==================================" << endl;
cout << "\t----------------------------------" << endl;
cout << "\tYou are a returning user, please fill in your details" << endl;
while(!passwordFile.eof()) {
getline(passwordFile, line);
instream.clear();
instream.str(line);
username = line;
getline(passwordFile, line);
instream.clear();
instream.str(line);
password = line;
}
do {
cout << "Username: " << endl;
cin >> userIn;
cout << "Password: " << endl;
cin >> passIn;
if (userIn == username && passIn == password) {
displayMenu();
} else {
cout << "Username and Password Do Not Match, Try Again" << endl;
}
} while(userIn != username && passIn != password);
} else {
cout << "file no exist";
ofstream passwordFile;
passwordFile.open ("passwords.txt", ios:: in | ios::app);
cout << "\t==================================" << endl;
cout << "\t----------------------------------" << endl;
cout << "\tThis is your first run, please enter a username and password" << endl;
cout << "\tUsername: " << endl;
cin >> username;
cout << "\tPassword: " << endl;
cin >> password;
/*
Do Loop:
Prompts Re-Entry if PasswordAgain is not equal to Password
*/
do {
cout << "Re-Type Password: ";
cin >> passwordAgain;
if(password != passwordAgain) {
cout << "Passwords Do Not Match! Try Again" << endl;
}
} while(password != passwordAgain);
passwordFile << username << "\n";
passwordFile << password;
}
}
Thank you very much for your time.
p.s for the life of me I cannot find out how to do:
Username:[cin>>username] on the same console line, sorry for doubling up but didn't deem it a big enough question for its own post! Thanks.
EDIT:
I have succesfully been able to decrypt the username and pass when created and stored in the text file. Then when the user comes back, what they entered is encrypted and compared with the file.
Problem being this only works for short words, user pass works, but username and password does not... any ideas why? Here is my encryption code:
char encryptKey = 'h';
cout << "\tUsername: ";
cin >> userIn;
cout << "\tPassword: ";
cin >> passIn;
for (int i = 0; i < userIn.size(); i++) {
userIn[i] ^= encryptKey;
}
for (int x = 0; x < passIn.size(); x++) {
passIn[x] ^= encryptKey;
}
if (userIn == username && passIn == password) {
displayMenu();
} else {
cout << "\tUsername and Password Do Not Match, Try Again" << endl;
}
The right thing to is not to encrypt the passwords file - the issue is that the encryption key for the file would need to be stored somewhere that the program can access it, which would make it relatively easy to find and abuse.
Instead, you should be using password hashing (using a strong hash algorithm like SHA1). A hash algorithm is a algorithm that deterministically maps a piece of text onto a large number (called its hash), and is designed to be irreversible without great effort. The basic concept is that you take the password, use it to compute its hash, and then store that hash. Later, when the user enters the password to log in, you compute its hash again and compare the resulting hash to the stored hash. Even if someone gains access to the hashes, they do not obtain the password, which is important, because people often share passwords between applications. Don't implement your own SHA1 hash - see "What is the best encryption library in C/C++?" for a list of libraries.
You must also use salting and key stretching to defend against common brute force attacks.