Last active
August 29, 2015 14:20
-
-
Save thadeuluiz/b21a3003b51c3a343c3b to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include <set> | |
#include <vector> | |
#include <map> | |
#include <algorithm> | |
#include <string> | |
#include <fstream> | |
#include <sstream> | |
#include <iostream> | |
using namespace std; | |
class Animal; | |
class AnimalKingdom; //Contains all known animals | |
class AnimalSet; //All known animals that share a property | |
ostream& operator<<(ostream&, const Animal&); | |
istream& operator>>(istream&, Animal&); | |
class Animal { | |
public: | |
static const char DELIMITER = ';'; | |
bool has_attribute(const string& attribute) const { | |
return attributes.find(attribute) != attributes.end(); | |
}; | |
string name; | |
set<string> attributes; | |
}; | |
//serialized inputs and outputs | |
ostream& operator<<(ostream& os, const Animal& animal){ | |
os << animal.name << Animal::DELIMITER; | |
for(auto attribute: animal.attributes) | |
os << attribute << Animal::DELIMITER; | |
return os; | |
} | |
istream& operator>>(istream& is, Animal& animal){ | |
string line; | |
getline (is, line); | |
stringstream linestream{line}; | |
getline( linestream, animal.name, Animal::DELIMITER ); | |
animal.attributes.clear(); | |
for( string attr; getline(linestream, attr, Animal::DELIMITER); ) | |
animal.attributes.insert(attr); | |
return is; | |
} | |
class AnimalKingdom{ | |
public: | |
AnimalKingdom(string t_ifile_name, string t_ofile_name=""): | |
ifile_name{t_ifile_name}, ofile_name{t_ofile_name}{ | |
ifstream animals_record{ifile_name}; | |
for(Animal animal; animals_record >> animal;){ | |
animals.push_back(animal); | |
} | |
}; | |
~AnimalKingdom(){ | |
if(!ofile_name.empty()){ | |
ofstream animal_record{ofile_name}; | |
for(auto& animal : animals) | |
animal_record << animal << endl; | |
} | |
}; | |
string ifile_name, ofile_name; | |
vector<Animal> animals; | |
}; | |
class AnimalSet{ | |
public: | |
size_t count() const { | |
return filtered_animals.size(); | |
}; | |
string most_common_attribute() const { | |
map <string, int> attribute_frequency; | |
for(auto filtered_animal_p: filtered_animals ) | |
for(auto attribute: filtered_animal_p->attributes){ | |
if(filtered_attributes.find(attribute) == filtered_attributes.end()) //attribute is not within current filter | |
++attribute_frequency[attribute]; | |
} | |
int max = 0; | |
string most_frequent; | |
for(auto pair = attribute_frequency.begin(); pair!=attribute_frequency.end(); ++pair) | |
if(pair->second > max) { | |
most_frequent = pair->first; | |
max = pair->second; | |
} | |
return most_frequent; | |
}; | |
AnimalSet filter_with(const string& attribute, bool positive = true) { | |
AnimalSet new_set; | |
new_set.filtered_attributes = filtered_attributes; | |
if(positive) new_set.filtered_attributes.insert(attribute); | |
copy_if(filtered_animals.begin(), | |
filtered_animals.end(), | |
back_inserter(new_set.filtered_animals), | |
[&attribute, positive](const Animal* animal){ | |
return positive == animal->has_attribute(attribute); | |
}); | |
return new_set; | |
} | |
vector<Animal*> filtered_animals; | |
set<string> filtered_attributes; | |
}; | |
int main (){ | |
AnimalKingdom kingdom{"animal_kingdom.txt", "animal_kingdom.txt"}; | |
AnimalSet current_set; | |
transform(kingdom.animals.begin(), | |
kingdom.animals.end(), | |
back_inserter(current_set.filtered_animals), | |
[](Animal& animal){return &animal;}); | |
cout << "Welcome to ANIMAL. Think of an animal and type Y. --> "; | |
istream_iterator<char> response{cin}; | |
for(;tolower(*response)!='y';++response){ | |
cout << "Ok. type Y when ready. --> "; | |
}; | |
while(current_set.count() > 1){ | |
string common = current_set.most_common_attribute(); | |
cout << "is your animal: "<< common << "? --> "; | |
for(char c = tolower(*(++response)); c != 'y' && c != 'n'; c =*++response) | |
cout << "Oops, i didnt understand that. Type Y/N --> "; | |
current_set = current_set.filter_with(common, *response=='y'); | |
} | |
if(current_set.count() == 1){ | |
cout << "is your animal the " << current_set.filtered_animals.front()->name << "? --> "; | |
for(char c = tolower(*++response); c != 'y' && c != 'n'; c =*++response) | |
cout << "Oops, i didnt understand that. Type Y/N --> "; | |
if(tolower(*response) == 'y'){ | |
cout << "Haha!, I knew it!" << endl; | |
return 0; | |
} | |
} | |
//we dont know this animal | |
Animal new_animal; | |
cin.ignore(numeric_limits<streamsize>::max(), '\n'); //clean of '\n's | |
cout << "Ok, i give up, which animal is it?: "; | |
getline(cin, new_animal.name); | |
cout << "Which unique attribute does it have? "; | |
string new_attribute; | |
getline(cin, new_attribute); | |
new_animal.attributes = current_set.filtered_attributes; | |
new_animal.attributes.insert(new_attribute); | |
kingdom.animals.push_back(new_animal);//insert into the kingdom | |
return 0; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment