BRIAN: In this lab, your task is going to be to write a program in C that simulates the inheritance of blood type genes within a family. To give a little bit of science background, your blood type is determined by alleles. Alleles are different versions of a gene. And there are three different alleles with regard to blood type, called A, B, and O. Each person has two of these alleles. Maybe you have two A's, two B's, two O's. Or maybe you mix and match, have an A and a B, or a B and an O, or an A or an O, for example. And when a parent has a child, each parent passes on one of their alleles to their child. So for example, if we imagine two parents, one that has a blood type of AB and one who has a blood type of OO, tthen their child is going to inherit one blood type of little from each of their parents. For example, we might randomly choose A from one parent, and between the other parent O, and ultimately get a blood type of AO. But we also could have gotten a blood type of BO, for example. Which of the two alleles is passed on is just chosen at random. In order to simulate this type of inheritance inside of our program, we're going to need some sort of data structure that lets us represent the connection between people and their parents, as well as what alleles they have for their blood type. And because there is no type built into C to do just that, we can create a type of our own using a typedef. So here, we have typedef struct person, where every person is going to be represented by these two fields. Struct person star *parents[2] means that every person is going to have an array of 2 parents, where each of those parents is going to be a pointer to another person. Meanwhile, every person is also going to have an array of two characters called alleles, representing which two alleles, A, B, or O, this particular person has. And because each person has two alleles, this is going to be an array of size 2 to represent both of those alleles. So in the example we saw before, we might, for this particular child, have the letter A stored at this child's alleles 0 and 0 stored at alleles 1. And meanwhile, parents[0] would point to one of the parents and parents[1] would point to the other parent. Let's see how these pieces now would come together inside of the distribution code that we give to you for the lab. There is a fair amount of distribution code that we already give to you inside of inheritance.c But let's try and distill it to just what's most important. Here we'll notice that same typedef, that we define a person as having pointers to two parents in this array of 2 pointers and also having an array of two characters, representing the two alleles that this person has for their blood type. Next up is this relevant variable called const int GENERATIONS, a constant integer, which is set equal to the number of 3. And this is going to represent the number of generations of data that we're going to simulate generating. In this case, we're simply waiting three generations worth of data for blood types, which means we're not just going to simulate the single child, but also generation 2, their parents, and also generation 3, that child's grandparents as well. We then have some prototypes for functions, but let's skip down to the main function to really see what it is that this program is doing. The main function is already written for you. Nothing you need to do here. But we start by seeding the random number generator, just so that we're able to generate pseudo random numbers, which is going to be useful. Because when we decide how genes are inherited, we want to be able to randomly choose which gene is going to be passed on from parent to child. Next we call the create_family function to create a family with a specified number of generations, returning a pointer to the most recent generation of person in that family. So if we create a family with three generations, we'll end up with a pointer to one person. But using their parent pointers, we could access that child's parents as well as that child's grandparents, but no further if we're only looking at a family with three generations. The create_family function will be up to you to write. But the print family function we will write. After you've already created a family, we've already written for you a function that will take that family and print them out as a hierarchical family tree, printing out what blood type each of the people in that family has. Finally, you'll write the free_family function, which will free all of the memory that you may have allocated in the process of creating this family. Because recall that for each of the people that you want to represent inside of your computer's memory, you'll likely need to allocate memory for them by using the malloc function to allocate some memory dynamically. But any time you allocate memory with malloc, you'll also want to free that memory, giving it back to the computer so that it can be used for other purposes. Here then, in the create_family function, is going to be what you'll implement, allocating memory for a new person and then dealing with two possible cases. One, if there are potential parents that this child has that we need to recursively generate, or else, if we're just generating a single generation, generating just a single person without any parent data. You'll also, then, write the free_family function, which takes as input a pointer to a person p. And the task for this function is to free p as well as any ancestors of p. So if person p has parents or grandparents or other ancestors as well, you'll want to make sure to free them, too. The print family function we've written for you. No need to do anything here. It takes a person and goes ahead and prints out their entire family tree, along with their blood types. And this random allele function that we wrote might be helpful for you, too. It randomly chooses an allele, A, B, or O, which can be useful if you get to a point where you need to randomly generate an allele to store inside of that allele's array. So with that distribution code in mind, let's then walk through what it is that your program is going to do. The first thing you should do is complete the create_family function to create a family with a specified number of generations. In order to do so, the first thing you should do is allocate memory for a new person, calling malloc, passing in size of person to make sure you have enough memory for a new person. And then you'll use that person to potentially generate ancestors if there are more generations that you need to work with. So if generations is greater than 1, meaning there are more generations that you need to generate, then you'll recursively create those previous generations. What does it mean to recursively create previous generations? Well, if you're trying to create a child that has two generations of parents then you'll recursively call the create_family function for each of those parents where each one of those parents will have one generation of parents, and so on and so forth. So if generations is greater than 1, you'll want to recursively create those previous generations. And using the return value you get from those create_family functions, you'll update this new person's parents, setting parents[0] equal to the result of one recursive call and setting parents[1] equal to the result of some other recursive call. After you set that person's parents, recall that every person not only has two pointers to parents, but also has two alleles. So now you'll need to do the actual inheritance step, inheriting one allele from each parent at random. So you want to inherit the alleles from the parents by looking at one parents two alleles, randomly choosing one, and setting that as the child's allele 0. And then doing the same with the other parent, looking at their two alleles, randomly choosing one, and using one of those as alleles[1] so that the child ends up with two alleles, one inherited from either parent. Otherwise, if generations is equal to 1, that means you're only generating one generation worth of family, that is, an individual person with no parents. And if that's the case, then both of the parent pointers should be set to null. And because there is nothing to inherit, because we don't have any data about the parents, you'll go ahead and randomly generate alleles for each of the two alleles for this particular person. And recall that, in the distribution code, we give to you a function that will randomly generate those alleles. The final step for this lab is going to be to write the free_family function to free all of that allocated memory. Recall that every time you called the create_family function, you were calling malloc at least once in order to generate data for a new person, to allocate memory for that person dynamically inside of the computer's heap. Now, after you've malloced that memory, it's your task at the end of the program to free all of that memory up and give it back to the computer. In order to do so, you'll want to first handle the base case. If the input to free_family is null, there is no action you should take. You should never be freeing the null pointer. But after that, you'll want to deal with the recursive case, recursively freeing the parents, and then after that, freeing the child. How do you recursively free the parents? Well, you'll want to call the free_family function on each of the child's two parents. Recursively then, that will also call for a family on the child's grandparents and higher generations, if there are other generations, as well. And after those parents have been freed then you can use free in order to free the child as well, ultimately freeing all of the memory that you've allocated throughout the program. After you've written these two functions, you should then be able to run your inheritance program in order to simulate the inheritance of blood types across multiple generations, seeing what blood types the grandparents had, seeing how those blood types translated into the blood types of a child's parent, and ultimately, what blood type that child inherited as well. My name is Brian. And this was inheritance.