Basic efforts with JavaScript, challenging object construction, properties and methods, courtesy of the Codecademy Mysterious Organism Project.

The premise is to simulate the DNA of a newly discovered deep sea organism, P.aequor, using objects. Two helper functions, returnRandBase() and mockUpStrand() are provided.

The goal was to code a JavaScript program to perform the following:

  • Create a factory function to produce virtual samples of P.aequor
  • Create a method that performs random mutation of a single base within the DNA strand of a sample.
  • Create a method to compare one sample with another, and report the percentage of identical bases in identical positions in the ‘DNA strand’
  • Create a method to determine sample “survival” likelihood based on composition of the strand
  • Create a set of 30 virtual samples that are likely to “survive”

As an additional challenge, the code should:

  • Create a method that will return the “complementary strand” of the current sample
  • Find the most related samples in the sample set, ie highest correlation of identical bases to identical strand position.
// Returns a random DNA base
const returnRandBase = () => {
    const dnaBases = ['A', 'T', 'C', 'G'];
    return dnaBases[Math.floor(Math.random() * 4)];
};

// Returns a random single stand of DNA containing 15 bases
const mockUpStrand = () => {
    const newStrand = [];
    for (let i = 0; i < 15; i++) {
        newStrand.push(returnRandBase());
    }
    return newStrand;
};

//factory function for pAequor
const pAequorFactory = (index, baseArray) => {
    return {
        specimenNum: index,
        dna: baseArray,
        mutate() {
            //randomaly select a base in the dna property and replace it with a random different value
            const randIndex = Math.floor(Math.random() * this.dna.length);
            let randBase = returnRandBase();
            //ensures new value is different
            while (this.dna[randIndex] === randBase) {
                randBase = returnRandBase();
            }
            this.dna[randIndex] = randBase;
        },
        //compare the dna of two samples and display percentage of identical bases that appear in the same position
        compareDNA(pAequor) {
            let sameCount = 0;
            if (this.dna.length != pAequor.dna.length) {
                console.log('DNA strands of differing length!')
            } else {
                for (let i = 0; i < this.dna.length; i++) {
                    if (this.dna[i] === pAequor.dna[i]) {
                        sameCount++
                    }
                }
            }
            const pctSame = Math.floor((sameCount / this.dna.length) * 100);
            //console.log(`Specimen #${this.specimenNum} and specimen #${pAequor.specimenNum} have ${pctSame}% DNA in common.`);
            return pctSame;
        },
        //pAequor sample has higher chance of survival if it contains 60pct or more C and G bases - return true if that is the case, false otherwise
        willLikelySurvive() {
            if (this.dna.length != 15) {
                console.log('Invalid sample length.');
            } else {
                let cgCount = 0;
                this.dna.forEach(base => {
                    if (base === 'C' || base === 'G') {
                        cgCount++;
                    }
                }
                );
                return Math.floor((cgCount / this.dna.length) * 100) >= 60;
            }
        },
        complementStrand() {
            let compStrand = [];
            if (this.dna.length != 15) {
                console.log('Invalid sample length.');
            } else {
                this.dna.forEach(base => {
                    switch (base) {
                        case 'A':
                            compStrand.push('T');
                            break;
                        case 'T':
                            compStrand.push('A');
                            break;
                        case 'C':
                            compStrand.push('G');
                            break;
                        case 'G':
                            compStrand.push('C');
                            break;
                        default:
                            console.log('Invalid base detected!');
                    }
                })
                return compStrand;
            }
        }
    };
}

//Create function that returns an array of 30 pAequor samples that are likely to survive

const buildSampleSet = () => {
    let sampleSet = [];
    let sampleIndex = 1;
    while (sampleSet.length < 30) {
        let currentSample = pAequorFactory(sampleIndex, mockUpStrand());
        if (currentSample.willLikelySurvive()) {
            sampleSet.push(currentSample);
        };
        sampleIndex++;
    }
    return sampleSet;
};

//Function to find most related instances of pAequor in the sample set
const findMostRelated = pAequorSet => {
    let testSet = pAequorSet;
    let currentMaxPct = 0;
    let currentS1;
    let currentS2;
    while (testSet.length > 1) {
        let currentSample = testSet.pop();
        for (let i = 0; i < testSet.length; i++) {
            if (currentSample.compareDNA(testSet[i]) > currentMaxPct) {
                currentMaxPct = currentSample.compareDNA(testSet[i])
                currentS1 = currentSample;
                currentS2 = testSet[i];
            }
        }
    };
    console.log(`The most related specimens are #${currentS2.specimenNum} and #${currentS1.specimenNum} having ${currentMaxPct}% DNA in common.`);
};
//****** TEST CODE *******
//const testP = pAequorFactory(1,mockUpStrand());
//console.log(testP.dna);
//testP.mutate();
//const testP2 = pAequorFactory(2,mockUpStrand());
//console.log(testP2.dna);
//testP.compareDNA(testP2);
//console.log(testP.willLikelySurvive());
//const sampleSet = buildSampleSet();
//console.log(sampleSet.length);
//console.log(sampleSet[25]);
//console.log(sampleSet[25].willLikelySurvive());
//console.log(testP.complementStrand());
//findMostRelated(sampleSet);