So I am creating an hangman game and want to add a char into a string. I want to add a char of guess to the gatherguess string until the gatherguess matches hangman. Feel free to add some helpful tips to my code that will make me better. Also if it would be more then nice if you can also give me some sample code with dynamic memory allocation.
#include <stdio.h>
#include <string.h>
#include <iostream> // std::cout
#include <stdio.h>
#include <string.h>
#include <iostream> // std::cout
#include <algorithm> // std::for_each
#include <vector>
#include <set>
#include <string>
bool isitdone(std::string foo, std::string hang){
return foo == hang ? true : false ;
}
int main(){
std::string hangman;
char guess;
std::string gatherguess; //Get the letters guessed.
std::cin >> hangman; //Player enter the word to guess.
bool checkstatement; // Check to see if game is over.
for(int i =0; i < 10; ++i) {
std::cin >> guess; //Individual characters to guess
std::string doo;
int wordsin;
doo = hangman;
int y;
if(doo.rfind(guess) != std::string::npos) {
std::cout << "Right " << guess << " Is in the word" << std::endl;
std::cout << std::endl;
checkstatement = isitdone(gatherguess,doo);// I want to add guess char into gatherguess
//then check to see if gatherguess is equal to the word then the game will be complete
if(checkstatement == true) {
return 0;
}
} else {
std::cout << "Wrong" << std::endl;
}
}
return 0;
}
First of all, you should initialize gatherguess with enough placeholder characters:
auto hangman = std::string{};
std::cin >> hangman;
auto gatherguess = std::string{hangman.size(), '_'};
Now you can simply overwrite the '_' characters.
auto pos = hangman.find(guess)
if(pos != std::string::npos) {
// ...
do {
gatherguess[pos] = guess; // overwrite
pos = hangman.find(guess, pos); // find next ocurrence
} while(pos != std::string::npos)
// ...
}
I made some changes on your code. It contains some pieces of advice as comment.
//#include <stdio.h> // Do not include a library if you don not use it, because it makes the performance worse.
//#include <string> // Do not include a library if you don not use it, because it makes the performance worse.
#include <iostream> // std::cout
//#include <stdio.h> // It is pointless to include a library twice.
//#include <string.h>
//#include <iostream> // std::cout
//#include <algorithm> // std::for_each
//#include <vector> // Do not include a library if you don not use it, because it makes the performance worse.
//#include <set> // Do not include a library if you don not use it, because it makes the performance worse.
#include <string>
bool isitdone(const std::string& foo, const std::string& hang){ // Passing argument by const reference makes performance much better.
return foo == hang ? true : false ; // Indenting makes the code much more readable.
}
int main(){
const int N=10; // Store constant number in constant variable, because you can change its' value later easily.
std::string hangman;
char guess;
std::string gatherguess; //Get the letters guessed.
std::cin >> hangman; //Player enter the word to guess.
bool checkstatement; // Check to see if game is over.
for(int i =0; i < N; ++i)
{
std::cin >> guess; //Individual characters to guess
std::string doo;
int wordsin;
doo = hangman;
int y;
if(doo.rfind(guess) != std::string::npos)
{
std::cout << "Right " << guess << " Is in the word" << std::endl;
std::cout << std::endl;
checkstatement = isitdone(gatherguess,doo);// I want to add guess char into gatherguess
//then check to see if gatherguess is equal to the word then the game will be complete
if(checkstatement == true)
{
return 0;
}
} else
{
std::cout << "Wrong" << std::endl;
}
}
return 0;
}
I think there is a logical mistake in your program. What happens if a word contains more than 10 different characters? Do not count if the tipp is right.
You can add a char to a string this way:
#include <iostream>
#include <string>
int main(){
std::string str="123";
str+='4';
std::cout<<str<<std::endl;
return 0;
}
Related
Relatively new to c++.
Having trouble understanding an issue I am having with the compare() function returning 1 instead of 0.
I have a program which reads a text file containing an arbitrary number of questions and answers for a quiz. It is formatted as such:
Q: How many days in a week?
A: seven
I have three files, main.cpp, Quiz.cpp, and Quiz.h:
main.cpp:
#include <iostream>
#include <vector>
#include <fstream>
#include <algorithm>
#include <ctime>
#include <cstdlib>
#include "Quiz.h"
using namespace std;
int main(int argc, char* argv[]){
srand(unsigned(time(0)));
vector<Quiz> quizVector;
ifstream inputQuiz;
inputQuiz.open(argv[1]);
string q, a;
int questionCount = 0;
if(inputQuiz.is_open()){
getline(inputQuiz, q);
getline(inputQuiz, a);
while(!inputQuiz.eof()){
Quiz *instance = new Quiz(q, a);
quizVector.push_back(*instance);
questionCount++;
getline(inputQuiz, q);
getline(inputQuiz, a);
}
}
random_shuffle(quizVector.begin(), quizVector.end());
string userInput;
for(int i = 0; i < questionCount; i++){
cout << quizVector[i].getQuestion() << endl;
cout << "A: ";
getline(cin, userInput);
if(quizVector[i].getAnswer().compare("A: " + userInput) == 0){
cout << "Correct." << endl;
}
else{
cout << "Incorrect." << endl;
}
}
return 0;
}
Quiz.cpp:
#include <string>
#include "Quiz.h"
int Quiz::score = 0;
std::string Quiz::getQuestion(){
return question;
}
std::string Quiz::getAnswer(){
return answer;
}
Quiz.h:
#ifndef QUIZ_H
#define QUIZ_H
class Quiz{
private:
std::string question {""};
std::string answer {""};
public:
Quiz() = default;
Quiz(std::string q, std::string a) : question {q}, answer {a} {}
std::string getQuestion();
std::string getAnswer();
};
#endif
My problem lies within main.cpp:
for(int i = 0; i < questionCount; i++){
cout << quizVector[i].getQuestion() << endl;
cout << "A: ";
getline(cin, userInput);
if(quizVector[i].getAnswer().compare("A: " + userInput) == 0){
cout << "Correct." << endl;
}
else{
cout << "Incorrect." << endl;
}
}
When I input the correct answer corresponding to each question, compare() does not return 0, but consistently returns 1. There are no leading or trailing spaces at the start or ends of each line in the text file. Am I misunderstanding how getline() or compare() works? Is it something else? Any help is appreciated!
I see a number of problems with this code:
std::random_shuffle() is deprecated in C++14 and removed in C++17, use std::shuffle() instead.
you are not validating that argv contains an input parameter before using it.
Your use of eof() in the while loop is wrong. For instance, if the last question/answer pair in the file is terminated by EOF instead of a line break, getline() will still return the question/answer to you, but it will also set the eofbit flag on the stream, which will cause eof() to return true and thus you will skip saving the last pair into the vector. The stream is not technically in a failed state yet in this situation (see the diagram at https://en.cppreference.com/w/cpp/io/basic_ios/eof), so you shouldn't skip the last pair if it terminates with EOF rather than a line break.
Your while loop is leaking memory.
you don't need questionCount at all, use quizVector.size() instead. Or better, a range-for loop.
you don't really need to use compare() at all, you can use operator== instead. But, if you do use compare(), you should take into account that it is case-sensitive (as is operator==). You should also take advantage of the fact that compare() lets you specify an index to start comparing from, so you can ignore the A: prefix in the stored answer (alternatively, you could just strip off the Q: and A: prefixes when storing the question/answer in Quiz's constructor). Otherwise, you can use your compiler's strcmpi() function instead (if it offers one).
Try something more like this instead:
#include <iostream>
#include <vector>
#include <fstream>
#include <algorithm>
#include <random>
#include <cctype>
#include "Quiz.h"
using namespace std;
string toLowercase(string s) {
transform(s.begin(), s.end(), s.begin(),
[](unsigned char c){ return tolower(c); }
);
return s;
}
int main(int argc, char* argv[]){
if (argc < 2){
cerr << "Please specify a file to open!" << endl;
return 0;
}
ifstream inputQuiz(argv[1]);
if (!inputQuiz.is_open()) {
cerr << "Can't open the file!" << endl;
return 0;
}
vector<Quiz> quizVector;
string q, a, userInput;
while (getline(inputQuiz, q) && getline(inputQuiz, a)) {
quizVector.emplace_back(q, a);
}
random_device rd;
mt19937 g(rd());
shuffle(quizVector.begin(), quizVector.end(), g);
for(auto &quiz : quizVector){
cout << quiz.getQuestion() << endl;
cout << "A: ";
getline(cin, userInput);
userInput = toLowercase(userInput);
a = toLowercase(quiz.getAnswer());
if (a == ("a: " + userInput)) {
// or:
// if (a.compare(2, string::npos, userInput) == 0) {
// or, if you strip off "A:" beforehand:
// if (a == userInput) {
cout << "Correct." << endl;
}
else {
cout << "Incorrect." << endl;
}
}
return 0;
}
We have a char. We need to replace all ab characters from our char with the letter c.
Example we have :
abracadabra
the output will be :
cracadcra
I tried to use replace() function from C++, but no success.
#include <iostream>
#include <cstring>
using namespace std;
int main()
{
string test;
cin>>test;
for(int i=0;i<(strlen(test)-1);i++)
{
if((test[i]=='a')&&(test[i+1]=='b')){
test.replace( test[i], 'c' );
test.replace( test[i+1] , ' ' );
}
}
cout << test << endl;
return 0;
}enter code here
You can use C++11 regex:
#include <iostream>
#include <regex>
#include <string>
int main() {
std::string str = "abracadabra";
std::regex r("ab");
std::cout << std::regex_replace(str, r, "c") << "\n"; // cracadcra
}
Problem:
That is not the syntax of std::string::replace.
Solution:
As is mentioned here the syntax is std::string::replace(size_t pos, size_t len, const string& str). Do test.replace(i, 2, "c" ) instead of test.replace(test[i],'c').
Or use regular expressions as dtell pointed.
Adittional information:
using namespace std; is considered a bad practice (More info here).
You should use std::string::size instead of strlen when you're working with std::string.
To work with std::string you should use #include <string> instead of #include <cstring>.
Full code:
#include <iostream>
int main()
{
std::string test;
std::cin >> test;
for(unsigned int i = 0; i < test.size() - 1; i++)
{
if((test[i]=='a') && (test[i+1]=='b'))
{
test.replace(i, 2, "c" );
}
}
std::cout << test << std::endl;
return 0;
}
The simplest thing you can do by using the standard library is first to find ab and then replace it. The example code I wrote is finding string ab unless there is None in the string and replacing it with c.
#include <iostream>
#include <string>
int main()
{
std::string s = "abracadabra";
int pos = -1;
while ((pos = s.find("ab")) != -1)//finding the position of ab
s.replace(pos, sizeof("ab") - 1, "c");//replace ab with c
std::cout << s << std::endl;
return 0;
}
//OUTPUT
cracadcra
I'm trying to take a Magic 8 Ball program that was originally using arrays and change it to a program that uses vectors instead. The task that I was given was to take the code below and do a couple of things to it.
use the push_back() function to initialize the vector
modify the signature and prototype of the getAnswer() function
modify the code in the body of the getAnswer() function
remove any unneeded code, such as your constant for the number of
answers
#include <iostream>
#include <string>
#include <iomanip>
#include <string>
#include <stdio.h>
#include <fstream>
#include <stdio.h>
using namespace std;
string getAnswer();
const string exitString = "x";
const int SIZEOF_ANSWERS = 8;
string magicEightBallAnswers[SIZEOF_ANSWERS] = { "Yes", "No", "Maybe", "It's not certain", "The outlook is good",
"The outlook is poor", "Time will tell", "Most likely" };
int main(int argc, char *argv[])
{
bool keepGoing = true;
while (keepGoing)
{
string question;
//prompt for and get the question
cout << "What is your question? (Enter 'x' to exit)" << endl;
getline(cin, question);
//this assumes that the user enters a lower case x
if (question.compare(exitString) == 0)
keepGoing = false;
else
{
cout << getAnswer() << endl;
}
}
return 0;
}
string getAnswer()
{
int index = rand() % SIZEOF_ANSWERS;
return magicEightBallAnswers[index];
}
This example might help:
#include <iostream>
#include <string>
#include <vector>
#include <cstdlib>
using namespace std;
string getAnswer(vector<string> & magicEightBallAnswers)
{
int i = rand() % magicEightBallAnswers.size();
return magicEightBallAnswers[i];
}
int main()
{
vector<string> magicEightBallAnswers {
"Yes",
"No",
"Maybe",
"It's not certain",
"The outlook is good",
"The outlook is poor",
"Time will tell",
"Most likely"
};
// Initialize rand()
srand(time(NULL));
string question;
while (true) {
// Prompt for and get the question
cout << "What is your question? (Enter 'x' to exit)" << endl;
getline(cin, question);
if (question == "x")
break;
// Ask question
cout << getAnswer(magicEightBallAnswers) << endl;
}
// Done
cout << "Bye! Let's play again soon!" << endl;
return 0;
}
Specifically:
Use C++ features to your advantage, to eliminate unnecessary code like "push_back() or initializing with "(8)".
Never use a hard-coded constant like "SIZEOF_ANSWER" if there's a dynamic alternative like "vector.size()".
Note the use of pass by reference: in string getAnswer(vector<string> & magicEightBallAnswers).
You should call "srand()" with a seed before using "rand()".
Etc.
Hello I am trying to generate a random array of the length that the user inputs. My array should then print and display the occurences of those letters in the array. So far this only prints up to the letter g and the occurences are incorrect. If someone could tell me what I am doing wrong it would help alot. Thank you.
#include <iostream>
#include <cstring>
#include <ctime>
#include <cstdlib>
using namespace std;
int main()
{
srand(time(0));
int i, num;
char ch;
char chars[]={'a','b','c','d','e','f','g','h','i','j','k','l','m','n','o','p','q','r','s','t','u','v','w','x','y','z'};
int freq[26]={0};
cout << "How many letters do you want in your string? ";
cin >> num;
for (i=0; i < num; i++)
{
ch = chars[rand()%26];
chars[i]=ch;
freq[i] +=1;
cout << ch;
}
for (char lower = 'a'; lower <='z'; lower++)
{
cout << "\nLetter" << lower << "is " << freq[lower] << "times";
}
}
Problem 1
The lines
chars[i]=ch;
freq[i] +=1;
are not right. You need to use:
int index = ch - 'a';
freq[index] += 1;
Problem 2
The index in the for loop for printing the data is not correct either.
You need to use:
for (char lower = 'a'; lower <='z'; lower++)
{
int index = lower - 'a';
cout << "\nLetter" << lower << "is " << freq[index] << "times";
}
Important Note
It is worth noting that the C++ standard does not guarantee that lower case letters are contiguous. (Thanks #MartinBonner). For instance, if your system uses EBCDIC encoding your program won't work.
To make your code robust, it will be better to use a std::map.
int main()
{
srand(time(0));
int i, num;
char ch;
char chars[]={'a','b','c','d','e','f','g','h','i','j','k','l','m','n','o','p','q','r','s','t','u','v','w','x','y','z'};
std::map<char, int> freq;
// Initialize freq.
for ( ch : chars )
{
freq[ch] = 0;
}
cout << "How many letters do you want in your string? ";
cin >> num;
for (i=0; i < num; i++)
{
ch = chars[rand()%26];
freq[ch] +=1;
}
for (auto item : freq )
{
cout << "\nLetter" << item.first << "is " << item.second << "times";
}
}
You might wanna give a look to C++11 Pseudo-random number generation here is a short way of generating the range that you want using this:
#include <algorithm>
#include <array>
#include <random>
#include <vector>
using namespace std;
int main()
{
int arraySize = 35;
mt19937 engine{random_device{}()};
uniform_int_distribution<> dist{'a', 'z'};
vector<char> vec;
generate_n(back_inserter(vec), arraySize, [&]() { return static_cast<char>(dist(engine); }));
//To count occurrences
array<int, 26> freq;
for (auto c : vec) { ++freq[c-'a']; }
return 0;
}
You should not write into chars, and freq should be extended to cover the a...z range (the ASCII codes), which it does not. Also, increase at index ch, not at i.
I do not even know that range from the top of my head, but it could be modified to track all possible bytes instead (0...255), see result on https://ideone.com/xPGls7
List of changes:
int freq[256]={0}; // instead of int freq[26]={0};
// chars[i]=ch; is removed
freq[ch] +=1; // instead of freq[i] +=1;
Then it works.
Using lambda functions to do most of the work.
#include <algorithm>
#include <functional>
#include <iostream>
#include <map>
#include <numeric>
#include <ostream>
#include <random>
#include <string>
#include <utility>
#include <vector>
using namespace std::string_literals;
int main()
{
std::mt19937::result_type seed = std::random_device{}();
auto engine = std::mt19937(seed);
auto dist = std::uniform_int_distribution<>('a', 'z');
auto random_letter = [&engine, &dist]() { return static_cast<char>(dist(engine)); };
std::cout << "How many letters do you want to generate? "s;
int n;
if (!(std::cin >> n)) { return EXIT_FAILURE; }
auto letters = std::vector<char>();
std::generate_n(std::back_inserter(letters), n, random_letter);
auto zero = std::map<char, int>();
auto const frequencies = std::accumulate(std::cbegin(letters), std::cend(letters), zero,
[](auto& acc, auto c)
{
++acc[c];
return acc;
});
for (auto const [c, freq] : frequencies)
{
std::cout << "The letter '"s << c << "' appeared "s << freq << " times." << std::endl;
}
return 0;
}
I'm trying to write a program that first checks if a name is in a vector and if not then adds it to the vector. My code seems to have difficulties with parsing, at least that's what I get out of it. I tried changing the string to a char but it did not help me much.
#include <iostream>
#include <vector>
#include <string>
bool isinVector(std::string uElement, std::vector<std::string> uArray)
{
for (unsigned int i = 0; i <= sizeof(uArray); i++) {
if (uArray[i] == uElement) {
return true;
}
else {
return false;
}
}
}
int main()
{
bool trigger = false;
while (!trigger) {
std::vector<std::string> names;
names.push_back("Bart");
std::string newName;
getline(std::cin, newName);
if (isinVector(newName, names))
{
std::cout << "true" << std::endl;
trigger = true;
}
else
{
std::cout << "false" << std::endl;
names.push_back(newName);
for (int i = 0; i <= sizeof(names); i++) {
std::cout << names[i] << std::endl;
}
}
}
}
I made some adjustments to your code, removing your isinVector function and using a lambda inside the main function instead. In the future please provide a concise question and example.
#include <iostream>
#include <vector>
#include <string>
#include <algorithm>
using std::vector;
using std::string;
using std::cout;
using std::cin;
using std::endl;
using std::find_if;
int main(){
bool trigger = false;
while (!trigger) {
vector<string> names;
names.push_back("Bart");
string newName;
getline(cin, newName);
if(find_if(names.begin(), names.end(), [newName] (const string& name){
return !name.compare(newName);
}) != names.end()){
cout << "true" << endl;
trigger = true;
}
else{
cout << "false" << endl;
names.push_back(newName);
for (size_t i = 0; i < names.size(); i++) {
cout << names.at(i) << endl;
}
}
}
return 0;
}
The code uses std::find_if to check if the element exists in the vector. If std::find_f does not return the iterator to uArray.end() Then the element exists. Also your for loop used sizeof which is incorrect, use the vector.size method. And you were looping until <= , it should be < uArray.size() And it's safer to access elements in the vector through the .at method rather than an index [] since the .at will throw an out_of_range exception.
Among the things wrong in the updated post.
Improper use of sizeof
Reinventing a standard algorithm
Lack of error checking
Consider the tasks you're trying to accomplish. You want to:
Initialize a starting vector containing the name Bart
Continuously read new names. For each new name read:
a. Check to see if it is already in the vector.
if it is present terminate the read loop
else add it to the vector, and print the entire vector
This sequence of operations can be accomplished with stepwise refinement.
Step 1. Read names
First, you need to be able to continuously read names:
#include <iostream>
#include <string>
int main()
{
std::string name;
while (std::getline(std::cin, name))
std::cout << name << '\n';
}
Simple enough. Running this will echo any strings you type, one at a time, separated by newlines.
Step 2. Accumulate names in a vector
Next, we need to add a vector to hold the strings we're reading, with an initial population of the name "Bart". For this pass we'll be just putting every string we read into the vector
#include <iostream>
#include <vector>
#include <string>
int main()
{
std::vector<std::string> names = { "Bart" };
std::string name;
while (std::getline(std::cin, name))
{
names.emplace_back(name);
for (auto const& s : names)
std::cout << s << ' ';
std::cout.put('\n');
}
}
In addition to what was done prior, we're now accumulating strings in the vector, including duplicates, and reporting the vector content after each name read. This gets us closer to our stated goal.
Step 3: Conditional loop exit based on duplicate detection
Now we need to check for duplicates, and terminate the loop once it happens. We can do this using std::find. The final code is below:
#include <iostream>
#include <algorithm>
#include <vector>
#include <string>
int main()
{
std::vector<std::string> names = { "Bart" };
std::string name;
while (std::getline(std::cin, name))
{
if (std::find(names.begin(), names.end(), name) != names.end())
break;
names.emplace_back(name);
for (auto const& s : names)
std::cout << s << ' ';
std::cout.put('\n');
}
}
That's it. This is a simple task, but it lends itself nicely to an example of how you break a multi-part task down to manageable objectives , then build it in pieces.
Hope you found it useful.
Now my code looks like this:
#include <iostream>
#include <vector>
#include <string>
#include <algorithm>
bool isinVector (std::string uElement, std::vector<std::string> uArray) {
bool invector = false;
std::vector<std::string>::iterator it = std::find(uArray.begin(),
uArray.end(),uElement);
if(it != uArray.end()){
invector = true;
}
return invector;
}
int main(){
bool trigger = false;
std::string name;
std::vector<std::string> names = { "Bart" };
while (std::getline(std::cin, name)){
if (isinVector(name, names)) {
std::cout << "true" << std::endl;
break;
}
else
{
std::cout << "false" << std::endl;
names.emplace_back(name);
}
}
return 0;
}
and it works, thanks a lot guys!