inheritance.c Code

// Simulate genetic inheritance of blood type
#define _DEFAULT_SOURCE
#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
#include <time.h>

// Each person has two parents and two alleles
typedef 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();

/*
Each person should have alleles assigned to them. The oldest generation should have alleles randomly
chosen (as by calling the random_allele function), and younger generations should inherit one allele
(chosen at random) from each parent. Each person should have parents assigned to them. The oldest
generation should have both parents set to NULL, and younger generations should have parents be an
array of two pointers, each pointing to a different parent.
*/

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)
{
    // TODO: 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);

        // TODO: Set parent pointers for current person
        p->parents[0] = parent0;
        p->parents[1] = parent1;
        // TODO: 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
    {
        // TODO: Set parent pointers to NULL
        p->parents[0] = NULL;
        p->parents[1] = NULL;
        // TODO: Randomly assign alleles
        p->alleles[0] = random_allele();
        p->alleles[1] = random_allele();
    }

    // TODO: Return newly created person
    return p;
}

// Free `p` and all ancestors of `p`.
void free_family(person *p)
{
    // TODO: Handle base case
    if (p == NULL)
    {
        return;
    }
    // TODO: Free parents recursively
    free_family(p->parents[0]);
    free_family(p->parents[1]);
    // TODO: 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';
    }
}

speller.c Code


// Implements a dictionary's functionality

#include "dictionary.h"
#include <ctype.h>
#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <strings.h>

// Represents a node in a hash table
typedef struct node
{
    char word[LENGTH + 1];
    struct node *next;
} node;

// TODO: Choose number of buckets in hash table
const unsigned int N = 26;

// Hash table
node *table[N];

// words count
int count = 0;

// Returns true if word is in dictionary, else false
bool check(const char *word)
{
    // TODO
    /*
    1. Hash first letter of the word and save in bucket
    2. look in table[bucket]
    3. iterate through and comapre if word is here
    4. do that until NULL
    5. if word found return true otherwise false
    */
    int bucket = hash(word);
    node *ptr = table[bucket];
    while (ptr != NULL)
    {
        if (strcasecmp(word, ptr->word) == 0)
        {
            return true;
        }
        ptr = ptr->next;
    }
    return false;
}

// Hashes word to a number
unsigned int hash(const char *word)
{
    // TODO: Improve this hash function
    return toupper(word[0]) - 'A';
}

// Loads dictionary into memory, returning true if successful, else false
bool load(const char *dictionary)
{
    // TODO
    /*
    read word and work with the hash function to know where
    this word belongs to
    */
    int bucket = 0;

    FILE *f = fopen(dictionary, "r");
    if (f == NULL)
    {
        return false;
    }
    char word[LENGTH + 1];
    while (fscanf(f, "%s", word) != EOF)
    {
        // give me the hash value
        bucket = hash(word);

        // create a node
        node *n = malloc(sizeof(node));
        if (n == NULL)
        {
            fclose(f);
            return false;
        }

        // store the word in the node
        strcpy(n->word, word);

        // store the location of next node
        n->next = table[bucket];

        // make list point at the location of the node
        table[bucket] = n;
        count++;
    }
    // close the file
    fclose(f);

    // if count is above 0 return true (signifing sucess loading into memory)
    return (count > 0);
}

// Returns number of words in dictionary if loaded, else 0 if not yet loaded
unsigned int size(void)
{
    // TODO
    /*
    (i starts with 0 after each loop it increses by one)
    1. table buckt i not NULL ?
    2. go inside, and keep incremeting on each node found (e.g counter)
    3. repeat step 2 until the attribute next of the node delievers NULL
    4. go back to step 1, until the size of N
    5. return the final value of 2.
    */
    return count;
    /*node *ptr = table[0];
    int wordcount=0;
    for (int i = 0; i<N; i++)
    {
        if(table[i] != NULL)
        {
            ptr = table[i];
            while (ptr->next != NULL)
            {
                wordcount++;
                ptr=ptr->next;
            }
        }
    }
    return wordcount;*/
}

// Unloads dictionary from memory, returning true if successful, else false
bool unload(void)
{
    node *ptrfront = NULL;
    node *ptrback = NULL;
    int deleted = 0;
    for (int i = 0; i < N; i++)
    {
        if (table[i] != NULL)
        {
            ptrfront = table[i];
            while (ptrfront != NULL)
            {
                ptrback = ptrfront;
                ptrfront = ptrfront->next;
                free(ptrback);
                deleted++;
            }
        }
    }
    return (deleted == count);
}