Skip to content

Instantly share code, notes, and snippets.

@matt-winzer
Last active July 26, 2019 17:22
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save matt-winzer/f4dd1205f379c18204f9ee48bd050081 to your computer and use it in GitHub Desktop.
Save matt-winzer/f4dd1205f379c18204f9ee48bd050081 to your computer and use it in GitHub Desktop.

Part I: Foundations of Programming

Basic Requirements

Numbers

  1. Enter the following expressions into your console.

    1 + 2
    3 * 5
    5 / 4 - 13
    5000 * 234
    1073 / 57 + 200
  2. Why are the values produced by the following two expressions different? What are they?

    3 + 2 * 4 - 1;        // => 10
    (3 + 2) * (4 - 1);    // => 15

    ANSWER: The first expression evaluates to 10 and the second expression evaluates to 15. The addition of parentheses in the second example to wrap (3 + 2) and (4 - 1) changes the order in which the code is evaluated. This is because JavaScript evaluates mathematical expressions according to an order of operations, just like in mathematics. The order is PEMDAS (Parentheses, Exponents, Multiplication, Division, Addition, Subtraction).

  3. Calculate how old you are in minutes using the console.

    // If you are 30 years old:
    30 * 365 * 24 * 60;     // => 15768000
  4. What is the percentage of people in the class with brown hair? Use the console to find out.

    12 / 15 * 100;     // => 80
  5. Try the following expressions in the console:

    6 % 2
    42 % 10
    5 % 2
    6 % 3
    7 % 4
    100 % 12

    What is the significance of the result? How does the % (modulus) operator work?

    ANSWER: The modulo operator works by dividing the first operand (the one to the left of the %) by the second operand (the one to the right of the %) and returning the remainder of that division.

  6. Try the following:

    3 % 2
    4 % 2
    5 % 2
    6 % 2

    What do the results tell you about the first operand to the modulus operator?

    ANSWER: The first operand is the number being divided.

Strings

  1. Write a string that represents your full name.

    'Ernest Hemingway';
  2. Write a string that represents your favorite food.

    'Steak';
  3. Use the + operator to combine (known as concatenation) two or more strings, e.g.:

    // Your first and last names
    "John" + " " + "Doe"
    • Your first and last names (as shown above)
      "Ernest" + " " + "Hemingway";
    • Your parents' full names
      "Clarence Hemingway" + " " + "Grace Hemingway";
    • Your home town and state
      "Oak Park" + ", " + "Illinois";
  4. Fix the errors in the following strings:

    Where are all the quotes?
    'hmm something is not right"
    'Do other ' * 'operators work with string concatenation?

    FIXED:

    "Where are all the quotes?";
    "hmm something is not right";
    'Do other ' + 'operators work with string concatenation?';

Part II: Functions

Basic Requirements

  1. In your console, copy the following function and verify that the following invocations match your expectations:

    function square(num){
       return num * num;
    }
    
    square(10) + 2;
    square(100) + square(77);
    square(8 / 2)
    square(2 + 17);
    square(square(15));
  2. Write a sentence in plain English describing how square(square(15)) is evaluated.

    ANSWER: The inner function call square(15) is evaluated first, then its result is used to evaluate the outer function call.

  3. Rename square's num parameter in your above code to monkey, and rename the uses of that parameter in the body to monkey as well. Will the function square still work? Why or why not?

    ANSWER: The function square will still work, because the parameter monkey simply represents a placeholder for an actual value that is provided when the function is called. Thus, it does not need to be named semantically for the code to work.

  4. What is wrong with the following definitions of square? Write a sentence or two describing the issue(s); then, try copying the erroneous examples into a console one-at-a-time and observing the error(s) generated (you may have to attempt to invoke the functions to see the error). What errors are produced (if any) for each erroneous version? Do the errors make sense?

    function square(monkey) {
      return x * x;
    }

    PROBLEM: There is no reference to x available. The parameter monkey should be refactored to x or vice versa for the function to work.

    function square(5) {
      return 5 * 5;
    }

    PROBLEM: The number 5 cannot be used as a function parameter. Parameters must be placeholders/labels, not actual values.

    function square("x") {
      return "x" * "x";
    }

    PROBLEM: Similar to above, the string "x" cannot be used as a function parameter. Parameters must be placeholders/labels, not actual values. Also, strings cannot be multiplied together. The parameter should be refactored to x and the body of the function should be refactored to: return x * x;

  5. Fix the invalid syntax in the following functions (you can copy and paste these invalid definitions into your console and then edit them there):

    func square1(x {
      return x * x;
    }
    
    functionsquare2 x)
      return x * x;
    }
    
    function (x) square3 {
      return x * x;

    FIXED:

    function square1(x) {
      return x * x;
    }
    
    function square2(x) {
      return x * x;
    }
    
    function square3(x) {
      return x * x;
    }
  6. The following functions exhibit poor style -- fix these issues using the original version of square as a reference.

    function square(x){return x*x;}
    
    function square (x) { return x *x;
    }
    
    function square(x)
    {
    return x * x;
    }

    FIXED:

    function square(x) {
       return x * x;
    }
    
    function square(x) {
       return x * x;
    }
    
    function square(x) {
       return x * x;
    }
  7. Complete the function cube that returns the cube of x:

function cube(x) {
  // your code here
}

ANSWER:

function cube(x) {
  return x * x * x;
}

// OR

function cube(x) {
  return Math.pow(x, 3);
}
  1. Complete the function fullName that should take two parameters, firstName and lastName, and returns the firstName and lastName concatenated together with a space in between.

    // don't forget the parameters!
    function fullName() {
     // your code here
    }
    fullName("John", "Doe") // => "John Doe"

    ANSWER:

    function fullName(firstName, lastName) {
       return firstName + " " + lastName;
    }
  2. Write a function average that takes two numbers as input (parameters), and returns the average of those numbers.

    function average(num1, num2) {
       return (num1 + num2) / 2;
    }
  3. Write a function greeter that takes a name as an argument and greets that name by returning something along the lines of "Hello, <name>!"

function greeter(name) {
   return "Hello, " + name + "!";
}
  1. Using the document found at this link, translate the first page of geometric formulas into JavaScript functions.

    As an example, a function to compute the perimeter of a rectangle might look like this:

    function perimeterRect(l, w) {
      return 2 * (l + w);
    }

    NOTE: JavaScript provides some nifty mathematical functions and constants built into the language that you'll need for this exercise. The two that we'll be making use of are:

    Math.PI; // => 3.141592653589793
    Math.sqrt(256); // => 16

    To test your answers, you'll need to:

    1. Code your function in the console in the way that you think it will work
    2. Call the function with arguments in the console to see the result, e.g. perimeterRect(2, 6).
    3. Eventually, you may want to verify that the output is correct. Google is a great tool for this:

    google geometry answer

More Practice

Translate the rest of the geometric formulas found here into JavaScript functions.

Advanced (extra practice)

  1. Compound interest can be calculated with the formula:

    future value

    • F: future value
    • P: present value
    • i: nominal interest rate
    • n: compounding frequency
    • t: time

Write a function futureValue that can be used to calculate the future value of a quantity of money using compound interest.

Use the function to calculate what the future value of $1700 (P = 1700) deposited in a bank that pays an annual interest rate of 4.7% (i = 0.047), compounded quarterly (n = 4) after 6 years (t = 6) (you can use Math.pow to do exponentiation).

function futureValue(presentVal, interestRate, compoundingFreq, time) {
   return presentVal * Math.pow(1 + interestRate / compoundingFreq, compoundingFreq * time);
}

futureValue(1700, 0.047, 4, 6)    // => 2250.1218394891257
  1. Write a power function that accepts the parameters base and exponent and returns the result. Replace square and cube with the power function you just wrote. Do not use Math.pow.

    // Using Math.pow
    function power(base, exponent) {
       return Math.pow(base, exponent);
    }
    
    // Not using Math.pow
    function power(base, exponent) {
       var result = 1;
       for (var i = 0; i < exponent; i++) {
          result = result * base;
       }
       return result;
    }
  2. Write your own square-root function called sqrt that accepts a number parameter and returns an approximate square root. Square-root approximations make use of averages. Be sure to use the average function you previously wrote. The first version of your square root function should perform no more than 3 successive averages.

Part III: Booleans, Comparisons & Conditionals

Basic Requirements

Comparison Operators

  1. Type the two boolean values -- true and false -- into your console.

  2. Use the console to accomplish the following:

    • Write an expression using > that will evaluate to false
    • Write an expression using > that will evaluate to true
    • Write an expression using < that will evaluate to false
    • Write an expression using < that will evaluate to true
    • Write an expression using two numbers and === that will evaluate to true
    • Write an expression using two numbers and === that will evaluate to false
    • Write an expression using two strings and === that will evaluate to true
    • Write an expression using two strings and === that will evaluate to false
  3. Fill in the ??? with the following operators or values to make the statements output the expected Boolean value.

    12 ??? 78
    // => true
    
    24 ??? 16
    // => false
    
    45 !== ???
    // => true
    
    "45" ??? 45
    // => false
    
    "6" ??? "six"
    // => true

    POTENTIAL ANSWERS:

    12 < 78
    // => true
    
    24 > 16
    // => false
    
    45 !== 46
    // => true
    
    "45" === 45
    // => false
    
    "6" !== "six"
    // => true
  4. Write a function oldEnoughToDrink that takes an age as an argument and returns true if the person with that age is old enough to drink.

    function oldEnoughToDrink(age) {
      if (age >= 21) {
        return true;
      }
      return false;
    }
  5. There's an easy way to figure out how long a string is by adding .length to the end of it. Try this out in the console:

"hello".length;
"".length;
"John Doe".length;

Write a function sameLength that accepts two strings as arguments, and returns true if those strings have the same length, and false otherwise.

function sameLength(string1, string2) {
  if (string1.length === string2.length) {
    return true;
  }
  return false;
}
  1. Write a function passwordLongEnough that accepts a "password" as a parameter and returns true if that password is long enough -- you get to decide what constitutes long enough.

    function passwordLongEnough(password) {
      if (password.length >= 8) {
        return true;
      }
      return false;
    }

Conditionals: if

  1. Write a function bouncer that accepts a person's name and age as arguments, and returns either "Go home, NAME.", or "Welcome, NAME!" (where NAME is the parameter that represents the person's name) depending on whether or not the person is old enough to drink.

    function bouncer(name, age) {
      if (age >= 21) {
        return 'Welcome, ' + name + '!';
      }
      return 'Go home, ' + name + '.';
    }
  2. Write a function max that takes two numbers as arguments, and returns the larger one.

    function max(num1, num2) {
      if (num1 > num2) {
        return num1;
      }
      return num2;
    }
  3. Write a function min that takes two numbers as arguments, and returns the smaller one.

    function min(num1, num2) {
      if (num1 < num2) {
        return num1;
      }
      return num2;
    }
  4. Write functions larger and smaller that each accept two strings as arguments, and return the larger and smaller strings, respectively.

    function larger(string1, string2) {
      if (string1.length > string2.length) {
        return string1;
      }
      return string2;
    }
    
    function smaller(string1, string2) {
      if (string1.length < string2.length) {
        return string1;
      }
      return string2;
    }

More Practice

  1. Fill in the ??? with the following operators or values to make the statements output the expected Boolean value.

    106 ??? 12
    // => false
    
    "wiz" ??? "wiz"
    // => true
    
    7 * 7  ??? 49
    // => true
    
    12 ??? (24 / 2)
    // => false
    
    (20 % 2) <= ???
    // => true
    
    (9 / 3) + (5 * 5) === ???
    // => true

    POTENTIAL ANSWERS:

    106 <= 12
    // => false
    
    "wiz" === "wiz"
    // => true
    
    7 * 7  === 49
    // => true
    
    12 !== (24 / 2)
    // => false
    
    (20 % 2) <= 10
    // => true
    
    (9 / 3) + (5 * 5) === 28
    // => true
  2. Write the following functions that each accept a single number as an argument:

    • even: returns true if its argument is even, and false otherwise.
    function even(num) {
      // The number is even if it can be divided by 2 with no remainder
      if (num % 2 === 0) {
        return true;
      }
      return false;
    }
    • odd: the opposite of the above.
    function odd(num) {
      // The number is odd if it cannot be divided by 2 with no remainder
      if (num % 2 !== 0) {
        return true;
      }
      return false;
    }
    • positive: returns true if its argument is positive, and false otherwise.
    function positive(num) {
      if (num >= 0) {
        return true;
      }
      return false;
    }
    • negative: the opposite of the above.
    function negative(num) {
      if (num < 0) {
        return true;
      }
      return false;
    }
  3. A couple of other useful built-in mathematical functions are Math.random, Math.floor and Math.ceil. Look these functions up on MDN to learn how they work, and use them to implement the following functions:

    • randInt: Should accept a single numeric argument (n), and return a number from 0 to n.

      function randInt(n) {
        return Math.floor(Math.random() * (n + 1));
      }
    • guessMyNumber: Should accept a single numeric argument and compare it to a random number between 0 and 5. It should return one of the following strings:

      • "You guessed my number!" if the argument matches the random number.
      • "Nope! That wasn't it!" if the argument did not match the random number.
      function guessMyNumber(guess) {
         var randomNum = Math.floor(Math.random() * 6);
         if (guess === randomNum) {
           return "You guessed my number!";
         }
         return "Nope! That wasn't it!";
      }

Part IV: Logical Operators & Advanced Conditionals

Basic Requirements

Logical Operators

  1. Is the ! operator a unary operator, or binary operator?

    ANSWER: It is a unary operator, because it has only one operand.

  2. Evaluate each of the following expressions first on a whiteboard, and then in a console:

    !(2 >= 2)      // => false
    !(4 === 4)     // => false
    !(5 !== 5)     // => true
  3. Evaluate each of the following expressions first on a whiteboard, and then in a console:

    1 > 2 || 2 > 2 || 3 > 2    // => true
    5 < 5 || 75 < 74           // => false

Conditionals: else if & else

  1. This guy named "Joe" keeps blacking out at the bar that your function, bouncer (from the previous module), is in charge of; thus, management has decided to add him to the "blacklist" -- modify the bouncer function from the previous section so that the person named "Joe" is rejected with an appropriate message, regardless of his age.

    function bouncer(name, age) {
      if (name === 'Joe') {
        return 'Go home, ' + name + '. You are banned from the bar.';
      } else if (age >= 21) {
        return 'Welcome, ' + name + '!';
      }
      return 'Go home, ' + name + '.';
    }
  2. Write a function called scoreToGrade that accepts a number as a parameter and returns a string representing a letter grade corresponding to that score.

    For example, the following grades should be returned given these scores:

    • 'A' >= 90
    • 'B' >= 80
    • 'C' >= 70
    • 'D' >= 60
    • 'F' < 60
    function scoreToGrade(score) {
      if (score >= 90) {
        return 'A';
      } else if (score >= 80) {
        return 'B';
      } else if (score >= 70) {
        return 'C';
      } else if (score >= 60) {
        return 'D';
      } else {
        return 'F';
      }
    }
    scoreToGrade(95); // => 'A'
    scoreToGrade(72); // => 'C'
  3. Modify the scoreToGrade function so that it returns 'INVALID SCORE' if the score is greater than 100 or less than 0.

    function scoreToGrade(score) {
      if (score > 100 || score < 0) {
        return 'INVALID SCORE';
      } else if (score >= 90) {
        return 'A';
      } else if (score >= 80) {
        return 'B';
      } else if (score >= 70) {
        return 'C';
      } else if (score >= 60) {
        return 'D';
      } else {
        return 'F';
      }
    }

More Practice

  1. Think of at least three activities that you enjoy doing outdoors and the range of temperatures and weather patterns (e.g sunny, windy, snowy, rainy, etc.) that are best for these activities. Write a function whatToDoOutside that accepts a temperature and condition as parameters and outputs a string of the format: "The weather is ideal for: ACTIVITY" (where ACTIVITY is an actual activity). Make sure to include an else that indicates what should be done if the conditions do not match any activities. If you're short on inspiration, here are some ideas:

    • Snow Sports: snowboarding, skiing
    • Water Sports: surfing, sailing, paddle boarding, swimming
    • Team Sports: basketball, baseball, football (American or everywhere else), etc.
    function whatToDoOutside(temperature, condition) {
      var activity = '';
      
      if (temperature >= 80 && condition === 'sunny') {
        activity = 'swimming';
      } else if (temperature >= 80 && condition === 'windy') {
        activity = 'sailing';
      } else if (temperature >= 60 && condition === 'sunny') {
        activity = 'basketball';
      } else if (temperature >= 60 && condition === 'windy') {
        activity = 'hiking';
      } else if (temperature < 60 && condition === 'snowy') {
        activity = 'skiing';
      } else {
        activity = 'building a bonfire';
      }
      
      return 'The weather is ideal for: ' + activity + '.';
    }
  2. The guessMyNumber function from the Booleans & Conditionals module (More Practice section) accepts a guess n and checks it against a random number from 0 to 5 -- if the guess n is greater than 5, output a different message indicating that the guess is out of bounds.

    • NOTE: It will be helpful to first write a randInt function that accepts a number n and computes a random integer from 0 to n; then, you can use this function in guessMyNumber.

      function randInt(n) {
        return Math.floor(Math.random() * (n + 1));
      }
      
      function guessMyNumber(n) {
         var randomNum = randInt(5);
         
         if (n > 5) {
           return "Your guess is out bounds."
         } else if (n === randomNum) {
           return "You guessed my number!";
         }
         return "Nope! That wasn't it!";
      }
  3. Modify the scoreToGrade function so that it returns 'A+/A-' for scores of 98-100/90-92 respectively. Apply the same logic for all other letter grades.

    function scoreToGrade(score) {
      if (score > 100 || score < 0) {
        return 'INVALID SCORE';
      } else if (score >= 98) {
        return 'A+';
      } else if (score >= 93) {
        return 'A';
      } else if (score >= 90) {
        return 'A-';
      } else if (score >= 88) {
        return 'B+';
      } else if (score >= 83) {
        return 'B';
      } else if (score >= 80) {
        return 'B-';
      } else if (score >= 78) {
        return 'C+';
      } else if (score >= 73) {
        return 'C';
      } else if (score >= 70) {
        return 'C-';
      } else if (score >= 68) {
        return 'D+';
      } else if (score >= 63) {
        return 'D';
      } else if (score >= 60) {
        return 'D-';
      } else {
        return 'F';
      }
    }

Advanced

  1. The bar that employs our bouncer function has decided to do live music on Friday and Saturday nights, and will be admitting those that are over 18 to the bar on those nights; the catch however, is that all who are 21 or older will need to be given a wristband to distinguish them from the minors. Modify your bouncer function to handle this situation.

    function bouncer(name, age, day) {
      if (name === 'Joe') {
        return 'Go home, ' + name + '. You are banned from the bar.';
      } else if ((day === 'Friday' || day === 'Saturday') && age >= 21) {
        return 'Welcome, ' + name + '! Here is your wristband.'
      } else if ((day === 'Friday' || day === 'Saturday') && age >= 18) {
        return 'Welcome, ' + name + '! You can come in but no drinking.'
      } else if (age >= 21) {
        return 'Welcome, ' + name + '!';
      }
      return 'Go home, ' + name + '.';
    }
  2. You should have noticed a large amount of repetitive code when modifying scoreToGrade to accommodate + or - grades. When we do lots of repetitive things, that's a clear signal that there's a better way. Write a helper function letterGrade that accepts two arguments, letter and score, and works as follows:

    function letterGrade(letter, score) {
      if (score % 10 >= 8) {
        return letter + '+';
      } else if (score % 10 >= 3) {
        return letter;
      } else {
        return letter + '-';
      }
    }
    
    // These are examples of what a *working* function would output.
    letterGrade('A', 95); // => 'A'
    letterGrade('A', 91); // => 'A-'
    letterGrade('B', 88); // => 'B+'
    letterGrade('monkey', 160); // => 'monkey-'

    Finally, use letterGrade to remove the repetition in scoreToGrade.

    function scoreToGrade(score) {
      if (score > 100 || score < 0) {
        return 'INVALID SCORE';
      } else if (score === 100) {
        return 'A+';
      } else if (score >= 90) {
        return letterGrade('A', score);
      } else if (score >= 80) {
        return letterGrade('B', score);
      } else if (score >= 70) {
        return letterGrade('C', score);
      } else if (score >= 60) {
        return letterGrade('D', score);
      } else {
        return 'F';
      }
    }
  3. It turns out that we can write logical and and logical or in terms of each other and logical not using De Morgan's Laws.

    • Write a function or that works like ||, but only uses ! and &&.
    function or(a, b) {
      return !(!a && !b);
    }
    
    or(true, false);    // => true
    or(true, true);     // => true
    or(false, false);   // => false
    • Write a function and that works like &&, but only uses ! and ||.
    function and(a, b) {
      return !(!a || !b);
    }
    
    and(true, false);   // => false
    and(true, true);    // => true
    and(false, false);  // => false

Part V: Variables

Basic Requirements

  1. Fix each of the following variable declarations in a console -- some are syntactically invalid, some are disobey style guidelines, and some are just weird.

    var "animal" = "monkey";
    var "monkey" = animal;
    var x= 15;
    var y =10;
    var var = "huh?";
    var true = false;
    var isTenEven = 10 % 2 = 0;

    FIXED:

    var animal = "monkey";
    var monkey = animal;
    var x = 15;
    var y = 10;
    var variable = "huh?";
    var truth = false;
    var isTenEven = 10 % 2 === 0;
  2. Perform the following in the console:

    • Create a variable firstName and assign your first name to it.
    • Create another variable, lastName, and assign your last name to it.
    • Have a middle name? If so, repeat the process.
    • Now, create a variable fullName and assign your full name to it by using the above variables.
    var firstName = 'Michael';
    var lastName = 'Jordan';
    var middleName = 'Jeffrey';
    var fullName = firstName + ' ' + middleName + ' ' + lastName;
  3. For each of the following code blocks, use a whiteboard (or a piece of paper) to reason about what the value of x is supposed to be on the last line. Once you have arrived at a conclusion that you are comfortable with, enter the lines into a console and check your answer. Was your hypothesis correct? If not, ensure that you understand why (talk with a classmate, or ask for help).

    var x = 5;
    x + 10;
    x; // => ???

    ANSWER:

    x; // => 5
    var x = 17;
    x = (x + 1) / 2;
    x * 4;
    x; // => ???

    ANSWER:

    x; // => 9
    var x = 5;
    var y = 20;
    x = y;
    y = y + 7;
    x; // => ???

    ANSWER:

    x; // => 20
    var x = 10;
    var y = 5;
    x = (x * 4) - 3;
    x + 17;
    x = x + y;
    x; // => ???

    ANSWER:

    x; // => 42
  4. Write a function called counter that, when invoked, always returns a number that is one more than the previous invocation. For instance:

    var count = 0;
    
    function counter() {
      count = count + 1;
      return count;
    }
    counter(); // => 1
    counter(); // => 2
    counter(); // => 3
    // etc.

    HINT: You'll need a variable for this. Where should the variable be declared?

    ANSWER: Declaring the variable outside of the function (in global scope) allows the program to properly track how many times the counter() function has been called. The value of the count variable is persistent.

More Practice

All of the following exercises involve augmenting the guessMyNumber function.

  1. In a previous module you wrote a function called guessMyNumber that simulated a guessing game: the idea is that the function picks a random number between 0 and 5, and you invoke the function with your guess -- if you and the function are thinking of the same number, you win! Otherwise, the function informs you that your guess was incorrect. A version of this game might look like this (the randInt function is included for convenience):

    function guessMyNumber(n) {
      if (n > 5) {
        return "Out of bounds! Please try a number between 0 and 5.";
      } else if (n === randInt(5)) {
        return "You guessed my number!";
      }
      return "Nope! That wasn't it!";
    }
    
    function randInt(n) {
      return Math.floor(Math.random() * (n + 1))
    }

    Read and test both of the functions in your console and affirm that you understand how they work; then, answer the following questions:

    • At present, the guess should be between 0 and 5. We can think of 5 as the upper bound of the guess. How many times is the upper bound repeated? What if we wanted to change the upper bound to 6? How many changes would be required?

      ANSWER: Changes would be needed each time the number 5 is used. For the function above, that would be 3 changes in total.

    • Create a variable called upperBound to hold the upper bound, and then reference it instead of the number 5. If you were asked to change the upper bound to some other number (e.g. 7), you should only have to make one change.

    function guessMyNumber(n) {
      var upperBound = 5;
    
      if (n > upperBound) {
        return "Out of bounds! Please try a number between 0 and " + upperBound + ".";
      } else if (n === randInt(upperBound)) {
        return "You guessed my number!";
      }
      return "Nope! That wasn't it!";
    }
    
    function randInt(n) {
      return Math.floor(Math.random() * (n + 1))
    }
    • Modify guessMyNumber so that if the guess is incorrect, guessMyNumber includes the correct guess in its output, e.g. "Nope! The correct number was: X" (where X would have been the correct number).
    function guessMyNumber(n) {
      var upperBound = 5;
      var randomNum = randInt(upperBound);
    
      if (n > upperBound) {
        return "Out of bounds! Please try a number between 0 and " + upperBound + ".";
      } else if (n === randomNum)) {
        return "You guessed my number!";
      }
      return "Nope! That wasn't it! The correct answer was: " + randomNum;
    }
    
    function randInt(n) {
      return Math.floor(Math.random() * (n + 1))
    }
  2. At present, the guessing game picks a new random number every time it is "played" (invoked). Now that you know how to make information persistent between function invocations, change the guessing game so that it picks a random number once and allows you to guess until you get the correct answer.

    var upperBound = 5;
    var randomNum = randInt(upperBound);
    
    function guessMyNumber(n) {
      if (n > upperBound) {
        return "Out of bounds! Please try a number between 0 and " + upperBound + ".";
      } else if (n === randomNum) {
        return "You guessed my number!";
      }
      return "Nope! That wasn't it!";
    }
    
    function randInt(n) {
      return Math.floor(Math.random() * (n + 1))
    }
  3. It would be really cool if, after the answer was guessed, the message included the number of guesses it had taken to find the answer; for example, "You guessed my number in 3 guesses."

    • Tangent Problem: What happens if you get the number right on the first try? Does it say, "You guessed my number in 1 guesses."? If so, perhaps the wording should be different? Some better ideas are:

      • "You guessed my number in 1 guess."
      • "Congratulations! You guessed my number on the first try!"
    var upperBound = 5;
    var randomNum = randInt(upperBound);
    var guessCount = 0;
    
    function guessMyNumber(n) {
      guessCount = guessCount + 1;
      
      if (n > upperBound) {
        return "Out of bounds! Please try a number between 0 and " + upperBound + ".";
      } else if (n === randomNum && guessCount === 1) {
        return "Congratulations! You guessed my number on the first try!";
      } else if (n === randomNum) {
        return "You guessed my number! It took you " + guessCount + ' guesses.';
      }
      return "Nope! That wasn't it!";
    }
    
    function randInt(n) {
      return Math.floor(Math.random() * (n + 1))
    }
  4. Implement a way to limit the number of guesses that can be made so that a player loses after exceeding the limit.

    var upperBound = 5;
    var randomNum = randInt(upperBound);
    var guessCount = 0;
    var guessLimit = 4;
    
    function guessMyNumber(n) {
      guessCount = guessCount + 1;
      
      if (guessCount > guessLimit) {
        randomNum = randInt(upperBound);
        return "You have exceeded the maximum number of guesses. You lose!";
      } else if (n > upperBound) {
        return "Out of bounds! Please try a number between 0 and " + upperBound + ".";
      } else if (n === randomNum && guessCount === 1) {
        randomNum = randInt(upperBound);
        return "Congratulations! You guessed my number on the first try!";
      } else if (n === randomNum) {
        randomNum = randInt(upperBound);
        return "You guessed my number! It took you " + guessCount + ' guesses.';
      }
      return "Nope! That wasn't it!";
    }
    
    function randInt(n) {
      return Math.floor(Math.random() * (n + 1))
    }
  5. Keep track of a high score (the lowest number of guesses) between games, and, when the correct number has been guessed in a record number of times, include in the message something that indicates that a new high score has been set.

    var upperBound = 5;
    var randomNum = randInt(upperBound);
    var guessCount = 0;
    var guessLimit = 4;
    var highScore = guessLimit + 1;
    
    function guessMyNumber(n) {
      guessCount = guessCount + 1;
    
      if (guessCount > guessLimit) {
        guessCount = 0;
        randomNum = randInt(upperBound);
        return "You have exceeded the maximum number of guesses. You lose!";
      } else if (n > upperBound) {
        return "Out of bounds! Please try a number between 0 and " + upperBound + ".";
      } else if (n === randomNum && guessCount === 1 && guessCount < highScore) {
        highScore = guessCount;
        guessCount = 0;
        randomNum = randInt(upperBound);
        return "Congratulations! You guessed my number on the first try! And you set a new high score!";
      } else if (n === randomNum && guessCount < highScore) {
        var guesses = guessCount;
        highScore = guessCount;
        guessCount = 0;
        randomNum = randInt(upperBound);
        return "You guessed my number! It took you " + guesses + ' guesses, which is a new high score!';
      } else if (n === randomNum) {
        var guesses = guessCount;
        guessCount = 0;
        randomNum = randInt(upperBound);
        return "You guessed my number! It took you " + guesses + ' guesses.';
      }
      return "Nope! That wasn't it!";
    }
    
    function randInt(n) {
      return Math.floor(Math.random() * (n + 1))
    }
  6. Whenever a player wins, increase the difficulty by increasing the upperBound; whenever a player loses, decrease the difficulty by decreasing the upperBound.

    var upperBound = 5;
    var randomNum = randInt(upperBound);
    var guessCount = 0;
    var guessLimit = 4;
    var highScore = guessLimit + 1;
    
    function guessMyNumber(n) {
      guessCount = guessCount + 1;
    
      if (guessCount > guessLimit) {
        guessCount = 0;
        upperBound = upperBound - 1;
        randomNum = randInt(upperBound);
        return "You have exceeded the maximum number of guesses. You lose!";
      } else if (n > upperBound) {
        return "Out of bounds! Please try a number between 0 and " + upperBound + ".";
      } else if (n === randomNum && guessCount === 1 && guessCount < highScore) {
        highScore = guessCount;
        guessCount = 0;
        upperBound = upperBound + 1;
        randomNum = randInt(upperBound);
        return "Congratulations! You guessed my number on the first try! And you set a new high score!";
      } else if (n === randomNum && guessCount < highScore) {
        var guesses = guessCount;
        highScore = guessCount;
        guessCount = 0;
        upperBound = upperBound + 1;
        randomNum = randInt(upperBound);
        return "You guessed my number! It took you " + guesses + ' guesses, which is a new high score!';
      } else if (n === randomNum) {
        var guesses = guessCount;
        guessCount = 0;
        upperBound = upperBound + 1;
        randomNum = randInt(upperBound);
        return "You guessed my number! It took you " + guesses + ' guesses.';
      }
      return "Nope! That wasn't it!";
    }
    
    function randInt(n) {
      return Math.floor(Math.random() * (n + 1))
    }
  7. Implement a high/low hinting system to tell the the user that the guess is either too high or too low. You may want to increase the upperBound on the guess.

    var upperBound = 5;
    var randomNum = randInt(upperBound);
    var guessCount = 0;
    var guessLimit = 4;
    var highScore = guessLimit + 1;
    
    function guessMyNumber(n) {
      var hint = '';
      guessCount = guessCount + 1;
    
      if (n < randomNum) {
        hint = 'Your guess was too low.';
      } else if (n > randomNum) {
        hint = 'Your guess was too high.';
      }
    
      if (guessCount > guessLimit) {
        guessCount = 0;
        upperBound = upperBound - 1;
        randomNum = randInt(upperBound);
        return "You have exceeded the maximum number of guesses. You lose!";
      } else if (n > upperBound) {
        return "Out of bounds! Please try a number between 0 and " + upperBound + ".";
      } else if (n === randomNum && guessCount === 1 && guessCount < highScore) {
        highScore = guessCount;
        guessCount = 0;
        upperBound = upperBound + 1;
        randomNum = randInt(upperBound);
        return "Congratulations! You guessed my number on the first try! And you set a new high score!";
      } else if (n === randomNum && guessCount < highScore) {
        var guesses = guessCount;
        highScore = guessCount;
        guessCount = 0;
        upperBound = upperBound + 1;
        randomNum = randInt(upperBound);
        return "You guessed my number! It took you " + guesses + ' guesses, which is a new high score!';
      } else if (n === randomNum) {
        var guesses = guessCount;
        guessCount = 0;
        upperBound = upperBound + 1;
        randomNum = randInt(upperBound);
        return "You guessed my number! It took you " + guesses + ' guesses.';
      }
      return "Nope! That wasn't it! " + hint;
    }
    
    function randInt(n) {
      return Math.floor(Math.random() * (n + 1))
    }

Advanced

There is an optimal way to play this game that works like this, given upperBound as the upper bound, lowerBound as the lower bound, and guess as the guess:

  1. Initialize the starting values:

    • guess as half of the upperBound
    • lowerBound as 0
  2. Execute guessMyNumber with guess:

    • If the guess was too high, repeat (2) where:
      • the new guess is half of the difference of guess and lowerBound
      • the new upperBound is guess
    • If the guess was too low, repeat (2) where:
      • The new guess is half of the difference of upperBound and guess
      • The new lowerBound is guess
    • If the guess was correct stop.

Your task is to write a function that implements the above algorithm to play the game on your behalf. The first thing that you will need to do is create another version of guessMyNumber that returns output that will be easier for another function to work with, e.g. use 1 for too high, -1 for too low, 0 for correct.

Relative to upperBound, how many guesses does it take on average to guess correctly?

Some recommendations:

  • Make use of a whiteboard.
  • Play the existing game yourself using the above steps to get an idea of how the algorithm works.
  • Work with a partner.
  • Read about console.log on MDN and use it to help with debugging.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment