diff --git a/.gitignore b/.gitignore index 248ca2f..7e88db6 100644 --- a/.gitignore +++ b/.gitignore @@ -1,4 +1,7 @@ -build +bin .codelite *.workspace +GPATH +GRTAGS +GTAGS diff --git a/compile.sh b/compile.sh index eac8adb..958b69a 100755 --- a/compile.sh +++ b/compile.sh @@ -1,2 +1,2 @@ -g++ -o build/release/famt -std=gnu++20 -Ofast -flto -fipa-pta -fallow-store-data-races -fgcse-sm -fgcse-las -s -DNDEBUG *.cpp +g++ -o bin/release/famt -std=gnu++20 -Ofast -flto -fipa-pta -fallow-store-data-races -fgcse-sm -fgcse-las -s -DNDEBUG *.cpp diff --git a/compile_debug.sh b/compile_debug.sh index 2e5dac8..6bc7113 100755 --- a/compile_debug.sh +++ b/compile_debug.sh @@ -1,2 +1,2 @@ -g++ -o build/debug/famt -std=gnu++20 -g -Og -Wall *.cpp +g++ -o bin/debug/famt -std=gnu++20 -g -Og -Wall *.cpp -lncursesw diff --git a/help.cpp b/help.cpp index 3bb2f0e..e181713 100644 --- a/help.cpp +++ b/help.cpp @@ -1,69 +1,69 @@ -#include"help.h" -#include"tree.h" - -unsigned strLen(const char* str) -{ - unsigned len = 0; - for (; str[len] != '\0'; ++len) - ; - return len; -} - -void strCopy(char *to, const char* from) -{ - unsigned i = 0; - for (; from[i] != '\0'; ++i) - to[i] = from[i]; - to[i] = '\0'; -} - -bool strComp(const char* first, const char* second) -{ - for (unsigned i = 0; first[i] != '\0' || second[i] != '\0'; ++i) - { - if (first[i] != second[i]) - return 0; - } - return 1; -} - -char* mergeStr(const char* first, const char* second) //Create new string from 2 existing and return it -{ - char *result = new char[strLen(first) + strLen(second) + 1]; - unsigned j = 0; - for (unsigned i = 0; first[i] != '\0'; ++i, ++j) - result[j] = first[i]; - for (unsigned i = 0; second[i] != '\0'; ++i, ++j) - result[j] = second[i]; - result[j] = '\0'; - return result; -} - -Relation strToRel(const char* str) -{ - if (strComp(str, "Father")) - return Father; - else if (strComp(str, "Mother")) - return Mother; - else if (strComp(str, "Son")) - return Son; - else if (strComp(str, "Daughter")) - return Daughter; - else if (strComp(str, "Brother")) - return Brother; - else if (strComp(str, "Sister")) - return Sister; - else if (strComp(str, "HalfBrother")) - return HalfBrother; - else if (strComp(str, "HalfSister")) - return HalfSister; - else if (strComp(str, "Wife")) - return Wife; - else if (strComp(str, "Husband")) - return Husband; - else if (strComp(str, "ExWife")) - return ExWife; - else if (strComp(str, "ExHusband")) - return ExHusband; - return Invalid; -} \ No newline at end of file +#include"help.h" +#include"tree.h" + +unsigned strLen(const char* str) +{ + unsigned len = 0; + for (; str[len] != '\0'; ++len) + ; + return len; +} + +void strCopy(char *to, const char* from) +{ + unsigned i = 0; + for (; from[i] != '\0'; ++i) + to[i] = from[i]; + to[i] = '\0'; +} + +bool strComp(const char* first, const char* second) +{ + for (unsigned i = 0; first[i] != '\0' || second[i] != '\0'; ++i) + { + if (first[i] != second[i]) + return 0; + } + return 1; +} + +char* mergeStr(const char* first, const char* second) //Create new string from 2 existing and return it +{ + char *result = new char[strLen(first) + strLen(second) + 1]; + unsigned j = 0; + for (unsigned i = 0; first[i] != '\0'; ++i, ++j) + result[j] = first[i]; + for (unsigned i = 0; second[i] != '\0'; ++i, ++j) + result[j] = second[i]; + result[j] = '\0'; + return result; +} + +Relation strToRel(const char* str) +{ + if (strComp(str, "Father")) + return Father; + else if (strComp(str, "Mother")) + return Mother; + else if (strComp(str, "Son")) + return Son; + else if (strComp(str, "Daughter")) + return Daughter; + else if (strComp(str, "Brother")) + return Brother; + else if (strComp(str, "Sister")) + return Sister; + else if (strComp(str, "HalfBrother")) + return HalfBrother; + else if (strComp(str, "HalfSister")) + return HalfSister; + else if (strComp(str, "Wife")) + return Wife; + else if (strComp(str, "Husband")) + return Husband; + else if (strComp(str, "ExWife")) + return ExWife; + else if (strComp(str, "ExHusband")) + return ExHusband; + return Invalid; +} diff --git a/main.cpp b/main.cpp index ec7b99f..05e9c91 100644 --- a/main.cpp +++ b/main.cpp @@ -1,3 +1,4 @@ +#include #include #include "tree.h" #include "help.h" @@ -36,18 +37,22 @@ int main() test2.saveTree();*/ Tree firstTree("firstTree"); - firstTree.addPerson("Адам,", {0, 1, 6}, true); - firstTree.addPerson("Ева", {0, 1, 6}, false); + + firstTree.addPerson("Адам,", true, Nobody, Nobody, {0, 1, 6}); + firstTree.addPerson("Ева", false, Nobody, Nobody, {0, 1, 6}); firstTree.addRelation(0, Husband, 1); - firstTree.addPerson("Кайн", {}, true, 0, 1); - firstTree.addPerson("Авел", {}, true, 0, 1); - firstTree.addPerson("Сит", 230, true, 0, 1); + firstTree.addPerson("Кайн", true, 0, 1); + firstTree.addPerson("Авел", true, 0, 1); + firstTree.addPerson("Сит", true, 0, 1, 230); firstTree.addRelation(2, Brother, 3); firstTree.addRelation(2, Brother, 4); firstTree.print(); firstTree.saveTree(); + + firstTree.printRel(3); + firstTree.printOldestAncestors(3); Array trees; @@ -127,11 +132,11 @@ int main() break; case 4: //addPerson std::cin >> name >> day >> month >> year >> sex; - trees[curTree].addPerson(name, EventTime(year, month, day) , sex); + trees[curTree].addPerson(name, sex, Nobody, Nobody, EventTime(year, month, day)); break; case 5: //addPersonWP std::cin >> name >> day >> month >> year >> sex >> father >> mother; - trees[curTree].addPerson(name, EventTime(year, month, day), sex, father, mother); + trees[curTree].addPerson(name, sex, father, mother, EventTime(year, month, day)); break; case 6: //addRelation std::cin >> name >> input >> secondName; diff --git a/person.cpp b/person.cpp index c57d6df..6dc9f13 100644 --- a/person.cpp +++ b/person.cpp @@ -1,11 +1,11 @@ #include #include -#include"person.h" +#include"person.h" #include "help.h" -using std::cout; - +using std::cout; + EventTime::EventTime(I16 Year, U8 Month, U16 Day, I8 Hour, I8 Minute) : year(Year) , month(Month) @@ -18,7 +18,6 @@ EventTime::EventTime(I16 Year, U8 Month, U16 Day, I8 Hour, I8 Minute) void EventTime::print() const { - cout << "Birth: "; if (day != UNKNOWN_DATE) cout << (I32)day; else @@ -37,76 +36,84 @@ void EventTime::print() const cout << "????"; cout << '\n'; } - - -Person::Person(const char* Name, EventTime Birth, bool IsMale) - : name(Name) - , numRel(0) - , birth(Birth) - , isMale(IsMale) -{ -} - - -/*Person& Person::operator=(const Person &other) -{ - if (&other!=this) - { - rename(other.name); - numRel = other.numRel; - isMale = other.isMale; - day = other.day; - month = other.month; - year = other.year; - } - return *this; -}*/ - - -bool Person::operator==(const Person &other)const -{ - return name == other.name && isMale == other.isMale; //TODO && day == other.day || !day || !other.day) && (month == other.month || !month || !other.month) && (year == other.year || !year || !other.year); -} - - -void Person::save(std::ofstream &file)const -{ - // - char nameLen = name.size(); - file.write(reinterpret_cast(&nameLen), sizeof(nameLen)); - file.write(name.data(), nameLen * sizeof(name[0])); - file.write(reinterpret_cast(&numRel), sizeof(numRel)); - file.write(reinterpret_cast(&isMale), sizeof(isMale)); - //file.write(reinterpret_cast(&day), sizeof(day)); TODO - //file.write(reinterpret_cast(&month), sizeof(month)); - //file.write(reinterpret_cast(&year), sizeof(year)); -} - -void Person::load(std::ifstream &file) -{ - char nameLen; - file.read((char*)&nameLen, sizeof(nameLen)); //Check len - - C8 nameBuf[128]; - file.read(nameBuf, nameLen * sizeof(*nameBuf)); + + +Person::Person(const char* name, EventTime birth, bool isMale, EventTime death) + : name_(name) + , numRel_(0) + , birth_(birth) + , isMale_(isMale) + , death_(death) +{ +} + + +/*Person& Person::operator=(const Person &other) +{ + if (&other!=this) + { + rename(other.name); + numRel = other.numRel; + isMale = other.isMale; + day = other.day; + month = other.month; + year = other.year; + } + return *this; +}*/ + + +bool Person::operator==(const Person &other)const +{ + return name_ == other.name_ && isMale_ == other.isMale_; //TODO && day == other.day || !day || !other.day) && (month == other.month || !month || !other.month) && (year == other.year || !year || !other.year); +} + + +void Person::save(std::ofstream &file)const +{ + // + char nameLen = name_.size(); + file.write(reinterpret_cast(&nameLen), sizeof(nameLen)); + file.write(name_.data(), nameLen * sizeof(name_[0])); + file.write(reinterpret_cast(&numRel_), sizeof(numRel_)); + file.write(reinterpret_cast(&isMale_), sizeof(isMale_)); + //file.write(reinterpret_cast(&day), sizeof(day)); TODO + //file.write(reinterpret_cast(&month), sizeof(month)); + //file.write(reinterpret_cast(&year), sizeof(year)); +} + +void Person::load(std::ifstream &file) +{ + char nameLen; + file.read((char*)&nameLen, sizeof(nameLen)); //Check len + + C8 nameBuf[128]; + file.read(nameBuf, nameLen * sizeof(*nameBuf)); nameBuf[nameLen] = '\0'; - name = nameBuf; - - file.read(reinterpret_cast(&numRel), sizeof(numRel)); - file.read(reinterpret_cast(&isMale), sizeof(isMale)); - //file.read(reinterpret_cast(&day), sizeof(day)); TODO - //file.read(reinterpret_cast(&month), sizeof(month)); - //file.read(reinterpret_cast(&year), sizeof(year)); -} - -void Person::rename(const char* newName) -{ - name = newName; -} - -void Person::print()const -{ - std::cout << name << '\n'; - birth.print(); - std::cout << (isMale ? "Male\n\n" : "Female\n\n"); -} + name_ = nameBuf; + + file.read(reinterpret_cast(&numRel_), sizeof(numRel_)); + file.read(reinterpret_cast(&isMale_), sizeof(isMale_)); + //file.read(reinterpret_cast(&day), sizeof(day)); TODO + //file.read(reinterpret_cast(&month), sizeof(month)); + //file.read(reinterpret_cast(&year), sizeof(year)); +} + +void Person::rename(const char* newName) +{ + name_ = newName; +} + +void Person::print()const +{ + cout << name_ << '\n'; + cout << (isMale_ ? "Male\n" : "Female\n"); + + cout << "Birth: "; + birth_.print(); + + cout << "Death: "; //TODO: only print if known + death_.print(); + + cout << '\n'; +} diff --git a/person.h b/person.h index a5bdfc0..c985280 100644 --- a/person.h +++ b/person.h @@ -24,7 +24,7 @@ class Person public: Person() = default; - Person(const char* Name, EventTime Birth, bool Sex); + Person(const char* name, EventTime birth, bool sex, EventTime death); bool operator==(const Person &other)const; @@ -36,9 +36,9 @@ public: friend class Tree; private: - std::string name; - unsigned numRel; //Number of close relatives - mother, father, brother, sister, wife/husband, child, ex-wife/husband - EventTime birth; - bool isMale; - EventTime death; + std::string name_; + unsigned numRel_; //Number of close relatives - mother, father, brother, sister, wife/husband, child, ex-wife/husband + EventTime birth_; + bool isMale_; + EventTime death_; }; diff --git a/tree.cpp b/tree.cpp index c2873ac..7482861 100644 --- a/tree.cpp +++ b/tree.cpp @@ -1,446 +1,446 @@ -#include -#include -#include"tree.h" -#include"person.h" +#include +#include +#include"tree.h" +#include"person.h" #include"help.h" -using std::cout; - - +using std::cout; + + Tree::Tree() - : treeName("Unnamed") - , numPeople(0) -{} - -Tree Tree::operator+ (const Tree& other)// -{ - Tree result(treeName + other.treeName); //The tree resulting from the addition - unsigned *newId = new unsigned[other.numPeople]; //The indexes members of the II tree will have in result - - unsigned idCounter = numPeople; - for (unsigned i = 0, j; i < other.numPeople; ++i) //Searches for people present in both trees and gives them the same index in result - { - for (j = 0; j < numPeople; ++j) - { - if (other.people[i] == people[j]) - { - newId[i] = j; - break; - } - } - if (j >= numPeople) - newId[i] = ++idCounter; - } - result.numPeople = idCounter; //The number of members the resulting tree has - - result.people.resize(result.numPeople); - result.people = people; //Adds the members of the I tree to the resulting tree - for (unsigned i=0; i < other.numPeople; ++i) //Adds the members of the II tree to the resulting tree - { - if (newId[i] >= numPeople) - result.people.push(other.people[i]); - } - - result.relatives.resize(result.numPeople); - result.relations.resize(result.numPeople); - result.relatives = relatives; - result.relations = relations; - - for (unsigned i=0; i < other.numPeople; ++i) //Adds the relatives from the II tree - { - if (newId[i] >= numPeople) //If the member is found in the II tree but not in the I - { - result.relatives.push(other.relatives[i]); - result.relations.push(other.relations[i]); - } - else //If he's found in both - { - for (unsigned j = 0; j < other.people[i].numRel; ++j) //Adds the number of relatives from the II to the number in the I - { - if(newId[other.relatives[i][j]] > numPeople) - ++result.people[newId[i]].numRel; - } - - result.relatives[newId[i]].resize(result.people[newId[i]].numRel); - result.relations[newId[i]].resize(result.people[newId[i]].numRel); - - result.relatives[newId[i]] = relatives[newId[i]]; - result.relations[newId[i]] = relations[newId[i]]; - result.relatives[newId[i]] += other.relatives[i]; //The relatives from the II tree - result.relations[newId[i]] += other.relations[i]; - } - } - - delete[]newId; - return result; -} - -Tree& Tree::operator+=(const Tree& other) -{ - unsigned *newId = new unsigned[other.numPeople]; //The indexes people from II tree will have in I tree - - unsigned idCounter = numPeople; - for (unsigned i = 0, j; i < other.numPeople; ++i) //Searches for people present in both trees and gives them the same index in I - { - for (j = 0; j < numPeople; ++j) - { - if (other.people[i] == people[j]) - { - newId[i] = j; - break; - } - } - if (j >= numPeople) - newId[i] = idCounter++; - } - - people.resize(idCounter); - for (unsigned i = 0; i < other.numPeople; ++i) //Adds the member personal data of II tree to I tree - { - if (newId[i] >= numPeople) - people.push(other.people[i]); - } - - relatives.resize(idCounter); - relations.resize(idCounter); - for (unsigned i = 0; i < other.numPeople; ++i) //Merges the relative data - { - if (newId[i] >= numPeople) - { - relatives.push(other.relatives[i]); - for (unsigned j = 0; j < other.people[i].numRel; ++j) - relatives[newId[i]][j] = newId[ relatives[newId[i]][j] ]; - relations.push(other.relations[i]); - } - else //If the member is present in both trees - { - for (unsigned j = 0; j < other.people[i].numRel; ++j) //Adds the number of relatives from the II to the number in the I - { - if (newId[other.relatives[i][j]] >= numPeople) - ++people[newId[i]].numRel; - } - relatives[newId[i]].resize(people[newId[i]].numRel); - relations[newId[i]].resize(people[newId[i]].numRel); - for (unsigned j = 0; j < other.people[i].numRel; ++j) - { - relatives[newId[i]][j + people[newId[i]].numRel - other.people[i].numRel] = newId[other.relatives[i][j]]; - relations[newId[i]][j + people[newId[i]].numRel - other.people[i].numRel] = other.relations[i][j]; - } - } - } - - delete[]newId; - numPeople = idCounter; //Number of members in I tree - return *this; -} - -Tree& Tree::operator-= (const Tree& other) -{ - for (unsigned i = 0; i < numPeople; ++i) - { - for (unsigned j = 0; j < other.numPeople; ++j) - { - if (people[i] == other.people[j]) - { - removePerson(i); - --i; - break; - } - } - } - return *this; -} - - - -void Tree::rename(const char* newName) -{ - treeName = newName; -} - -unsigned Tree::findId(const char* name, const short year, const unsigned char month, const unsigned char day)const + : treeName("Unnamed") + , numPeople(0) +{} + +Tree Tree::operator+ (const Tree& other)// { - //TODO - //Person sought(name, day, month, year,) - for (unsigned i = 0; i < numPeople; ++i) - { - if (name == people[i].name) //&& (year == people[i].year || !year || !people[i].year) && (month == people[i].month || !month || !people[i].month) && (day == people[i].day || !day || people[i].day)) - return i; - } - return Nobody; -} - -unsigned Tree::findOldestAncestor(const unsigned &id, const bool &isMale)const -{ - for (unsigned i = 0; i < people[id].numRel; ++i) - { - if (relations[id][i] == Son && people[ relatives[id][i] ].isMale == isMale) - return findOldestAncestor(relatives[id][i], isMale); - } - return id; -} - -unsigned Tree::findCommonAncestor(const unsigned firstId, const unsigned secondId)const -{ - Array visited(numPeople); //if a member is visited twice he's a common ancestor - for (unsigned i = 0; i < numPeople; ++i) - visited[i] = 0; - commonAncestorRec(firstId, visited); - commonAncestorRec(secondId, visited); - - unsigned oldestId = Nobody; - U16 oldestBday = SHRT_MAX; - for (unsigned i = 0; i < numPeople; ++i) - { - if (visited[i] == 2 && people[i].birth.year(&numPeople), sizeof(numPeople)); - for (unsigned i = 0; i < numPeople; ++i) - people[i].save(peopleFile); - peopleFile.close(); - - std::ofstream relativeFile(treeName + ".relatives", std::ios::binary); - std::ofstream relationFile(treeName + ".relations", std::ios::binary); - - /*relativeFile.write((char*)&numPeople, sizeof(numPeople)); - relationFile.write((char*)&numPeople, sizeof(numPeople));*/ - for (unsigned i = 0; i < numPeople; ++i) - { - //relativeFile.write((char*)&people[i].numRel, sizeof(people[i].numRel)); - for (unsigned j = 0; j < people[i].numRel; ++j) - relativeFile.write(reinterpret_cast(&relatives[i][j]), sizeof(relatives[i][j])); - - //relationFile.write((char*)&people[i].numRel, sizeof(people[i].numRel)); - for (unsigned j = 0; j < people[i].numRel; ++j) - relationFile.write(reinterpret_cast(&relations[i][j]), sizeof(relations[i][j])); - } - relativeFile.close(); - relationFile.close(); -} - -bool Tree::loadTree() -{ - std::ifstream peopleFile(treeName + ".people", std::ios::binary); - if (peopleFile.peek() == std::char_traits::eof()) - { - peopleFile.close(); - return 0; - } - - peopleFile.read(reinterpret_cast(&numPeople), sizeof(numPeople)); - people.resize(numPeople); - for (unsigned i = 0; i < numPeople; ++i) - people[i].load(peopleFile); - people.sNum(numPeople); - peopleFile.close(); - - std::ifstream relativeFile(treeName + ".relatives", std::ios::binary); - std::ifstream relationFile(treeName + ".relations", std::ios::binary); - - relatives.resize(numPeople); - relations.resize(numPeople); - for (unsigned i = 0; i < numPeople; ++i) - { - relatives[i].resize(people[i].numRel); - for (unsigned j = 0; j < people[i].numRel; ++j) - relativeFile.read(reinterpret_cast(&relatives[i][j]), sizeof(relatives[i][j])); - relatives[i].sNum(people[i].numRel); - - relations[i].resize(people[i].numRel); - for (unsigned j = 0; j < people[i].numRel; ++j) - relationFile.read(reinterpret_cast(&relations[i][j]), sizeof(relations[i][j])); - relations[i].sNum(people[i].numRel); - } - relatives.sNum(numPeople); - relations.sNum(numPeople); - relativeFile.close(); - relationFile.close(); - return 1; -} - -void Tree::addPerson(const char *name, EventTime birth, bool isMale, unsigned father, unsigned mother) -{ - Person newPerson(name, birth, isMale); - people.push(newPerson); - Array newRelative; - relatives.push(newRelative); - Array newRelation; - relations.push(newRelation); - ++numPeople; - addRelation(father, Father, numPeople - 1); - addRelation(mother, Mother, numPeople - 1); -} - -bool Tree::addRelation(const char* firstName, const Relation type, const char* secondName) -{ - - return addRelation(findId(firstName), type, findId(secondName)); -} - -bool Tree::addRelation(const unsigned firstId, const Relation type, const unsigned secondId, bool opposite)// -{ - if (firstId == Nobody || firstId >= numPeople || secondId == Nobody || secondId >= numPeople || type == Invalid) - return 0; - - unsigned i = 0; - for (; i < people[firstId].numRel; ++i) //If they are already relatives - { - if (relatives[firstId][i] == secondId) - { - relations[firstId][i] = type; - break; - } - } - if (i >= people[firstId].numRel) - { - relatives[firstId].push(secondId); - relations[firstId].push(type); - ++people[firstId].numRel; - } - - if (!opposite) - { - if (people[secondId].isMale) - { - switch (type) - { - case Father: - case Mother: - addRelation(secondId, Son, firstId, 1); - break; - case Son: - case Daughter: - addRelation(secondId, Father, firstId, 1); - break; - case Brother: - case Sister: - addRelation(secondId, Brother, firstId, 1); - break; - case HalfBrother: - case HalfSister: - addRelation(secondId, HalfBrother, firstId, 1); - break; - case Wife: - addRelation(secondId, Husband, firstId, 1); - break; - case ExWife: - addRelation(secondId, ExHusband, firstId, 1); - break; - } - } - else - { - switch (type) - { - case Father: - case Mother: - addRelation(secondId, Daughter, firstId, 1); - break; - case Son: - case Daughter: - addRelation(secondId, Mother, firstId, 1); - break; - case Brother: - case Sister: - addRelation(secondId, Sister, firstId, 1); - break; - case HalfBrother: - case HalfSister: - addRelation(secondId, HalfSister, firstId, 1); - break; - case Husband: - addRelation(secondId, Wife, firstId, 1); - break; - case ExHusband: - addRelation(secondId, ExWife, firstId, 1); - break; - } - } - } - return 1; -} - -void Tree::removeRelation(const char* firstName, const char* secondName) -{ - removeRelation(findId(firstName), findId(secondName)); -} - -void Tree::removePerson(const unsigned id) -{ - unsigned relId; //Íoìåð íà òåêóùèÿ ðîäíèíàòà - for (unsigned i = 0; i < people[id].numRel; ++i) //Ïðåìàõâàò ñå âðúçêèòå íà ÷ëåíà çà ïðåìàõâàíå - { - relId = relatives[id][i]; - for (unsigned j = 0; j < people[relId].numRel; ++j) - { - if (relatives[relId][j] == id) - { - relatives[relId].remove(j); - relations[relId].remove(j); - break; - } - } - --people[relId].numRel; - } - for (unsigned i = 0; i < people[numPeople - 2].numRel; ++i) //Ïîñëåäíèÿò ÷ëåí âçåìà íîìåðà íà ïðåìàõíàòèÿ - { - relId = relatives[numPeople - 1][i]; - for (unsigned j = 0; j < people[relId].numRel; ++j) - { - if (relatives[relId][j] == numPeople - 1) - { - relatives[relId][j] = id; - break; - } - } - } - relatives.remove(id); - relations.remove(id); - people.remove(id); - --numPeople; -} - -void Tree::removePerson(const char* personName, const short year, const unsigned char month, const unsigned char day) -{ - removePerson(findId(personName, year, month, day)); -} - -void Tree::removeRelation(const unsigned firstId, const unsigned secondId) -{ - for (unsigned i = 0; i < people[firstId].numRel; ++i) - { - if (relatives[firstId][i] == secondId) - { - relatives[firstId].remove(i); - relations[firstId].remove(i); - --people[firstId].numRel; - break; - } - } - for (unsigned i = 0; i < people[secondId].numRel; ++i) - { - if (relatives[secondId][i] == firstId) - { - relatives[secondId].remove(i); - relations[secondId].remove(i); - --people[secondId].numRel; - break; - } - } -} - - + Tree result(treeName + other.treeName); //The tree resulting from the addition + unsigned *newId = new unsigned[other.numPeople]; //The indexes members of the II tree will have in result + + unsigned idCounter = numPeople; + for (unsigned i = 0, j; i < other.numPeople; ++i) //Searches for people present in both trees and gives them the same index in result + { + for (j = 0; j < numPeople; ++j) + { + if (other.people[i] == people[j]) + { + newId[i] = j; + break; + } + } + if (j >= numPeople) + newId[i] = ++idCounter; + } + result.numPeople = idCounter; //The number of members the resulting tree has + + result.people.resize(result.numPeople); + result.people = people; //Adds the members of the I tree to the resulting tree + for (unsigned i=0; i < other.numPeople; ++i) //Adds the members of the II tree to the resulting tree + { + if (newId[i] >= numPeople) + result.people.push(other.people[i]); + } + + result.relatives.resize(result.numPeople); + result.relations.resize(result.numPeople); + result.relatives = relatives; + result.relations = relations; + + for (unsigned i=0; i < other.numPeople; ++i) //Adds the relatives from the II tree + { + if (newId[i] >= numPeople) //If the member is found in the II tree but not in the I + { + result.relatives.push(other.relatives[i]); + result.relations.push(other.relations[i]); + } + else //If he's found in both + { + for (unsigned j = 0; j < other.people[i].numRel_; ++j) //Adds the number of relatives from the II to the number in the I + { + if(newId[other.relatives[i][j]] > numPeople) + ++result.people[newId[i]].numRel_; + } + + result.relatives[newId[i]].resize(result.people[newId[i]].numRel_); + result.relations[newId[i]].resize(result.people[newId[i]].numRel_); + + result.relatives[newId[i]] = relatives[newId[i]]; + result.relations[newId[i]] = relations[newId[i]]; + result.relatives[newId[i]] += other.relatives[i]; //The relatives from the II tree + result.relations[newId[i]] += other.relations[i]; + } + } + + delete[]newId; + return result; +} + +Tree& Tree::operator+=(const Tree& other) +{ + unsigned *newId = new unsigned[other.numPeople]; //The indexes people from II tree will have in I tree + + unsigned idCounter = numPeople; + for (unsigned i = 0, j; i < other.numPeople; ++i) //Searches for people present in both trees and gives them the same index in I + { + for (j = 0; j < numPeople; ++j) + { + if (other.people[i] == people[j]) + { + newId[i] = j; + break; + } + } + if (j >= numPeople) + newId[i] = idCounter++; + } + + people.resize(idCounter); + for (unsigned i = 0; i < other.numPeople; ++i) //Adds the member personal data of II tree to I tree + { + if (newId[i] >= numPeople) + people.push(other.people[i]); + } + + relatives.resize(idCounter); + relations.resize(idCounter); + for (unsigned i = 0; i < other.numPeople; ++i) //Merges the relative data + { + if (newId[i] >= numPeople) + { + relatives.push(other.relatives[i]); + for (unsigned j = 0; j < other.people[i].numRel_; ++j) + relatives[newId[i]][j] = newId[ relatives[newId[i]][j] ]; + relations.push(other.relations[i]); + } + else //If the member is present in both trees + { + for (unsigned j = 0; j < other.people[i].numRel_; ++j) //Adds the number of relatives from the II to the number in the I + { + if (newId[other.relatives[i][j]] >= numPeople) + ++people[newId[i]].numRel_; + } + relatives[newId[i]].resize(people[newId[i]].numRel_); + relations[newId[i]].resize(people[newId[i]].numRel_); + for (unsigned j = 0; j < other.people[i].numRel_; ++j) + { + relatives[newId[i]][j + people[newId[i]].numRel_ - other.people[i].numRel_] = newId[other.relatives[i][j]]; + relations[newId[i]][j + people[newId[i]].numRel_ - other.people[i].numRel_] = other.relations[i][j]; + } + } + } + + delete[]newId; + numPeople = idCounter; //Number of members in I tree + return *this; +} + +Tree& Tree::operator-= (const Tree& other) +{ + for (unsigned i = 0; i < numPeople; ++i) + { + for (unsigned j = 0; j < other.numPeople; ++j) + { + if (people[i] == other.people[j]) + { + removePerson(i); + --i; + break; + } + } + } + return *this; +} + + + +void Tree::rename(const char* newName) +{ + treeName = newName; +} + +unsigned Tree::findId(const char* name, const short year, const unsigned char month, const unsigned char day)const +{ + //TODO + //Person sought(name, day, month, year,) + for (unsigned i = 0; i < numPeople; ++i) + { + if (name == people[i].name_) //&& (year == people[i].year || !year || !people[i].year) && (month == people[i].month || !month || !people[i].month) && (day == people[i].day || !day || people[i].day)) + return i; + } + return Nobody; +} + +unsigned Tree::findOldestAncestor(const unsigned &id, const bool &isMale)const +{ + for (unsigned i = 0; i < people[id].numRel_; ++i) + { + if (relations[id][i] == Son && people[ relatives[id][i] ].isMale_ == isMale) + return findOldestAncestor(relatives[id][i], isMale); + } + return id; +} + +unsigned Tree::findCommonAncestor(const unsigned firstId, const unsigned secondId)const +{ + Array visited(numPeople); //if a member is visited twice he's a common ancestor + for (unsigned i = 0; i < numPeople; ++i) + visited[i] = 0; + commonAncestorRec(firstId, visited); + commonAncestorRec(secondId, visited); + + unsigned oldestId = Nobody; + U16 oldestBday = SHRT_MAX; + for (unsigned i = 0; i < numPeople; ++i) + { + if (visited[i] == 2 && people[i].birth_.year < oldestBday) + { + oldestBday = people[i].birth_.year; + oldestId = i; + } + } + return oldestId; +} + +void Tree::saveTree() const +{ + std::ofstream peopleFile(treeName+ ".people", std::ios::binary); + + peopleFile.write(reinterpret_cast(&numPeople), sizeof(numPeople)); + for (unsigned i = 0; i < numPeople; ++i) + people[i].save(peopleFile); + peopleFile.close(); + + std::ofstream relativeFile(treeName + ".relatives", std::ios::binary); + std::ofstream relationFile(treeName + ".relations", std::ios::binary); + + /*relativeFile.write((char*)&numPeople, sizeof(numPeople)); + relationFile.write((char*)&numPeople, sizeof(numPeople));*/ + for (unsigned i = 0; i < numPeople; ++i) + { + //relativeFile.write((char*)&people[i].numRel_, sizeof(people[i].numRel_)); + for (unsigned j = 0; j < people[i].numRel_; ++j) + relativeFile.write(reinterpret_cast(&relatives[i][j]), sizeof(relatives[i][j])); + + //relationFile.write((char*)&people[i].numRel_, sizeof(people[i].numRel_)); + for (unsigned j = 0; j < people[i].numRel_; ++j) + relationFile.write(reinterpret_cast(&relations[i][j]), sizeof(relations[i][j])); + } + relativeFile.close(); + relationFile.close(); +} + +bool Tree::loadTree() +{ + std::ifstream peopleFile(treeName + ".people", std::ios::binary); + if (peopleFile.peek() == std::char_traits::eof()) + { + peopleFile.close(); + return 0; + } + + peopleFile.read(reinterpret_cast(&numPeople), sizeof(numPeople)); + people.resize(numPeople); + for (unsigned i = 0; i < numPeople; ++i) + people[i].load(peopleFile); + people.sNum(numPeople); + peopleFile.close(); + + std::ifstream relativeFile(treeName + ".relatives", std::ios::binary); + std::ifstream relationFile(treeName + ".relations", std::ios::binary); + + relatives.resize(numPeople); + relations.resize(numPeople); + for (unsigned i = 0; i < numPeople; ++i) + { + relatives[i].resize(people[i].numRel_); + for (unsigned j = 0; j < people[i].numRel_; ++j) + relativeFile.read(reinterpret_cast(&relatives[i][j]), sizeof(relatives[i][j])); + relatives[i].sNum(people[i].numRel_); + + relations[i].resize(people[i].numRel_); + for (unsigned j = 0; j < people[i].numRel_; ++j) + relationFile.read(reinterpret_cast(&relations[i][j]), sizeof(relations[i][j])); + relations[i].sNum(people[i].numRel_); + } + relatives.sNum(numPeople); + relations.sNum(numPeople); + relativeFile.close(); + relationFile.close(); + return 1; +} + +void Tree::addPerson(const char* name, bool isMale, unsigned father, unsigned mother, EventTime birth, EventTime death) +{ + Person newPerson(name, birth, isMale, death); + people.push(newPerson); + Array newRelative; + relatives.push(newRelative); + Array newRelation; + relations.push(newRelation); + ++numPeople; + addRelation(father, Father, numPeople - 1); + addRelation(mother, Mother, numPeople - 1); +} + +bool Tree::addRelation(const char* firstName, const Relation type, const char* secondName) +{ + + return addRelation(findId(firstName), type, findId(secondName)); +} + +bool Tree::addRelation(const unsigned firstId, const Relation type, const unsigned secondId, bool opposite)// +{ + if (firstId == Nobody || firstId >= numPeople || secondId == Nobody || secondId >= numPeople || type == Invalid) + return 0; + + unsigned i = 0; + for (; i < people[firstId].numRel_; ++i) //If they are already relatives + { + if (relatives[firstId][i] == secondId) + { + relations[firstId][i] = type; + break; + } + } + if (i >= people[firstId].numRel_) + { + relatives[firstId].push(secondId); + relations[firstId].push(type); + ++people[firstId].numRel_; + } + + if (!opposite) + { + if (people[secondId].isMale_) + { + switch (type) + { + case Father: + case Mother: + addRelation(secondId, Son, firstId, 1); + break; + case Son: + case Daughter: + addRelation(secondId, Father, firstId, 1); + break; + case Brother: + case Sister: + addRelation(secondId, Brother, firstId, 1); + break; + case HalfBrother: + case HalfSister: + addRelation(secondId, HalfBrother, firstId, 1); + break; + case Wife: + addRelation(secondId, Husband, firstId, 1); + break; + case ExWife: + addRelation(secondId, ExHusband, firstId, 1); + break; + } + } + else + { + switch (type) + { + case Father: + case Mother: + addRelation(secondId, Daughter, firstId, 1); + break; + case Son: + case Daughter: + addRelation(secondId, Mother, firstId, 1); + break; + case Brother: + case Sister: + addRelation(secondId, Sister, firstId, 1); + break; + case HalfBrother: + case HalfSister: + addRelation(secondId, HalfSister, firstId, 1); + break; + case Husband: + addRelation(secondId, Wife, firstId, 1); + break; + case ExHusband: + addRelation(secondId, ExWife, firstId, 1); + break; + } + } + } + return 1; +} + +void Tree::removeRelation(const char* firstName, const char* secondName) +{ + removeRelation(findId(firstName), findId(secondName)); +} + +void Tree::removePerson(const unsigned id) +{ + unsigned relId; //Íoìåð íà òåêóùèÿ ðîäíèíàòà + for (unsigned i = 0; i < people[id].numRel_; ++i) //Ïðåìàõâàò ñå âðúçêèòå íà ÷ëåíà çà ïðåìàõâàíå + { + relId = relatives[id][i]; + for (unsigned j = 0; j < people[relId].numRel_; ++j) + { + if (relatives[relId][j] == id) + { + relatives[relId].remove(j); + relations[relId].remove(j); + break; + } + } + --people[relId].numRel_; + } + for (unsigned i = 0; i < people[numPeople - 2].numRel_; ++i) //Ïîñëåäíèÿò ÷ëåí âçåìà íîìåðà íà ïðåìàõíàòèÿ + { + relId = relatives[numPeople - 1][i]; + for (unsigned j = 0; j < people[relId].numRel_; ++j) + { + if (relatives[relId][j] == numPeople - 1) + { + relatives[relId][j] = id; + break; + } + } + } + relatives.remove(id); + relations.remove(id); + people.remove(id); + --numPeople; +} + +void Tree::removePerson(const char* personName, const short year, const unsigned char month, const unsigned char day) +{ + removePerson(findId(personName, year, month, day)); +} + +void Tree::removeRelation(const unsigned firstId, const unsigned secondId) +{ + for (unsigned i = 0; i < people[firstId].numRel_; ++i) + { + if (relatives[firstId][i] == secondId) + { + relatives[firstId].remove(i); + relations[firstId].remove(i); + --people[firstId].numRel_; + break; + } + } + for (unsigned i = 0; i < people[secondId].numRel_; ++i) + { + if (relatives[secondId][i] == firstId) + { + relatives[secondId].remove(i); + relations[secondId].remove(i); + --people[secondId].numRel_; + break; + } + } +} + + void Tree::print() const { //for(const auto& member: people) @@ -448,85 +448,86 @@ void Tree::print() const for(int i=0; i &visited)const -{ - for (unsigned i = 0; i < people[id].numRel; ++i) - { - if (relations[id][i] == Son) - { - ++visited[relatives[id][i]]; - commonAncestorRec(relatives[id][i], visited); - } - } -} + +void Tree::printRel(const unsigned id)const +{ + cout << people[id].name_; + if (people[id].numRel_ == 0) + cout << " has no known relatives"; + else + { + unsigned relId; + cout << "'s relatives:\n"; + for (unsigned i = 0; i < people[id].numRel_; ++i) + { + relId = relatives[id][i]; + cout << people[relId].name_ << " - "; + + switch (relations[id][i]) + { + case Father: + case Mother: + cout << (people[relId].isMale_ ? "son" : "daughter"); + break; + case Son: + case Daughter: + cout << (people[relId].isMale_ ? "father" : "mother"); + break; + case Brother: + case Sister: + cout << (people[relId].isMale_ ? "brother" : "sister"); + break; + case HalfBrother: + case HalfSister: + cout << (people[relId].isMale_ ? "half brother" : "half sister"); + break; + case Husband: + cout << "wife"; + break; + case Wife: + cout << "husband"; + break; + case ExHusband: + cout << "ex-wife\n"; + break; + case ExWife: + cout << "ex-husband\n"; + break; + } + cout << '\n'; + } + cout << '\n'; + } +} + +void Tree::printMember(const unsigned id)const +{ + people[id].print(); +} + +void Tree::printOldestAncestors(const unsigned id)const +{ + people[findOldestAncestor(id)].print(); + people[findOldestAncestor(id, 1)].print(); +} + + + +unsigned Tree::gNumP()const +{ + return numPeople; +} + + + +void Tree::commonAncestorRec(const unsigned &id, const Array &visited)const +{ + for (unsigned i = 0; i < people[id].numRel_; ++i) + { + if (relations[id][i] == Son) + { + ++visited[relatives[id][i]]; + commonAncestorRec(relatives[id][i], visited); + } + } +} diff --git a/tree.h b/tree.h index b962083..b1cfa08 100644 --- a/tree.h +++ b/tree.h @@ -46,7 +46,7 @@ public: void saveTree()const;// bool loadTree(); - void addPerson(const char *name, EventTime birth, bool isMale, unsigned father = Nobody, unsigned mother = Nobody); + void addPerson(const char* name, bool isMale, unsigned father=Nobody, unsigned mother=Nobody, EventTime birth={}, EventTime death={}); bool addRelation(const char* firstName, const Relation, const char* secondName); //Adds a new relation or edits an old one. 0 - failure 1 - success bool addRelation(const unsigned firstId, const Relation, const unsigned secondId, bool opposite=0); //0 - failure 1 - success