projprog/C12.2.c
2021-11-15 16:23:24 +01:00

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);
}