Mysterious Organism Challenge Project (JavaScript)

Hello everyone.

This is my proposal for this challenge.

You can give me your opinion.

// 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;
};

const pAequorFactory = (serial, DNA) => {
  return {
    _serial: Math.floor(Math.random() * 100000) +1,
    _DNA: mockUpStrand(),
    mutate() {
      let setDNA = false;
      do {
        let ramdonPosition = Math.floor(Math.random() * 15);
        let originalADN = this._DNA[ramdonPosition];
        let newBase = returnRandBase();
        if (originalADN !== newBase) {
          this._DNA[ramdonPosition] = newBase;
          setDNA = true;
        }
      } while (setDNA == false);
      return this._DNA;
    },
    compareADN(ObToCompare) {
      let hitCount = 0; //Para contarl las coincidencias
      for (let i = 0; i < ObToCompare._DNA.length; i++) {
        if (this._DNA[i] === ObToCompare._DNA[i]) {
          hitCount++;
        }
      }
      porcentaje = Math.floor((hitCount / 15) * 10000) / 100;
      console.log(
        `Especimen ${this._serial} y Especimen ${ObToCompare._serial} have ${porcentaje} % DNA in common`
      );
    },
    willLikleSurvive() {
      let hitsC = null;
      let hitsG = null;
      let pos = 0;
      let base = null;
      do {
        base = this._DNA[pos];
        switch (base) {
          case "C":
            hitsC++;
            break;
          case "G":
            hitsG++;
            break;
          default:
        }
        pos++;
      } while (pos < this._DNA.length);
      let percentageC = (hitsC / 15) * 100;
      let percentageG = (hitsG / 15) * 100;
      if (percentageC >= 60 || percentageG >= 60) {
        return true;
      } else {
        return false;
      }
    },
  };
};





Here’s my code after adding the 2 optional features. Learned tons. Feel free to comment. I work in vs code mainly and got some help on outputting the array to json file, which I didn’t know was possible. While the json file object works perfect to copy/paste an array object into main.js, the factory methods (unsurprisingly) don’t work unless every object is created using the factory function, so I edited that array of objects–super-easy in vs code. I also discovered that using toFixed to format numbers converts them into strings, which looks great, as long as you don’t want to compare them, but there are solutions to that as well, beginning with Math.round(). All good!

// const fs = require('fs'); const returnRandBase = () => { const dnaBases = ['A', 'T', 'C', 'G']; return dnaBases[Math.floor(Math.random() * 4)]; }; const mockUpStrand = () => { const newStrand = []; for (let i = 0; i < 15; i++) { newStrand.push(returnRandBase()); } return newStrand; }; const dnaComplements = { 'A': 'T', 'T': 'A', 'C': 'G', 'G': 'C' }; const pAequorFactory = (specimenNumber, dna15BaseArr) => { return { specimenNum: specimenNumber, dna: dna15BaseArr, mutate() { const randPosition = Math.floor(Math.random() * this.dna.length); this.dna[randPosition] = newRandomBase(this.dna[randPosition]); return this.dna; }, compareDNA(specimen2) { if (this.dna.length !== specimen2.dna.length) return 0; const matchCount = this.dna.filter((element, index) => element === specimen2.dna[index]).length; const matchPercent = (matchCount / specimen2.dna.length) * 100; console.log(`specimen #${this.specimenNum} and specimen #${specimen2.specimenNum} have ${matchPercent.toFixed(0)}% DNA in common`); return matchPercent; }, compareDNA(specimen2) { if (this.dna.length !== specimen2.dna.length) return 0; const matchCount = this.dna.filter((element, index) => element === specimen2.dna[index]).length; const matchPercent = (matchCount / specimen2.dna.length) * 100; console.log(`specimen #${this.specimenNum} and specimen #${specimen2.specimenNum} have ${matchPercent.toFixed(0)}% DNA in common`); return matchPercent; // Return as a number }, willLikelySurvive() { const cgMatchCount = this.dna.filter(element => element === 'G' || element === 'C').length; const matchPercent = (cgMatchCount / this.dna.length) * 100; return (matchPercent >= 60); }, complementStrand() { return this.dna.map(neucleotide => dnaComplements[neucleotide]); }, toString() { return `Specimen #${this.specimenNum}: ${this.dna.join('')}`; }, }; }; const newRandomBase = excludeBase => { const bases = ["A", "T", "C", "G"]; const filteredBases = bases.filter(base => base !== excludeBase); return filteredBases[Math.floor(Math.random() * filteredBases.length)]; }; const closestRelated = pAequorArr => { let closest = 0; let compare = 0; let pair = null; for (let i = 0; i < pAequorArr.length; i++) { for (let j = 0; j < pAequorArr.length; j++) { if (i !== j) { // Skip comparison if i === j compare = pAequorArr[i].compareDNA(pAequorArr[j]); if (compare > closest) { closest = compare; pair = [pAequorArr[i], pAequorArr[j]]; } } } } console.log(`The closest related specimens are ${Math.round(closest)}% identical`); }; // // Create array of 30 pAequor likely to survive // const createLikely30 = () => { // const likely30 = []; // let currentNumber = 1; // let unlikelyNumber = 1; // while (likely30.length < 30) { // const prospect = pAequorFactory(currentNumber, mockUpStrand()); // if (prospect.willLikelySurvive()) { // likely30.push(prospect); // currentNumber++; // } else { // unlikelyNumber++; // } // } // return likely30; // }; // // Create the array let likelyToSurvive30 = //createLikely30(); // Note: to create the array, I logged the array to likelyToSurvive30.json and copy/pasted // To file log, I uncommented the first require line and removed type line from package.json // Then, uncomment next 7 lines, and the array assignment half-line 3 lines above // Note: I had to reformat as factory objects to get facotry object methods to work // const oneLineStringify = (obj) => { // return JSON.stringify(obj).replace(/},/g, '},\n'); // }; // fs.writeFile('likelyToSurvive30.json', oneLineStringify(likelyToSurvive30), (err) => { // if (err) throw err; // console.log('The file has been saved!'); // }); [ pAequorFactory(1, ["T","T","G","A","C","A","C","A","G","C","T","G","C","G","C"] ), pAequorFactory(2, ["T","G","G","A","C","C","C","C","A","G","A","C","A","G","G"] ), pAequorFactory(3, ["A","C","T","G","G","C","A","G","C","G","A","A","G","G","A"] ), pAequorFactory(4, ["C","G","C","T","C","G","C","A","C","G","G","G","G","C","T"] ), pAequorFactory(5, ["C","C","A","T","C","C","A","G","A","G","G","C","G","C","T"] ), pAequorFactory(6, ["T","G","C","G","G","T","T","A","G","G","G","C","C","T","T"] ), pAequorFactory(7, ["T","C","C","G","C","C","G","T","C","A","G","C","A","A","A"] ), pAequorFactory(8, ["A","C","G","C","C","T","C","A","C","G","C","C","A","C","C"] ), pAequorFactory(9, ["A","T","C","G","G","C","G","G","C","A","C","C","T","T","T"] ), pAequorFactory(10, ["G","G","A","A","T","C","G","T","G","G","C","T","G","G","A"] ), pAequorFactory(11, ["C","A","A","C","G","C","A","A","G","G","G","A","A","G","C"] ), pAequorFactory(12, ["T","C","C","C","G","G","G","A","T","C","G","G","T","T","C"] ), pAequorFactory(13, ["A","T","G","G","T","A","C","C","G","C","C","G","C","G","A"] ), pAequorFactory(14, ["T","C","A","C","G","A","A","G","C","G","C","A","G","C","T"] ), pAequorFactory(15, ["T","A","C","C","C","C","C","G","C","G","T","A","T","T","C"] ), pAequorFactory(16, ["G","G","G","C","C","A","T","C","C","T","G","C","G","T","G"] ), pAequorFactory(17, ["G","G","G","A","G","A","A","G","G","T","G","G","T","C","G"] ), pAequorFactory(18, ["G","C","G","C","G","G","A","C","T","A","T","C","T","G","G"] ), pAequorFactory(19, ["C","A","A","C","G","T","G","G","C","G","G","G","T","T","A"] ), pAequorFactory(20, ["C","C","C","G","C","G","T","A","G","C","T","G","A","T","G"] ), pAequorFactory(21, ["A","G","G","G","C","T","T","C","C","A","A","G","C","C","A"] ), pAequorFactory(22, ["G","G","G","A","A","T","G","A","G","G","A","G","G","G","T"] ), pAequorFactory(23, ["C","C","G","A","T","T","C","T","G","G","G","C","G","G","A"] ), pAequorFactory(24, ["C","T","T","C","T","C","G","C","T","C","T","T","C","G","C"] ), pAequorFactory(25, ["G","C","T","C","C","C","A","T","G","T","T","C","T","C","C"] ), pAequorFactory(26, ["C","A","C","G","G","G","T","G","C","T","C","A","T","C","T"] ), pAequorFactory(27, ["T","T","T","C","G","T","T","T","G","G","C","G","G","G","C"] ), pAequorFactory(28, ["G","A","G","C","T","T","T","G","C","G","G","G","T","A","C"] ), pAequorFactory(29, ["A","T","G","A","C","C","C","T","A","C","T","C","C","G","G"] ), pAequorFactory(30, ["G","C","G","C","C","C","T","A","G","G","C","T","C","A","A"] ) ]; const specimen1 = pAequorFactory(1, mockUpStrand()); const specimen2 = pAequorFactory(2, mockUpStrand()); console.log(`pAequous DNA: ${specimen1.dna.join(',')}`); console.log(`Complement strand: ${specimen1.complementStrand()}`); // closestRelated(likelyToSurvive30); // console.log(likelyToSurvive30); // console.log('Original DNA:', specimen1.dna); // console.log('Mutated DNA:', specimen1.mutate()); // console.log(specimen1.compareDNA(specimen2)); // console.log(specimen1.willLikelySurvive());

Here my code. I hope someone tells me some tips to write I more readble and efficient code. Have a nice code day!

1 Like

Here’s my code with the extra task. Have a great day!

1 Like

This was such a hard challenge - I feel like I have been thrown into the deep end. I admit I had to use Google and Copilot a lot to even understand what the tasks wanted me to do.

After looking at the solution, I am pleased with my approach and I enjoyed learning about the use of reduce() to count matches - up until now I only used it summing values in a number array. It’s very clever to use reduce() to count the matches and I will remember it for the future!

A note about my solution:

  • I added an extra helper function to calculate the percentages
  • I included a counter into the factory function itself so each new instance would be assigned a specimen number that increased by 1 each time, so I didn’t need the specimenNum parameter in the function.
  • I didn’t do the optional extra task, because quite honestly, I didn’t understand it!

My Solution

Here’s my code. After looking at some other solutions, I realize that I misunderstood the assignment when it comes to the mutate() method. I thought I had to change all of the bases in the organism, but I see now that I only needed to change one random base; I will go back and fix it. Any feedback would be appreciated.

This was my solution.
I had a slight issue where when finding the most related instance of PAequor.
When i used the .toFixed() method on line 36 to make the return of the compareDNA method limited to 2 decimal places, the mostRelated() function’s comparison on line 90 gave me an output where 6.66 was bigger than 53.33. I ‘fixed’ this bug by moving the toFixed() method into the splice on line 91. However i still don’t understand why the computer believed that 6.66 was bigger than 53.33.
Please explain if I’m not being crazy.

Hi all, :slightly_smiling_face:

This is my solution: GitHub JavaScript - I have to admit, at times I felt :exploding_head:

Hello there!

This is my version, I’ve also made the optionals… So I had to change the original output for the .compareDNA() method.

// 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
}

const sNums = [];                           //stores the created specimen's numbers
const survivors = [];                       //stores the survivors

function pAequorFactory(sNum, dnaArr) {     //factory function for P.Aequor
    return {                                //returns the object
        specimenNum: sNum,
        dna: dnaArr,
        mutate(){                           //mutates a random base of the specimen
            const obIndex = Math.floor(Math.random() * this.dna.length); //selects a random base from dna
            let newDna = this.dna[obIndex];
            while (this.dna[obIndex] === newDna){newDna = returnRandBase();}
            this.dna[obIndex] = newDna;     //sets the new dna base.
        },
        compareDNA(specTwo){
            let counter = 0;
            let res = 0;
            for (x=0; x < this.dna.length; x++){
                if (this.dna[x] === specTwo.dna[x]){counter++};
            }
            res = counter / this.dna.length * 100;
            //console.log(`#${this.specimenNum} and specimen #${specTwo.specimenNum} have ${res.toFixed(2)}% DNA in common`)
            return res; // massive comparison. For the original comment this and uncomment the previous line.
        },
        willLikelySurvive(){
            let counter = this.dna.filter(el => el === "C" || el === "G").length;
            return (counter/this.dna.length * 100) > 60? true: false;
        },
        complementStrand(){
            const complement = [];
            for (const base of this.dna){
                switch (base){
                    case 'A': complement.push('T'); break;
                    case 'T': complement.push('A'); break;
                    case 'C': complement.push('G'); break;
                    case 'G': complement.push('C'); break;
                }
            }
            return complement;
        }
    };
}

function iWillSurvive(){            //generates speciments until at least 30 likely survive
    while (survivors.length < 30){
        const bug = pAequorFactory(newID(), mockUpStrand());
        if (bug.willLikelySurvive()) {survivors.push(bug)};
    }
}

function bestMatch(batch){           //compare a batch of specimens and returns the best matching pair.
    let match = {                   //stores the most compatible ones.
        idOne: 0,
        idTwo: 0,
        compatibility: 0,
    };
    for (let x=0; x<batch.length; x++){  //loops throug the batch
        for (let y=0; y<batch.length; y++){ //loops throug the batch again to compare
            if (x !== y){           //ensures to not compare the specimen with itself
                let calc = batch[x].compareDNA(batch[y]);
                if (calc > match.compatibility){
                    match.compatibility = calc;
                    match.idOne = batch[x].specimenNum;
                    match.idTwo = batch[y].specimenNum;
                }
            }
        }
    }
    return match;
}

const newID = () =>{                        //generates a new specimen's number
    sNums.push(sNums.length + 1);           //adds the new id.
    return sNums.length;                    //returns the new id.
}

// generates specimens for the original tests:
/*const bug = pAequorFactory(newID(), mockUpStrand());
const bugTwo = pAequorFactory(newID(), mockUpStrand());
const bugThree = pAequorFactory(newID(), mockUpStrand());
const bugFour = pAequorFactory(newID(), mockUpStrand());
const bugFive = pAequorFactory(newID(), mockUpStrand());*/

// test original functions request:
/*console.log('Before mutation: ' + bug.dna.join(''));
bug.mutate();
console.log('After mutation:  ' + bug.dna.join(''));
bug.compareDNA(bugTwo);
bugThree.compareDNA(bugFive);*/

//test masive creation:
/*iWillSurvive();
console.log(survivors);
console.log(survivors.length);*/

//test complement:
/*console.log(bug.dna.join(''));
console.log(bug.complementStrand().join(''));*/

//optionals:
iWillSurvive();
const pair = bestMatch(survivors);
console.log(`The specimen #${pair.idOne} and #${pair.idTwo} are the best match with a compatibility of ${pair.compatibility.toFixed(2)}%`);

See ya!

I thought doing while the dna is not itself keep randomizing was kind of a cheat way to do it but the solution code did it so it must be good enough XD I’m happy enough with that for now anway

Happy with my progress on this one also yay, didn’t take too long like the previous one (credit card checker)

Code: mystery-organism-starter/main.js at main · enzodia1908/mystery-organism-starter · GitHub

This includes the bonus assignments, also made sure that each of the 30 Instances are unique.

Hi! Glad to meet you here. I have completed the new organism project and learnt a lot on how to better use the factory function in this project! Since i major in Biology, this has been fun and meaningful for me.
My code is in the link below:

Mysterious Organism

Hello, here is my code this project. The task was difficult for me, but exciting.

MysteriousOrganism.js

Hey guys here is my solution to the challenge. I have also done the complement strand query. Feedback and or criticism will be really appreciated . thank you.
link to github : JavaScript/mysteriousOrganism/mystery-organism-starter/main.js at main · vanda-mugo/JavaScript · GitHub

// 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())
}
//console.log(mock up strand ${newStrand});
return newStrand
};

const pAequorFactory = (num, dnaArr) => {
return {spicemenNum: num,
dna: dnaArr,
mutate(){
// random number in range of length of dna strand
let randNum = Math.floor(Math.random() * this.dna.length);
let newBase = returnRandBase();
// to ensure the values are not the same we use a while loop
while(newBase === this.dna[randNum]){
newBase = returnRandBase();
}
//console.log(changed base at index ${randNum} from ${this.dna[randNum]} to ${newBase});
this.dna[randNum] = newBase;
return this.dna;
},
compareDNA(pAequor){
try{
if(pAequor.length !== this.dna.length || !Array.isArray(pAequor)){
// when you use new you create an instance of an Error that includes a
// message and a stack trace
throw new Error(‘lengthOfDnaError: the length of passed Dna differ, Attribute return value highly affected’);
}
let count = 0;
for(let i = 0; i < this.dna.length; i++){
if(pAequor[i] === this.dna[i]){
count += 1;
}
}
return (count/this.dna.length) * 100;
}catch(error){
console.log("An Error occured: ");
console.log(error.message);
return;
}
},
willLikelySurvive(){
let count = 0;
for(let i = 0; i < this.dna.length; i++){
if ((this.dna[i] === ‘C’)||(this.dna[i] === ‘G’)){
// this shows the likelyhood to survive
count += 1;
}
}
if(((count/this.dna.length) * 100) >= 60){
return true;
}
return false;
},
complementStrand(){
let complementDna = new Array();
for(let i = 0; i < this.dna.length; i++){
if(this.dna[i] === ‘A’ || this.dna[i] === ‘T’){
if(this.dna[i] === ‘A’){
complementDna[i] = ‘T’;
continue;
}
// since now we only remain if its T
complementDna[i] = ‘A’;
}
if(this.dna[i] === ‘C’ || this.dna[i] === ‘G’){
if(this.dna[i] === ‘C’){
complementDna[i] = ‘G’;
continue;
}
// since now we only remain if its T
complementDna[i] = ‘C’;
}
}
return complementDna;
}};
};

// to create 30 instances of pAequor, array to be studied la
let pAequorArray = new Array();
count = 0;
while (pAequorArray.length < 30){
// we call pAequorFactory to get a return
let pAequorInstance = pAequorFactory(count, mockUpStrand())//
// the pAequorInstance has the return object, we can use this to check ability to survive . only update count within the block
if(pAequorInstance.willLikelySurvive() === true){
pAequorArray.push(pAequorInstance);
count += 1;
}
}

// uncomment this to text the above script
/*
let obj = pAequorFactory(1, mockUpStrand());
console.log(obj);

console.log(“mutate value :”);
console.log(obj.mutate());
console.log(“to check the possibility of survival :”);
console.log(obj.willLikelySurvive());
console.log(“compare with random DNA strand :”);
// lets check the value of .compareDNA
console.log(obj.compareDNA(mockUpStrand()));

console.log(“value of obj before complementStrand is called :”);
console.log(obj);

console.log(“value of complement :”);
console.log(obj.complementStrand());

*/

Hello everyone, this is my take on the project Mysterious Organism.
Any feedback is highly appreciated. Thanks.

Hi all, here’s my solution

My first post in the forums :slight_smile:

Will be appreciated if you can review my code