From fbfe017284ba2b4b56118c657dd50bc36b4447f2 Mon Sep 17 00:00:00 2001 From: Venelin Date: Sat, 20 Aug 2022 15:43:58 +0300 Subject: [PATCH] rename files, sex- --- array.h | 152 ++++++++++++ common/basicTypes.h | 16 ++ compile.sh | 1 + compile_debug.sh | 1 + help.cpp | 69 ++++++ help.h | 9 + main.cpp | 238 ++++++++++++++++++ person.cpp | 92 +++++++ person.h | 30 +++ readme.md | 72 ++++++ tree.cpp | 574 ++++++++++++++++++++++++++++++++++++++++++++ tree.h | 71 ++++++ 12 files changed, 1325 insertions(+) create mode 100644 array.h create mode 100644 common/basicTypes.h create mode 100755 compile.sh create mode 100755 compile_debug.sh create mode 100644 help.cpp create mode 100644 help.h create mode 100644 main.cpp create mode 100644 person.cpp create mode 100644 person.h create mode 100644 readme.md create mode 100644 tree.cpp create mode 100644 tree.h 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. +};