This is a tough one. Could really use some quality help. Most of the text in her
ID: 3576040 • Letter: T
Question
This is a tough one. Could really use some quality help. Most of the text in here is description of what the program should look like. Thanks in advance.
Write a C++ program named ftree that builds a family tree based on simple descriptions of relationships between people.
Your program will read the relationship specification in from cin and ultimately print out the information on cout using a specific format. The input format uses a series of keyword and value pairs on each line to describe how a person is related to other people:
PERSON: This specifies a person by name. All following keyword/value pairs are applied to this person, until another PERSON line is encountered.
SEX: Must be either "M" to mean male or "F" to mean female.
FATHER: This specifies the father of the current person. It implies that the father is a male. A person can only have one father.
MOTHER: This specifies the mother of the current person. It implies that the mother is a female. A person can only have one mother.
FATHER_OF: This specifies that the current person is the father of the given person. It implies that the current person is a male. A person may have any number of children.
MOTHER_OF: This specifies that the current person is the mother of the given person. It implies that the current person is a female. A person may have any number of children.
Note that names do not contain spaces, so every name is a single string. For example names such as "Bob" or "Frank" are ok, but not "Billy Bob" or "James Clerk Maxwell".
Use the example below
PERSON Bob
FATHER_OF Frank
FATHER_OF Lester
FATHER_OF Diana
PERSON Nancy
MOTHER_OF Frank
MOTHER_OF Lester
MOTHER_OF Diana
PERSON Diana
SEX F
PERSON Frank
SEX M
PERSON Lester
SEX M
This example defines five people. Bob and Nancy are the Father and Mother, respectively, of Diana, Frank, and Lester. Bob, Frank, and Lester are males, and Nancy and Diana are females.
Your ftree program must read this data in and build the necessary data structures to track all of the information about each person. After all information has been read in, ftree should print out the data for each person using the following format:
A line showing the person's name.
The word Sex: followed by the person's sex, which is printed as Male, Female, or unknown.
The word Father: followed by the person's father's name, or unknown if they don't have a father.
The word Mother: followed by the person's mother's name, or unknown if they don't have a mother.
The word Children: followed by a space separated list of all children of the person, or none if they have no children.
A blank line before the next person's entry.
The output order should be alphabetic based on the person's name. Here is an example:
Bob
Sex: Male
Father: unknown
Mother: unknown
Children: Frank Lester Diana
Diana
Sex: Female
Father: Bob
Mother: Nancy
Children: none
Frank
Sex: Male
Father: Bob
Mother: Nancy
Children: none
Lester
Sex: Male
Father: Bob
Mother: Nancy
Children: none
Nancy
Sex: Female
Father: unknown
Mother: unknown
Children: Frank Lester Diana
As you read through the input, you must do error checking to look for impossible relationships. Moreover, you must be sure to include all explicit and implicit information and relationships. For example, if A is said to be B's father, then that means that A is male, even if A doesn't have a SEX entry. If A is later said to be C's mother, then that is an error and the offending line should be ignored. Finally, a person may not have their own PERSON entry in the input, but if the existence of the person is implied in another person's entry you should create the person automatically. For example, consider this input:
PERSON Fred
SEX M
FATHER Sam
This input defines two people: Fred and Sam. Both Fred and Sam are males (Fred explicitly so, Sam because he is Fred's father). Sam is Fred's father, and Fred is one of Sam's children.
The most important thing about ftree is to deal with this inference in robust fashion. Always include as much information as possible based on the given input, and always check every value before updating anything to be sure it does not conflict with previous information. Specifically, you should check all of this information as you read in the data:
A person cannot have two fathers or two mothers.
A father cannot be female, and a mother cannot be male.
A person's sex cannot be changed once set to either male or female.
If you detect any of these errors, you should print a warning to the user and skip that line of input. The rest of the data should be read in as normal, i.e., do not exit or stop reading because of an error of this sort. Be careful not to update any of your data structures until you are sure that there are no errors with the line. Also note that it is perfectly ok to specify repeated data so long as it does not conflict with the current information. For example:
PERSON Sam
FATHER_OF Fred
SEX M
PERSON Fred
SEX M
FATHER Sam
PERSON Sam
FATHER_OF Fred
SEX M
There is a lot of redundant information in this input, but there are no errors. Everything given is self-consistent so your ftree program should not flag any errors.
Finally, your program must check for the existence of cycles in the family tree. If a cycle is detected, that means that at least one person is his or her own descendant, which is impossible. You should check for cycles one time after all the input has been read, and if there is a cycle, print out an error message explaining what happened and then exit (this is the only time you should exit the program early).
There are many pieces you will need to accomplish this program. First, you will need a person class that represents one person. Clearly the person class needs the following member variables:
Name (string)
Sex (string)
Father (person pointer)
Mother (person pointer)
Children (STL list of person pointers)
Extra variables for the cycle check
You need to write your own person class that has all of these values along with appropriate methods to get and set each one of the variables.
As you read in the input lines, you will build an STL map that contains all of the people. The key values should be strings (the name of the person) and mapped values should be pointers to your person class (person pointers). That makes it easy to search for values by name in the map, which you will do often. Every time you read a line of input you will potentially add/update one or two person objects, and you have to do all the error checking to be sure that nothing is conflicting. If everything is ok, then you'll update the person objects with the name relationship information.
Note that your ftree program reads the input from cin, not from a file. Of course, you'll want to use files to store your test input cases so that you don't have to type everything in every time you run it. Recall that you can redirect the contents of a file to be cin for a program with the < operator on the command line. For example: $./ftree < test0
Explanation / Answer
main.cpp
#include <iostream>
#include "Person.hpp"
#include <map>
int main(int argc, const char * argv[]) {
string in;
string name, pName;
map<string, Person> people;
map<string, Person>::iterator it, pIt;
while(cin >> in) {
cin >> name;
if (in == "PERSON") {
pName = name; // Keep track of what person is currently being evaluated
people.insert(pair<string, Person>(name, *new Person(name, "")));
} else if (in == "FATHER_OF") {
// If child exists make pName their father
// Else create child and set their father to pName
if((it = people.find(name)) != people.end()) {
pIt = people.find(pName);
if (pIt->second.getSex() == "M" || pIt->second.getSex() == "") {
// Check to make sure you aren't assigning a person to be its own father
if(pIt->second.getName() != it->second.getName()){
it->second.setFather(&pIt->second); // Set the childs father
pIt->second.addChild(&it->second); // Add child into fathers children list
// Assign the father's sex if it's currently unassigned
if(pIt->second.getSex() == "")
pIt->second.setSex("M");
} else {
printf(FYEL("Warning["%s"]: "%s" cannot be their own father "), in.c_str(), pName.c_str());
}
} else {
printf(FYEL("Warning["%s"]: "%s" is a female "), in.c_str(), name.c_str());
}
}
else {
// Create a new person
people.insert(pair<string, Person>(name, *new Person(name, "")));
it = people.find(name);
pIt = people.find(pName);
it->second.setFather(&pIt->second); // Assign pName as their father
pIt->second.addChild(&it->second); // Add child into fathers children set
// Assign the fathers sex if it's currently unassigned
if(pIt->second.getSex() == "")
pIt->second.setSex("M");
}
} else if (in == "FATHER") {
// If name exists, set name as pName's father
// Else create person(name) and set pName's father as person(name)
if((it = people.find(name)) != people.end()) {
pIt = people.find(pName);
// Make sure pName doesn't already have a father
if (pIt->second.getFather() == nullptr){
// Make sure the fathers sex isn't female
if (it->second.getSex() == "M" || it->second.getSex() == "") {
pIt->second.setFather(&it->second);
it->second.addChild(&pIt->second);
it->second.setSex("M");
} else {
printf(FYEL("Warning["%s"]: "%s" is a female "), in.c_str(), name.c_str());
}
} else {
printf(FYEL("Warning["%s"]: "%s" already has a father "), in.c_str(), pName.c_str());
}
} else {
pIt = people.find(pName);
// Make sure the pName doesn't already have a father
if(pIt->second.getFather() == nullptr){
people.insert(pair<string, Person>(name, *new Person(name, "M")));
it = people.find(name);
pIt->second.setFather(&it->second);
it->second.addChild(&pIt->second);
} else {
printf(FYEL("Warning["%s"]: "%s" already has a father "), in.c_str(), pName.c_str());
}
}
} else if (in == "MOTHER_OF") {
// If child exists make pName the mother
// Else create child and set father to pName
if((it = people.find(name)) != people.end()) {
pIt = people.find(pName);
if (pIt->second.getSex() == "F" || pIt->second.getSex() == "") {
// Check to make sure you aren't assigning a person to be its own mother
if (pIt->second.getName() != it->second.getName()) {
it->second.setMother(&pIt->second);
pIt->second.addChild(&it->second); // Add child into mothers children set
// Assign the mothers sex if it's currently unassigned
if(pIt->second.getSex() == "")
pIt->second.setSex("F");
} else {
printf(FYEL("Warning["%s"]: "%s" cannot be their own mother "), in.c_str(), pName.c_str());
}
} else {
printf(FYEL("Warning["%s"]: "%s" is a male "), in.c_str(), pName.c_str());
}
} else {
// Create a new person
people.insert(pair<string, Person>(name, *new Person(name, "")));
it = people.find(name);
pIt = people.find(pName);
it->second.setMother(&pIt->second); // Assign pName as their mother
pIt->second.addChild(&it->second); // Add child into mothers children set
// Assign the mothers sex if it's currently unassigned
if(pIt->second.getSex() == "")
pIt->second.setSex("F");
}
} else if (in =="MOTHER") {
// If name exists, set name as pName's mother
// Else create person(name) and set pName's mother as person(name)
if((it = people.find(name)) != people.end()) {
pIt = people.find(pName);
// Make sure pName doesn't already have a mother
if (pIt->second.getMother() == nullptr){
// Make sure the mothers sex isn't male
if (it->second.getSex() == "F" || it->second.getSex() == "") {
pIt->second.setMother(&it->second);
it->second.addChild(&pIt->second);
it->second.setSex("F");
} else {
printf(FYEL("Warning["%s"]: "%s" is a male "), in.c_str(), name.c_str());
}
} else {
printf(FYEL("Warning["%s"]: "%s" already has a mother "), in.c_str(), pName.c_str());
}
} else {
pIt = people.find(pName);
// Make sure the pName doesn't already have a mother
if(pIt->second.getMother() == nullptr) {
// Create a new person
people.insert(pair<string, Person>(name, *new Person(name, "F")));
it = people.find(name);
pIt->second.setMother(&it->second); // Assign the newly created person as pNames mother
it->second.addChild(&pIt->second); // Add pName to the newly created persons children set
} else {
printf(FYEL("Warning["%s"]: "%s" already has a mother "), in.c_str(), pName.c_str());
}
}
} else if (in == "SEX") {
if((it = people.find(pName)) != people.end()) {
it->second.setSex(name);
}
} else {
printf(FRED("Error: input: "%s" name: "%s" pName: "%s" "), in.c_str(), name.c_str(), pName.c_str());
}
}
for (it = people.begin(); it != people.end(); it++) {
it->second.Print();
}
return 0;
}
Person.hpp
#ifndef Person_hpp
#define Person_hpp
#include <stdio.h>
#include <string>
#include <set>
#include <list>
#include "colors.h"
#endif /* Person_hpp */
using namespace std;
class Person {
public:
Person(string name, string sex);
void Print();
// Setters
void setName(string name);
void setSex(string sex);
void setFather(Person* father);
void setMother(Person* mother);
void addChild(Person* child);
// Getters
string getName();
string getSex();
Person* getFather();
Person* getMother();
private:
string name;
string sex;
Person* father;
Person* mother;
list<Person> children;
};
Person.cpp
// Eric Lange
// COMP 4472
#include "Person.hpp"
#include <iostream>
// Constructor
Person::Person(string name, string sex):
name(name),
sex(sex)
{}
// Getters
string Person::getName() {
return name;
}
string Person::getSex() {
return sex;
}
Person* Person::getFather() {
return father;
}
Person* Person::getMother() {
return mother;
}
// Setters
void Person::setName(string name) {
this->name = name;
}
void Person::setSex(string sex) {
this->sex = sex;
}
void Person::setFather(Person* father) {
this->father = father;
}
void Person::setMother(Person* mother){
this->mother = mother;
}
void Person::addChild(Person* child) {
children.push_back(*child);
}
void Person::Print() {
printf(FWHT(" %s "), name.c_str());
printf(FYEL(" Sex: "));
if(sex == "M") {
printf(FBLU("Male "));
} else if (sex == "F") {
printf(FMAG("Female "));
} else {
printf(FRED("unknown "));
}
printf(FYEL(" Father: "));
if(father == nullptr) {
printf(FRED("unknown "));
} else {
printf(FWHT("%s "), father->name.c_str());
}
printf(FYEL(" Mother: "));
if(mother == nullptr) {
printf(FRED("unknown "));
} else {
printf(FWHT("%s "), mother->name.c_str());
}
printf(FYEL(" Children: "));
if(children.empty()) {
printf(FRED("none "));
} else {
list<Person>::iterator it;
for(it = children.begin(); it != children.end(); it++) {
printf(FWHT("%s "), it->getName().c_str());
}
printf(" ");
}
}
colors.h
#ifndef _COLORS_
#define _COLORS_
/* FOREGROUND */
#define RST "[0m"
#define KRED "[31m"
#define KGRN "[32m"
#define KYEL "[33m"
#define KBLU "[34m"
#define KMAG "[35m"
#define KCYN "[36m"
#define KWHT "[37m"
#define FRED(x) KRED x RST
#define FGRN(x) KGRN x RST
#define FYEL(x) KYEL x RST
#define FBLU(x) KBLU x RST
#define FMAG(x) KMAG x RST
#define FCYN(x) KCYN x RST
#define FWHT(x) KWHT x RST
#define BOLD(x) "[1m" x RST
#define UNDL(x) "[4m" x RST
#endif /* _COLORS_ */
Related Questions
drjack9650@gmail.com
Navigate
Integrity-first tutoring: explanations and feedback only — we do not complete graded work. Learn more.