/**********************************************************************
* 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 <stdio.h>' 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 <stdio.h>
/*
* 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 cs<ct, 0 if cs==ct,
* >0 if cs>ct .
*/
#include <string.h>
/**********************************************************************
* 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 <stdio.h>" 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<DimAllelePairs; ...)' */
*pNumAllelePairs = numAllelePairs;
return;
} /* End of 'void getMomsAndDadsAllelePairsFromKidsType()' */
/**********************************************************************
* Function 'void sortUniqueTypes()'
*********************************************************************/
/*
* This function sortUniqueTypes() assumes that on entry each of the
* elements of the argument array typesArg[i] is an enum value
* TypAP, TypAN, TypBP, TypBN, TypOP, TypON, TypABP, TypABN, or
* TypUnknown, for all subscripts i in the interval
* 0 <= i <= *pNumTypes - 1 . 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
* *pNumTypes active elements of array typesArg[] on entry.
* The values in active elements of array typesArg[] on entry
* need not be sorted.
*
* In effect, this function will sort the active values that were
* initially in array typesArg[] into arithmetically increasing
* order and will discard duplicate values. In other words, this
* function will overwrite the value of 'int' argument *pNumTypes
* with the number of distinct typedef BloodType enum values that
* were initially among the active elements of array typesArg[],
* and this function will overwrite the contents of the first
* (returned value of *pNumTypes) elements of array typesArg[] by
* those distinct typedef BloodType enum values sorted into
* arithmetically increasing order.
*
* The 'int' value of argument *pNumTypes on return will always be
* less than or equal to the value of that argument on entry,
* because any duplicate values initially in that array will be
* discarded.
*
* For the example, if on entry the arguments have the values
* *pNumTypes = 7,
* typesArg[0] = TypBP,
* typesArg[1] = TypAP,
* typesArg[2] = typUnknown,
* typesArg[3] = typBP,
* typesArg[4] = TypABP,
* typesArg[5] = typBP, and
* typesArg[6] = typAP,
* then on return the arguments will have the values
* *pNumTypes = 4,
* typesArg[0] = TypAP,
* typesArg[1] = TypBP,
* typesArg[2] = typABP, and
* typesArg[3] = typUnknown,
* while the following 3 array elements still keep the values they
* had on entry although they are no longer considered to be active
* on return:
* typesArg[4] = TypABP,
* typesArg[5] = typBP, and
* typesArg[6] = typAP .
*/
void sortUniqueTypes(
int *pNumTypes, /* In/Out: *pNumTypes =
* (the number of active
* elements used in argument
* array typesArg[], where
* 0 <= (*pNumTypes on return)
* <= (*pNumTypes on entry)
* <= DimBloodTypes + 1
* = 9 = DimGenotypes).
*/
BloodType typesArg[DimGenotypes])
/* In/Out: On entry or return,
* for each subscript i bounded
* by 0 <= i <= *pNumTypes,
* typesArg[i] is an enum value
* for one of the blood genotypes
* or phenotypes A+, A-, B+, B-,
* O+, or O-, or one of the
* phenotypes AB+ or AB-, or the
* special enum value
* TypUnknown .
*/
{
/*
* Declare local storage on the runtime stack
*/
int iArg; /* Moving 'int' subscript for
* argument array typesArg[] .
*/
int jCnt; /* Moving 'int' subscript for
* local array typesCount[],
* which corresponds to blood
* type '(BloodType) jCnt'.
*/
int typesCount[DimBloodTypes + 1];
/* typesCount[j] =
* (the number of elements found
* so far among active elements
* of argument array typesArg[]
* equal to (BloodType) j).
*/
/*
* Begin execution of sortUniqueTypes() by initializing the values
* of all DimBloodTypes + 1 = 9 elements of array typesCount[]
* to zero.
*/
for (jCnt = 0; jCnt <= DimBloodTypes; jCnt++)
typesCount[jCnt] = 0;
/*
* For each integer j bounded by 0 <= j <= DimBloodTypes = 8,
* store into typesCount[j] the number of times that the enum
* value '(BloodType) j' occurs among the active elements of the
* argument array typesArg[] .
*/
for (iArg = 0; iArg < *pNumTypes; iArg++)
typesCount[typesArg[iArg]]++;
/*
* Store into the beginning elements of the argument array
* typesArg[] only the blood types that were found in the
* original contents of that array based on the counts 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.
*/
iArg = 0;
for (jCnt = 0; jCnt <= DimBloodTypes; jCnt++)
if (typesCount[jCnt] > 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