Mystery Organism
- Codecademy Logo Project -

This is my take on the 'Mystery Organism' project which is part of the Full-Stack Developer course by Codecademy. After completing the requirements for the project, I thought about how I could share my code with others in a more interesting format, so they could follow along more easily. I hope you like what I've created, and as always, if you have any questions or feedback, feel free to !

Prerequisites:

In order to complete this project, you should have completed the first few sections of Introduction to JavaScript (through Learn JavaScript: Objects).

Project Requirements:

Look over the starter code. There are two helper functions: returnRandBase() and mockUpStrand().

DNA is comprised of four bases (Adenine, Thymine, Cytosine, and Guanine). When returnRandBase() is called, it will randomly select a base and return the base ('A','T','C', or 'G').

mockUpStrand() is used to generate an array containing 15 bases to represent a single DNA strand with 15 bases.

You’ll use these helper functions later to create your objects that represent P. aequor.

Since you need to create multiple objects, create a factory function pAequorFactory() that has two parameters:

The first parameter is a number (no two organisms should have the same number). The second parameter is an array of 15 DNA bases. pAequorFactory() should return an object that contains the properties specimenNum and dna that correspond to the parameters provided.

You’ll also add more methods to this returned object in the later steps.

Your team wants you to simulate P. aequor‘s high rate of mutation (change in its DNA).

To simulate a mutation, in pAequorFactory()‘s returned object, add the method .mutate().

.mutate() is responsible for randomly selecting a base in the object’s dna property and changing the current base to a different base. Then .mutate() will return the object’s dna.

For example, if the randomly selected base is the 1st base and it is 'A', the base must be changed to 'T', 'C', or 'G'. But it cannot be 'A' again.

Your research team wants to be able to compare the DNA sequences of different P. aequor. You’ll have to add a new method (.compareDNA()) to the returned object of the factory function.

.compareDNA() has one parameter, another pAequor object.

The behavior of .compareDNA() is to compare the current pAequor‘s .dna with the passed in pAequor‘s .dna and compute how many bases are identical and in the same locations. .compareDNA() does not return anything, but prints a message that states the percentage of DNA the two objects have in common — use the .specimenNum to identify which pAequor objects are being compared.

P. aequor have a likelier chance of survival if their DNA is made up of at least 60% 'C' or 'G' bases.

In the returned object of pAequorFactory(), add another method .willLikelySurvive().

.willLikelySurvive() returns true if the object’s .dna array contains at least 60% 'C' or 'G' bases. Otherwise, .willLikelySurvive() returns false.

With the factory function set up, your team requests that you create 30 instances of pAequor that can survive in their natural environment. Store these instances in an array for your team to study later.

If you’d like to challenge yourself further, you could consider the following:

Create a .complementStrand() method to the factory function’s object that returns the complementary DNA strand. The rules are that 'A's match with 'T's and vice versa. Also, 'C's match with 'G's and vice versa.

Use the .compareDNA() to find the two most related instances of pAequor.

// Returns a random DNA base
const returnRandBase = () => {
  const dnaBases = ['A', 'T', 'C', 'G']
  return dnaBases[Math.floor(Math.random() * 4)]
}

// Returns a random single strand of DNA containing 15 bases
const mockUpStrand = () => {
  const newStrand = [];
  for (let i = 0; i < 15; i++) {
    newStrand.push(returnRandBase())
  }
  return newStrand;
}
function pAequorFactory(number, array){
  const specimen = {
    specimenNum: number,
    dna: array,

    mutate(){
      let newBase = returnRandBase();
      const index = Math.floor(Math.random() * 15);
      const existingBase = this.dna[index];
      do {
        newBase = returnRandBase();
      } while (newBase === existingBase);
      this.dna[index] = newBase;
      return this.dna;
    },

    compareDNA(otherpAequor){
      let tally = 0;
      for (let i = 0; i <15; i++){
        if (this.dna[i] === otherpAequor.dna[i]){
          tally += 1;
        }
      }
      const percentage = Math.floor(( tally / 15 ) * 100).toString() + '%';
      console.log(`Specimen #${this.specimenNum} and specimen #${otherpAequor.specimenNum} have ${percentage} DNA in common.`)
    },



// initial approach to require at least 60% of C or G individually
// willLikelySurvive(){
//   let cTally = 0;
//   let gTally = 0;
//   this.dna.map((base) => {
//     if (base === 'C'){
//       cTally += 1;
//     } else if (base === 'G'){
//       gTally += 1;
//     }
//   })
//   const cPercentage = Math.floor(( cTally / 15 ) * 100);
//   const gPercentage = Math.floor(( gTally / 15 ) * 100);
//   if (cPercentage >= 60 || gPercentage >= 60){
//     return true;
//   } else {
//     return false;
//   }
// }

// Second approach to require 60% of C or G combined to reduce the necessary iterations and compute power to meet the requirements for the 'createSurvivingSpecimens' function
    willLikelySurvive(){
      let tally = 0;
      this.dna.map((base) => {
        if (base === 'C' || base === 'G'){
          tally += 1;
        }
      });
      const percentage = Math.floor(( tally / 15 ) * 100);
      if (percentage >= 60){
        return true;
      } else {
        return false;
      }
    },

    complementStrand(){
      const newStrand = [];
      this.dna.map((base) => {
        switch (base){
          case 'A':
            newStrand.push('T');
            break;
          case 'T':
            newStrand.push('A');
            break;
          case 'C':
            newStrand.push('G');
            break;
          case 'G':
            newStrand.push('C');
            break;
          default:
            console.log('Error: DNA base must be "A", "C", "G" or "T".');
            break;
        }
      });
      return newStrand;
    },
  }
  return specimen;
}

    function createSurvivingSpecimens(amount){
      let survivingSpecimens = [];
      let i = 0;
      do {
        const specimen = pAequorFactory(i, mockUpStrand());
        if (specimen.willLikelySurvive() === true) {
          survivingSpecimens.push(specimen);
        }
        i ++;
      } while (survivingSpecimens.length < amount);
      return survivingSpecimens;
    }

    const survivingSpecimens = createSurvivingSpecimens(30);
// Sample data for tests
const first = pAequorFactory(12, mockUpStrand());
First sample:
  specimenNum: 12,
  dna:[
    'A','A','A','A',
    'A','A','G','G',
    'A','C','G','T',
    'G','A','T'
  ]

const second = pAequorFactory(15, mockUpStrand());
Second sample:
  specimenNum: 15,
  dna:[
    'T','T','A','T',
    'T','A','G','T',
    'A','A','T','G',
    'C','G','T'
  ]

------------------------------------------------

// .mutate() function test

Original DNA: 'A','A','A','A','A','A','G','G','A','C','G','T','G','A','T';

// Running "first.mutate()"...
New DNA: 'A','A','A','A','A','C','G','G','A','C','G','T','G','A','T';

------------------------------------------------

// .compareDNA() function test

// Running "second.compareDNA(first)"...
Specimen #15 and specimen #12 have 26% DNA in common.
undefined

------------------------------------------------

// .willLikelySurvive() function test

// Running "first.willLikelySurvive()"...
First specimen will likely survive: false
// createSurvivingSpecimens() function test

// Running "const survivingSpecimens = createSurvivingSpecimens(30)"

survivingSpecimens:
[
  {
    specimenNum: 5,
    dna: 'G','T','A','C','G','G','G','C','G','G','A','A','C','A','C',
    mutate: [Function: mutate],
    compareDNA: [Function: compareDNA],
    willLikelySurvive: [Function: willLikelySurvive],
    complementStrand: [Function: complementStrand]
  },
  {
    specimenNum: 10,
    dna: 'G','C','C','T','G','A','A','C','C','C','T','C','T','C','A',
    mutate: [Function: mutate],
    compareDNA: [Function: compareDNA],
    willLikelySurvive: [Function: willLikelySurvive],
    complementStrand: [Function: complementStrand]
  },
  {
    specimenNum: 11,
    dna: 'C','T','C','T','C','C','G','C','T','G','C','C','C','T','G',
    mutate: [Function: mutate],
    compareDNA: [Function: compareDNA],
    willLikelySurvive: [Function: willLikelySurvive],
    complementStrand: [Function: complementStrand]
  },
  ... (showAllResults)
]
  {
    specimenNum: 12,
    dna: 'T','G','G','C','G','G','G','G','C','T','A','G','A','C','A',
    mutate: [Function: mutate],
    compareDNA: [Function: compareDNA],
    willLikelySurvive: [Function: willLikelySurvive],
    complementStrand: [Function: complementStrand]
  },
  {
    specimenNum: 17,
    dna: 'C','A','A','G','A','G','G','G','T','G','T','C','T','G','G',
    mutate: [Function: mutate],
    compareDNA: [Function: compareDNA],
    willLikelySurvive: [Function: willLikelySurvive],
    complementStrand: [Function: complementStrand]
  },
  {
    specimenNum: 22,
    dna: 'A','C','A','T','G','T','G','A','G','G','G','T','C','G','G',
    mutate: [Function: mutate],
    compareDNA: [Function: compareDNA],
    willLikelySurvive: [Function: willLikelySurvive],
    complementStrand: [Function: complementStrand]
  },
  {
    specimenNum: 23,
    dna: 'G','G','T','G','C','A','G','G','C','A','C','C','T','C','G',
    mutate: [Function: mutate],
    compareDNA: [Function: compareDNA],
    willLikelySurvive: [Function: willLikelySurvive],
    complementStrand: [Function: complementStrand]
  },
  {
    specimenNum: 25,
    dna: 'A','C','A','C','T','C','A','G','A','G','C','T','G','C','C',
    mutate: [Function: mutate],
    compareDNA: [Function: compareDNA],
    willLikelySurvive: [Function: willLikelySurvive],
    complementStrand: [Function: complementStrand]
  },
  {
    specimenNum: 28,
    dna: 'A','G','T','C','T','G','T','A','G','G','A','G','G','G','C',
    mutate: [Function: mutate],
    compareDNA: [Function: compareDNA],
    willLikelySurvive: [Function: willLikelySurvive],
    complementStrand: [Function: complementStrand]
  },
  {
    specimenNum: 29,
    dna: 'A','A','G','T','A','C','C','T','C','C','C','T','G','C','C',
    mutate: [Function: mutate],
    compareDNA: [Function: compareDNA],
    willLikelySurvive: [Function: willLikelySurvive],
    complementStrand: [Function: complementStrand]
  },
  {
    specimenNum: 31,
    dna: 'C','G','T','G','T','C','C','A','G','C','T','A','T','G','G',
    mutate: [Function: mutate],
    compareDNA: [Function: compareDNA],
    willLikelySurvive: [Function: willLikelySurvive],
    complementStrand: [Function: complementStrand]
  },
  {
    specimenNum: 34,
    dna: 'A','G','C','G','C','G','T','C','T','C','C','A','C','C','A',
    mutate: [Function: mutate],
    compareDNA: [Function: compareDNA],
    willLikelySurvive: [Function: willLikelySurvive],
    complementStrand: [Function: complementStrand]
  },
  {
    specimenNum: 35,
    dna: 'G','A','C','C','A','T','G','G','G','A','C','G','T','G','T',
    mutate: [Function: mutate],
    compareDNA: [Function: compareDNA],
    willLikelySurvive: [Function: willLikelySurvive],
    complementStrand: [Function: complementStrand]
  },
  {
    specimenNum: 42,
    dna: 'G','C','G','A','C','T','G','G','A','C','T','G','T','G','A',
    mutate: [Function: mutate],
    compareDNA: [Function: compareDNA],
    willLikelySurvive: [Function: willLikelySurvive],
    complementStrand: [Function: complementStrand]
  },
  {
    specimenNum: 44,
    dna: 'T','A','C','T','C','C','C','G','T','A','G','C','C','T','C',
    mutate: [Function: mutate],
    compareDNA: [Function: compareDNA],
    willLikelySurvive: [Function: willLikelySurvive],
    complementStrand: [Function: complementStrand]
  },
  {
    specimenNum: 47,
    dna: 'C','G','A','T','G','G','T','C','C','C','G','A','T','T','G',
    mutate: [Function: mutate],
    compareDNA: [Function: compareDNA],
    willLikelySurvive: [Function: willLikelySurvive],
    complementStrand: [Function: complementStrand]
  },
  {
    specimenNum: 53,
    dna: 'T','G','G','T','C','G','C','C','T','T','C','A','C','T','C',
    mutate: [Function: mutate],
    compareDNA: [Function: compareDNA],
    willLikelySurvive: [Function: willLikelySurvive],
    complementStrand: [Function: complementStrand]
  },
  {
    specimenNum: 56,
    dna: 'G','G','A','T','G','G','C','G','G','G','C','T','G','C','A',
    mutate: [Function: mutate],
    compareDNA: [Function: compareDNA],
    willLikelySurvive: [Function: willLikelySurvive],
    complementStrand: [Function: complementStrand]
  },
  {
    specimenNum: 59,
    dna: 'G','C','C','T','C','G','G','C','C','C','T','G','C','C','A',
    mutate: [Function: mutate],
    compareDNA: [Function: compareDNA],
    willLikelySurvive: [Function: willLikelySurvive],
    complementStrand: [Function: complementStrand]
  },
  {
    specimenNum: 62,
    dna: 'T','G','T','T','G','C','T','G','C','C','G','T','T','G','C',
    mutate: [Function: mutate],
    compareDNA: [Function: compareDNA],
    willLikelySurvive: [Function: willLikelySurvive],
    complementStrand: [Function: complementStrand]
  },
  {
    specimenNum: 63,
    dna: 'C','C','G','A','C','A','T','C','T','T','G','G','G','C','G',
    mutate: [Function: mutate],
    compareDNA: [Function: compareDNA],
    willLikelySurvive: [Function: willLikelySurvive],
    complementStrand: [Function: complementStrand]
  },
  {
    specimenNum: 67,
    dna: 'C','G','G','T','G','G','G','C','G','T','C','C','A','T','G',
    mutate: [Function: mutate],
    compareDNA: [Function: compareDNA],
    willLikelySurvive: [Function: willLikelySurvive],
    complementStrand: [Function: complementStrand]
  },
  {
    specimenNum: 70,
    dna: 'C','G','C','G','A','T','C','T','C','A','G','C','C','C','C',
    mutate: [Function: mutate],
    compareDNA: [Function: compareDNA],
    willLikelySurvive: [Function: willLikelySurvive],
    complementStrand: [Function: complementStrand]
  },
  {
    specimenNum: 71,
    dna: 'C','T','C','G','C','C','A','T','G','C','C','C','C','T','A',
    mutate: [Function: mutate],
    compareDNA: [Function: compareDNA],
    willLikelySurvive: [Function: willLikelySurvive],
    complementStrand: [Function: complementStrand]
  },
  {
    specimenNum: 73,
    dna: 'C','T','G','C','A','T','G','T','G','A','A','C','C','C','G',
    mutate: [Function: mutate],
    compareDNA: [Function: compareDNA],
    willLikelySurvive: [Function: willLikelySurvive],
    complementStrand: [Function: complementStrand]
  },
  {
    specimenNum: 74,
    dna: 'T','A','G','G','T','C','C','C','G','A','C','G','C','T','A',
    mutate: [Function: mutate],
    compareDNA: [Function: compareDNA],
    willLikelySurvive: [Function: willLikelySurvive],
    complementStrand: [Function: complementStrand]
  },
  {
    specimenNum: 76,
    dna: 'T','A','C','T','C','G','T','C','T','G','G','C','C','T','G',
    mutate: [Function: mutate],
    compareDNA: [Function: compareDNA],
    willLikelySurvive: [Function: willLikelySurvive],
    complementStrand: [Function: complementStrand]
  },
  {
    specimenNum: 80,
    dna: 'C','G','T','T','A','C','G','A','G','C','C','A','C','T','C',
    mutate: [Function: mutate],
    compareDNA: [Function: compareDNA],
    willLikelySurvive: [Function: willLikelySurvive],
    complementStrand: [Function: complementStrand]
  },
  {
    specimenNum: 81,
    dna: 'C','T','G','A','C','A','G','C','C','C','C','C','C','C','C',
    mutate: [Function: mutate],
    compareDNA: [Function: compareDNA],
    willLikelySurvive: [Function: willLikelySurvive],
    complementStrand: [Function: complementStrand]
  },
  {
    specimenNum: 84,
    dna: 'A','T','G','C','C','A','G','C','T','A','C','C','C','T','C',
    mutate: [Function: mutate],
    compareDNA: [Function: compareDNA],
    willLikelySurvive: [Function: willLikelySurvive],
    complementStrand: [Function: complementStrand]
  },
] (click to hide)
------------------------------------------------

// Project Extension:

// Testing ".complementStrand()" function
Initial DNA sequence: 'T','T','A','T','T','A','G','T','A','A','T','G','C','G','T'
Complementary DNA sequence: 'A','A','T','A','A','T','C','A','T','T','A','C','G','C','A'