/********************************************************************** * Description of this file 'bloodtype1.c' *********************************************************************/ /* * FILE NAME: bloodtype1.c * * * PROGRAM: bloodtype1 * * * LANGUAGE: ANSI C * * * REVISION: 1.02 -- 02/19/08 Made minor improvements to several * comments. * By Don Braun. * * 1.01 -- 04/25/07 Corrected handling of a read error * before any characters on the input * line, and improved many comments. * By Don Braun. * * 1.00 -- 04/17/07 Initial version. * By Don Braun. * * * USAGE #1: bloodtype1 * USAGE #2: bloodtype1 < Blood1In.txt > Blood1Out.txt * * * FOR HELP: bloodtype1 -h | more (prints 98 lines) * * * ARGUMENTS: No arguments are expected on the command line, but * text input and text output may be redirected. * * * PURPOSE: * * This program bloodtype1 solves "Problem A+, Consanguine * Calculations" for the 2007 World Finals of the ACM * (Association for Computing Machinery) International Collegiate * Programming Contest. This is the first problem described in * the file at the Web address * http://icpc.baylor.edu/icpc/Finals/2007WorldFinalProblemSet.pdf * as follows. * * Every person's blood has 2 markers called ABO alleles. Each of * the markers is represented by one of three letters: A, B, or * O. This gives six possible combinations of these alleles that * a person can have, each of them resulting in a particular ABO * blood type for that person. * * Combination ABO Blood Type * ----------- -------------- * AA A * AB AB * AO A * BB B * BO B * OO O * * Likewise, every person has two alleles for the blood Rh factor, * represented by the characters + and -. Someone who is * "Rh positive" or "Rh+" has at least one + allele, but * could have two. Someone who is "Rh negative" always has * two - alleles. * * The blood type of a person is a combination of ABO blood type * and Rh factor. The blood type is written by suffixing the * ABO blood type with the + or - representing the Rh factor. * Examples include A+, AB-, and O-. * * Blood types are inherited: each biological parent donates one * ABO allele (randomly chosen from their two) and one Rh factor * allele to their child. Therefore 2 ABO alleles and 2 Rh * factor alleles of the parents determine the child's blood * type. For example, if both parents of a child have blood type * A-, then the child could have either type A- or type O- blood. * A child of parents with blood types A+ and B+ could have any * blood type. * * In this problem, you will be given the blood type of either both * parents or one parent and a child; you will then determine * the (possibly empty) set of blood types that might * characterize the child or the other parent. * * Note: an uppercase letter "Oh" is used in this problem to * denote blood types, not a digit (zero). * * Input * ----- * * The input consists of multiple test cases. Each test case is * on a single line in the format: the blood type of one parent, * the blood type of the other parent, and finally the blood type * of the child, except that the blood type of one parent or the * child will be replaced by a question mark. To improve * readability, whitespace may be included anywhere on the line * except inside a single blood type specification. * * The last test case is followed by a line containing the letters * E, N, and D separated by whitespace. * * Output * ------ * * For each test case in the input, print the case number * (beginning with 1) and the blood type of the parents and the * child. If no blood type for a parent is possible, print * "IMPOSSIBLE". If multiple blood types for parents or child * are possible, print all possible values in a comma-separated * list enclosed in curly braces. The order of the blood types * inside the curly braces does not matter. * * The sample output illustrates multiple output formats. Your * output format should be similar. * * Sample Input Output for the Sample Input * ------------ ------------------------------------------ * O+ O- ? Case 1: O+ O- {O+, O-} * O+ ? O- Case 2: O+ {A-, A+, B-, B+, O-, O+} O- * AB- AB+ ? Case 3: AB- AB+ {A+, A-, B+, B-, AB+, AB-} * AB+ ? O+ Case 4: AB+ IMPOSSIBLE O+ * E N D * * * SECTION HEADINGS: * * The section headings in this file are listed here as a summary: * * Description of this file 'bloodtype1.c' * Describe terminology and briefly summarize genetic inheritance * List prototypes for functions in this source file * Declare standard C '#include' header files * Define enum constants for some exit status values from this program * Globals helpMsg1Format and helpMsg2Array[] for the help messages * #define; bloodTypeNames[]; 'typedef enum { TypAP, ... } BloodType' * Global array 'BloodType typeFrom2AllelePairs[6][6] = {{Typ...},...}' * Global array 'BloodType allAllelePairs[6] = {Typ..., ...}' * Function 'void fprintMsg()' * Function 'int fgetline()' * Function 'void getMomsAndDadsAllelePairsFromKidsType()' * Function 'void sortUniqueTypes()' * Function 'void getTypesFromAnyAlleles1AndAnyAlleles2()' * Function 'void keepMomDadAllelesOnlyIfMomsType()' * Function 'void keepDadMomAllelesOnlyIfDadsType()' * Function 'BloodType getTypeEnumFromTypeStr()' * Function 'BloodType getStrFromTypeEnums()' * Declarations for program main(...) * main(): Begin execution by printing a help message if necessary * main(): Begin 'while (1)' loop; read and parse the next input line * main(): Find mom's allowed blood types if 1st input field was "?" * main(): Find dad's allowed blood types if 2nd input field was "?" * main(): Find kid's allowed blood types if 3rd input field was "?" * main(): End of loop 'while (1)'; end of function 'int main()' * End of this file 'bloodtype1.c' */ /********************************************************************** * Describe terminology and briefly summarize genetic inheritance *********************************************************************/ /* * 1. Blood group * * Four human blood groups exist, called A, B, O (letter "Oh"), * and AB. Those blood groups denote what antigens (particular * kinds of proteins) are attached to the surface of each of a * person's red blood cells. The normal function of red blood * cells is to carry oxygen from the lungs to parts of the body. * Group A blood has only one kind of antigen (the "A" protein) * attached to each red blood cell, group B blood has only a * second kind of antigen (the "B" protein), group O blood has * neither kind of antigen, and group AB blood has both kinds of * antigen. * * 2. Rhesus factor (or Rh Factor) * * In addition to blood groups, two human blood Rh factors exist, * denoted by the characters + and -. Blood with Rh factor + * (also called "RhD positive" or simply "Rh+") has a particular * kind of antigen (called Rh D) attached to each red blood cell, * but blood with Rh factor - (also called "RhD negative" or * "Rh-") does not have that antigen. * * 3. Blood type * * Each person has one of 8 blood types consisting of the blood's * ABO group and the Rh factor, denoted by A+, A-, B+, B-, O+, O-, * AB+, or AB-. Approximate percentages of the U.S. population * with each of those blood types from common to rare are: 38% O+, * 34% A+, 9% B+, 7% O-, 6% A-, 3% AB+, 2% B-, 1% AB- * (see Web address http://www.howstuffworks.com/question593.htm). * Populations of different ethnic or racial groups typically have * different percentages for blood types. As an extreme example, * essentially no people whose ancestors are all Indians of Peru * have A or B antigens, so 100% of them have blood type O+ or O-. * The Web page http://www.bloodbook.com/world-abo.html lists * percentages of blood groups for many ethnic and racial groups. * * 4. Immune system reaction to blood types * * When a person receives whole blood by transfusion, the immune * system (including white blood cells) can attack new red blood * cells if those red blood cells have any of the antigens that * are not naturally present in that person's blood. Typically, a * foreign antigen causes the immune system to generate antibodies * to attack that antigen. These antibodies cause blood with the * corresponding antigen to clump together, and those clots may * lead to organ failure or death. Therefore, for example, a * recipient with group A blood can be given blood safely from a * donor with group A or O but not from a donor with group B or * AB blood. Likewise, a recipient with Rh factor - can get blood * from a donor with Rh factor -, but not from a donor with Rh * factor +. * * The following matrix shows whether ("YES") or not ("no") every * possible blood transfusion can be done safely with the * recipient's immune system accepting the donor's blood. * * --------------------------------------------------------- * | Donor | Recipient blood type | * | blood |===============================================| * | type | A+ | A- | B+ | B- | O+ | O- | AB+ | AB- | * |-------|-----|-----|-----|-----|-----|-----|-----|-----| * | A+ | YES | no | no | no | no | no | YES | no | * | A- | YES | YES | no | no | no | no | YES | YES | * | B+ | no | no | YES | no | no | no | YES | no | * | B- | no | no | YES | YES | no | no | YES | YES | * | O+ | YES | no | YES | no | YES | no | YES | no | * | O- | YES | YES | YES | YES | YES | YES | YES | YES | * | AB+ | no | no | no | no | no | no | YES | no | * | AB- | no | no | no | no | no | no | YES | YES | * --------------------------------------------------------- * * A person with blood type O- is called a universal donor because * that person can give blood to people with any blood type * without an adverse reaction from the recipient's immune system. * Likewise, a person with AB+ can be called a universal recipient * because that person can receive blood of any type without an * adverse reaction. In contrast, a person with type O- blood can * receive only type O- blood without an adverse reaction. * * 5. Genetic inheritance * * (somatic cell; chromosome; DNA; chromatid; centromere; * double helix; nucleotide bases A, T, C, and G; * tri-nucleotide codon; RNA; nucleotide base U; * amino acid; start codon; stop codon; gene; protein; * genome; locus of a gene on a chromosome; allele; * diploid organism; homologous pair of chromosomes; * genotype; homozygous genes; heterozygous genes; * phenotype; dominant and recessive alleles of a gene, * or co-dominant alleles of a gene) * * Except for the sex cells called gametocytes from which the ova * (that is, egg cells) in a female and sperm in a male are made * and the undifferentiated stem cells, every cell type in the * mammalian body is called a somatic cell. Internal organs, skin, * bones, blood, and connective tissue are all made up of somatic * cells. The nucleus of a somatic human cell contains 23 pairs * of chromosomes of genetic material, giving a total of 46 * chromosomes per cell. One of these chromosomes in each pair was * inherited from the person's mother and the other one was * inherited from the person's father. * * Each of these chromosomes is a pair of linear macromolecules of * DNA (deoxyribonucleic acid) that are joined at a region * typically near the middle called the centromere. Each of these * two DNA macromolecules is called a chromatid and contains a pair * of strands of nucleotides, which are tightly entwined around * each other in the shape of a ladder with short stiff rungs whose * two long flexible rails are twisted into a double helix. In the * actual DNA molecule where each rung of the twisted ladder shape * meets one of the two rails there is one of 4 kinds of chemical * nucleotide bases called adenine, thyamine, cytosine, and * guanine, which are generally abbreviated by the letters A, T, C, * and G, respectively. An adenine (A) base where a rung meets one * rail of the ladder shape is almost always paired by a hydrogen * bond with a thyamine (T) base where the opposite end of that * rung meets the other rail. A cytosine (C) base where a rung * meets one rail is almost always paired with a guanine (G) base * where the opposite end of that rung meets the other rail. Each * ordered sequence of 3 DNA nucleotide bases (such as ACT or TGG) * is called a codon. Thus, 4*4*4 = 64 possible codons exist. * After a DNA codon is transcribed into a related RNA (ribonucleic * acid) codon, where DNA thyamine (T) bases are replaced by * uracil (U) bases in RNA, the codon can be used either to direct * the synthesis of one of 20 amino acids or else to specify the * start (RNA codon AUG) or end (RNA codon UAA, UAG, or UGG) of a * sequence of bases called a gene. Codons in a DNA molecule * between a stop codon and the next start codon are not part of * any gene. A gene usually directs the synthesis of a protein, * which is built by chaining together the amino acids that are * associated with the codons forming the gene. Genes can interact * with each other to influence physical development and behavior. * A human DNA molecule consists of from 50,961,097 nucleotide base * pairs including 231 genes in the shortest chromosome (called Y) * up to 245,203,898 nucleotide base pairs including 2968 genes in * the longest chromosome (called #1). A typical gene consists of * hundreds to thousands of codons of necleotide base triplets * between the start codon and the next stop codon. The human * genome (that is, the hereditary information encoded in the * sequences of DNA nucleotides on all 23 distinct chromosomes) * includes about 20,000 to 25,000 protein-coding genes. * * One or more genes in certain loci (that is, positions) on * particular chromosomes can determine an inherited characteristic * such as blood type or eye color. An allele is one of perhaps * several possible particular DNA sequences of the nucleotides * A, T, C, and G that can code the gene at a specific locus (or * sometimes can code a non-gene sequence of DNA). An individual * organism's genotype for that gene is the set of its alleles that * person happens to possess. A diploid organism, including a * human, is one that has two homologous (or similarly structured) * versions of each chromosome, where one of those two chromosomes * is inherited from each parent. For a diploid organism, the two * alleles for a gene (with one on each of the two similar * chromosomes) make up the individual's genotype for the * corresponding gene. A diploid organism in which the two copies * of the gene are identical (that is, have the same allele) is * called homozygous for that gene. An organism that has two * different alleles of the gene is called heterozygous. * * Phenotypes (the expressed characteristics) associated with a * certain allele can sometimes be dominant or recessive, but often * they are neither. A dominant phenotype will be expressed when * at least one allele of its associated type is present, whereas a * recessive phenotype will only be expressed when both alleles are * of its associated type. For blood, the Rh+ allele is dominant * over the recessive Rh- allele. However, the blood group A * allele is co-dominant with the blood group B allele for that * gene, which means that if an A or B allele is present in that * gene inherited from either the mother or the father then that * allele gets expressed in the phenotype of the child. * * References: * For example, see the Wikipedia articles (under the Web address * http://en.wikipedia.org/wiki/) for Somatic_cell, Chromosome, * Centromere, DNA, Codon, RNA, Gene, and Allele. * Also see http://waynesword.palomar.edu/lmexer3.htm about the * structure and function of DNA. * * 6. Blood genotype allele pair from mom or else from dad * * Each person has two blood genotype allele pairs, inheriting one * pair from the mother and the other pair from the father. Each * of these two allele pairs consists of an allele for any one of * the 3 blood groups (A, B, or O) paired with an allele for one of * the 2 Rh factors (+ or -). The 6 possible values of such an * allele pair are denoted by A+, A-, B+, B-, O+, and O-. * * 7. Blood phenotype (or blood type) * * Each person exhibits one blood phenotype (which is usually * simply called the blood type) based on the two blood genotype * allele pairs inherited from the parents. The 8 possible * phenotypes consist of the exhibited blood group (A, B, O, or AB) * and the exhibited Rh factor (+ or -), and so they are denoted by * A+, A-, B+, B-, O+, O-, AB+, AB-. The rules that determine a * person's blood phenotype from the two inherited blood genotype * allele pairs will be stored below in the global array * typeFrom2AllelePairs[][] . * * 8. The importance of the Rh factor for pregnancy * * The Rh factor is also important for pregnant women. If an Rh+ * man and an Rh- woman have a child, the child can be Rh+ or Rh-, * depending upon the genotype of the father. If the fetus is Rh+, * this can cause problems. While in the womb, some blood cells * from the fetus will cross the placenta into the mother's blood * stream. The mother will make antibodies against the Rh+ cells. * If the woman becomes pregnant again and if the baby is Rh+, the * mother's anti-Rh antibodies will cross into the baby's blood and * destroy its red blood cells, which can kill the baby. If * diagnosed early, it is possible to save a baby under these * circumstances by replacing the baby's blood with transfusions * that are free of the Rh antibodies. Also, if this situation is * known, it is possible to treat an Rh- woman with anti-Rh * antibodies (RhoGam) immediately after childbirth to inactivate * the baby's Rh+ cells and prevent the mother from forming * anti-Rh antibodies (desensitize her). (This was quoted from the * Web address http://www.howstuffworks.com/question593.htm .) */ /********************************************************************** * List prototypes for functions in this source file *********************************************************************/ /* * void fprintMsg( * FILE *pFileMsg, * const char * const *msgPtrArray); * * int fgetline( * FILE *fp, * char str[], * int lim); * * void getMomsAndDadsAllelePairsFromKidsType( * const BloodType kidsType, * int *pNumAllelePairs, * BloodType momsAllelePairs[DimGenotypes], * BloodType dadsAllelePairs[DimGenotypes]); * * void sortUniqueTypes( * int *pNumTypes, * BloodType typesArg[DimGenotypes]); * * void getTypesFromAnyAlleles1AndAnyAlleles2( * const int numAlleles1, * const BloodType allelePairs1[DimGenotypes], * const int numAlleles2, * const BloodType allelePairs2[DimGenotypes], * int *pNumTypes, * BloodType typesArg[DimGenotypes]); * * void keepMomDadAllelesOnlyIfMomsType( * const BloodType momsType, * int *pNumAlleles, * BloodType momsAllelePairs[DimGenotypes], * BloodType dadsAllelePairs[DimGenotypes]); * * void keepDadMomAllelesOnlyIfDadsType( * const BloodType dadsType, * int *pNumAlleles, * BloodType dadsAllelePairs[DimGenotypes], * BloodType momsAllelePairs[DimGenotypes]); * * BloodType getTypeEnumFromTypeStr( * const char *bloodTypeStr); * * const char *getStrFromTypeEnums( * const int numTypes, * const BloodType typeEnums[DimGenotypes]); * * int main( * int argc, * char *argv[]); */ /********************************************************************** * Declare standard C '#include' header files *********************************************************************/ /* * The statement '#include ' declares types, macros, and * input and output functions implemented in the ANSI C standard * library. * * The standard ANSI C library input and output header file stdio.h * will '#define' or otherwise declare the following constants, * 'typedef's, and macros: * FILE - typedef for a structure used for buffered file I/O * NULL - typically ((void *) 0) or else ((char *) 0) * stdin - standard input FILE pointer (i.e., input stream) * stdout - standard output FILE pointer (i.e., output stream) * getc() - macro that gets next character as 'int' from stream * and will declare a prototype of the following standard ANSI C * library function: * sscanf() - formatted input from a character string * fprintf() - formatted printing to a FILE pointer (output stream) * printf() - formatted printing to standard output (stdout) */ #include /* * The standard C header file string.h will declare prototypes for * ANSI C standard library functions for manipulating null-terminated * character strings. * * In the following table, the function arguments are assumed to have * these type declarations in the function: * * char *s; (The caller's argument for s must be a * pointer to a string of alterable * characters which is generally terminated * by a null character, (char) '\0'. * The characters in that string may be * altered by the function.) * * const char *cs; (The caller's argument for cs must be a * pointer to a string of alterable or * unalterable characters which is generally * terminated by a null character. * The characters in that string will not be * altered by the function.) * * const char *ct; (The caller's argument for ct must be a * pointer to a string of alterable or * unalterable characters which is generally * terminated by a null character. * The characters in that string will not be * altered by the function.) * * As an example, in the following code fragment the first call to * function strcpy() is acceptable because its first argument * (myStr) passed is a pointer to a string of alterable characters, * which is required. The second argument passed for this first call * is a pointer to a string of unalterable characters. * However, the second call to strcpy() is unacceptable because the * first argument passed is a pointer to a string of unalterable * characters, which is not allowed. The second argument (myStr) * passed for this second call is a pointer to a string of alterable * characters. * * char myStr[80]; * strcpy(myStr, "A constant source string is OKAY"); * strcpy("A constant destination string is NOT ALLOWED", myStr); * * C library function Description * ======================= =========================================== * char *strcpy(s,ct) Copy string ct to string s, including * '\0'; return s . * char *strcat(s,ct) Concatenate string ct to end of string * s; return s . * char *strcmp(cs,ct) Compare string cs to string ct; * return <0 if cs0 if cs>ct . */ #include /********************************************************************** * Define enum constants for some exit status values from this program *********************************************************************/ enum { ExitStatusSuccess = 0, /* Exit status to be returned to the * operating system upon successful * completion of this program, * indicating that all input lines * contained proper information with * the expected format and were * processed successfully */ ExitStatusHelp = 1, /* Exit status code to be returned to the * operating system if this program * successfully completes printing * its detailed online help message * because the option -h was specified */ ExitStatusBadCmdArgs = 2, /* Exit status code to be returned to the * operating system if this program * detects any command line arguments * except one '-h' */ ExitStatusBadInputData = 3 /* Exit status code to be returned to the * operating system if at least one * input line contained improper * information or had an unexpected * format that could not be processed */ }; /* End of 'enum { ExitStatus... }' */ /********************************************************************** * Globals helpMsg1Format and helpMsg2Array[] for the help messages *********************************************************************/ /* * Initialize a null-terminated unalterable character string to be used * as a format string for printing a brief help message about how to * use this program, to be used if command line arguments are bad. */ const char *helpMsg1Format = "USAGE #1: bloodtype1\n" "USAGE #2: bloodtype1 < Blood1In.txt > Blood1Out.txt\n" "\n" "FOR HELP: bloodtype1 -h | more (prints %d lines)\n"; /* * Initialize an array of pointers to null-terminated unalterable * character strings, where each string is one line of a detailed * help message to be printed when running the command line * 'bloodtype1 -h'. */ const char *helpMsg2Array[] = { "", "ARGUMENTS: No arguments are expected on the command line, but", " text input and text output may be redirected.", "", "REVISION: 1.02 -- 02/19/2008 by Don Braun", "", "PURPOSE:", "", " This program bloodtype1 solves \"Problem A+, Consanguine", " Calculations\" for the 2007 World Finals of the ACM", " (Association for Computing Machinery) International Collegiate", " Programming Contest. This is the first problem described in", " the file at the Web address", " http://" "icpc.baylor.edu/icpc/Finals/2007WorldFinalProblemSet.pdf", " as follows.", "", " Every person's blood has 2 markers called ABO alleles. Each of", " the markers is represented by one of three letters: A, B, or", " O. This gives six possible combinations of these alleles that", " a person can have, each of them resulting in a particular ABO", " blood type for that person.", "", " Combination ABO Blood Type", " ----------- --------------", " AA A", " AB AB", " AO A", " BB B", " BO B", " OO O", "", " Likewise, every person has two alleles for the blood Rh factor,", " represented by the characters + and -. Someone who is", " \"Rh positive\" or \"Rh+\" has at least one + allele, but", " could have two. Someone who is \"Rh negative\" always has", " two - alleles.", "", " The blood type of a person is a combination of ABO blood type", " and Rh factor. The blood type is written by suffixing the", " ABO blood type with the + or - representing the Rh factor.", " Examples include A+, AB-, and O-.", "", " Blood types are inherited: each biological parent donates one", " ABO allele (randomly chosen from their two) and one Rh factor", " allele to their child. Therefore 2 ABO alleles and 2 Rh", " factor alleles of the parents determine the child's blood", " type. For example, if both parents of a child have blood type", " A-, then the child could have either type A- or type O- blood.", " A child of parents with blood types A+ and B+ could have any", " blood type.", "", " In this problem, you will be given the blood type of either both", " parents or one parent and a child; you will then determine", " the (possibly empty) set of blood types that might", " characterize the child or the other parent.", "", " Note: an uppercase letter \"Oh\" is used in this problem to", " denote blood types, not a digit (zero).", "", " Input", " -----", "", " The input consists of multiple test cases. Each test case is", " on a single line in the format: the blood type of one parent,", " the blood type of the other parent, and finally the blood type", " of the child, except that the blood type of one parent or the", " child will be replaced by a question mark. To improve", " readability, whitespace may be included anywhere on the line", " except inside a single blood type specification.", "", " The last test case is followed by a line containing the letters", " E, N, and D separated by whitespace.", "", " Output", " ------", "", " For each test case in the input, print the case number", " (beginning with 1) and the blood type of the parents and the", " child. If no blood type for a parent is possible, print", " \"IMPOSSIBLE\". If multiple blood types for parents or child", " are possible, print all possible values in a comma-separated", " list enclosed in curly braces. The order of the blood types", " inside the curly braces does not matter.", "", " The sample output illustrates multiple output formats. Your", " output format should be similar.", "", " Sample Input Output for the Sample Input", " ------------ ------------------------------------------", " O+ O- ? Case 1: O+ O- {O+, O-}", " O+ ? O- Case 2: O+ {A-, A+, B-, B+, O-, O+} O-", " AB- AB+ ? Case 3: AB- AB+ {A+, A-, B+, B-, AB+, AB-}", " AB+ ? O+ Case 4: AB+ IMPOSSIBLE O+", " E N D", NULL }; const int numLinesHelpMsg1 = 4; const int numLinesHelpMsg2 = sizeof(helpMsg2Array) / sizeof(char *) - 1; /********************************************************************** * #define; bloodTypeNames[]; 'typedef enum { TypAP, ... } BloodType' *********************************************************************/ /* * Each input line (terminated by a newline character '\n') will be * read as a null-terminated string into buffer array inpLin[] * declared below in the function main() . * No input will contain more than DimInputLine - 2 characters before * the newline, or else an error message will be printed and this * program will terminate immediately while returning * ExitStatusBadInputData to the operating system. */ #define DimInputLine 5120 /* * DimAllelePairs = (the total number of allele pairs, consisting * of any one of the 3 blood groups [A, B, or O] * paired with one of the 2 Rh factors [+ or -]: * A+, A-, B+, B-, O+, O-) */ #define DimAllelePairs 6 /* * DimBloodTypes = (the total number of possible blood phenotypes: * A+, A-, B+, B-, O+, O-, AB+, AB-) */ #define DimBloodTypes 8 /* * DimBloodTypeStr = (the number characters, including the terminating * null character, of the longest output blood type * string for any person: * "{A+, A-, B+, B-, O+, O-, AB+, AB-}" * 123456789-123456789-123456789-1234) */ #define DimBloodTypeStr 35 /* * Initialize the array of pointers to null-terminated constant * character strings for each of the DimBloodTypes = 8 possible * blood phenotypes. */ const char *bloodTypeNames[DimBloodTypes] = { "A+", "A-", "B+", "B-", "O+", "O-", "AB+", "AB-" }; /* * Assign integers 0 through 5 to enum names of the * DimAllelePairs = 6 possible allele pairs. * Assign integers 0 through 7 to enum names of the * DimBloodTypes = 8 possible blood phenotypes. * Assign integer 8 to the enum name TypUnknown, which indicates * an unknown allele pair or blood phenotype. * * Define the typedef 'BloodType' for those DimBloodTypes + 1 = 9 * enumeration names. */ typedef enum { TypAP = 0, /* A+ allele pair or blood type */ TypAN, /* A- allele pair or blood type */ TypBP, /* B+ allele pair or blood type */ TypBN, /* B- allele pair or blood type */ TypOP, /* O+ allele pair or blood type */ TypON, /* O- allele pair or blood type */ TypABP, /* AB+ blood type only */ TypABN, /* AB- blood type only */ TypUnknown /* Unknown blood type (none of the 8 above */ } BloodType; /********************************************************************** * Global array 'BloodType typeFrom2AllelePairs[6][6] = {{Typ...},...}' *********************************************************************/ /* * Initialize the 2-dimensional array typeFrom2AllelePairs[][] with * data for the blood type exhibited by a child (that is, the * phenotype consisting of an ABO group and a Rhesus factor) whose * genes (that is, whose genotype) include two allele pairs (one * allele pair from each of that child's two parents, respectively). * This array represents the genetic rules of inheritance for blood * types, on which the computations of this program are based. */ /* Row: Column: */ /* allele pair allele pair */ /* from mom from dad */ /* -------------- -------------- */ BloodType typeFrom2AllelePairs[DimAllelePairs][DimAllelePairs] = { /* Allele Allele pair from dad */ /* pair ============================================== */ /* from mom A+ A- B+ B- O+ O- */ /* -------- ------- ------- ------- ------- ------- ------ */ /* A+ */ { TypAP, TypAP, TypABP, TypABP, TypAP, TypAP }, /* A- */ { TypAP, TypAN, TypABP, TypABN, TypAP, TypAN }, /* B+ */ { TypABP, TypABP, TypBP, TypBP, TypBP, TypBP }, /* B- */ { TypABP, TypABN, TypBP, TypBN, TypBP, TypBN }, /* O+ */ { TypAP, TypAP, TypBP, TypBP, TypOP, TypOP }, /* O- */ { TypAP, TypAN, TypBP, TypBN, TypOP, TypON } }; /* End of 'BloodType typeFrom2AllelePairs[][] =' */ /* * As a check, the blood phenotype values in the array * typeFrom2AllelePairs[][] defined just above form a symmetrical * 2-dimensional square matrix as it should; that is, the matrix * equals the transpose of itself because * typeFrom2AllelePairs[allelePair1][allelePair2] = * typeFrom2AllelePairs[allelePair2][allelePair1] * whenever 0 <= allelePair1 <= DimAllelePairs - 1 = 5 * and 0 <= allelePair2 <= DimAllelePairs - 1 = 5 . * That symmetry is necessary because inheriting the first particular * allele pair from mom and the second particular allele pair from * dad determines the same blood phenotype in the child as inheriting * that first particular allele pair from dad and that second * particular allele pair from mom. */ /* * The array typeFrom2AllelePairs[][] that was allocated and * initialized just above contains the following number of elements * equal to each typedef BloodType enum constant for a blood * phenotype. * * (# of array elements * equal to that phenotype) * = (# of distinct genotype * child's combinations of an * typedef allele pair from mom and * BloodType child's an allele pair from dad * int enum blood which could produce * value constant phenotype that phenotype) * ----- --------- --------- --------------------------- * 0 = TypAP A+ 9 * 1 = TypAN A- 3 * 2 = TypBP B+ 9 * 3 = TypBN B- 3 * 4 = TypOP O+ 3 * 5 = TypON O- 1 * 6 = TypABP AB+ 6 * 7 = TypABN AB- 2 * --------------------------- * TOTAL = 36 = 6 * 6 * * Therefore, the largest number of genotype combinations of allele * pairs from mom and dad that can produce any particular blood type * in a child is DimGenotypes = 9, because the child's blood * types A+ and B+ exhibited most frequently each are caused by * DimGenotypes = 9 genotypes as shown by the values in the table * just above. * * DimGenotypes = 9 will be used as the dimension of various arrays * below, especially because DimGenotypes is greater than both * DimAllelePairs and DimBloodTypes: * DimAllelePairs = 6 < DimBloodTypes = 8 < DimGenotypes = 9 . */ #define DimGenotypes 9 /********************************************************************** * Global array 'BloodType allAllelePairs[DimGenotypes] = {Typ...,...}' *********************************************************************/ /* * Initialize the 1-dimensional array allAllelePairs[] with the * DimAllelePairs = 6 enum constants for all possible allele pairs * in increasing arithmetic order. * Extend the array to a usual length of DimGenotypes = 9 elements * by appending DimGenotypes - DimAllelePairs = 9 - 6 = 3 * arbitrary values (each equal to TypUnknown). */ BloodType allAllelePairs[DimGenotypes] = { TypAP, TypAN, TypBP, TypBN, TypOP, TypON, TypUnknown, TypUnknown, TypUnknown }; /********************************************************************** * Function 'void fprintMsg()' *********************************************************************/ /* * Purpose of function fprintMsg(): * * This function prints a message to the open FILE pointer * specified by argument pFileMsg . * * Argument msgPtrArray points to the first element of an array of * pointers to null-terminated text strings. Each one of these * strings will be printed on a line by itself using the fprintf * format "%s\n" . The printing will stop when an element of * array msgPtrArray[] is found which contains a null pointer * (NULL or (char *) 0) . */ void fprintMsg( FILE *pFileMsg, /* Pointer to the open FILE * descriptor to which the * message will be written */ const char * const *msgPtrArray) /* Pointer to the first element * of an array of (constant) * pointers to the (constant) * first character on each line * of the message to be printed */ { while (*msgPtrArray) fprintf(pFileMsg, "%s\n", *msgPtrArray++); return; } /* End of 'void fprintMsg(...)' */ /******************************************************************** * Function 'int fgetline()' ********************************************************************/ /* * Get the next text line from file pointer fp into string str * up to a maximum of lim characters (including the * terminating null), and return the number of non-null * characters that were read and stored into array str[]. * * If the k'th character to be read (where 1 <= k <= lim-1) * is a newline, the value k will be returned by the function * name fgetline() with str[k-1] = '\n' and str[k] = '\0', * and no additional characters will be read. * * If no newline, null, or end-of-file (EOF) is found while * reading the first lim-1 characters from file *fp and * storing them into str[0] through str[lim-2], subsequent * characters from file *fp will be read and thrown away until * the next newline, null, or the EOF is found, a null will be * stored into str[lim-1], and the value lim-1 will be * returned. * * Let k denote the value returned by function name fgetline() . * 0 <= k <= lim-1 is always true. * str[k] = '\0' is returned whenever lim >= 1; no characters * are stored into str[j] for any j > k . * k = 0 indicates that lim <= 1 on entry, or an error, * a null character, or the end-of-file was found * before reading or storing any characters. * 1 <= k <= lim-1 and str[k-1] != '\n' * indicates that a read error, a null character, * or the end-of-file was found after reading * and storing k-1 characters. * 1 <= k <= lim-1 and str[k-1] = '\n' * indicates that a newline was found before * any characters were thrown away. * * On entry, lim >= 1 is required to allow the string stored into * the argument array str[] to be terminated by a null character. * * Use the STanDard I/O Header "#include " for the * "#define EOF" constant and for the "#define getc()" macro. * * This function fgetline() is partially based on the function * getline() in the book "The C Programming Language" by Brian W. * Kernighan and Dennis M. Ritchie, Second Edition (ANSI C), section * "4.1 Basics of Functions", page 69. */ int fgetline( FILE *fp, /* In: Pointer to the open FILE * to read from */ char str[], /* Out: Character string to store * characters into, * preallocated to allow * storage into str[0] * through str[lim-1] */ int lim) /* In: Maximum number of * characters that can be * stored into array * argument str[], * including the * terminating null byte. * lim >= 1 is typical. */ { int c = 'a'; /* Just in case lim < 2 */ int i = 0; while (--lim > 0 && (c=getc(fp)) != EOF && c != '\0' && c != '\n') str[i++] = (char) c; if (c == '\n') str[i++] = (char) c; else if (c != '\0' && c != EOF) while ((c=getc(fp)) != EOF && c != '\0' && c != '\n') ; if (lim >= 0) str[i] = (char) '\0'; return(i); } /* End of 'int fgetline (fp, str, lim)' */ /********************************************************************** * Function 'void getMomsAndDadsAllelePairsFromKidsType()' *********************************************************************/ /* * This function getMomsAndDadsAllelePairsFromKidsType() finds the * set of all allowed genotypes (that is, one of the inherited * allele pairs A+, A-, B+, B-, O+, or O- from each of the parents) * for a person with the phenotype (that is, the exhibited blood type * that is A+, A-, B+, B-, O+, O-, AB+, or AB-) of kidsType . * * The number of possible genotypes will be stored into the caller's * *pNumAllelePairs where 1 <= *pNumAllelePairs <= DimGenotypes, * and those genotypes inherited from the two parents will be stored * by this function into momsAllelePairs[k] and * dadsAllelePairs[k] for each subscript k in the interval * 0 <= k <= *pNumAllelePairs - 1 . * * In the exceptional (error) case when kidsType on entry has none of * the expected DimBloodTypes = 8 blood phenotype enum values * TypAP, TypAN, TypBP, TypBN, TypOP, TypON, TypABP, or TypABN, * this function will only store *pNumAllelePairs = 0 and will then * return to the caller. */ void getMomsAndDadsAllelePairsFromKidsType( const BloodType kidsType, /* In: The phenotype (i.e., the * blood type exhibited) for a * person. */ int *pNumAllelePairs, /* Out: This function will store * *pNumAllelePairs = * (the number of genotypes * [i.e., allele pairs] * that will be stored into * the argument arrays * momsAllelePairs[] and * dadsAllelePairs[]) . * On return, * 0 <= *pNumAllelePairs * <= DimGenotypes . */ BloodType momsAllelePairs[DimGenotypes], BloodType dadsAllelePairs[DimGenotypes]) /* Out: This function will store * the genotypes inherited from * parents into * momsAllelePairs[k] and * dadsAllelePairs[k] for * each subscript k bounded by * 0 <= k <= *pNumAllelePairs-1 . */ { /* * Declare local storage on the runtime stack */ int momsAllele; /* Moving 'int' value corresponding * to the enum value of type * BloodType of the allele pair * inherited from mom. */ int dadsAllele; /* Moving 'int' value corresponding * to the enum value of type * BloodType of the allele pair * inherited from dad. */ int numAllelePairs = 0; /* Moving count of the number of * genotypes stored so far into * the argument arrays * momsAllelePairs[] and * dadsAllelePairs[] . */ /* * Begin execution of getMomsAndDadsAllelePairsFromKidsType() */ for (momsAllele = 0; momsAllele < DimAllelePairs; momsAllele++) for (dadsAllele = 0; dadsAllele < DimAllelePairs; dadsAllele++) { if (typeFrom2AllelePairs[momsAllele][dadsAllele] == kidsType) { momsAllelePairs[numAllelePairs] = (BloodType) momsAllele; dadsAllelePairs[numAllelePairs] = (BloodType) dadsAllele; numAllelePairs++; } /* End 'if (typeFrom2AllelePairs[...][...] == kidsType)' */ } /* End 'for (dadsAllele=0; dadsAllele 0) typesArg[iArg++] = (BloodType) jCnt; /* * Return with argument *pNumTypes set to the number of distinct * blood types that were found. */ *pNumTypes = iArg; return; } /* End of 'void sortUniqueTypes()' */ /********************************************************************** * Function 'void getTypesFromAnyAlleles1AndAnyAlleles2()' *********************************************************************/ /* * This function getTypesFromAnyAlleles1AndAnyAlleles2() assumes * that on entry each of the elements of the argument array * allelePairs1[i] for all i bounded by 0 <= i <= numAlleles1 - 1 * and each of the elements of the argument array allelePairs2[j] * for all j bounded by 0 <= j <= numAlleles2 - 1 is an enum * value TypAP, TypAN, TypBP, TypBN, TypOP, or TypON. More than one * of those array elements on entry may contain the same enum value. * Some of the enumeration constants of typedef BloodType may not * be stored in any of the active elements of those two arrays on * entry. The values in active elements of arrays allelePairs1[] * and allelePairs2[] on entry need not be sorted. * * This function computes a sorted list of all distinct blood types (in * the order TypAP, TypAN, TypBP, TypBN, TypOP, TypON, TypABP, and * TypABN) that will result from a kid inheriting any one of the * numAlleles1 allele pairs stored in array allelePairs1[] * from mom and any one of the allele pairs stored in array * allelePairs2[] from dad. The number of distinct blood types in * that list will be stored into argument *pNumTypes so that * 0 <= *pNumTypes <= DimBloodTypes = 8, and the sorted list itself * will be stored into argument typesArg[k] for all k bounded by * 0 <= k <= *pNumTypes - 1 . */ void getTypesFromAnyAlleles1AndAnyAlleles2( const int numAlleles1, const BloodType allelePairs1[DimGenotypes], /* In: The first set of allele * pairs are allelePairs1[i] * for all subscripts i where * 0 <= i <= numAlleles1 - 1 . */ const int numAlleles2, const BloodType allelePairs2[DimGenotypes], /* In: The second set of allele * pairs are allelePairs2[i] * for all subscripts i where * 0 <= i <= numAlleles2 - 1 . */ int *pNumTypes, /* Out: *pNumTypes = * (the number of active * elements used in argument * array typesArg[], where * 0 <= *pNumTypes * <= DimBloodTypes = 8 * < DimGenotypes = 9 . */ BloodType typesArg[DimGenotypes]) /* Out: On return, * for each subscript m bounded * by 0 <= m <= *pNumTypes - 1, * typesArg[m] is an enum value * for one of the blood * phenotypes A+, A-, B+, B-, O+, * O-, AB+, or AB- that can * result from a child inheriting * any one of the numAlleles1 * allele pairs in array * allelePairs1[] from mom and * any one of the numAlleles2 * allele pairs in array * allelePairs2[] from dad. */ { /* * Declare local storage on the runtime stack */ int i1; /* Moving 'int' subscript for * argument array allelePairs1[] */ int j2; /* Moving 'int' subscript for * argument array allelePairs2[] */ int kArg; /* Moving 'int' subscript for * argument array typesArg[]. */ int mCnt; /* Moving 'int' subscript for * local array typesCount[], * which corresponds to blood * type '(BloodType) mCnt'. */ int typesCount[DimBloodTypes]; /* typesCount[m] = * (the number of blood * phenotypes of the child * found so far equal to * (BloodType) m, for each * integer m bounded by * 0 <= m <= DimBloodTypes-1 = 7) */ /* * Begin execution of getTypesFromAnyAlleles1AndAnyAlleles2() by * initializing the values of all DimBloodTypes = 8 elements of * array typesCount[] to zero. */ for (mCnt = 0; mCnt < DimBloodTypes; mCnt++) typesCount[mCnt] = 0; /* * For each integer m bounded by 0 <= m <= DimBloodTypes - 1 = 7, * store into typesCount[m] the number of times that the blood * type of the child has the enum value '(BloodType) m' when that * child inherits from mom any one of the allele pairs * allelePairs1[i] for each i in the interval * 0 <= i <= numAlleles1 - 1 and when that child inherits from * dad any one of the allele pairs allelePairs2[j] for each j * in the interval 0 <= j <= numAlleles2 - 1 . */ for (i1 = 0; i1 < numAlleles1; i1++) for (j2 = 0; j2 < numAlleles2; j2++) typesCount [ typeFrom2AllelePairs [allelePairs1[i1]] [allelePairs2[j2]] ]++; /* * Store into the beginning elements of the argument array * typesArg[] only the blood types that have counts of at least 1 * in local array typesCount[], overwriting the contents that * were present in array typesArg[] on entry. * This allows all those blood types with nonzero counts to be stored * easily in arithmetically increasing order with all duplicate * blood types removed. */ kArg = 0; for (mCnt = 0; mCnt < DimBloodTypes; mCnt++) if (typesCount[mCnt] > 0) typesArg[kArg++] = (BloodType) mCnt; /* * Return with argument *pNumTypes set to the number of distinct * blood types that were found. */ *pNumTypes = kArg; return; } /* End of 'void getTypesFromAnyAlleles1AndAnyAlleles2()' */ /********************************************************************** * Function 'void keepMomDadAllelesOnlyIfMomsType()' *********************************************************************/ /* * This function keepMomDadAllelesOnlyIfMomsType() will remove the * inherited allele pair elements momsAllelePairs[i] and * dadsAllelePairs[i] from those argument arrays for each subscript * i in the range 0 <= i <= (*pNumAlleles on entry) - 1 if mom's * blood genotype allele pair momsAllelePairs[i] would not allow * her to have the blood phenotype given by argument momsType . * * On return, the value of argument *pNumAlleles will be reduced if * necessary to contain the number of mom's allele pairs that are * compatible with her given blood type momsType, and those * compatible allele pairs for mom and the corresponding allele pairs * for dad (that were originally at the same subscripts as mom's) * will be stored into the elements momsAllelePairs[j] and * dadsAllelePairs[j] respectively for each j in the interval * 0 <= j <= (*pNumAlleles on return) - 1 . * * In the case when none of mom's allele pairs on entry is compatible * with her given blood type, the argument value *pNumAlleles = 0 * will be returned and the values of * momsAllelePairs[(*pNumAlleles on entry) - 1] and of * dadsAllelePairs[(*pNumAlleles on entry) - 1] will be copied * over all originally active elements of those two arrays, * respectively. */ void keepMomDadAllelesOnlyIfMomsType( const BloodType momsType, /* In: The given phenotype (that * is, one of the blood types * A+, A-, B+, B-, O+, O-, AB+, * or AB-) exhibited by mom. */ int *pNumAlleles, /* In/Out: On entry or return, * *pNumAlleles = * (the number of active elements * used at the beginning of each * of the argument arrays * momsAllelePairs[] and * dadsAllelePairs[], where * 0 <= (*pNumAlleles on return) * <= (*pNumAlleles on entry) * <= DimGenotypes = 9). */ BloodType momsAllelePairs[DimGenotypes], BloodType dadsAllelePairs[DimGenotypes]) /* In/Out: On entry or return, * for each subscript i bounded * by 0 <= i <= *pNumAlleles - 1, * elements momsAllelePairs[i] * and dadsAllelePairs[i] are * enum values for mom or dad, * respectively, selected from * blood allele pair genotypes * A+, A-, B+, B-, O+, or O-, * such that the child has the * proper blood phenotype if * those two genotypes were * inherited from the parents. * This function will overwrite any * of these array elements * required to remove any * corresponding genotype allele * pairs momsAllelePairs[i] and * dadsAllelePairs[i] (on entry) * from mom and dad for each * subscript i when mom's * allele type momsAllelePairs[i] * would prevent her from having * the phenotype given by * argument momsType . * As usual, the blood genotype * allele pairs in all active * elements of arrays * momsAllelePairs[] and * dadsAllelePairs[] must be * selected from the set * { A+, A-, B+, B-, O+, O- }. */ { /* * Declare local storage on the runtime stack */ int iA; /* Moving subscript for elements * momsAllelePairs[iA] and * dadsAllelePairs[iA] now being * tested for compatibility with * blood type argument momsType. */ int jA; /* Moving subscript for elements * momsAllelePairs[jA] and * dadsAllelePairs[jA] now being * copied onto elements * momsAllelePairs[jA - 1] and * dadsAllelePairs[jA - 1] * to remove the elements * momsAllelePairs[iA] and * dadsAllelePairs[iA] . */ int kT; /* Moving subscript of dad's allele * pair for the elements * typeFrom2AllelePairs[][kT] * now being used to compare with * blood type argument momsType. */ int isAlleleOK; /* This value is nonzero (that is, * true) if and only if it is * known for sure that mom can * have the genotype allele pair * momsAllelePair[iA] and also * have the phenotype momsType . * This value is zero (that is, * false) if the truth of that * condition is still uncertain * or if mom's allele pair * momsAllelePair[iA] is * finally known to be * inconsistent with mom's * phenotype momsType . */ /* * Begin execution of keepMomDadAllelesOnlyIfMomsType() */ for (iA = 0; iA < *pNumAlleles; iA++) { for (kT = 0; kT < DimAllelePairs; kT++) if (isAlleleOK = (typeFrom2AllelePairs[momsAllelePairs[iA]][kT] == momsType)) break; /* Exit from this 'for (kT ...)' loop */ /* * Remove the allele pairs with subscript iA if it is known for * sure (indicated by isAlleleOK = 0) that mom cannot have the * genotype allele pair momsAllelePair[iA] while she also has * the phenotype momsType . */ if (! isAlleleOK) { /* * Remove element momsAllelePairs[iA] by overwriting elements * momsAllelePairs[iA] thru momsAllelePairs[*pNumAlleles-2] * respectively by elements * momsAllelePairs[iA+1] thru momsAllelePairs[*pNumAlleles-1]. * Remove element dadsAllelePairs[iA] by overwriting elements * dadsAllelePairs[iA] thru dadsAllelePairs[*pNumAlleles-2] * respectively by elements * dadsAllelePairs[iA+1] thru dadsAllelePairs[*pNumAlleles-1]. */ for (jA = iA + 1; jA < *pNumAlleles; jA++) { momsAllelePairs[jA - 1] = momsAllelePairs[jA]; dadsAllelePairs[jA - 1] = dadsAllelePairs[jA]; } /* End of 'for (jA = iA + 1; jA < *pNumAlleles; jA++)' */ /* * Decrement by one the number (argument *pNumAlleles) of * allele pairs still active in each of the arrays * momsAllelePairs[] and dadsAllelePairs[] . */ (*pNumAlleles)--; /* * Because the previous 'for (jA ...)' loop changed the value * of momsAllelePairs[iA], the current value of index iA * must be decremented by one so the next iteration of this * 'for (iA ...)' loop will examine that changed value in * array momsAllelePairs[] . */ iA--; } /* End of 'if (! isAlleleOK)' */ } /* End of 'for (iA = 0; iA < *pNumAlleles; iA++)' */ return; } /* End of 'void keepMomDadAllelesOnlyIfMomsType()' */ /********************************************************************** * Function 'void keepDadMomAllelesOnlyIfDadsType()' *********************************************************************/ /* * This function keepDadMomAllelesOnlyIfDadsType() will remove the * inherited allele pair elements dadsAllelePairs[i] and * momsAllelePairs[i] from those argument arrays for each subscript * i in the range 0 <= i <= (*pNumAlleles on entry) - 1 if dad's * blood genotype allele pair dadsAllelePairs[i] would not allow * him to have the blood phenotype given by argument dadsType . * * On return, the value of argument *pNumAlleles will be reduced if * necessary to contain the number of dad's allele pairs that are * compatible with his given blood type dadsType, and those * compatible allele pairs for dad and the corresponding allele pairs * for mom (that were originally at the same subscripts as dad's) * will be stored into the elements dadsAllelePairs[j] and * momsAllelePairs[j] respectively for each j in the interval * 0 <= j <= (*pNumAlleles on return) - 1 . * * In the case when none of dad's allele pairs on entry is compatible * with his given blood type, the argument value *pNumAlleles = 0 * will be returned and the values of * dadsAllelePairs[(*pNumAlleles on entry) - 1] and of * momsAllelePairs[(*pNumAlleles on entry) - 1] will be copied * over all originally active elements of those two arrays, * respectively. */ void keepDadMomAllelesOnlyIfDadsType( const BloodType dadsType, /* In: The given phenotype (that * is, one of the blood types * A+, A-, B+, B-, O+, O-, AB+, * or AB-) exhibited by dad. */ int *pNumAlleles, /* In/Out: On entry or return, * *pNumAlleles = * (the number of active elements * used at the beginning of each * of the argument arrays * dadsAllelePairs[] and * momsAllelePairs[], where * 0 <= (*pNumAlleles on return) * <= (*pNumAlleles on entry) * <= DimGenotypes = 9). */ BloodType dadsAllelePairs[DimGenotypes], BloodType momsAllelePairs[DimGenotypes]) /* In/Out: On entry or return, * for each subscript i bounded * by 0 <= i <= *pNumAlleles - 1, * elements dadsAllelePairs[i] * and momsAllelePairs[i] are * enum values for dad or mom, * respectively, selected from * blood allele pair genotypes * A+, A-, B+, B-, O+, or O-, * such that the child has the * proper blood phenotype if * those two genotypes were * inherited from the parents. * This function will overwrite any * of these array elements * required to remove any * corresponding genotype allele * pairs dadsAllelePairs[i] and * momsAllelePairs[i] (on entry) * from dad and mom for each * subscript i when dad's * allele type dadsAllelePairs[i] * would prevent him from having * the phenotype given by * argument dadsType . * As usual, the blood genotype * allele pairs in all active * elements of arrays * dadsAllelePairs[] and * momsAllelePairs[] must be * selected from the set * { A+, A-, B+, B-, O+, O- }. */ { /* * Begin execution of keepDadMomAllelesOnlyIfDadsType() . * * Because the rules for mom's allele pairs are symmetric to the * rules for dad's allele pairs as explained above where array * typeFrom2AllelePairs[][] was initialized, the computation * required for this function * keepDadMomAllelesOnlyIfDadsType() * can be accomplished by interchanging roles of mom and dad * while calling the function * keepMomDadAllelesOnlyIfMomsType() . */ keepMomDadAllelesOnlyIfMomsType(dadsType, pNumAlleles, dadsAllelePairs, momsAllelePairs); return; } /* End of 'void keepDadMomAllelesOnlyIfDadsType()' */ /********************************************************************** * Function 'BloodType getTypeEnumFromTypeStr()' *********************************************************************/ /* * This function getTypeEnumFromTypeStr() returns the typedef * BloodType enumeration constant (TypAP, TypAN, TypBP, TypBN, * TypOP, TypON, TypABP, TypABN, or TypUnknown) which corresponds * to the null-terminated string argument bloodTypeStr ("A+", "A-", * "B+", "B-", "O+", "O-", "AB+", "AB-", or anything else). */ BloodType getTypeEnumFromTypeStr( const char *bloodTypeStr) /* In: bloodTypeStr = * (address pointer to a null- * terminated text string * representing a blood type). */ { /* * Declare local storage on the runtime stack */ int typeInt; /* Moving 'int' value corresponding * to each enum value of typedef * BloodType . */ /* * Begin execution of this function */ for (typeInt = 0; typeInt < DimBloodTypes; typeInt++) { if (strcmp(bloodTypeStr, bloodTypeNames[typeInt]) == 0) return (BloodType) typeInt; } /* End 'for (typeInt=0; typeInt < DimBloodTypes; typeInt++)' */ return TypUnknown; } /* End of 'BloodType getTypeEnumFromTypeStr()' */ /********************************************************************** * Function 'BloodType getStrFromTypeEnums()' *********************************************************************/ /* * This function getStrFromTypeEnums() returns the address pointer to * a null-terminated string of constant (i.e., unalterable) * characters based on the numTypes blood types in argument array * typeEnums[] . * * If numTypes == 0 then an address pointer to the first character of * the string "IMPOSSIBLE" will be returned. * * If numTypes == 1 then a pointer to one of the DimBloodTypes = 8 * strings "A+", "A-", "B+", "B-", "O+", "O-", "AB+", or "AB-" * will be returned. * * If 2 <= numTypes <= DimBloodTypes = 8 then return a pointer to a * comma-separated list of the names of the numTypes blood type * enumerations in argument array typeEnums[] enclosed in curly * braces. For example, if * numTypes = 3, * typeEnums[0] = TypAP, * typeEnums[1] = TypBN, and * typeEnums[2] = TypABP, * then return a pointer to the string "{A+, B-, AB+}" . * * Although no check will be made, numTypes > DimBloodTypes = 8 * is not allowed and could result in writing beyond the end of * the local static character array typesStr[] . */ const char *getStrFromTypeEnums( const int numTypes, /* In: Number of blood phenotype * enumeration constants stored * in array typeEnums[] . */ const BloodType typeEnums[DimGenotypes]) /* In: The blood phenotype names * to be stored into the return * string are based on the * blood type enumeration * constants stored in elements * typeEnums[i] for all * subscripts i in the interval * 0 <= i <= numTypes - 1 . */ { /* * Declare local storage (either 'static' or else on runtime stack) */ static char typesStr[DimBloodTypeStr]; /* If numTypes >= 2 then this * function's name will return * the address of the first * character of this string, * where a comma-separated list * of blood types enclosed by * curly brackets will be stored. * This array of characters is * declared to be 'static' so it * will remain allocated in * memory and will keep its * contents instead of being * automatically removed (i.e., * "popped") from the temporary * runtime stack and possibly * overwritten after this * function returns to the * caller. */ int iType; /* Moving subscript of argument * array typeEnums[] . */ /* * Begin execution of this function */ if (numTypes == 0) return "IMPOSSIBLE"; if (numTypes == 1) return bloodTypeNames[typeEnums[0]]; /* * Here, numTypes >= 2 is assumed. */ for (iType = 0; iType < numTypes; iType++) { if (iType == 0) strcpy(typesStr, "{"); else strcat(typesStr, ", "); strcat(typesStr, bloodTypeNames[typeEnums[iType]]); } /* End of 'for (iType = 0; iType < numTypes; iType++)' */ strcat(typesStr, "}"); return typesStr; } /* End of 'BloodType getStrFromTypeEnums()' */ /********************************************************************** * Declarations for program main(...) *********************************************************************/ int main( int argc, /* (# of command line args) + 1 */ char *argv[]) /* Array of argc pointers to * argument strings including * the name argv[0] of this * program */ { /* * Declare local storage for program main(...) */ char inpLin[DimInputLine]; /* Each input line (terminated by a * newline '\n') will be read * into this buffer as a * null-terminated string. * No input line should contain * more than DimInputLine - 2 * characters before the newline, * or else an error message will * be printed and this program * will terminate immediately. */ int indexNewline; /* inpLin[indexNewline] = '\n' * is a newline character for * each input line that is read * from standard input (stdin). */ int exitStatus = ExitStatusSuccess; /* When an input line containing * the 3 characters 'E', 'N', and * 'D' separated by whitespace is * finally read and causes this * program to terminate, the exit * status code exitStatus will * be returned to the operating * system. Generally, * exitStatus = 0 * = ExitStatusSuccess * indicates that all input lines * contained proper information * with the expected format and * were processed successfully, * but * exitStatus = 3 * = ExitStatusBadInputData * indicates that at least one * input line contained improper * information or had an * unexpected format that could * not be processed. */ int numCase = 0; /* The current case number, which * equals the number of input * lines read so far. */ int numMomsAllelePairs; int numDadsAllelePairs; /* The number of active allele pair * enum values of type BloodType * now stored in the beginning * elements of array * momsAllelePairs[] or * dadsAllelePairs[], * respectively. */ BloodType momsAllelePairs[DimGenotypes]; BloodType dadsAllelePairs[DimGenotypes]; /* The beginning elements of each * array will contain enum values * of one of the two sets of * allele pairs for mom or dad, * respectively. * This set of allele pairs is * inherited by the kid from mom * or dad. */ BloodType lostAllelePairs[DimGenotypes]; /* The beginning elements of this * array will contain enum values * of the set of allele pairs for * mom or dad that is not * inherited by their kid. */ int numMomsTypes; int numDadsTypes; int numKidsTypes; /* The number of active blood type * enum values of type BloodType * now stored in the beginning * elements of array * momsTypes[], * dadsTypes[], or * kidsTypes[], respectively. */ BloodType momsTypes[DimGenotypes]; BloodType dadsTypes[DimGenotypes]; BloodType kidsTypes[DimGenotypes]; /* The beginning elements of each * array will contain enum values * of one of the two sets of * blood types for mom, dad, or * the kid, respectively. * This set of blood types is * inherited by the kid from mom * and dad. */ char strMomsType[DimInputLine]; char strDadsType[DimInputLine]; char strKidsType[DimInputLine]; /* The first 3 text fields of the * current input line (where each * such text field contains no * whitespace characters, and the * 3 fields are separated by one * or more whitespace characters) * will be read into these 3 * arrays, corresponding to the * blood types of mom, dad, and * their kid, respectively. * Each text field will be read * from the input line as a * string of nonwhitespace * characters and will be * terminated by appending a null * character ('\0') while being * stored into one of these 3 * arrays. * One of these 3 strings is * expected to be "?", * indicating whose allowed blood * types should be found when * this input line is processed. * Although the longest proper * string that should be stored * in any one of these 3 arrays * is only DimBloodTypeStr = 35 * characters including the * terminating null character, * DimInputLine characters are * allocated for each array to * avoid possibly writing beyond * the end of the array when * function sscanf() is used * below. */ /********************************************************************** * main(): Begin execution by printing a help message if necessary *********************************************************************/ /* * Examine any command line arguments. * Print usage (and help) information and exit if necessary. */ if (argc != 1) { /* * The command line includes at least 1 argument, so print brief * usage information */ printf(helpMsg1Format, numLinesHelpMsg1 + numLinesHelpMsg2); /* * Print detailed help information if the only command line * argument is the 2 characters '-h' */ if (argc == 2 && strcmp(argv[1], "-h") == 0) { fprintMsg(stdout, helpMsg2Array); return ExitStatusHelp; } /* End of 'if (argc == 2 && strcmp(argv[1], "-h") == 0)' */ /* * Return immediately after printing usage information above * because at least one bad command line argument is present */ return ExitStatusBadCmdArgs; } /* End of 'if (argc != 1)' */ /********************************************************************** * main(): Begin 'while (1)' loop; read and parse the next input line *********************************************************************/ /* * This function main() contains a large 'while (1)' loop that * reads and processes one more input line on each iteration. * * This loop will normally continue until this program is terminated * when an input line is read that contains the single characters * 'E', 'N', and 'D' as the first 3 fields separated by * whitespace. Alternatively, this loop will end with immediate * program termination if an error is detected (such as an * excessively long input line or a read error, but not merely * improper formatting of arguments) while reading any line from * stdin . */ while (1) { /* * For the next case, read the input line (including its * terminating newline character '\n') into buffer inpLin[] * as a null-terminated text string. */ numCase++; indexNewline = fgetline(stdin, inpLin, DimInputLine) - 1; /* * If the input line was too long (with more than DimInputLine - 2 * characters before its terminating newline), or if an error or * null character or end-of-file was read before the next * newline, then immediately terminate this program and return * ExitStatusBadInputData to the operating system. */ if (indexNewline == -1 || inpLin[indexNewline] != '\n') { printf("Case %d: *** ERROR: The input line was bad, so " "terminate this program.\n", numCase); return ExitStatusBadInputData; } /* End of 'if (indexNewline == -1 || inpLin[...] != '\n')' */ /* * Overwrite the newline character at the end of the input line * stored in array inpLin[] by a terminating null character, * effectively removing that newline character from the string. */ inpLin[indexNewline] = '\0'; /* * Try to copy the first 3 whitespace-separated fields from the * current input line from character array inpLin[] into * character arrays strMomsType[], strDadsType[], and * strKidsType[] as null-terminated strings. */ if (sscanf(inpLin, "%s%s%s", strMomsType, strDadsType, strKidsType) != 3) { /* * Print an error message if this input line did not begin with * at least 3 fields separated by whitespace */ printf("Case %d: *** ERROR: 3 fields are not on input line " "\"%s\".\n", numCase, inpLin); /* * Skip to the next iteration of this 'while (1)' loop */ continue; } /* End 'if (sscanf(inpLin, "%s%s%s", ...) != 3)' */ /* * If the first 3 whitespace-separated fields on the current input * line contain only the 3 characters 'E', 'N', and 'D' then * terminate this program 'main()' and return the exit status * code exitStatus to the operating system with the value or * either ExitStatusSuccess = 0 (to indicate success) or * ExitStatusBadInputData = 3 (to indicate at least one input * line did not contain valid data with the proper format). */ if (strcmp(strMomsType, "E") == 0 && strcmp(strDadsType, "N") == 0 && strcmp(strKidsType, "D") == 0) return exitStatus; /********************************************************************** * main(): Find mom's allowed blood types if 1st input field was "?" *********************************************************************/ /* * The following large 'if' statement processes the current * input line provided that it contains * a "?" instead of mom's blood type in the 1st input field. * * When mom's blood type is given as "?", print an error message if * a proper blood type for dad is not in the 2nd input field or * a proper blood type for kid is not in the 3rd input field; * otherwise, compute and print all allowable distinct blood * types for mom in sorted order. */ if (strcmp(strMomsType, "?") == 0) { /* * Store the BloodType enum constant for dad's blood type into * dadsTypes[0] that corresponds to the string strDadsType * that was read from the 2nd field on the current input line. * * This corresponds to numDadsTypes = 1 . */ if ((dadsTypes[0] = getTypeEnumFromTypeStr(strDadsType)) == TypUnknown) { /* * Print an error message, prepare to eventually return the * exit status ExitStatusBadInputData to indicate bad * input data, and then skip to the next iteration of this * 'while (1)' loop. */ printf("Case %d: *** ERROR: Dad's (2nd) input blood type " "\"%s\" is bad.\n", numCase, strDadsType); exitStatus = ExitStatusBadInputData; continue; } /* End 'if ((dadsTypes[0] = ...) == TypUnknown)' */ /* * Store the BloodType enum constant for kid's blood type into * kidsTypes[0] that corresponds to the string strKidsType * that was read from the 3rd field on the current input line. * * This corresponds to numKidsTypes = 1 . */ if ((kidsTypes[0] = getTypeEnumFromTypeStr(strKidsType)) == TypUnknown) { /* * Print an error message, prepare to eventually return the * exit status ExitStatusBadInputData to indicate bad * input data, and then skip to the next iteration of this * 'while (1)' loop. */ printf("Case %d: *** ERROR: Kid's (3rd) input blood type " "\"%s\" is bad.\n", numCase, strKidsType); exitStatus = ExitStatusBadInputData; continue; } /* End 'if ((kidsTypes[0] = ...) == TypUnknown)' */ /* * Compute the maximum allowed number numDadsAllelePairs and * that many possible combinations of allele pairs (storing * them into momsAllelePairs[i] and dadsAllelePairs[i] for * each i in the interval 0 <= i <= numDadsAllelePairs - 1) * that could have been inherited from mom and dad to make the * kid's given blood type kidsTypes[0] . */ getMomsAndDadsAllelePairsFromKidsType(kidsTypes[0], &numDadsAllelePairs, momsAllelePairs, dadsAllelePairs); /* * The following function call removes the inherited allele pair * elements dadsAllelePairs[i] and momsAllelePairs[i] * from those arrays for each subscript i in the range * 0 <= i <= (numDadsAllelePairs on entry) - 1 * if dad's blood genotype allele pair dadsAllelePairs[i] * would not allow him to have the blood phenotype given by * dadsTypes[0] . * * On return from that function call, the value of local variable * numDadsAllelePairs will be reduced if necessary to contain * the number of dad's allele pairs that are compatible with * his given blood type dadsTypes[0], and those compatible * allele pairs for dad and the corresponding allele pairs for * mom (that were originally at the same subscripts as dad's) * will be stored into the elements dadsAllelePairs[j] and * momsAllelePairs[j] respectively for each j bounded by * 0 <= j <= (numDadsAllelePairs on return) - 1 . */ keepDadMomAllelesOnlyIfDadsType(dadsTypes[0], &numDadsAllelePairs, dadsAllelePairs, momsAllelePairs); numMomsAllelePairs = numDadsAllelePairs; /* * The following function call computes a sorted list of all * distinct blood types (in the order TypAP, TypAN, TypBP, * TypBN, TypOP, TypON, TypABP, and TypABN) that will result * from mom inheriting any one of the numMomsAllelePairs * allele pairs stored in array momsAllelePairs[] from one of * her parents and any of the DimAllelePairs = 6 possible * allele pairs from her other parent. * * The number of distinct blood types in that list will be * stored into the argument numMomsTypes so that * 0 <= numMomsTypes <= DimBloodTypes = 8, * and the sorted list itself will be stored into argument * momsTypes[k] for all k bounded by * 0 <= k <= numMomsTypes - 1 . */ getTypesFromAnyAlleles1AndAnyAlleles2( numMomsAllelePairs, momsAllelePairs, DimAllelePairs, allAllelePairs, &numMomsTypes, momsTypes); /* * Print the answer line for this case to stdout . */ printf("Case %d: %s %s %s\n", numCase, getStrFromTypeEnums(numMomsTypes, momsTypes), strDadsType, strKidsType); /* * Skip to the next iteration of this 'while (1)' loop */ continue; } /* End of 'if (strcmp(strMomsType, "?") == 0)' */ /********************************************************************** * main(): Find dad's allowed blood types if 2nd input field was "?" *********************************************************************/ /* * The following large 'if' statement processes the current * input line provided that it contains * a "?" instead of dad's blood type in the 2nd input field. * * When dad's blood type is given as "?", print an error message if * a proper blood type for mom is not in the 1st input field or * a proper blood type for kid is not in the 3rd input field; * otherwise, compute and print all allowable distinct blood * types for dad in sorted order. */ if (strcmp(strDadsType, "?") == 0) { /* * Store the BloodType enum constant for mom's blood type into * momsTypes[0] that corresponds to the string strMomsType * that was read from the 1st field on the current input line. * * This corresponds to numMomsTypes = 1 . */ if ((momsTypes[0] = getTypeEnumFromTypeStr(strMomsType)) == TypUnknown) { /* * Print an error message, prepare to eventually return the * exit status ExitStatusBadInputData to indicate bad * input data, and then skip to the next iteration of this * 'while (1)' loop. */ printf("Case %d: *** ERROR: Mom's (1st) input blood type " "\"%s\" is bad.\n", numCase, strMomsType); exitStatus = ExitStatusBadInputData; continue; } /* End 'if ((momsTypes[0] = ...) == TypUnknown)' */ /* * Store the BloodType enum constant for kid's blood type into * kidsTypes[0] that corresponds to the string strKidsType * that was read from the 3rd field on the current input line. * * This corresponds to numKidsTypes = 1 . */ if ((kidsTypes[0] = getTypeEnumFromTypeStr(strKidsType)) == TypUnknown) { /* * Print an error message, prepare to eventually return the * exit status ExitStatusBadInputData to indicate bad * input data, and then skip to the next iteration of this * 'while (1)' loop. */ printf("Case %d: *** ERROR: Kid's (3rd) input blood type " "\"%s\" is bad.\n", numCase, strKidsType); exitStatus = ExitStatusBadInputData; continue; } /* End 'if ((kidsTypes[0] = ...) == TypUnknown)' */ /* * Compute the maximum allowed number numMomsAllelePairs and * that many possible combinations of allele pairs (storing * them into momsAllelePairs[i] and dadsAllelePairs[i] for * each i in the interval 0 <= i <= numMomsAllelePairs - 1) * that could have been inherited from mom and dad to make the * kid's given blood type kidsTypes[0] . */ getMomsAndDadsAllelePairsFromKidsType(kidsTypes[0], &numMomsAllelePairs, momsAllelePairs, dadsAllelePairs); /* * The following function call removes the inherited allele pair * elements momsAllelePairs[i] and dadsAllelePairs[i] * from those arrays for each subscript i in the range * 0 <= i <= (numMomsAllelePairs on entry) - 1 * if mom's blood genotype allele pair momsAllelePairs[i] * would not allow her to have the blood phenotype given by * momsTypes[0] . * * On return from that function call, the value of local variable * numMomsAllelePairs will be reduced if necessary to contain * the number of mom's allele pairs that are compatible with * her given blood type momsTypes[0], and those compatible * allele pairs for mom and the corresponding allele pairs for * dad (that were originally at the same subscripts as mom's) * will be stored into the elements momsAllelePairs[j] and * dadsAllelePairs[j] respectively for each j bounded by * 0 <= j <= (numMomsAllelePairs on return) - 1 . */ keepMomDadAllelesOnlyIfMomsType(momsTypes[0], &numMomsAllelePairs, momsAllelePairs, dadsAllelePairs); numDadsAllelePairs = numMomsAllelePairs; /* * The following function call computes a sorted list of all * distinct blood types (in the order TypAP, TypAN, TypBP, * TypBN, TypOP, TypON, TypABP, and TypABN) that will result * from dad inheriting any one of the numDadsAllelePairs * allele pairs stored in array dadsAllelePairs[] from one of * his parents and any of the DimAllelePairs = 6 possible * allele pairs from his other parent. * * The number of distinct blood types in that list will be * stored into the argument numDadsTypes so that * 0 <= numDadsTypes <= DimBloodTypes = 8, * and the sorted list itself will be stored into argument * dadsTypes[k] for all k bounded by * 0 <= k <= numDadsTypes - 1 . */ getTypesFromAnyAlleles1AndAnyAlleles2( numDadsAllelePairs, dadsAllelePairs, DimAllelePairs, allAllelePairs, &numDadsTypes, dadsTypes); /* * Print the answer line for this case to stdout . */ printf("Case %d: %s %s %s\n", numCase, strMomsType, getStrFromTypeEnums(numDadsTypes, dadsTypes), strKidsType); /* * Skip to the next iteration of this 'while (1)' loop */ continue; } /* End of 'if (strcmp(strDadsType, "?") == 0)' */ /********************************************************************** * main(): Find kid's allowed blood types if 3rd input field was "?" *********************************************************************/ /* * The following large 'if' statement processes the current * input line provided that it contains * a "?" instead of kid's blood type in the 3rd input field. * * When kid's blood type is given as "?", print an error message if * a proper blood type for mom is not in the 1st input field or * a proper blood type for dad is not in the 2nd input field; * otherwise, compute and print all allowable distinct blood * types for kid in sorted order. */ if (strcmp(strKidsType, "?") == 0) { /* * Store the BloodType enum constant for mom's blood type into * momsTypes[0] that corresponds to the string strMomsType * that was read from the 1st field on the current input line. * * This corresponds to numMomsTypes = 1 . */ if ((momsTypes[0] = getTypeEnumFromTypeStr(strMomsType)) == TypUnknown) { /* * Print an error message, prepare to eventually return the * exit status ExitStatusBadInputData to indicate bad * input data, and then skip to the next iteration of this * 'while (1)' loop. */ printf("Case %d: *** ERROR: Mom's (1st) input blood type " "\"%s\" is bad.\n", numCase, strMomsType); exitStatus = ExitStatusBadInputData; continue; } /* End 'if ((momsTypes[0] = ...) == TypUnknown)' */ /* * Store the BloodType enum constant for dad's blood type into * dadsTypes[0] that corresponds to the string strDadsType * that was read from the 2nd field on the current input line. * * This corresponds to numDadsTypes = 1 . */ if ((dadsTypes[0] = getTypeEnumFromTypeStr(strDadsType)) == TypUnknown) { /* * Print an error message, prepare to eventually return the * exit status ExitStatusBadInputData to indicate bad * input data, and then skip to the next iteration of this * 'while (1)' loop. */ printf("Case %d: *** ERROR: Dad's (2nd) input blood type " "\"%s\" is bad.\n", numCase, strDadsType); exitStatus = ExitStatusBadInputData; continue; } /* End 'if ((dadsTypes[0] = ...) == TypUnknown)' */ /* * Compute the maximum allowed number numMomsAllelePairs and * that many possible combinations of allele pairs (storing * them into momsAllelePairs[i] and lostAllelePairs[i] for * each i in the interval 0 <= i <= numMomsAllelePairs - 1) * that mom could have inherited her parents to make her given * blood type momsTypes[0] . Because of the symmetry of data * in array typeFrom2AllelePairs[], the same allele pairs * (but perhaps in a different order) will be stored in both * array momsAllelePairs[] and in array lostAllelePairs[]. * Soon it will be assumed that mom's blood genotype allele * pairs stored here into array momsAllelePairs[] can be * passed from mom to her kid, while mom's genotype allele * pairs stored here into array lostAllelePairs[] will be * ignored when computing the kid's inherited genotype. */ getMomsAndDadsAllelePairsFromKidsType(momsTypes[0], &numMomsAllelePairs, momsAllelePairs, lostAllelePairs); /* * Compute the maximum allowed number numDadsAllelePairs and * that many possible combinations of allele pairs (storing * them into dadsAllelePairs[i] and lostAllelePairs[i] for * each i in the interval 0 <= i <= numDadsAllelePairs - 1) * that dad could have inherited his parents to make his given * blood type dadsTypes[0] . Because of the symmetry of data * in array typeFrom2AllelePairs[], the same allele pairs * (but perhaps in a different order) will be stored in both * array dadsAllelePairs[] and in array lostAllelePairs[]. * Soon it will be assumed that dad's blood genotype allele * pairs stored here into array dadsAllelePairs[] can be * passed from dad to his kid, while dad's genotype allele * pairs stored here into array lostAllelePairs[] will be * ignored when computing the kid's inherited genotype. */ getMomsAndDadsAllelePairsFromKidsType(dadsTypes[0], &numDadsAllelePairs, dadsAllelePairs, lostAllelePairs); /* * The following two calls to function sortUniqueTypes() are * not necessary, but those calls will eliminate duplicates of * any particular allele pairs in array momsAllelePairs[] * as well as in array dadsAllelePairs[], thus * reducing computations when function * getTypesFromAnyAlleles1AndAnyAlleles2() is called below. */ sortUniqueTypes(&numMomsAllelePairs, momsAllelePairs); sortUniqueTypes(&numDadsAllelePairs, dadsAllelePairs); /* * The following function call computes a sorted list of all * distinct blood types (in the order TypAP, TypAN, TypBP, * TypBN, TypOP, TypON, TypABP, and TypABN) that will result * from the kid inheriting any one of the numMomsAllelePairs * allele pairs stored in array momsAllelePairs[] from the * kid's mom and inheriting any one of the numDadsAllelePairs * allele pairs stored in array dadsAllelePairs[] from the * kid's dad. * * The number of distinct blood types in that list will be * stored into the argument numKidsTypes so that * 0 <= numKidsTypes <= DimBloodTypes = 8, * and the sorted list itself will be stored into argument * kidsTypes[k] for all k bounded by * 0 <= k <= numKidsTypes - 1 . */ getTypesFromAnyAlleles1AndAnyAlleles2( numMomsAllelePairs, momsAllelePairs, numDadsAllelePairs, dadsAllelePairs, &numKidsTypes, kidsTypes); /* * Print the answer line for this case to stdout . */ printf("Case %d: %s %s %s\n", numCase, strMomsType, strDadsType, getStrFromTypeEnums(numKidsTypes, kidsTypes)); /* * Skip to the next iteration of this 'while (1)' loop */ continue; } /* End of 'if (strcmp(strKidsType, "?") == 0)' */ /********************************************************************** * main(): End of loop 'while (1)'; end of function 'int main()' *********************************************************************/ printf("Case %d: *** ERROR: Missing \"?\" in 3 args of input line " "\"%s\"\n", numCase, inpLin); } /* End of the loop 'while (1)' */ } /* End of 'int main()' */ /********************************************************************** * End of this file 'bloodtype1.c' *********************************************************************/