Mysterious Organism 7th step

Hello all!

So I’m not understanding exactly why my last step (countFunc) isn’t working. It’s taking forever to load and not outputting anything to the console.

From my understanding we want to take the mutated strands(mutated()) and test for survivors via the willLikelySurvive object and then push the arrays that are true in the willLikelySurvive method into an array(survivors).

Am I missing something?

Any guidance would be appreciated.

Cheers.

Here’s the project link:
https://www.codecademy.com/paths/full-stack-engineer-career-path/tracks/fscp-javascript-syntax-part-ii/modules/fecp-challenge-project-mysterious-organism/projects/mysterious-organism

// 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 = (num, array) => { return { specimenNum: num, dna: array, mutate() { //console.log(this.dna); let randIndex = (Math.floor(Math.random() * this.dna.length)); //console.log(randIndex); let randBase = this.dna[randIndex]; let randBase2 = returnRandBase(); while (randBase === randBase2) { randBase2 = returnRandBase(); } this.dna[randIndex] = randBase2; //console.log(randBase2); //console.log(this.dna); //console.log(randIndex); //console.log(this.dna.length); return this.dna }, compareDNA(pAequor) { let percentage = 0; let count = 0; let dna1 = pAequor; console.log(dna1); let dna2 = this.mutate(); console.log(dna2); for (i = 0; i < dna1.length; i++) { if (dna1[i] !== dna2[i]) { ++count; } } return percentage = ((count / dna1.length) * 100).toFixed(1); //console.log(count); //console.log(`The strands are ${((count / dna1.length) * 100).toFixed(1)}% different.`) }, willLikelySurvive() { let percentCG = 0; let count2 = 0; for (i = 0; i < this.dna.length; i++) { if (this.dna[i] === 'C' || this.dna[i] === 'G') { ++count2; } } percentCG = ((count2 / this.dna.length) * 100).toFixed(1) if (percentCG >= 60) { return true; } else { return false; } } } } let factory factory = (pAequorFactory(1, mockUpStrand())); //console.log(factory) //console.log(factory.mutate()) //console.log(factory.compareDNA(mockUpStrand())) //console.log(factory.willLikelySurvive()); //console.log(factory.willLikelySurvive()); //console.log(factory.dna); const countFunc = () => { let survivors = []; while (survivors.length < 10) { if (factory.willLikelySurvive() === true) { survivors.push(factory.mutate()); } } return survivors; } console.log(countFunc());

I think your indentations got mixed, I copied in VS Code and willLikelySurvive() is not a method inside the factory, so I believe calling it on if (factory.willLikelySurvive() === true) is not working because that object does not have that method. The “misplaced” (for lack of better word) closing } is the one on line 97, if my hypothesis is correct =]

Hey, thanks for the response.

I looked at line 97 and that curly brace seems to correspond with line 67, so that seems like they are closed there. Then there’s the comma on line 97 so that I can list the next method.

Other than that does the logic make sense? Does the code seem right?

You got this error right? Error: TypeError: Cannot read property ‘length’ of undefined. This means that somewhere you are trying to read the length property of an undefined object. Probably an array that youre trying to loop through. Look at all the times you invoke length and make sure every object that you invoke length on is defined.

Thanks for the reply,

I only get that error on the codebytes console for the forum not in the codecademy project console.

I console logged everywhere that .length was applied and got defined objects.

The only place where the program doesn’t run is the while loop in countFunc. If I comment out the while loop, then console log survivors, I get an empty array, like I should. But the moment I reinstate the while loop it doesn’t run anymore. It’s making me think that because I am applying .length to an empty array as its condition for running the loop it’s bugging out.

Any thoughts?

@cecilmahumane1469686
The problem is in your main loop. The While loop is never finishing because the survivors array is never going past 0 items.
This is happening because factory.willLikelySurvive() is always returning the exact same percentage of CG. If below 60% it will never return true and the while will never complete.

What I am not clear is what should be the correct behavior as I haven’t gotten to the instructions of the project. From the context I infer that at some point in the iteration process your factory should be mutating.

The willLikelySurvive() does not mutate the factory by itself. So maybe you are supposed to be mutating during every iteration in your main while loop and then use that mutated factory for the if statement.

Or maybe you are meant to be using the compareDNA() function that does some mutation. This function is not used anywhere.

I do find odd that in the While loop, if the factory will likely survive, then you are pushing a mutated factory into the survivors array. This would be a different factory from the one that just tested true. I think you may just need to be pushing the same dna that just tested true. Then the mutate is called outside the if statement before the next iteration of the while loop.

  while (survivors.length < 10) {
    if (factory.willLikelySurvive() === true) {
      survivors.push(factory.mutate());
    }
  }

Print to the console the percentage that willLikelySurvive is generating and you will see.

Still there is another issue I want to warn you about and has to do with how you are adding the dna sequences to your survivors array.

To show you, I modified your function to assume you want to mutate in every iteration and save to survivors those which are likely to survive. Like this:

const countFunc = () => {
  let survivors = [];

  while (survivors.length < 10) {
    if (factory.willLikelySurvive() === true) {
      survivors.push(factory.dna);
    }
    factory.mutate();
  }

  return survivors;
};

console.log(countFunc());

You are expecting to save the current dna array sequence into your survivor array. But in JS, Objects such as arrays will be passed by reference and not value. So you are really storing a reference to the array object passed. Which in all cases is the same object as factory.dna.
So in the end all the survivors will point to the same factory.dna object. Which keeps mutating every iteration, an all the items in your survivors array will be the same as the final value of factory.dna.

To overcome this, you need to store a copy of the dna sequence array into your survivors array instead. There are many ways to copy an object but a simple one for arrays would be: survivors.push(factory.dna.slice(0));

For more details on passing by value vs reference look here:

The outcome of my version gives me 10 different dna sequences that will likely survive. You can adjust to the correct logic.

Hope this helps you get to the desired outcome soon!

Here is an additional good learning post on copying Objects in JS. In my solution above, the array slice function is enough as your array contains Primitive values. (All string characters) If your array contained other nested arrays, or other objects. You may need to perform a deep copy, if you want to ensure the copied object is completely different in all properties.
It is a very important topic to master for the future when dealing with more complex projects. Will save you a lot of headaches.

First off thanks for taking the time to write such an extensive and thorough answer. I really appreciate it.

If I understand what your saying, as each factory.dna array is pushed to the survivors array, what is actually pushed is a changeable reference. In my case this results in the same array 10 times because the source object has changed 10 times as well, changing all the previous references along with.

As well the reason your solution works is that .slice() is taking a shallow copy of factory.dna each iteration of the while loop.

One probably very simple question I have though is why we invoke factory.mutate() inside the while loop. Invoking that method results in an array, yet we don’t return that array. What happens to it? I’m sure this is something so simple, but any clarification would help.

1 Like

Read and bookmarked :grinning_face_with_smiling_eyes:

Glad you got it figured out. For the question on factory.mutate().
I just called factory.mutate() in that spot to get a version of the code that worked. In the project instructions they may be requesting something different, but I have not been through this project myself to help with more specifics there. In any case I assume they need you to mutate the objects at some moment which was not happening before as your if statement was never called.

Your factory.mutate() method modifies the factory.dna sequence and also returns it at the end. What is returned is the same dna object that factory already has. Since all of this time you are working with the same factory object instance you created, then its dna sequence can be accessed at any point by just getting factory.dna. So I mutated it in one step, then called it in the next iteration. Again this was my version of getting a working example. The project may be asking a different thing.

Thanks!