1 00:00:00,000 --> 00:00:00,500 2 00:00:00,500 --> 00:00:02,430 BRIAN: In this lab, your task is going to be 3 00:00:02,430 --> 00:00:07,530 to write a program in C that simulates the inheritance of blood type genes 4 00:00:07,530 --> 00:00:09,210 within a family. 5 00:00:09,210 --> 00:00:11,130 To give a little bit of science background, 6 00:00:11,130 --> 00:00:14,220 your blood type is determined by alleles. 7 00:00:14,220 --> 00:00:16,490 Alleles are different versions of a gene. 8 00:00:16,490 --> 00:00:19,620 And there are three different alleles with regard to blood type, 9 00:00:19,620 --> 00:00:22,440 called A, B, and O. 10 00:00:22,440 --> 00:00:25,170 Each person has two of these alleles. 11 00:00:25,170 --> 00:00:27,840 Maybe you have two A's, two B's, two O's. 12 00:00:27,840 --> 00:00:31,170 Or maybe you mix and match, have an A and a B, or a B and an O, 13 00:00:31,170 --> 00:00:34,150 or an A or an O, for example. 14 00:00:34,150 --> 00:00:38,670 And when a parent has a child, each parent passes on one of their alleles 15 00:00:38,670 --> 00:00:40,180 to their child. 16 00:00:40,180 --> 00:00:42,840 So for example, if we imagine two parents, 17 00:00:42,840 --> 00:00:47,740 one that has a blood type of AB and one who has a blood type of OO, 18 00:00:47,740 --> 00:00:51,420 tthen their child is going to inherit one blood type of little 19 00:00:51,420 --> 00:00:53,230 from each of their parents. 20 00:00:53,230 --> 00:00:56,820 For example, we might randomly choose A from one parent, 21 00:00:56,820 --> 00:01:01,380 and between the other parent O, and ultimately get a blood type of AO. 22 00:01:01,380 --> 00:01:05,110 But we also could have gotten a blood type of BO, for example. 23 00:01:05,110 --> 00:01:09,990 Which of the two alleles is passed on is just chosen at random. 24 00:01:09,990 --> 00:01:14,380 In order to simulate this type of inheritance inside of our program, 25 00:01:14,380 --> 00:01:16,560 we're going to need some sort of data structure 26 00:01:16,560 --> 00:01:20,400 that lets us represent the connection between people and their parents, 27 00:01:20,400 --> 00:01:24,200 as well as what alleles they have for their blood type. 28 00:01:24,200 --> 00:01:27,550 And because there is no type built into C to do just that, 29 00:01:27,550 --> 00:01:31,290 we can create a type of our own using a typedef. 30 00:01:31,290 --> 00:01:35,850 So here, we have typedef struct person, where every person is going 31 00:01:35,850 --> 00:01:38,250 to be represented by these two fields. 32 00:01:38,250 --> 00:01:44,160 Struct person star *parents[2] means that every person is going to have 33 00:01:44,160 --> 00:01:48,480 an array of 2 parents, where each of those parents is going to be a pointer 34 00:01:48,480 --> 00:01:50,770 to another person. 35 00:01:50,770 --> 00:01:55,020 Meanwhile, every person is also going to have an array of two characters called 36 00:01:55,020 --> 00:02:01,710 alleles, representing which two alleles, A, B, or O, this particular person has. 37 00:02:01,710 --> 00:02:06,370 And because each person has two alleles, this is going to be an array of size 2 38 00:02:06,370 --> 00:02:09,759 to represent both of those alleles. 39 00:02:09,759 --> 00:02:13,720 So in the example we saw before, we might, for this particular child, 40 00:02:13,720 --> 00:02:20,230 have the letter A stored at this child's alleles 0 and 0 stored at alleles 1. 41 00:02:20,230 --> 00:02:25,180 And meanwhile, parents[0] would point to one of the parents and parents[1] would 42 00:02:25,180 --> 00:02:27,660 point to the other parent. 43 00:02:27,660 --> 00:02:30,540 Let's see how these pieces now would come together inside 44 00:02:30,540 --> 00:02:34,020 of the distribution code that we give to you for the lab. 45 00:02:34,020 --> 00:02:36,090 There is a fair amount of distribution code 46 00:02:36,090 --> 00:02:39,570 that we already give to you inside of inheritance.c 47 00:02:39,570 --> 00:02:42,510 But let's try and distill it to just what's most important. 48 00:02:42,510 --> 00:02:46,410 Here we'll notice that same typedef, that we define a person 49 00:02:46,410 --> 00:02:50,670 as having pointers to two parents in this array of 2 pointers 50 00:02:50,670 --> 00:02:53,340 and also having an array of two characters, 51 00:02:53,340 --> 00:02:58,550 representing the two alleles that this person has for their blood type. 52 00:02:58,550 --> 00:03:02,690 Next up is this relevant variable called const int GENERATIONS, 53 00:03:02,690 --> 00:03:06,410 a constant integer, which is set equal to the number of 3. 54 00:03:06,410 --> 00:03:10,190 And this is going to represent the number of generations of data 55 00:03:10,190 --> 00:03:12,170 that we're going to simulate generating. 56 00:03:12,170 --> 00:03:14,900 In this case, we're simply waiting three generations 57 00:03:14,900 --> 00:03:17,660 worth of data for blood types, which means we're not just 58 00:03:17,660 --> 00:03:20,600 going to simulate the single child, but also generation 59 00:03:20,600 --> 00:03:27,578 2, their parents, and also generation 3, that child's grandparents as well. 60 00:03:27,578 --> 00:03:29,370 We then have some prototypes for functions, 61 00:03:29,370 --> 00:03:32,160 but let's skip down to the main function to really see 62 00:03:32,160 --> 00:03:34,440 what it is that this program is doing. 63 00:03:34,440 --> 00:03:36,390 The main function is already written for you. 64 00:03:36,390 --> 00:03:38,110 Nothing you need to do here. 65 00:03:38,110 --> 00:03:41,160 But we start by seeding the random number generator, 66 00:03:41,160 --> 00:03:44,220 just so that we're able to generate pseudo random numbers, which 67 00:03:44,220 --> 00:03:45,420 is going to be useful. 68 00:03:45,420 --> 00:03:48,210 Because when we decide how genes are inherited, 69 00:03:48,210 --> 00:03:51,420 we want to be able to randomly choose which gene is going 70 00:03:51,420 --> 00:03:54,910 to be passed on from parent to child. 71 00:03:54,910 --> 00:04:00,430 Next we call the create_family function to create a family with a specified 72 00:04:00,430 --> 00:04:05,260 number of generations, returning a pointer to the most recent generation 73 00:04:05,260 --> 00:04:07,340 of person in that family. 74 00:04:07,340 --> 00:04:09,850 So if we create a family with three generations, 75 00:04:09,850 --> 00:04:12,190 we'll end up with a pointer to one person. 76 00:04:12,190 --> 00:04:14,230 But using their parent pointers, we could 77 00:04:14,230 --> 00:04:18,010 access that child's parents as well as that child's grandparents, 78 00:04:18,010 --> 00:04:23,580 but no further if we're only looking at a family with three generations. 79 00:04:23,580 --> 00:04:26,160 The create_family function will be up to you to write. 80 00:04:26,160 --> 00:04:28,650 But the print family function we will write. 81 00:04:28,650 --> 00:04:30,900 After you've already created a family, we've 82 00:04:30,900 --> 00:04:34,080 already written for you a function that will take that family 83 00:04:34,080 --> 00:04:36,990 and print them out as a hierarchical family tree, 84 00:04:36,990 --> 00:04:41,760 printing out what blood type each of the people in that family has. 85 00:04:41,760 --> 00:04:44,640 Finally, you'll write the free_family function, 86 00:04:44,640 --> 00:04:47,640 which will free all of the memory that you may have allocated 87 00:04:47,640 --> 00:04:49,860 in the process of creating this family. 88 00:04:49,860 --> 00:04:52,050 Because recall that for each of the people 89 00:04:52,050 --> 00:04:55,350 that you want to represent inside of your computer's memory, 90 00:04:55,350 --> 00:04:57,570 you'll likely need to allocate memory for them 91 00:04:57,570 --> 00:05:01,370 by using the malloc function to allocate some memory dynamically. 92 00:05:01,370 --> 00:05:03,990 But any time you allocate memory with malloc, 93 00:05:03,990 --> 00:05:07,530 you'll also want to free that memory, giving it back to the computer 94 00:05:07,530 --> 00:05:11,010 so that it can be used for other purposes. 95 00:05:11,010 --> 00:05:13,500 Here then, in the create_family function, 96 00:05:13,500 --> 00:05:17,280 is going to be what you'll implement, allocating memory for a new person 97 00:05:17,280 --> 00:05:19,830 and then dealing with two possible cases. 98 00:05:19,830 --> 00:05:22,770 One, if there are potential parents that this child has 99 00:05:22,770 --> 00:05:25,380 that we need to recursively generate, or else, 100 00:05:25,380 --> 00:05:27,930 if we're just generating a single generation, 101 00:05:27,930 --> 00:05:31,700 generating just a single person without any parent data. 102 00:05:31,700 --> 00:05:35,060 You'll also, then, write the free_family function, which 103 00:05:35,060 --> 00:05:37,990 takes as input a pointer to a person p. 104 00:05:37,990 --> 00:05:43,130 And the task for this function is to free p as well as any ancestors of p. 105 00:05:43,130 --> 00:05:47,000 So if person p has parents or grandparents or other ancestors 106 00:05:47,000 --> 00:05:50,200 as well, you'll want to make sure to free them, too. 107 00:05:50,200 --> 00:05:52,200 The print family function we've written for you. 108 00:05:52,200 --> 00:05:53,760 No need to do anything here. 109 00:05:53,760 --> 00:05:56,760 It takes a person and goes ahead and prints out their entire family 110 00:05:56,760 --> 00:05:58,620 tree, along with their blood types. 111 00:05:58,620 --> 00:06:02,640 And this random allele function that we wrote might be helpful for you, too. 112 00:06:02,640 --> 00:06:06,360 It randomly chooses an allele, A, B, or O, 113 00:06:06,360 --> 00:06:08,430 which can be useful if you get to a point 114 00:06:08,430 --> 00:06:10,900 where you need to randomly generate an allele 115 00:06:10,900 --> 00:06:14,740 to store inside of that allele's array. 116 00:06:14,740 --> 00:06:17,140 So with that distribution code in mind, let's then 117 00:06:17,140 --> 00:06:20,530 walk through what it is that your program is going to do. 118 00:06:20,530 --> 00:06:24,310 The first thing you should do is complete the create_family function 119 00:06:24,310 --> 00:06:28,270 to create a family with a specified number of generations. 120 00:06:28,270 --> 00:06:31,120 In order to do so, the first thing you should do 121 00:06:31,120 --> 00:06:34,750 is allocate memory for a new person, calling malloc, 122 00:06:34,750 --> 00:06:36,850 passing in size of person to make sure you 123 00:06:36,850 --> 00:06:38,980 have enough memory for a new person. 124 00:06:38,980 --> 00:06:42,580 And then you'll use that person to potentially generate ancestors 125 00:06:42,580 --> 00:06:45,860 if there are more generations that you need to work with. 126 00:06:45,860 --> 00:06:50,560 So if generations is greater than 1, meaning there are more generations 127 00:06:50,560 --> 00:06:53,170 that you need to generate, then you'll recursively 128 00:06:53,170 --> 00:06:55,960 create those previous generations. 129 00:06:55,960 --> 00:06:59,410 What does it mean to recursively create previous generations? 130 00:06:59,410 --> 00:07:03,820 Well, if you're trying to create a child that has two generations of parents 131 00:07:03,820 --> 00:07:06,820 then you'll recursively call the create_family function 132 00:07:06,820 --> 00:07:09,520 for each of those parents where each one of those parents 133 00:07:09,520 --> 00:07:14,060 will have one generation of parents, and so on and so forth. 134 00:07:14,060 --> 00:07:16,390 So if generations is greater than 1, you'll 135 00:07:16,390 --> 00:07:19,810 want to recursively create those previous generations. 136 00:07:19,810 --> 00:07:24,400 And using the return value you get from those create_family functions, 137 00:07:24,400 --> 00:07:29,470 you'll update this new person's parents, setting parents[0] equal to the result 138 00:07:29,470 --> 00:07:34,240 of one recursive call and setting parents[1] equal to the result of some 139 00:07:34,240 --> 00:07:36,850 other recursive call. 140 00:07:36,850 --> 00:07:39,400 After you set that person's parents, recall 141 00:07:39,400 --> 00:07:42,560 that every person not only has two pointers to parents, 142 00:07:42,560 --> 00:07:44,590 but also has two alleles. 143 00:07:44,590 --> 00:07:48,310 So now you'll need to do the actual inheritance step, inheriting 144 00:07:48,310 --> 00:07:51,580 one allele from each parent at random. 145 00:07:51,580 --> 00:07:55,290 So you want to inherit the alleles from the parents by looking at one parents 146 00:07:55,290 --> 00:08:01,050 two alleles, randomly choosing one, and setting that as the child's allele 0. 147 00:08:01,050 --> 00:08:04,440 And then doing the same with the other parent, looking at their two alleles, 148 00:08:04,440 --> 00:08:10,770 randomly choosing one, and using one of those as alleles[1] so that the child 149 00:08:10,770 --> 00:08:16,780 ends up with two alleles, one inherited from either parent. 150 00:08:16,780 --> 00:08:19,840 Otherwise, if generations is equal to 1, that 151 00:08:19,840 --> 00:08:23,230 means you're only generating one generation worth of family, that is, 152 00:08:23,230 --> 00:08:26,050 an individual person with no parents. 153 00:08:26,050 --> 00:08:30,375 And if that's the case, then both of the parent pointers should be set to null. 154 00:08:30,375 --> 00:08:32,500 And because there is nothing to inherit, because we 155 00:08:32,500 --> 00:08:34,600 don't have any data about the parents, you'll 156 00:08:34,600 --> 00:08:37,780 go ahead and randomly generate alleles for each of the two 157 00:08:37,780 --> 00:08:39,970 alleles for this particular person. 158 00:08:39,970 --> 00:08:42,130 And recall that, in the distribution code, 159 00:08:42,130 --> 00:08:46,780 we give to you a function that will randomly generate those alleles. 160 00:08:46,780 --> 00:08:50,950 The final step for this lab is going to be to write the free_family function 161 00:08:50,950 --> 00:08:53,230 to free all of that allocated memory. 162 00:08:53,230 --> 00:08:56,410 Recall that every time you called the create_family function, 163 00:08:56,410 --> 00:08:58,930 you were calling malloc at least once in order 164 00:08:58,930 --> 00:09:02,170 to generate data for a new person, to allocate memory 165 00:09:02,170 --> 00:09:06,080 for that person dynamically inside of the computer's heap. 166 00:09:06,080 --> 00:09:07,960 Now, after you've malloced that memory, it's 167 00:09:07,960 --> 00:09:10,960 your task at the end of the program to free all of that memory 168 00:09:10,960 --> 00:09:13,240 up and give it back to the computer. 169 00:09:13,240 --> 00:09:16,750 In order to do so, you'll want to first handle the base case. 170 00:09:16,750 --> 00:09:20,860 If the input to free_family is null, there is no action you should take. 171 00:09:20,860 --> 00:09:23,800 You should never be freeing the null pointer. 172 00:09:23,800 --> 00:09:26,710 But after that, you'll want to deal with the recursive case, 173 00:09:26,710 --> 00:09:31,390 recursively freeing the parents, and then after that, freeing the child. 174 00:09:31,390 --> 00:09:33,610 How do you recursively free the parents? 175 00:09:33,610 --> 00:09:36,700 Well, you'll want to call the free_family function 176 00:09:36,700 --> 00:09:38,860 on each of the child's two parents. 177 00:09:38,860 --> 00:09:41,680 Recursively then, that will also call for a family 178 00:09:41,680 --> 00:09:44,290 on the child's grandparents and higher generations, 179 00:09:44,290 --> 00:09:46,520 if there are other generations, as well. 180 00:09:46,520 --> 00:09:50,680 And after those parents have been freed then you can use free in order 181 00:09:50,680 --> 00:09:54,520 to free the child as well, ultimately freeing all of the memory 182 00:09:54,520 --> 00:09:57,000 that you've allocated throughout the program. 183 00:09:57,000 --> 00:09:59,050 After you've written these two functions, 184 00:09:59,050 --> 00:10:02,160 you should then be able to run your inheritance program in order 185 00:10:02,160 --> 00:10:06,390 to simulate the inheritance of blood types across multiple generations, 186 00:10:06,390 --> 00:10:08,880 seeing what blood types the grandparents had, 187 00:10:08,880 --> 00:10:12,630 seeing how those blood types translated into the blood types of a child's 188 00:10:12,630 --> 00:10:17,610 parent, and ultimately, what blood type that child inherited as well. 189 00:10:17,610 --> 00:10:18,690 My name is Brian. 190 00:10:18,690 --> 00:10:21,500 And this was inheritance. 191 00:10:21,500 --> 00:10:22,000