Input Combining with Previous Input Acts Correctly - c++

In my class, I want the family data member to be one of the five strings in the static array fiveNewYorkFamilies[5]. I made a constructor to take input from the user and see if it corresponds to one of the elements in the array. If it does match, then I go on with my program; if not, I repeat the step using a goto. My program works fine, but there's one thing I don't understand: When I first insert the input, the variable family is empty as indicated by the empty function I put atop of it. However, if I fail to insert a correct input the first time, and continue to insert an input a second time, I am inserting an input atop the previous input. For example, if I input "Lebron" the first time and then insert "Corleone" the second time (the empty function reassures me that family is not empty), the variable family would be "LebronCorleone." In spite of this, my program works just fine. Can someone explain to me why is that? And if I'm misunderstanding the situation, can someone clear it up? Thank you.
class Godfather
{
std::string family;
public:
explicit Godfather(std::istream & is);
Godfather(): family("Corleone") {}
static std::string fiveNewYorkFamilies[5];
std::string getFamily() const {return this->family;}
};
std::string Godfather::fiveNewYorkFamilies[5] = {"Corleone", "Barzini", "Cuneo", "Stracci", "Tattaglia"};
Godfather::Godfather(std::istream & is)
{
label:
std::cout << family.empty();
is >> family;
bool match = false;
for(std::string * ptr = fiveNewYorkFamilies; ptr != fiveNewYorkFamilies + 5; ++ptr)
if(*ptr == family)
match = true;
if(!match)
goto label;
}
int main()
{
Godfather vito(std::cin);
}

You can improve the code by removing the goto label. Instead, use a while loop. When an input is correct, just return so the function ends.
Also, use a foreach loop when you parse the possible names. This way you won't care if the size of the possible names is changing (hence you won't need to change from 5 to 6, 6 to 7 etc. whenever you add a new possible name in the array).
Godfather::Godfather(std::istream& is) {
while (is >> family) {
for (const auto& possibleName : fiveNewYorkFamilies) {
if (family == possibleName)
return;
}
}
}
P.S. Good luck with your Sa:Mp server.

Related

Removing element from the standard list

Suppose I have the following class
class Human
{
public:
Human();
Human(string,int);
virtual ~Human();
string getName();
protected:
private:
string name;
int staj;
};
I have created list with 2 elements that I pushed in
list<Human> mylist;
Human x ("Mike",13);
Human y("pavlek",33);
I am trying to remove if there is element with name "Mike",I tried removing it like this :
for(list<Human>::iterator it=mylist.begin();it!=mylist.end();++it)
{
if(it->getName()=="Mike")
{
mylist.remove(it);
cout<< "removed";
cout<<it->getName();
}
}
However I get error at passing the value to the remove() function,what should I exactly pass in order to delete this element from the list?
You have simply mistaken erase and remove. According to the C++ reference, remove is used to remove from the list all elements whose values are equals to the given parameter. On the other hand, erase removes a single element given its position or a range of elements given the start and end positions.
If you only need to delete the first element containing "Mike" as its name, simply do something like this:
for(list<Human>::iterator it=mylist.begin();it!=mylist.end();++it)
{
if(it->getName() == "Mike")
{
mylist.erase(it);
break;
}
}
Please notice that after using erase, your iterator will be invalidated. You can circumvent it by using the returned value of erase, which is the next valid iterator value. This detail is important if your list might contain multiple elements whose name is "Mike".
Matheus Portela's solution was the old C++98 method. It's a lot easier now:
mylist.remove_if( [](Human const& h){return h.getName()=="Mike";} );
The condition here is [](Human const& h){return h.getName()=="Mike";}. That is a lambda expression which returns true if the Human h should be removed. You can test any other property or combination of properties there. The { } part of the lambda is a real function body; you could even have for-loops in there:
Other examples:
mylist.remove_if( [](Human const& h){return h.getName().size() > 4; } );
mylist.remove_if( [](Human const& h) {
for (char c: h.getName())
if (c=='i') return true; // remove if name contains an i
return false; } );
Mind you, the latter would be easier with std::any_of.

How to iterate through all elements of set C++

[UPDATE: My problem is solved! Lots of thanks to Mike Seymour and Niall and all you guys!]
My code has errors in the for loop and I do not know how to fix it :(
MyClass::ITECH7603Class(set<Student>* students) {
/* Initialize dynamically the group field */
group = new map<string, Student>();
for (set<Student>::iterator it = students->begin(); it != students->end(); it++) {
addStudent(it);
}
}
void MyClass::addStudent(Student* studentPtr) {
string fullName = studentPtr->getName() + " " + studentPtr->getSurname();
group->insert(pair<string, Student>(fullName, *studentPtr));
}
So the main idea is to loop through all students in the set, and add each student into a map group. Any help? Thank you very much!
for (set<Student>::iterator it = students->begin; it != students->end; it++) {
addStudent(it);
}
should be:
for (set<Student>::iterator it = students->begin(); it != students->end(); it++) {
//^^ //^^
addStudent(it);
}
addStudent takes a pointer, while it is an iterator, so can't be passed directly.
You should change addStudent to take either a value or a pointer/reference to const:
// option 1
void addStudent(Student);
addStudent(*it);
// option 2
void addStudent(Student const &);
addStudent(*it);
// option 3
void addStudent(Student const *);
addStudent(&*it);
If, as you say in a comment, you must leave it taking a mutable pointer, then you'll need some grotesquery to deal with the fact that elements of the set are immutable:
// nasty option
addStudent(const_cast<Student*>(&*it));
// slightly less nasty option
Student copy = *it;
addStudent(&copy);
Beware that the first option will give undefined behaviour if the function uses the dodgy pointer to make any modification to the Student object stored in the set. The second makes a temporary copy, which can be modified without breaking the set. This is fine as long as addStudent only stores a copy of the object passed to it, not the pointer itself, which will become invalid when copy is destroyed.
In c++11 you can use range for sytax:
for (const auto &student : *students)
{
addStudent(it);
}
Then change addStudent function signature to accept reference:
void MyClass::addStudent(const Student &student) {
While you've gotten answers that "fix" your code to the extent of compiling and producing results that you apparently find acceptable, I don't find them very satisfying in terms of code style. I would do this job rather differently. In particular, my code to do this wouldn't have a single (explicit) loop. If I needed to do approximately what you're asking for, I'd probably use code something like this:
std::pair<std::string, Student> make_mappable(Student &stud) {
return std::make_pair(stud.getName() + " " + stud.getSurName(), stud);
}
std::map<std::string, Student> gen_map(std::set<Student> const &input) {
std::map<std::string, Student> ret;
std::transform(input.begin(), input.end(),
std::inserter(ret, ret.end()),
make_mappable);
return ret;
}
There definitely would not be any new in sight, nor would there be any passing a pointer to a Student.
OTOH, since the data you're using as the key for your map is data that's already in the items in the set, it may more convenient all around to continue to use a set, and just specify a comparison function based on the student's name:
struct by_given_name {
bool operator()(Student const &a, Student const &b) const {
if (a.getName() < b.getName())
return true;
if (b.getName() < a.getName())
return false;
return a.getSurName() < b.getSurName();
}
};
std::set<Student, by_given_name> xform(std::set<Student> const &in) {
return std::set<Student, by_given_name>{in.begin(), in.end()};
}
For what its worth, a Live Demo of the latter.
Whether the latter is practical will typically depend on one other factor though: your ability to create a Student from only a name/surname. If you can't do that, searching by name will be inconvenient (at best), so you'd want to use a map.
I realize this probably isn't much (if any) help in completely what's apparently home-work for a class--but even if your class prevents you from actually turning in decent code, it seems worthwhile to me to at least try to learn to write decent code in addition to what it requires. If you do pass the class and get a job writing code, you'd probably rather your coworkers didn't want to hurt you.

Checking contents of string C++

If I had a program reading a file that contained something along the lines of "Boss1 Dave Jim Boss3 Coleen Boss 7 Harris Todd Elaine" and I'm trying to separate the inputs into a list of bosses and a list of names, I would check each string inputted, but how can I tell if the person is a boss or not? I would set up something like this to begin with:
void read(std::istream& is, Bosses<std::string>& bossList, Employees<std::string> empList){
std::string name;
while(!is.eof()){
is >> name;
}
}
But I would need to check in the while loop if something like name=="Boss_" but I don't understand strings well enough to know how to set this up.
You can use the insertion operator to parse the string of names as your string is whitespace delimited, and the insertion operator skips over whitespace (by default):
void read(std::istream& is, Bosses<std::string>& bossList, Employees<std::string> empList) {
std::string temp;
std::vector<std::string> all_names;
//the insertion operator reads the string and bypasses all whitespace by default
while (is >> temp) {
//find bosses by using `std::string
if (temp.find("Boss") != std::string::npos) {
boosList.push_back(temp);//you didn't state what container `Bosses` uses but, `push_back is valid for `lists`, `vectors` and `deques`
}
else {
empList.push_back(temp);//you didn't state what container `Employees` uses but, `push_back is valid for `lists`, `vectors` and `deques`
}
}
}

Overloading a function using identical definitions in C++

I am aware of the process of function overloading in C++ through the use of differing parameters and definitions. However if I have two functions which are identical apart from their parameters is there a way to only have this definition once.
The functions I have used are to check for correct input (i.e. a number not a character is entered). One is for an int and the other a float. Because of this and the fact that I pass the variable by reference the definitions are exactly identical.
The two functions declarations are as follows:
void Input (float &Ref);
void Input (int &Ref);
And they then share the common definition of:
Function_Header
{
static int FirstRun = 0; // declare first run as 0 (false)
if (FirstRun++) // increment first run after checking for true, this causes this to be missed on first run only.
{ //After first run it is required to clear any previous inputs leftover (i.e. if user entered "10V"
// previously then the "V" would need to be cleared.
std::cin.clear(); // clear the error flags
std::cin.ignore(INT_MAX, '\n'); // discard the row
}
while (!(std::cin >> Ref)) // collect input and check it is a valid input (i.e. a number)
{ // if incorrect entry clear the input and request re-entry, loop untill correct user entry.
std::cin.clear(); // clear the error flags
std::cin.ignore(INT_MAX, '\n'); // discard the row
std::cout << "Invalid input! Try again:\t\t\t\t\t";
}
}
If there was a way around having to have two identical copies of the same code while it still being used for both parameter types then I could shorten the code of my programme significantly. I'm sure I'm not the only person with this issue but all my searches are returning are explanations of how to overload functions using multiple definitions.
Any help or advice would be much appreciated.
The best (and only ?) solution is to use template
Templates are useful:
template <typename T>
void Input (T &Ref)
{
...
}
std::string s;
int i;
float f;
Input(s);
Input(i);
Input(f);
template<class T>
void Input(T& ref)
{
..
}

Is there a more elegant way to achieve a "cheat code" implementation for a game in C++?

I have been learning C++ by diving into a project, a simple 2d game. I have attempted to implement a set of cheats but I'm seriously novice at string manipulation. I'm sure there would be a more elegant way to achieve what I would like than my code below.
As requested, stringBuffer is just a string that contains the last 12 pressed characters. I prepend it because it's trimmed at the end later with resize, and hence my cheats have to be backwards. I'm very much a noob at string manipulation, and I know something is wrong here, which I why I asked for it to be looked at and possibly improved.
//The following code is in my keyPressed function
cheatBuffer = (char)key + cheatBuffer;
cheatBuffer.resize(12);
string tempBuffer;
string cheats[3] = {"1taehc","2taehc","3taehc"};
for(int i = 0;i < 3;i++){
tempBuffer = cheatBuffer;
tempBuffer.resize(cheats[i].size());
if(cheats[i] == tempBuffer){
switch(i){
case 1:
//activate cheat 1
break;
case 2:
//active cheat 2
break;
case 3:
//active cheat 3
break;
}
}
}
The codes are "cheat1", "cheat2" and "cheat3" respectively. I can't help thinking that this could be a lot better. Any insight would be greatly appreciated.
You might want to consider using:
std::map<std::string, std::function<void ()>> (If you can use C++0x)
std::map<std::string, std::tr1::function<void ()>> (If you can use TR1)
std::map<std::string, boost::function<void ()>> (If you can use Boost)
(Of course, the signature of the function can differ)
Example using C++0x
#include <map>
#include <functional>
#include <string>
#include <iostream>
typedef std::map<std::string, std::function<void ()>> cheat_map;
inline void cheat1()
{
std::cout << "cheat 1 used!" << std::endl;
}
inline void cheat2()
{
std::cout << "cheat 2 used!" << std::endl;
}
int main()
{
cheat_map myCheats;
myCheats.insert(std::pair<std::string, std::function<void ()>>("cheat1", std::function<void ()>(cheat1)));
myCheats.insert(std::pair<std::string, std::function<void ()>>("cheat2", std::function<void ()>(cheat2)));
std::string buffer;
while (std::getline(std::cin, buffer)) {
if (!std::cin.good()) {
break;
}
cheat_map::iterator itr = myCheats.find(buffer);
if (itr != myCheats.end()) {
myCheats[buffer]();
}
}
}
Input:
notourcheat
cheat1
cheat2
cheat1
Output:
cheat 1 used!
cheat 2 used!
cheat 1 used!
Live demo
I would store the strings in a trie:
http://en.wikipedia.org/wiki/Trie
(in the Wikipedia article there are also links to C++ implementations).
In the leafs of the trie you can add additional data concerning the cheat.
When you lookup a string you simple check whether the string is contained in the trie with the cheat codes. If yes, you get the additional data (for example a function pointer to a function that does what you want to do; or more Object-Oriented: a pointer to a class instance that when you call one of its member functions does the "cheating stuff").
This code can be improved in several ways.
Make your immutable strings const static
static const std::string const foo[] = { "1taehc", "2taehc", "3taehc" };
So they don't have to be allocated every time in your "KeyPressed" handler.
Associate each cheat with a value that you can use in a case statement
I don't think all the additional logic to facilitate the switch is a good idea. What about something like this:
const int CHEAT_ONE = 1;
const int CHEAT_TWO = 2;
const int CHEAT_THREE = 3;
static const std::pair<std::string, int> const foo[] = {
std::make_pair("1taehc", CHEAT_ONE),
std::make_pair("2taehc", CHEAT_TWO),
std::make_pair("3taehc", CHEAT_THREE),
};
This way you get an integer which you can use as a case label for each of your cheat codes.
Search for the cheat to activate
You want to be able to search for a cheat code that has been activated easily. Let's break up the std::pair instances and use a std::map instead.
const int CHEAT_ONE = 1;
const int CHEAT_TWO = 2;
const int CHEAT_THREE = 3;
std::pair<std::string, int> cheatcodes[] = {
std::make_pair("1taehc", CHEAT_ONE),
std::make_pair("2taehc", CHEAT_TWO),
std::make_pair("3taehc", CHEAT_THREE),
};
std::map<std::string, int> cheatmap(
cheatcodes, cheatcodes + sizeof (cheatcodes) / sizeof (cheatcodes[0]));
Now, assuming that candidate is your keypress buffer, you can just do
auto pair = cheatmap.find(candidate);
if (pair != cheatmap.end()) {
switch(pair->second) {
case CHEAT_ONE:
case CHEAT_TWO:
case CHEAT_THREE:
}
}
I would do it this way: when pressing some specific button first, for example enter, it would start to fill the cheatBuffer, and after one char was filled in the end of the buffer, it would use that buffer to check if a value of it exists in an std::map. And when that value exists, it would execute a function, which pointer was stored in std::map.
This might be overkill and too much work, but you could make a finite state machine to handle your key inputs, storing your current state instead of storing a key history. Your starting state 0 represents no applicable keys pressed. A 'c' will put you into state 1, where an 'h' will bring you to state 2, a 'c' will keep you at state 1, and anything else will send you back to 0. So on a given keypress you switch on the current state, and inside of that, switch on the character supplied to see which state you transition into. If it was a final state then execute the cheat and transition back to 0.