Welcome to the Treehouse Community

Want to collaborate on code errors? Have bugs you need feedback on? Looking for an extra set of eyes on your latest project? Get support with fellow developers, designers, and programmers of all backgrounds and skill levels here with the Treehouse Community! While you're at it, check out some resources Treehouse students have shared here.

Looking to learn something new?

Treehouse offers a seven day free trial for new students. Get access to thousands of hours of content and join thousands of Treehouse students and alumni in the community today.

Start your free trial

JavaScript JavaScript Numbers The Math Object Random Number Challenge – Two Numbers Solution

Dawid Jacobs
seal-mask
.a{fill-rule:evenodd;}techdegree seal-36
Dawid Jacobs
Full Stack JavaScript Techdegree Graduate 17,835 Points

Can someone please check if this is also correct? My code runs correct but is totally different from the solution

So I understand the solution that they gave as well and it is obviously a better way to compile the code, but I would just like to know if what I compiled is also always going to run correctly or if there is a chance of it failing.

// Collect input from a user
const userInputLow = prompt("Please Type your lowest number");
const userInputHigh = prompt("Please Type your highest number");

// Convert the input to a number
const highNum = parseInt(userInputHigh);
const lowerNum = parseInt(userInputLow);
// Use Math.random() and the user's number to generate a random number
const randomNum = Math.floor(Math.random() * highNum) + 1;

// Create a message displaying the random number


if((highNum) && (lowerNum) && randomNum <= highNum && randomNum >= lowerNum){
  console.log(`${randomNum} is a number between ${lowerNum} and ${highNum}.`);
}else if(randomNum > highNum || randomNum < lowerNum){
  const randomNum = Math.floor(Math.random() * highNum) + 1;
}else if(highNum != true || lowerNum != true){
    alert("You need to provide a number, please try again");
}

Thanks in advance!

1 Answer

Alexandra Hadjidaki
Alexandra Hadjidaki
26,496 Points

First of all, just wanted to say don't worry too much about your answers matching the teacher's solutions. We all have different ways of approaching problems and solving them! As long as the logic is solid and you cover your bases, it should be alright.

TL;DR Your code will not always run correctly and it has the chance of failing, even when all user inputs are valid.

You had a good start but then things got less clear.
I'll start by writing the pseudocode (as I understand it from your code) first and then dive into the code and explain why it looks like yours would fail in certain situations. I will follow your code structure as is for the sake of answering your question exactly.

At the end of my answer i'll also add a "Optimisation suggestions" section with explanations, in case you want to have a look at that too. I'll include the final optimised code, reconstructed based on your answer, that would provide a more reliable result.

THE PSEUDOCODE

// Collect input from a user
// Convert the input to a number
// Generate a random number
// Check validity of inputs and random number
// If inputs are valid AND the generated number is within the range
    // Show a message with the random number to the user
// Else if the generated number is outside the range
    // Generate another random number
// Else if inputs are not valid
    // Show an error message to the user

DIVING INTO THE CODE

The way you collect and convert the data is fine, even if it's written in a more concise way in the teacher's solution.

Then you try generating a random number, before checking the validity of the user's input. But that's not the problem here, the user's input could be valid and the program should finish running successfully if that's the case.

The problem here is that the code you use to generate the random number does not consider the lowerNum for the range. As a result, you would get a random number between 1 and highNum:

// Get a random number between 1 and highNum
Math.floor( Math.random() * highNum) + 1;

// Get a random number between lowerNum and highNum
Math.floor( Math.random() * (highNum - lowerNum + 1) ) + lowerNum;

Even when the user input is valid, the random number could be outside the range the user provided, so from this point on your program would have inconsistent results.
It could fail or succeed any time it runs, no way to tell for sure. Even worse, it could falsely "succeed" and have an unreliable response for the user, or no response at all which is a terrible user experience.
In my book, this is a fundamental error in the program's logic (for the problem we are trying to solve with our code) and the program would fail the goal of this task from this point on.

Having said that, let's have a look at the checks without correcting the above code!
Let's take the checks one by one and see if there's a chance of them failing.

if( (highNum) && (lowerNum) && randomNum <= highNum && randomNum >= lowerNum ) {
    console.log(`${randomNum} is a number between ${lowerNum} and ${highNum}.`);
}
  • If either or both of the values IS NOT a number (the code should not run)
    • e.g. if( NaN && NaN && ... ) or if( NaN && 5 && ... ) or if( 3 && NaN && ... )
    • The code inside the block will never run, in which case this code SUCCEEDS
  • If both values ARE numbers (the code should run)
    • If either or both of the values are equal to 0
      • e.g. if( 0 && 0 && ... ) or if( 0 && 5 && ... ) or if( 3 && 0 && ... )
      • The code inside the block will never run, in which case this code FAILS
    • If both values are greater than 0 BUT the random number generator does not use the correct logic (original code)
      • If the random number is between 1 and lowerNum (less than lowerNum)
        • e.g. lowerNum=5, highNum=10 and randomNum=3
        • The code inside the block will never run, in which case this code FAILS
    • If both values are greater than 0 AND the random number generator uses the correct logic (corrected code)
      • e.g. lowerNum=5, highNum=10 and randomNum=7
      • The code inside the block will always run, in which case this code SUCCEEDS

Conclusion: the first check has the chance of failing under certain conditions, even when it should succeed.

else if( randomNum > highNum || randomNum < lowerNum ) {
  const randomNum = Math.floor(Math.random() * highNum) + 1;
}
  • If either or both of the values IS NOT a number (the code should not run)
    • e.g. if( NaN > NaN || NaN < NaN ) or if( 5 > NaN || 5 < NaN )
    • The code inside the block will never run, in which case this code SUCCEEDS
  • If both values ARE numbers (the code should run)
    • If the random number generator does not use the correct logic (original code)
      • If the random number is greater than highNum
        • e.g. highNum=0 and randomNum=1
        • The code inside the block will always run, in which case you get a SyntaxError that randomNum has already been declared, no new random number is assigned to randomNum
        • Nothing else happens, the program ends here
        • This code FALSELY SUCCEEDS
      • If the random number is between 1 and lowerNum (less than lowerNum)
        • e.g. lowerNum=5, highNum=10 and randomNum=3
        • The code inside the block will always run, in which case you get a SyntaxError that randomNum has already been declared, no new random number is assigned to randomNum
        • Nothing else happens, the program ends here
        • This code FALSELY SUCCEEDS
    • If the random number generator uses the correct logic (corrected code)
      • Neither of the two conditions will ever be true, the code inside the block will never run based on this conditional

Conclusion: the second check has the chance of failing under certain conditions. It should never run if the program logic is correct, but based on the existing code it could potentially run, which is a false success. If it runs, an error is thrown and nothing else really happens, leaving the user hanging without any response (fail).

else if( highNum != true || lowerNum != true ) {
    alert("You need to provide a number, please try again");
}
  • If either or both of the values IS NOT a number (the code should run)
    • e.g. if( NaN != true || NaN != true ) or if( NaN != true || 5 != true )
    • The code inside the block will always run, in which case this code SUCCEEDS
  • If both values ARE numbers (the code should have never reached here and should not run)
    • e.g. if( 5 != true || 0 != true ) or if( 0 != true || 0 != true )
    • The code inside the block will always run, in which case this code FAILS
    • except for if( 1 != true || 1 != true ) which will not run the code, but would be a FALSE SUCCESS

Conclusion: the third and last check has the chance of failing under certain conditions, when the first conditional doesn't catch the code properly.


OPTIMISATION SUGGESTIONS

After you collect and convert the user's input, you try generating a random number before even checking the validity of the user's input.

What if the user provided a word or nothing at all?

// Convert non-numeric strings to numbers
const lowNum = parseInt("hello");
// output: NaN
const highNum = parseInt("");
// output: NaN

// Generate random number in a range using variables above
const randomNumInRange = Math.floor( Math.random() * (highNum - lowNum + 1) ) + lowNum; 
// output: NaN

Before even attempting this step, you should perform all your checks first to avoid bugs before branching your code accordingly. This gives you more control over your code from the start and minimises the chance of things going wrong unexpectedly.
The optimised pseudocode:

// Collect input from a user
// Convert the input to a number
// Check user input for validity first, then branch the program accordingly
// If either input is not valid (we want numbers)
    // Show an error message to the user
// Else if both inputs are valid
    // Generate a random number within that range
    // Show a message with the random number to the user

The more optimised your checks are, the less time your program spends doing unnecessary operations and the faster it can react to and correct the user interaction.

Checks like the following are completely unnecessary and in some cases can give the wrong result:

  • if( randomNumInRange <= highNum && randomNumInRange >= lowNum )
  • if( randomNumInRange > highNum || randomNumInRange < lowNum )
  • if( (highNum) && (lowNum) )
  • if( highNum != true || lowNum != true )

Here's why:

  • The way that random numbers are generated, they will always fall within a range and that range depends on the logic you provide it. If generated correctly, they will never be outside the range you expect so checking for that is just extra work for nothing.
  • The parseInt() function can only have two possible return values: a number or NaN. You will never get another type of value and it will never be null or undefined. Also, you should generally avoid checking numbers as if they were boolean in conditionals as different numbers translate to different boolean values, giving unexpected results when working with variables.
    • For example: (0) && (0) => false, (1) && (2) => true and (2) && (0) => false. They are all valid numbers, but not all will yield the same result.
    • Another example: 0 != true => true, 1 != true => false and 2 != true => true (same for any number greater than 2). Again, they are all valid numbers, but not all will yield the same result.

Basically, the only check you need to do is whether the user provided numbers or not with the isNaN() function and branch your code accordingly.

I'll use the pseudocode above and the structure of your code to provide you a more optimised and reliable solution based on my suggested optimisations above:

// Collect input from a user
const userInputLow = prompt("Please Type your lowest number");
const userInputHigh = prompt("Please Type your highest number");

// Convert the input to a number
// (we will either get a number or NaN as values)
const highNum = parseInt(userInputHigh);
const lowerNum = parseInt(userInputLow);

// Check user input for validity first, then branch the program accordingly

// If either input is not valid (we want numbers)
if( isNaN(highNum) || isNaN(lowerNum) ) {
    // Show an error message to the user
    console.log('Please provide two numbers. Try again.');
}
// Else if both inputs are valid
else {
    // Generate a random number within that range (corrected from original code!)
    const randomNum = Math.floor( Math.random() * (highNum - lowerNum + 1) ) + lowerNum;
    // Show a message with the random number to the user
    console.log(`${randomNum} is a number between ${lowerNum} and ${highNum}.`);
}
Dawid Jacobs
seal-mask
.a{fill-rule:evenodd;}techdegree seal-36
Dawid Jacobs
Full Stack JavaScript Techdegree Graduate 17,835 Points

Hi Alexandra, thanks for taking the time for this extensive explanation! I had an idea that my code would not always run but couldn't really figure out why it would not, but what you say regarding the logic in the random number generator makes sense. thanks again!