538 lines
14 KiB
C++
538 lines
14 KiB
C++
#include <iostream>
|
|
#include<fstream>
|
|
#include"tree.h"
|
|
#include"person.h"
|
|
#include"help.h"
|
|
|
|
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
|
|
{
|
|
//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<char> 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<const char*>(&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<char*>(&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<char*>(&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<char>::eof())
|
|
{
|
|
peopleFile.close();
|
|
return 0;
|
|
}
|
|
|
|
peopleFile.read(reinterpret_cast<char*>(&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<char*>(&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<char*>(&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<unsigned> newRelative;
|
|
relatives.push(newRelative);
|
|
Array<Relation> 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::draw() const
|
|
{
|
|
|
|
}
|
|
|
|
void Tree::print() const
|
|
{
|
|
//for(const auto& member: people)
|
|
// member.print();
|
|
for(int i=0; i<numPeople;++i)
|
|
people[i].print();
|
|
}
|
|
|
|
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<char> &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);
|
|
}
|
|
}
|
|
}
|