commit fbfe017284ba2b4b56118c657dd50bc36b4447f2 Author: Venelin Date: Sat Aug 20 15:43:58 2022 +0300 rename files, sex- diff --git a/array.h b/array.h new file mode 100644 index 0000000..8113450 --- /dev/null +++ b/array.h @@ -0,0 +1,152 @@ +#pragma once +#include + +template +class Array +{ +private: + unsigned size, num; //Size and number of elements + T* arr; + + void copy(const Array &other); +public: + + + Array(); + Array(unsigned S); + // + Array& operator=(const Array &other); + ~Array(); + + void resize(unsigned toAdd = 0); + unsigned gSize()const; + unsigned gNum()const; + void sNum(unsigned); + void push(const T&); + void remove(const unsigned id); + + T& operator[](const unsigned i); + T& operator[](const unsigned i)const; + Array& operator+=(const Array &other); +}; + + + +template +Array::Array() : + size(0), + num(0), + arr(nullptr) +{} + +template +Array::Array(unsigned S) : + size(S), + num(0) +{ + arr = new T[S]; +} + +template +Array& Array::operator=(const Array &other) +{ + copy(other); + return *this; +} + +template +Array::~Array() +{ + delete[] arr; +} + + + +template +void Array::resize(unsigned toAdd) +{ + toAdd = toAdd ? toAdd : size / 2; + T *temp = new T[num]; + for (unsigned i = 0; i < num; ++i) + temp[i] = arr[i]; + delete[] arr; + arr = new T[size + toAdd + 1]; + for (unsigned i = 0; i < num; ++i) + arr[i]=temp[i]; + size += toAdd + 1; + delete[] temp; +} + +template +unsigned Array::gSize()const +{ + return size; +} + +template +unsigned Array::gNum()const +{ + return num; +} + +template +void Array::sNum(unsigned newNum) +{ + num = newNum; +} + +template +void Array::copy(const Array &other) +{ + if (size < other.num) + { + delete[] arr; + arr = new T[other.num]; + size = other.num; + } + for (unsigned i = 0; i < other.num; ++i) + arr[i] = other.arr[i]; + num = other.num; +} + +template +void Array::push(const T& newEl) +{ + if (num >= size) + resize(); + arr[num] = newEl; + ++num; +} + +template +void Array::remove(const unsigned id) +{ + --num; + arr[id] = arr[num]; +} + + + +template +T& Array::operator[](const unsigned i) +{ + return arr[i]; +} + +template +T& Array::operator[](const unsigned i)const +{ + return arr[i]; +} + +template +Array& Array::operator+=(const Array &other) +{ + if (size < other.num + num) + resize(other.num); + unsigned i = 0; + for (; i < other.num; ++i) + arr[num + i] = other.arr[i]; + num += i; + return *this; +} \ No newline at end of file diff --git a/common/basicTypes.h b/common/basicTypes.h new file mode 100644 index 0000000..a2da5c4 --- /dev/null +++ b/common/basicTypes.h @@ -0,0 +1,16 @@ +#pragma once + +#include + +typedef char C8; + +typedef int8_t I8; +typedef uint8_t U8; +typedef int16_t I16; +typedef uint16_t U16; +typedef int32_t I32; +typedef uint32_t U32; +typedef int64_t I64; +typedef uint64_t U64; + + diff --git a/compile.sh b/compile.sh new file mode 100755 index 0000000..3023111 --- /dev/null +++ b/compile.sh @@ -0,0 +1 @@ +g++ -Ofast -flto -fipa-pta -s *.cpp\ diff --git a/compile_debug.sh b/compile_debug.sh new file mode 100755 index 0000000..5d0e44d --- /dev/null +++ b/compile_debug.sh @@ -0,0 +1 @@ +g++ *.cpp diff --git a/help.cpp b/help.cpp new file mode 100644 index 0000000..3bb2f0e --- /dev/null +++ b/help.cpp @@ -0,0 +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 diff --git a/help.h b/help.h new file mode 100644 index 0000000..e53773d --- /dev/null +++ b/help.h @@ -0,0 +1,9 @@ +#pragma once + +enum Relation : char; + +unsigned strLen(const char* str); +void strCopy(char *to, const char* from); +bool strComp(const char* firts, const char* second); //0 - diffrent 1 - same +char* mergeStr(const char* first, const char* second); +Relation strToRel(const char* str); \ No newline at end of file diff --git a/main.cpp b/main.cpp new file mode 100644 index 0000000..e97d5da --- /dev/null +++ b/main.cpp @@ -0,0 +1,238 @@ +#include +#include "tree.h" +#include "help.h" + +int main() +{ + /*Tree test1("Dechkovi"); //addTree Dechkovi addTree Karamanovi load 0 load 1 (to work with these example trees) + Tree test2("Karamanovi"); + + test1.addPerson("Rumen", 1968, 8, 9, 0); + test1.addPerson("Nadejda", 1972, 12, 15, 1); + test1.addRelation(0, Husband, 1); + test1.addPerson("Venelin", 1998, 6, 9, 0, 0, 1); + test1.addPerson("Vasil", 2001, 1, 16, 0, 0, 1); + test1.addRelation(2, Brother, 3); + test1.addPerson("Maria-Veronika", 2009, 9, 3, 1, 0, 1); + test1.addRelation(2, Brother, 4); + test1.addRelation(3, Brother, 4); + + test2.addPerson("Vasil Dimitrov", 1941, 5, 18, 0); + test2.addPerson("Maria", 0, 0, 0, 1); + test2.addRelation(0, Husband, 1); + test2.addPerson("Dimitar", 0, 0, 0, 0, 0, 1); + test2.addPerson("Nadejda", 1972, 12, 15, 1, 0, 1); + test2.addRelation(2, Brother, 3); + test2.addPerson("Branimira", 0, 0, 0, 1); + test2.addRelation(2, Husband, 4); + test2.addPerson("Ioan", 0, 0, 0, 0, 2, 4); + test2.addPerson("Rumiana", 0, 0, 0, 1, 2, 4); + test2.addRelation(5, Brother, 6); + + test1.saveTree(); + test2.saveTree();*/ + + + Array trees; + + bool quit=0; + char input[128]; + short i; //Number of the entered command + const short numCom = 23; + const char* const commandList[] = + { + "quit", //0 + "rename", //1 + "load", //2 + "save", //3 + "addPerson", //4 + "addPersonWP", //5 Adds a person and connects him to his parents, by their number + "addRelation", //6 Adds a relation between two people input by name + "addRelationID", //7 -||- by number + "findID", //8 + "equate", //9 Enter the number of two trees, the second becomes equal to the first + "combine", //10 + "subtract", //11 + "removePerson", //12 + "removePersonID", //13 + "removeRelation", //14 + "removeRelationID", //15 + "addTree", //16 + "prtRelatives", //17 + "prtMember", //18 + "prtAncestors", //19 + "chooseTree", //20 + "prtCommonAncestor",//21 + "prtOldestAncestors"//22 + }; + + unsigned curTree = 0, //Currently selected tree ID + id, secondId; //Indexes + Tree *newTree; + char name[128], secondName[128]; + unsigned char day, month; + short year; + bool sex; + unsigned father, mother; + + do + { + std::cout << "Enter a command\n\n"; + std::cin >> input; + for (i = 0; i < numCom; ++i) + { + if (strComp(input, commandList[i])) + break; + } + + switch (i) + { + default: + std::cout << "Unknown command, try again\n\n"; + break; + case 0: //quit + quit = 1; + break; + case 1: //rename + std::cout << "Enter new name\n\n"; + std::cin >> name; + trees[curTree].rename(name); + break; + case 2: //load + if (!trees[curTree].loadTree()) + std::cout << "File doesnt exist or is empty.\n\n"; + break; + case 3: //save + trees[curTree].saveTree(); + break; + case 4: //addPerson + std::cin >> name >> day >> month >> year >> sex; + trees[curTree].addPerson(name, year, month, day, sex); + break; + case 5: //addPersonWP + std::cin >> name >> day >> month >> year >> sex >> father >> mother; + trees[curTree].addPerson(name, year, month, day, sex, father, mother); + break; + case 6: //addRelation + std::cin >> name >> input >> secondName; + while (!strToRel(input)) + { + std::cout << "Invalid Relation, try again!\n"; + std::cin >> input; + } + if(!trees[curTree].addRelation(name, strToRel(input), secondName)) + std::cout << "Failure! One or both of the relatives don't exist.\n\n"; + break; + case 7: //addRelationID + std::cin >> id >> input >> secondId; + while (!strToRel(input)) + { + std::cout << "Invalid Relation, try again!\n"; + std::cin >> input; + } + if(trees[curTree].addRelation(id, strToRel(input), secondId)) + std::cout << "Failure! One or both of the relatives don't exist.\n\n"; + break; + case 8: //findID + std::cin >> name; + id = trees[curTree].findId(name); + if (id == Nobody) + std::cout << "No such person in tree " << curTree <<"\n\n"; + else + std::cout << id << "\n\n"; + break; + case 9: //equate + std::cin >> id >> secondId; + trees[id] = trees[secondId]; + break; + case 10: //combine + std::cin >> id >> secondId; + trees[id] += trees[secondId]; + break; + case 11: //subtract + std::cin >> id >> secondId; + trees[id] -= trees[secondId]; + break; + case 12: //removePerson + std::cin >> name; + if (trees[curTree].findId(name) != Nobody) + trees[curTree].removePerson(name); + else + std::cout << "No such member!\n\n"; + break; + case 13: //removePersonID + std::cin >> id; + if (trees[curTree].gNumP() > id) + trees[curTree].removePerson(id); + else + std::cout << "No such member!\n\n"; + break; + case 14: //removeRelation + std::cin >> name >> secondName; + if (trees[curTree].gNumP() > trees[curTree].findId(name) && trees[curTree].gNumP() > trees[curTree].findId(secondName)) + trees[curTree].removeRelation(name, secondName); + else + std::cout << "No such member!\n\n"; + break; + case 15: //removeRelationID + std::cin >> id >> secondId; + if (trees[curTree].gNumP() > id && trees[curTree].gNumP() > secondId) + trees[curTree].removeRelation(id, secondId); + else + std::cout << "No such member\n\n"; + break; + case 16: //addTree + std::cin >> name; + newTree = new Tree(name); + trees.push(*newTree); + delete newTree; + break; + case 17: //printRelatives + std::cin >> id; + if (id < trees[curTree].gNumP()) + trees[curTree].printRel(id); + else + std::cout << "No such member\n\n"; + break; + case 18: //printMember + std::cin >> id; + if (id < trees[curTree].gNumP()) + trees[curTree].printMember(id); + else + std::cout << "No such member\n\n"; + break; + case 19: //printAncestors + std::cin >> id; + /*if (id < trees[curTree].gNumP()) + trees[curTree].printAncestors(id); + else + std::cout << "No such member\n\n";*/ + break; + case 20: //chooseTree + std::cout << "Enter tree ID\n\n"; + std::cin >> id; + if (id < trees.gNum()) + curTree = id; + else + std::cout << "No such tree\n\n"; + break; + case 21: //prtCommonAncestor + std::cin >> id >> secondId; + if (id < trees[curTree].gNumP() || secondId < trees[curTree].gNumP()) + trees[curTree].printMember(trees[curTree].findCommonAncestor(id, secondId)); + else + std::cout << "No such member\n\n"; + break; + case 22: //prtOldestAncestors + std::cin >> id; + if (id < trees[curTree].gNumP()) + trees[curTree].printOldestAncestors(id); + else + std::cout << "No such member\n\n"; + break; + } + + } while (!quit); + + return 0; +} diff --git a/person.cpp b/person.cpp new file mode 100644 index 0000000..93b5315 --- /dev/null +++ b/person.cpp @@ -0,0 +1,92 @@ +#include"person.h" +#include"help.h" +#include + +/*Person::Person(): + name(nullptr), + numRel(0), + day(0), + month(0), + year(0), + isMale(true) +{}*/ + +Person::Person(const char* Name, unsigned char Day, unsigned char Month, short Year, bool IsMale) : + numRel(0), + day(Day), + month(Month), + year(Year), + isMale(IsMale) +{ + name = new char[strLen(Name) + 1]; + strCopy(name, Name); +} + + +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; +} + +Person::~Person() +{ + delete[] name; +} + + +bool Person::operator==(const Person &other)const +{ + return strComp(name, other.name) && isMale == other.isMale && (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 = strLen(name); + file.write(reinterpret_cast(&nameLen), sizeof(nameLen)); + file.write(name, nameLen * sizeof(*name)); + file.write(reinterpret_cast(&numRel), sizeof(numRel)); + file.write(reinterpret_cast(&isMale), sizeof(isMale)); + file.write(reinterpret_cast(&day), sizeof(day)); + 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)); + + name = new char[nameLen + 1]; + file.read(name, nameLen * sizeof(*name)); + name[nameLen] = '\0'; + + file.read(reinterpret_cast(&numRel), sizeof(numRel)); + file.read(reinterpret_cast(&isMale), sizeof(isMale)); + file.read(reinterpret_cast(&day), sizeof(day)); + file.read(reinterpret_cast(&month), sizeof(month)); + file.read(reinterpret_cast(&year), sizeof(year)); +} + +void Person::rename(const char* newName) +{ + delete[] name; + name = new char[strLen(newName) + 1]; + strCopy(name, newName); +} + +void Person::print()const +{ + std::cout << name << "\nBirthday: " << (int)day << "." << (int)month << "." << year << "\nSex: "; + std::cout << (isMale ? "Male\n\n" : "Female\n\n"); +} diff --git a/person.h b/person.h new file mode 100644 index 0000000..18ddc32 --- /dev/null +++ b/person.h @@ -0,0 +1,30 @@ +#pragma once +#include +#include "common/basicTypes.h" + +class Person +{ + +public: + Person() = default; + Person(const char* Name, unsigned char Day, unsigned char Monthay, short Year, bool Sex); + // + Person& operator=(const Person &other); + ~Person(); + + bool operator==(const Person &other)const; + + void save(std::ofstream &file)const;// + void load(std::ifstream &file); + void rename(const char* newName); + void print()const; + + friend class Tree; + +private: + char *name; + unsigned numRel; //Number of close relatives - mother, father, brother, sister, wife/husband, child, ex-wife/husband + unsigned char day, month; //Birth + short year; + bool isMale; +}; diff --git a/readme.md b/readme.md new file mode 100644 index 0000000..c0295b5 --- /dev/null +++ b/readme.md @@ -0,0 +1,72 @@ +# FamilyTree + +I wrote this program in C ++ on Visual Studio 2017, starting with a blank project. I used iostream for input and output and fstream for saving and loading trees. Instead of using vector, I chose to write a dynamic array myself. I used HxD hex editor to look for errors in the files. +In the program, "family trees" are weighted graphs implemented through a list of neighbors. The program allows for addition, subtraction (removal of common members) and comparison of trees, saving them to and loading them from files and more. + +Thus large constructs consisting of multiple family trees can be created and managed using this program. + +# How to use + +The program works with an array of trees numbered from 0. In order to execute a command on a tree you need to enter its number(treeID). +(S/E) = (Space/Enter) + +Relations are as followed and cap sensitive: + + Father + Mother + Son + Daughter + Brother + Sister + HalfBrother + HalfSister + Wife + Husband + ExWife + ExHusband + +List of commands: + + "quit" (S/E) - close the program + + "chooseTree" (S/E) TreeID (S/E) - Choose tree to execute commands on + + "addTree" (S/E) TreeName (S/E) - Adds a tree to the array + + "rename" (S/E) NewName (S/E) - Renames a tree + + "load" (S/E) TreeID (S/E) - Loads a tree based on its name + + "save" (S/E) TreeID (S/E) - Saves a tree based on its name + + "addPerson" (S/E) BirthDay (S/E) BirthMonth (S/E) BirthYear (S/E) PersonSex (S/E) - Add a person to a tree with treeID with a birthday on BirthDay.BirthMonth.BirthYear and sex (PersonSex) 0 = Male 1 = Female + + "addPersonWP" (S/E) BirthDay (S/E) BirthMonth (S/E) BirthYear (S/E) PersonSex (S/E) FatherID (S/E) MotherID - The same as addPerson but adds father and motherbased on their IDs + + "addRelation" (S/E) FirstRelativeName (S/E) Relation (S/E) SecondRelativeName - Adds a relation betwean two members based on their full names + + "addRelationID" (S/E) FirstRelativeID (S/E) Relation (S/E) SecondRelativeID - Same as addElation but based on ID + + "findID" (S/E) SoughtPersonName (S/E) - Prints the ID of a person with the given name + + "equate" (S/E) FirstTreeID (S/E) SecondTreeID - Enter the IDs of two trees, the first one becomes equal to the second one + + "combine" (S/E) FirstTreeID (S/E) SecondTreeID - Enter the IDs of two trees, the first one becomes equal to the combinatio of the two + + "subtract" (S/E) FirstTreeID (S/E) SecondTreeID - Enter the IDs of two trees, the members that are present in both trees are removed from the first tree + + "removePerson" (S/E) Name - Remove person with the given name + + "removePersonID" (S/E) Name - Remove person with the given ID + + "removeRelation" (S/E) FirstName (S/E) SecondName - Remove the relation betwean the people with the given names if they have one + + "removeRelationID" (S/E) FirstName (S/E) SecondName - Same as removeRelation but with IDs instead + + "prtRelatives" (S/E) PersonID - Print the relatives the person with the given ID in the console + + "prtMember" (S/E) PersonID - Print the personal data of a member on the console + + "prtCommonAncestor" (S/E) FirstPersonID (S/E) SecondPersonID (S/E) + + "prtOldestAncestor" (S/E) PersonID (S/E) diff --git a/tree.cpp b/tree.cpp new file mode 100644 index 0000000..df0b8bb --- /dev/null +++ b/tree.cpp @@ -0,0 +1,574 @@ +#include"tree.h" +#include"person.h" +#include"help.h" +#include + + +Tree::Tree() : + numPeople(0) +{ + treeName = new char[strLen("Unnamed") + 1]; + strCopy(treeName, "Unnamed"); +} + +Tree::Tree(const char *Name): + numPeople(0) +{ + treeName = new char[strLen(Name) + 1]; + strCopy(treeName, Name); +} + +Tree::Tree(const Tree& other) : + numPeople(other.numPeople) +{ + treeName = new char[strLen(other.treeName) + 1]; + strCopy(treeName, other.treeName); + people = other.people; + relatives = other.relatives; + relations = other.relations; +} + +Tree& Tree::operator= (const Tree& other) +{ + if (this != &other) + { + rename(other.treeName); + numPeople = other.numPeople; + people = other.people; + relatives = other.relatives; + relations = other.relations; + } + return *this; +} + +Tree::~Tree() +{ + delete[] treeName; +} + + + +Tree Tree::operator+ (const Tree& other)// +{ + Tree result(mergeStr(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) +{ + delete[] treeName; + treeName = new char[strLen(newName) + 1]; + strCopy(treeName, newName); +} + +unsigned Tree::findId(const char* name, const short year, const unsigned char month, const unsigned char day)const +{ + //Person sought(name, day, month, year,) + for (unsigned i = 0; i < numPeople; ++i) + { + if (strComp(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; + short oldestBday = SHRT_MAX; + for (unsigned i = 0; i < numPeople; ++i) + { + if (visited[i] == 2 && people[i].year(&numPeople), sizeof(numPeople)); + for (unsigned i = 0; i < numPeople; ++i) + people[i].save(peopleFile); + peopleFile.close(); + + fileName = mergeStr(treeName, ".relatives"); + std::ofstream relativeFile(fileName, std::ios::binary); + delete[] fileName; + fileName = mergeStr(treeName, ".relations"); + std::ofstream relationFile(fileName, std::ios::binary); + delete[] fileName; + + /*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() +{ + char* fileName = mergeStr(treeName, ".people");//c + std::ifstream peopleFile(fileName, std::ios::binary); + delete[] fileName; + 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(); + + fileName = mergeStr(treeName, ".relatives"); + std::ifstream relativeFile(fileName, std::ios::binary); + delete[] fileName; + fileName = mergeStr(treeName, ".relations"); + std::ifstream relationFile(fileName, std::ios::binary); + delete[] fileName; + + 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, short year, unsigned char month, unsigned char day, bool isMale, unsigned father, unsigned mother) +{ + Person newPerson(name, day, month, year, 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; + } + } +} + + + +void Tree::printRel(const unsigned id)const +{ + if (people[id].numRel == 0) + { + std::cout << "No relatives"; + return; + } + + unsigned relId; + std::cout < &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 new file mode 100644 index 0000000..760c5e9 --- /dev/null +++ b/tree.h @@ -0,0 +1,71 @@ +#pragma once +#include +#include +#include"array.h" + +class Person; + +enum Relation : char +{ + Invalid = 0, + Father, + Mother, + Son, + Daughter, + Brother, + Sister, + HalfBrother, + HalfSister, + Wife, + Husband, + ExWife, + ExHusband +}; + +const unsigned Nobody = UINT_MAX; //Òîçè íîìåð ùå áúäå çàïàçeí çà ëèïñà íà âðúçêà/÷îâåê + +class Tree +{ +private: + char *treeName; + unsigned numPeople; + Array people; //The data for each member + Array> relatives; //The relatives of each member + Array> relations; //The type of relation each member has with his relatives +public: + Tree(); + Tree(const char *Name); + Tree(const Tree&); + Tree& operator= (const Tree& other); + ~Tree(); + + Tree operator+ (const Tree& other); + Tree operator- (const Tree& other); + Tree& operator+= (const Tree& other); + Tree& operator-= (const Tree& other); + + void rename(const char* newName); + unsigned findId(const char*, const short year=0, const unsigned char month=0, const unsigned char day=0)const; + unsigned findOldestAncestor(const unsigned &id, const bool &sex = 0)const;// + unsigned findCommonAncestor(const unsigned firstId, const unsigned secondId)const; //oldest common ancestor ID + void saveTree()const;// + bool loadTree(); + void addPerson(const char *, short year, unsigned char month, unsigned char day, bool sex, unsigned father = Nobody, unsigned mother = Nobody); + 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 + void removePerson(const unsigned id); //Removes a member and the last one takes his ID + void removePerson(const char*, const short year = 0, const unsigned char month = 0, const unsigned char day = 0); + void removeRelation(const unsigned firstId, const unsigned secondId); + void removeRelation(const char* firstName, const char* secondName); + + void printRel(const unsigned id)const; //Prints out close relatives + void printMember(const unsigned id)const; + void printOldestAncestors(const unsigned id)const;// + + unsigned gNumP()const; + +private: + void commonAncestorRec(const unsigned &id, const Array &visited)const; + + //Search, ect. +};