525 lines
14 KiB
C
525 lines
14 KiB
C
#include<string.h>
|
|
#include<stdio.h>
|
|
#include<stdlib.h>
|
|
|
|
#define NameLength 16
|
|
|
|
/* 1 */
|
|
|
|
/*
|
|
Le graphe représente les objets personnes rencontrés pendant la série.
|
|
Chaque case représente le départ d'une flèche vers un autre personnage (ou · pour pas de flèche) qui correspond à :
|
|
|
|
```
|
|
--------------
|
|
| 1 | 2 |
|
|
------------
|
|
| | 3 |
|
|
| nom |-----|
|
|
| | 4 |
|
|
-------------
|
|
| 6 | 5 |
|
|
-------------
|
|
```
|
|
1. Pointeur vers le père
|
|
2. Pointeur vers la mère
|
|
3. Chainage des frères et sœurs coté du père
|
|
4. Chainage des frères et sœurs coté de la mère
|
|
5. Pointeur vers le premier enfant
|
|
6. Liste de tous les personnages
|
|
|
|
|
|
Le chainage crée une «liste» accessible depuis n'importe lequel des membres
|
|
|
|
Pour le pointeur 6, la flèche pointant sur jihair représente le début de la liste.
|
|
*/
|
|
|
|
/* 2 */
|
|
|
|
// Le sexe des personnes qui sont parent peut être retrouvé (il suffit de regarder leur premier enfant, si ils en sont le père ou la mère).
|
|
// Les autres, on peut dire qu'on s'en fiche, leur sexe sera «défini» au moment ou un couple les contenant aura un enfant.
|
|
|
|
/* 3 */
|
|
|
|
// Le chainage général permet de pouvoir lister les personnage, et ainsi de pouvoir par exemple chercher un personnage de par son nom, ou toute autre information stoqué dedans.
|
|
|
|
/* 4 */
|
|
// L'avantage de ces listes chainées horizontales est qu'elle sont accessibles simplement depuis n'importe quel membre de la liste.
|
|
|
|
/* 5 */
|
|
|
|
struct personnage{
|
|
|
|
char* nom;
|
|
struct personnage* pere;
|
|
struct personnage* mere;
|
|
struct personnage* frereSuivantPapa;
|
|
struct personnage* frereSuivantMaman;
|
|
struct personnage* premierEnfant;
|
|
struct personnage* chaineGlobale;
|
|
|
|
char shouldFreeNom;
|
|
|
|
};
|
|
|
|
/* 6 */
|
|
|
|
struct personnage* getByName(struct personnage* origin, char* name){
|
|
|
|
while(origin!=NULL && strcmp(name,origin->nom)!=0){
|
|
origin = origin->chaineGlobale;
|
|
}
|
|
return origin;
|
|
|
|
}
|
|
|
|
/* 7 */
|
|
|
|
struct personnage* newUnrelatedM(struct personnage** originp, char* name, char shouldFreeNom){
|
|
if(name==NULL)return NULL;
|
|
struct personnage* dest = (struct personnage*) malloc(sizeof(struct personnage));
|
|
dest->nom = name;
|
|
dest->shouldFreeNom = shouldFreeNom;
|
|
dest->frereSuivantPapa = dest->frereSuivantMaman = dest;
|
|
dest->pere = dest->mere = dest->premierEnfant = NULL;
|
|
|
|
dest->chaineGlobale = *originp;
|
|
*originp = dest;
|
|
|
|
return dest;
|
|
}
|
|
|
|
struct personnage* newUnrelated(struct personnage** originp, char* name){
|
|
return newUnrelatedM(originp, name, 0);
|
|
}
|
|
|
|
/* 8 */
|
|
int papounet(struct personnage* pere, struct personnage* enfant){
|
|
if(pere==NULL || enfant==NULL)return 1;
|
|
enfant->pere = pere;
|
|
if(pere->premierEnfant==NULL){
|
|
pere->premierEnfant = enfant;
|
|
} else {
|
|
struct personnage* fraterie = pere->premierEnfant;
|
|
while(fraterie->frereSuivantPapa!=pere->premierEnfant)fraterie = fraterie->frereSuivantPapa;
|
|
// Fraterie est maintenant le dernier né du père
|
|
fraterie->frereSuivantPapa = enfant;
|
|
}
|
|
enfant->frereSuivantPapa = pere->premierEnfant;
|
|
return 0;
|
|
}
|
|
|
|
/* 9 */
|
|
int mamounette(struct personnage* mere, struct personnage* enfant){
|
|
if(mere==NULL || enfant==NULL)return 1;
|
|
enfant->mere = mere;
|
|
if(mere->premierEnfant==NULL){
|
|
mere->premierEnfant = enfant;
|
|
} else {
|
|
struct personnage* fraterie = mere->premierEnfant;
|
|
while(fraterie->frereSuivantMaman!=mere->premierEnfant)fraterie = fraterie->frereSuivantMaman;
|
|
// Fraterie est maintenant le dernier né de la mère
|
|
fraterie->frereSuivantMaman = enfant;
|
|
}
|
|
enfant->frereSuivantMaman = mere->premierEnfant;
|
|
return 0;
|
|
}
|
|
|
|
/* 10 */
|
|
char* nomOr(struct personnage* perso, char* orElse){
|
|
if(perso==NULL)return orElse;
|
|
return perso->nom;
|
|
}
|
|
|
|
void dumpState(struct personnage* liste){
|
|
|
|
printf("Liste des personnes chargées :\n");
|
|
|
|
while(liste!=NULL){
|
|
|
|
printf("%s : père %s et mère %s, frère-sœur coté père %s, et frère-sœur coté mère %s, son premier enfant est %s\n",
|
|
liste->nom, nomOr(liste->pere, "inconnu"), nomOr(liste->mere, "inconnue"),
|
|
liste->frereSuivantPapa->nom, liste->frereSuivantMaman->nom, nomOr(liste->premierEnfant, "aucun")
|
|
);
|
|
liste = liste->chaineGlobale;
|
|
}
|
|
|
|
printf(": seégrahc sennosrep sed etsiL\n");
|
|
|
|
}
|
|
|
|
/* 11 */
|
|
int scanfs(char* dest, int length){
|
|
|
|
if(fgets(dest, length-1, stdin)==NULL){
|
|
return 1;// Une erreur est survenue lors de la lecture (trop long ?)
|
|
}
|
|
|
|
// On doit supprimer le retour à la ligne qu'a capturé fgets.
|
|
int i;
|
|
for(i=0;i<length && (dest)[i]!='\n';i++){}
|
|
if(i>=length){// On a Overflow
|
|
// On nettoie les caracteres ecrits en trop
|
|
while( (!strchr(dest,'\n')) && (!strchr(dest,EOF)))
|
|
if(!fgets(dest, length-1,stdin))
|
|
break;
|
|
return 2;
|
|
}
|
|
dest[i] = '\0';
|
|
return 0;
|
|
}
|
|
|
|
struct personnage* addRegistryEntryM(struct personnage** liste, char* enfantN, char* pereN, char* mereN, char shouldFreeNoms){
|
|
if(enfantN==NULL) return NULL;
|
|
struct personnage *enfant, *pere, *mere;
|
|
|
|
enfant = getByName(*liste, enfantN);
|
|
if(enfant==NULL)enfant = newUnrelatedM(liste, enfantN, shouldFreeNoms&0b100);
|
|
if(pereN!=NULL){
|
|
pere = getByName(*liste, pereN);
|
|
if(pere==NULL)pere = newUnrelatedM(liste, pereN, shouldFreeNoms&0b010);
|
|
papounet(pere, enfant);
|
|
}
|
|
if(mereN!=NULL){
|
|
mere = getByName(*liste, mereN);
|
|
if(mere==NULL)mere = newUnrelatedM(liste, mereN, shouldFreeNoms&0b001);
|
|
mamounette(mere, enfant);
|
|
}
|
|
|
|
return enfant;
|
|
|
|
}
|
|
|
|
struct personnage* addRegistryEntry(struct personnage** liste, char* enfantN, char* pereN, char* mereN){
|
|
return addRegistryEntryM(liste, enfantN, pereN, mereN, 0);
|
|
}
|
|
|
|
struct personnage* askRegistryEntry(struct personnage** liste){
|
|
char* enfantN = malloc(NameLength*sizeof(char));
|
|
if(enfantN==NULL)return NULL;
|
|
char* pereN = malloc(NameLength*sizeof(char));
|
|
if(pereN==NULL){free(enfantN);return NULL;}
|
|
char* mereN = malloc(NameLength*sizeof(char));
|
|
if(mereN==NULL){free(pereN),free(enfantN);return NULL;}
|
|
|
|
do{
|
|
printf("Nom de l'enfant : ");
|
|
} while(scanfs(enfantN,NameLength));
|
|
do{
|
|
printf("Nom du père (vide pour non renseigné) : ");
|
|
} while(scanfs(pereN,NameLength));
|
|
do{
|
|
printf("Nom de la mère (vide pour non renseigné) : ");
|
|
} while(scanfs(mereN,NameLength));
|
|
|
|
// La chaine vide est représentée par un pointeur vers '\0' (la fin de la chaine)
|
|
if(*pereN=='\0'){free(pereN);pereN = NULL;}
|
|
if(*mereN=='\0'){free(mereN);mereN = NULL;}
|
|
|
|
return addRegistryEntryM(liste,enfantN, pereN, mereN, 0b111);
|
|
}
|
|
|
|
|
|
/* 12 */
|
|
// Voir le main à la fin du code.
|
|
|
|
/* 13 */
|
|
|
|
void paspapa(struct personnage* batard){
|
|
if(batard==NULL)return;// On n'enleve aucun lien
|
|
if(batard->frereSuivantPapa != batard){
|
|
if(batard->pere->premierEnfant == batard)batard->pere->premierEnfant = batard->frereSuivantPapa;
|
|
struct personnage* fraterie = batard;
|
|
while(fraterie->frereSuivantPapa!=batard)fraterie = fraterie->frereSuivantPapa;
|
|
// Fraterie est maintenant «juste avant» le batard
|
|
fraterie->frereSuivantPapa = batard->frereSuivantPapa;
|
|
batard->frereSuivantPapa = batard;
|
|
} else {
|
|
batard->pere->premierEnfant = NULL;
|
|
}
|
|
|
|
batard->pere = NULL;
|
|
}
|
|
|
|
/* 14 */
|
|
|
|
void pasmaman(struct personnage* batard){
|
|
if(batard==NULL)return;
|
|
if(batard->frereSuivantMaman != batard){
|
|
if(batard->mere->premierEnfant == batard)batard->mere->premierEnfant = batard->frereSuivantMaman;
|
|
struct personnage* fraterie = batard;
|
|
while(fraterie->frereSuivantMaman!=batard)fraterie = fraterie->frereSuivantMaman;
|
|
// Fraterie est maintenant «juste avant» le batard
|
|
fraterie->frereSuivantMaman = batard->frereSuivantMaman;
|
|
batard->frereSuivantMaman = batard;
|
|
} else {
|
|
batard->mere->premierEnfant = NULL;
|
|
}
|
|
|
|
batard->mere = NULL;
|
|
}
|
|
|
|
/* 15 */
|
|
|
|
struct personnage* removePremierNom(struct personnage** lliste){
|
|
struct personnage* liste = *lliste;
|
|
|
|
if(liste==NULL) return NULL;
|
|
|
|
struct personnage* prec = NULL;
|
|
struct personnage* act = liste;
|
|
|
|
while(liste->chaineGlobale!=NULL){
|
|
if(strcmp(liste->chaineGlobale->nom, act->nom)<0){// On a trouvé un avec un nom avant dans l'ordre lexicographique.
|
|
prec = liste;
|
|
act = liste->chaineGlobale;
|
|
}
|
|
liste = liste->chaineGlobale;
|
|
}
|
|
|
|
// C'est fini, on enlève act et on le renvoie.
|
|
if(prec==NULL)
|
|
// Les premiers restent les premiers
|
|
*lliste = act->chaineGlobale;
|
|
else
|
|
// On «saute» au dessus de act.
|
|
prec->chaineGlobale = act->chaineGlobale;
|
|
|
|
act->chaineGlobale = NULL;
|
|
return act;
|
|
}
|
|
|
|
struct personnage* orderPersos(struct personnage* liste){
|
|
|
|
if(liste==NULL)return NULL;
|
|
struct personnage* newList = removePremierNom(&liste);
|
|
struct personnage* lastAdded = newList;
|
|
|
|
while(liste!=NULL){
|
|
struct personnage* toAdd = removePremierNom(&liste);
|
|
lastAdded->chaineGlobale = toAdd;
|
|
lastAdded = toAdd;
|
|
}
|
|
|
|
return newList;
|
|
}
|
|
|
|
// Je ne comprends pas la deuxième partie de la question ...
|
|
|
|
/* 16 */
|
|
|
|
|
|
// L'objectif était de faire une sortie illisible, surtout lorsqu'il y a beaucoup de générations.
|
|
// Mais je peux mettre des parentheses
|
|
#define ParenthesesVraiNom 1
|
|
void printVraiNom(struct personnage* perso){
|
|
if(perso==NULL){
|
|
printf("personne");return;
|
|
}
|
|
if(ParenthesesVraiNom)printf("(");
|
|
printf("%s", perso->nom);
|
|
if(perso->mere !=NULL){
|
|
printf(", enfant de ");
|
|
printVraiNom(perso->mere);
|
|
if(perso->pere !=NULL){
|
|
printf(" et de ");
|
|
printVraiNom(perso->pere);
|
|
}
|
|
} else if (perso->pere != NULL){
|
|
printf(", enfant de ");
|
|
printVraiNom(perso->pere);
|
|
}
|
|
if(ParenthesesVraiNom)printf(")");
|
|
}
|
|
|
|
int printNthGP(struct personnage* racine, int hauteur, int dejafait){
|
|
if(racine==NULL)return 0;
|
|
if(hauteur==0){
|
|
printf(dejafait?", %s":"%s", racine->nom);
|
|
return dejafait+1;
|
|
} else {
|
|
if(racine->mere !=NULL)
|
|
if(racine->pere !=NULL)
|
|
return printNthGP(racine->mere, hauteur-1, printNthGP(racine->pere, hauteur-1, dejafait));
|
|
else
|
|
return printNthGP(racine->mere, hauteur-1, dejafait);
|
|
else if (racine->pere != NULL)
|
|
return printNthGP(racine->pere, hauteur-1, dejafait);
|
|
return dejafait;
|
|
}
|
|
}
|
|
|
|
|
|
void dumpAncetres(struct personnage* racine){
|
|
if(racine==NULL)return;
|
|
printf("Ancêtres de %s\n", racine->nom);
|
|
|
|
printf("Parents connus: ");
|
|
if(printNthGP(racine, 1, 0)){
|
|
int h = 2;
|
|
printf("\nGrand-parents connus : ");
|
|
while(printNthGP(racine, h, 0)){
|
|
h++;
|
|
printf("\nArrière-");
|
|
for(int i=3;i<h;i++)printf("arrière-");
|
|
printf("grand-parents connus : ");
|
|
}
|
|
printf("aucun\n");
|
|
} else {
|
|
printf("aucun\n");
|
|
}
|
|
|
|
|
|
printf(".sertecna sed niF\n");
|
|
}
|
|
|
|
/* 17 */
|
|
int dumpNthDescendents(struct personnage* vieux, int gen){
|
|
if(vieux==NULL)return 0;
|
|
int count = 0;
|
|
if(vieux->premierEnfant == NULL)return 0;
|
|
int sexe = vieux->premierEnfant->pere != vieux;// 1 si femme
|
|
struct personnage* fraterie = vieux->premierEnfant;
|
|
|
|
if(gen==0){
|
|
do{
|
|
printf("%s ", fraterie->nom);
|
|
count++;
|
|
fraterie = (sexe?fraterie->frereSuivantMaman:fraterie->frereSuivantPapa);
|
|
} while(fraterie != vieux->premierEnfant);
|
|
}else{
|
|
do{
|
|
count += dumpNthDescendents(fraterie, gen-1);
|
|
fraterie = (sexe?fraterie->frereSuivantMaman:fraterie->frereSuivantPapa);
|
|
} while(fraterie != vieux->premierEnfant);
|
|
}
|
|
return count;
|
|
|
|
}
|
|
|
|
/* 18 */
|
|
void dumpDescendenceUntil(struct personnage* vieux, int maxh){
|
|
|
|
if(vieux==NULL)return;
|
|
|
|
printf("Déscendence de %s\n", vieux->nom);
|
|
|
|
printf("Enfants connus: ");
|
|
if(dumpNthDescendents(vieux, 0)){
|
|
int h = 1;
|
|
printf("\nPetits-enfants connus : ");
|
|
while(dumpNthDescendents(vieux, h) || h>maxh){
|
|
h++;
|
|
printf("\nArrière-");
|
|
for(int i=2;i<h;i++)printf("arrière-");
|
|
printf("petits-enfants connus : ");
|
|
}
|
|
printf("aucun\n");
|
|
} else {
|
|
printf("aucun\n");
|
|
}
|
|
|
|
|
|
printf(".ecnedecsed al ed niF\n");
|
|
|
|
}
|
|
|
|
/* 19 */
|
|
int estSMoinsGeneration(struct personnage* moi, struct personnage* autre, int limit){
|
|
if(moi==NULL || autre==NULL)return 0;
|
|
if(limit==0)return 1;// On a fait trop de tours de récursivité ! Forcément une problème.
|
|
if(moi->premierEnfant == NULL)return 0;
|
|
int sexe = moi->premierEnfant->pere != moi;// 1 si femme
|
|
struct personnage* fraterie = moi->premierEnfant;
|
|
|
|
|
|
do{
|
|
if(fraterie==autre)return 1;
|
|
if(estSMoinsGeneration(fraterie,autre,limit-1))
|
|
return 1;
|
|
fraterie = (sexe?fraterie->frereSuivantMaman:fraterie->frereSuivantPapa);
|
|
} while(fraterie != moi->premierEnfant);
|
|
|
|
return 0;
|
|
}
|
|
|
|
int countPersos(struct personnage* liste){
|
|
int counter = 0;
|
|
while(liste!=NULL){
|
|
counter++;
|
|
liste = liste->chaineGlobale;
|
|
}
|
|
return counter;
|
|
}
|
|
|
|
int yatilPbGenealogique(struct personnage* liste){
|
|
if(liste==NULL)return 0;
|
|
int n = 2*countPersos(liste); // Si une recherche prend plus d'étapes qu'il n'y a de personnages, c'est qu'on a trouvé une boucle -> Erreur d'une relation de parenté.
|
|
while(liste->chaineGlobale!=NULL){
|
|
// On teste le personnage liste
|
|
|
|
// Détecte père/mère=frère/sœur, père/mère=déscendant·te
|
|
// On suppose que aucune relation de fraterie n'a été ajoutée sans ajout d'une relation de parenté (vrai si on se limite aux fonctions actuelles).
|
|
if(estSMoinsGeneration(liste, liste, n))return 1;
|
|
|
|
liste = liste->chaineGlobale;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
/* 20 */
|
|
void freeListe(struct personnage* origin){
|
|
struct personnage* ori2 = origin;
|
|
while(ori2!=NULL){
|
|
origin = ori2->chaineGlobale;
|
|
if(ori2->shouldFreeNom)free(ori2->nom);
|
|
free(ori2);
|
|
ori2 = origin;
|
|
}
|
|
}
|
|
|
|
|
|
|
|
///// Main pour les tests
|
|
|
|
int main(){
|
|
|
|
struct personnage* liste = NULL;
|
|
|
|
|
|
addRegistryEntry(&liste ,"Brandon","Jihair","Saoul-Helene");
|
|
addRegistryEntry(&liste,"Jessica","Jihair","Saoul-Helene");
|
|
addRegistryEntry(&liste,"Jennifer","Jihair","Saoul-Helene");
|
|
addRegistryEntry(&liste,"Jonatan","Huggy","Pamella");
|
|
addRegistryEntry(&liste,"Brenda","Huggy","Pamella");
|
|
addRegistryEntry(&liste,"Kevin","Huggy", "Pamella");
|
|
addRegistryEntry(&liste,"Jacques",NULL, NULL);
|
|
addRegistryEntry(&liste,"Valery","Jonathan","Jennifer");
|
|
addRegistryEntry(&liste,"Georges","Jonathan","Jennifer");
|
|
addRegistryEntry(&liste,"François","Jonathan","Jessica");
|
|
addRegistryEntry(&liste,"Charles","Kevin","Jessica");
|
|
askRegistryEntry(&liste);
|
|
// Entrée rendant la structure incohérente.
|
|
//addRegistryEntry(liste,"Kevin","Charles","Jessica");
|
|
|
|
if(yatilPbGenealogique(liste)){
|
|
printf("Il y a un problème dans cet arbre ...\n");
|
|
return 42;
|
|
}
|
|
dumpState(liste);
|
|
|
|
liste = orderPersos(liste);
|
|
|
|
printVraiNom(liste->chaineGlobale->chaineGlobale);
|
|
printf("\n");
|
|
dumpAncetres(liste->chaineGlobale->chaineGlobale);
|
|
dumpDescendenceUntil(getByName(liste, "Jihair"),3);
|
|
printf("\n");
|
|
dumpState(liste);
|
|
|
|
|
|
|
|
freeListe(liste);
|
|
}
|