Search Unity

How can i simplify this logic?

Discussion in 'Scripting' started by Nanako, Mar 1, 2015.

  1. Nanako

    Nanako

    Joined:
    Sep 24, 2014
    Posts:
    1,047
    Hi all. I'm writing a simulation of genetics and inheritance. Here is a specific case, a pair of blood antigen alleles are provided, and i'm working out the blood type from them

    There are threee possible blood alleles. A, B, and i. i is recessive so AA or Ai gives blood type A, and BB or Bi gives blood type B
    AB gives blood type AB, and the double recessive ii gives blood type O


    The code i've written for this is at the bottom of the page. imo, it's an unwieldy mess. I'm sure it'll run just fine, performance isn't an issue. But it took me far too long to write, and i'm going to end up having to write a lot more logic like this with dominant and recessive allele pairs.

    Can anyone think of a way to shorten this code, and make this type of logic go more smoothly?

    Code (CSharp):
    1. public int CalculateBloodType()
    2.     {
    3.         if (bloodAlleles.a == Genetics.BLOOD_ALLELE_A)//A
    4.         {
    5.             if (bloodAlleles.b == Genetics.BLOOD_ALLELE_B)
    6.             {
    7.                 bloodtype = Genetics.BLOOD_TYPE_AB;
    8.             }
    9.             else
    10.             {
    11.                 bloodType = Genetics.BLOOD_TYPE_A;
    12.             }
    13.         }
    14.         else if (bloodAlleles.a == Genetics.BLOOD_ALLELE_B)
    15.         {
    16.             if (bloodAlleles.b == Genetics.BLOOD_ALLELE_A)
    17.             {
    18.                 bloodtype = Genetics.BLOOD_TYPE_AB;
    19.             }
    20.             else
    21.             {
    22.                 bloodType = Genetics.BLOOD_TYPE_B;
    23.             }
    24.         }
    25.         else
    26.         {
    27.             if (bloodAlleles.a == Genetics.BLOOD_ALLELE_i)
    28.             {
    29.                 if (bloodAlleles.b == Genetics.BLOOD_ALLELE_i)
    30.                 {
    31.                     bloodType = Genetics.BLOOD_TYPE_O;
    32.                 }
    33.                 else if (bloodAlleles.a == Genetics.BLOOD_ALLELE_A)
    34.                 {
    35.                     bloodType = Genetics.BLOOD_TYPE_B;
    36.                 }
    37.                 else if (bloodAlleles.a == Genetics.BLOOD_ALLELE_B)
    38.                 {
    39.                     bloodType = Genetics.BLOOD_TYPE_B;
    40.                 }
    41.             }
    42.         }
    43.     }
     
  2. bloomingdedalus

    bloomingdedalus

    Joined:
    Aug 13, 2012
    Posts:
    139
    Code (csharp):
    1.  
    2.  
    3. public enum Alleles : byte { i = 0x01, A = 0x04, B = 0x02 };
    4. public enum BloodType : byte { A = 0x08, B = 0x04, AB = 0x06, O = 0x02 }; //assuming "O" is ii genotype
    5.  
    6. public BloodType GetBloodType(Alleles Num1, Alleles Num2)
    7. {
    8.      byte Type = Num1 + Num2;
    9.  
    10.      if((Type & 1) == 1)
    11.      {
    12.           return (BloodType)2*(Type ^ 0x01);
    13.      }
    14.      else
    15.      {
    16.            return (BloodType)(Type);
    17.      }
    18. }
    19.  
    20.  
    Or something along those lines...

    However, this might pose a problem if you have more than just three alleles...

    I'm not sure exactly what you mean "I'm going to have more allelles"

    Anyway, bitwise operations let you evaluate many switches at once if you do them properly... This is how a lot of Direct3d commands work in C++ by defining keywords as numbers that are the power of two allowing a large number of boolean arguments to be passed at once by simply adding the numbers (where I picked up the trick).
     
    Last edited: Mar 1, 2015
    Nanako likes this.
  3. Yemachu

    Yemachu

    Joined:
    Feb 1, 2015
    Posts:
    13
    Your function promisses an int as return-type, yet you don't seem to return anything... But that is not the issue you wanted assistance for. In any case, there is the point that I don't know the exact values (or even types) of Genetics.BLOOD_ALELE_#. My assumption is that they are enums, or at least constants. If they are, the value is most likely irrelevant; giving us the option of using bit-flags.

    Here is how I would go about it:
    Code (CSharp):
    1. public static class Genetics
    2. {
    3.  
    4.     [System.Flags]
    5.     public enum BloodAlele
    6.     {
    7.         i = 0,     // 0 or in bitwise representation: ...000
    8.         A = 1<<0,     // 1 or in bitwise representation: ...001
    9.         B = 1<<1,     // 2 or in bitwise representation: ...010
    10.         //C = 1<<2,   // 4  or in bitwise representation: ...100
    11.         //D = 1<<3
    12.         //E = 1<<4
    13.         //etc.
    14.  
    15.     }
    16.  
    17.     public enum BloodGroup
    18.     {
    19.         None,    //Can be removed if you please.
    20.         A,      
    21.         B,
    22.         AB,
    23.         O
    24.     }
    25.  
    26.     public static BloodGroup CalculateBloodType(BloodAlele alel1, BloodAlele alel2)
    27.     {
    28.         //Combines the two aleles, resulting in one of the following values.
    29.         switch(alel1 | alel2)
    30.         {
    31.         case BloodAlele.A:                     //Result is 1
    32.             return BloodGroup.A;
    33.         case BloodAlele.B:                    //Result is 2
    34.             return BloodGroup.B;
    35.         case BloodAlele.A | BloodAlele.B:    //Result is 3
    36.             return BloodGroup.AB;
    37.         case BloodAlele.i:                    //Result is 0
    38.             return BloodGroup.O;
    39.         }
    40.         //If you removed "None", you need to supply a new default value.
    41.         return BloodGroup.None;
    42.     }
    43. }
    Using the bitwise OR-operator (|, or 'pipe'), you get a value based on the bits which are turned on. If a bit on the Xth position is turned on by either value, the resulting value will have that bit turned on as well.

    • For bloodgroup A
      • i and A: 00 | 01 = 001 (1)
      • A and i: 01 | 00 = 001 (1)
      • A and A: 01 | 01 = 001 (1)
    • For bloodgroup B
      • i and B: 10 | 00 = 010 (2)
      • B and i: 00 | 10 = 010 (2)
      • B and B: 10 | 10 = 010 (2)
    • For bloodgroup AB
      • A and B: 01 | 10 = 011 (3)
      • B and A: 10 | 01 = 011 (3)
    • For bloodgroup O
      • i and i: 00 | 00 = 000 (0)
     
  4. Nanako

    Nanako

    Joined:
    Sep 24, 2014
    Posts:
    1,047
    not in this example, but future ones will almost certainly have more than three options. like eye colour.
     
  5. Nanako

    Nanako

    Joined:
    Sep 24, 2014
    Posts:
    1,047
    yeah they're just constants for differentiating. 0/1/2/3

    Here is how I would go about it:
     
  6. Nanako

    Nanako

    Joined:
    Sep 24, 2014
    Posts:
    1,047
    these solutions are complex and interesting, i will reread them a few more times and try to understand them (a little sleep deprived atm.)

    I could do with some assistance with the next one too; eye colour. The rough plan i have at the moment is for all colours to have a heirarchy of dominance/recessiveness, and where two alleles differe, the colour result is the most dominant of the pair.