Inheritance Tree: C Programming ( CS50 Project 5)

 Inheritance Tree in C

--CS50: Introduction to Computer Science Project 5 Implementation

Project 5:-

The Inheritance problem explores how traits are passed down through generations using concepts from genetics. Instead of working with real DNA, the program models a family tree where each person inherits blood type alleles from their parents.


Problem to Solve (edx)

A person’s blood type is determined by two alleles (i.e., different forms of a gene). The three possible alleles are A, B, and O, of which each person has two (possibly the same, possibly different). Each of a child’s parents randomly passes one of their two blood type alleles to their child. The possible blood type combinations, then, are: OO, OA, OB, AO, AA, AB, BO, BA, and BB. 

For example, if one parent has blood type AO and the other parent has blood type BB, then the child’s possible blood types would be AB and OB, depending on which allele is received from each parent. Similarly, if one parent has blood type AO and the other OB, then the child’s possible blood types would be AO, OB, AB, and OO.


🧬 Family Tree Structure (3 Generations)

Child (Generation 0)
alleles: [O][B]
parents[0] → Parent 0
parents[1] → Parent 1
Parent 0 (Gen 1)
alleles: [O][O]
parents[0] → Grandparent 0
parents[1] → Grandparent 1
Parent 1 (Gen 1)
alleles: [B][B]
parents[0] → Grandparent 2
parents[1] → Grandparent 3
Grandparent 0
alleles: [A][O]
parents: NULL
Grandparent 1
alleles: [O][O]
parents: NULL
Grandparent 2
alleles: [B][B]
parents: NULL
Grandparent 3
alleles: [B][B]
parents: NULL


Project Requirements

  • Define struct for each individual
  • Create family function which make structure of individual in memory and link to parents
  • Random allele generator for grandparents
  • Print family tree
  • Free family tree

Step 1: Define Struct Person

person (child)
 ├── parents[0] → person (Parent 0)
 │     ├── parents[0] → person (Grandparent)
 │     └── parents[1] → person (Grandparent)
 └── parents[1] → person (Parent 1)
       ├── parents[0] → person (Grandparent)
       └── parents[1] → person (Grandparent)


In C language we can make struct as user requirement, basically stuct is structure of multiple data types variable.

example.c

// Each person has two parents and two alleles
typedef struct person  // declare stuct name here for compiler to identify that parents is an array of pointers to struct person
{
    struct person *parents[2]; // pointer to their parent stuct
    char alleles[2];
} person;
  

Step 2: Create family function

The create_family function takes an int (generations) and allocate one person memory for each individual and connected to their two parents, so basically create function return a pointer to person with two parents.

Generation 0 means child and 2 belongs to their grandparents. In create_family function we use recursion to first allocate child memory and then go for their parents and so on. 

After base case hit our function put each member allele according to their parents.

Child get their alleles from their parents and grandparents alleles we put by random_allele fn

random.c

// Randomly chooses a blood type allele.
char random_allele()
{
    int r = random() % 3;
    if (r == 0)
    {
        return 'A';
    }
    else if (r == 1)
    {
        return 'B';
    }
    else
    {
        return 'O';
    }
}
  
create_family.c

// Create a new individual with `generations`
person *create_family(int generations)
{
    // Allocate memory for new person
    person *p = malloc(sizeof(person));


    // If there are still generations left to create
    if (generations > 1)
    {
        // Create two new parents for current person by recursively calling create_family
        person *parent0 = create_family(generations - 1);
        person *parent1 = create_family(generations - 1);

        // Set parent pointers for current person
        p->parents[0] = parent0;
        p->parents[1] = parent1;

        // Randomly assign current person's alleles based on the alleles of their parents
        p->alleles[0] = parent0->alleles[random()%2];
        p->alleles[1] = parent1->alleles[random()%2];
    }

    // If there are no generations left to create(grandparents)
    else
    {
        // Set parent pointers to NULL
        p->parents[0] = NULL;
        p->parents[1] = NULL;

        // Randomly assign alleles
        p->alleles[0] = random_allele();
        p->alleles[1] = random_allele();

    }

    // Return newly created person this pointer is key to access this generation tree
    return p;
}
  

Step 3: Print family

print_family function takes input a pointer which have access to generation tree and a integer means which generations want to print.

First we pass int 0 generation 0 which represent child so first we print present member generation number and their allele then go to each parent(which became a single member like child) and print each parent alleles and so on.

print_family.c

// Print each family member and their alleles.
void print_family(person *p, int generation)
{
    // Handle base case
    if (p == NULL)
    {
        return;
    }

    // Print indentation
    for (int i = 0; i < generation * INDENT_LENGTH; i++)
    {
        printf(" ");
    }

    // Print person
    if (generation == 0)
    {
        printf("Child (Generation %i): blood type %c%c\n", generation, p->alleles[0], p->alleles[1]);
    }
    else if (generation == 1)
    {
        printf("Parent (Generation %i): blood type %c%c\n", generation, p->alleles[0], p->alleles[1]);
    }
    else // for grandparents
    {
        for (int i = 0; i < generation - 2; i++)
        {
            printf("Great-");
        }
        printf("Grandparent (Generation %i): blood type %c%c\n", generation, p->alleles[0], p->alleles[1]);
    }

    // Print parents of current generation
    print_family(p->parents[0], generation + 1); 
    print_family(p->parents[1], generation + 1);
}
  

Step 4: Free family

While freeing memory which allocated by malloc, need to go end of tree and come at root with deleting each struct or node.

free_family.c

void free_family(person *p)
{
    // Handle base case
    if (p == NULL)
    {
        return;
    }

    // Free parents recursively
    free_family(p->parents[0]);
    free_family(p->parents[1]);

    // Free child
    free(p);
}
  

Step 5: Full Code Implementation

inheritance.c

// Simulate genetic inheritance of blood type

#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
#include <time.h>

// Each person has two parents and two alleles
typedef struct person  // declare stuct name here for compiler to identify that parents is an array of pointers to struct person
{
    struct person *parents[2];
    char alleles[2];
} person;

const int GENERATIONS = 3;
const int INDENT_LENGTH = 4;

person *create_family(int generations);
void print_family(person *p, int generation);
void free_family(person *p);
char random_allele();

int main(void)
{
    // Seed random number generator
    srandom(time(0));

    // Create a new family with three generations
    person *p = create_family(GENERATIONS);

    // Print family tree of blood types
    print_family(p, 0);

    // Free memory
    free_family(p);
}

// Create a new individual with `generations`
person *create_family(int generations)
{
    // Allocate memory for new person
    person *p = malloc(sizeof(person));


    // If there are still generations left to create
    if (generations > 1)
    {
        // Create two new parents for current person by recursively calling create_family
        person *parent0 = create_family(generations - 1);
        person *parent1 = create_family(generations - 1);

        // Set parent pointers for current person
        p->parents[0] = parent0;
        p->parents[1] = parent1;

        // Randomly assign current person's alleles based on the alleles of their parents
        p->alleles[0] = parent0->alleles[random()%2];
        p->alleles[1] = parent1->alleles[random()%2];
    }

    // If there are no generations left to create
    else
    {
        // Set parent pointers to NULL
        p->parents[0] = NULL;
        p->parents[1] = NULL;

        // Randomly assign alleles
        p->alleles[0] = random_allele();
        p->alleles[1] = random_allele();

    }

    // Return newly created person
    return p;
}

// Free `p` and all ancestors of `p`.
void free_family(person *p)
{
    // Handle base case
    if (p == NULL)
    {
        return;
    }

    // Free parents recursively
    free_family(p->parents[0]);
    free_family(p->parents[1]);

    // Free child
    free(p);
}

// Print each family member and their alleles.
void print_family(person *p, int generation)
{
    // Handle base case
    if (p == NULL)
    {
        return;
    }

    // Print indentation
    for (int i = 0; i < generation * INDENT_LENGTH; i++)
    {
        printf(" ");
    }

    // Print person
    if (generation == 0)
    {
        printf("Child (Generation %i): blood type %c%c\n", generation, p->alleles[0], p->alleles[1]);
    }
    else if (generation == 1)
    {
        printf("Parent (Generation %i): blood type %c%c\n", generation, p->alleles[0], p->alleles[1]);
    }
    else
    {
        for (int i = 0; i < generation - 2; i++)
        {
            printf("Great-");
        }
        printf("Grandparent (Generation %i): blood type %c%c\n", generation, p->alleles[0], p->alleles[1]);
    }

    // Print parents of current generation
    print_family(p->parents[0], generation + 1);
    print_family(p->parents[1], generation + 1);
}

// Randomly chooses a blood type allele.
char random_allele()
{
    int r = random() % 3;
    if (r == 0)
    {
        return 'A';
    }
    else if (r == 1)
    {
        return 'B';
    }
    else
    {
        return 'O';
    }
}

  

Example Execution

./inheritance.c

Output :-

Child (Generation 0): blood type OB
    Parent (Generation 1): blood type OO
        Grandparent (Generation 2): blood type AO
        Grandparent (Generatipe BBon 2): blood type OO
    Parent (Generation 1): blood type BB
        Grandparent (Generation 2): blood type BB
        Grandparent (Generation 2): blood type BB
Next Post Previous Post
No Comment
Add Comment
comment url