Lab 5: REPLs

Programming the Web: An Introduction (Spring 2021)


Learning goals


The gist

This laboratory assignment asks you to build two different guessing games. The first is a version of the “classic” high-low guessing game: the computer “thinks” of a number, the human player tries to guess that number in as few guesses as possible; the computer reports whether guesses are too low, too high or correct. Try playing the solution version which asks you to guess a number between 1 (inclusive) and 100 (exclusive). You can play for a different range of values by playing from the console as in:

> numberGuessingGame(50, 60);

The second game is a version of the word-guessing game “hangman”. It expects two human players (the computer is just the mediator). The first human player enters some alphabetic text (ideally an actual word). The computer then presents a masked version of that word (for instance, loop would appear as ***). The other player then tries to discover the word by guessing one letter at a time. After each guess, the computer responds whether the letter is in the word and then repeats the process, but now revealing where in the word the guessed letter occurs. For instance, if the secret word is loop and the player guesses o, the o’s are revealed as *OO* (the game is case insensitive and guesses are displayed by the computer as uppercase letters). Try playing the solution version.


Instructions


JavaScript console exercises

Open the JavaScript console in your Web browser (Command-Option-I). Using the browser’s JavaScript console, try these examples, in order, one at a time:

  > prompt('What happens if you click Cancel?')

  > null === "null"

  > let i = 0;
  > while (true) {
        console.log(i);
        if (i >= 5) {
           break;
        }
        i += 1;
     }
     
  > Number('this is not a number')
  > Number('31')
  > parseFloat('3four')
  > Number('3four')

Programming problems

Examine the files in the starter archive. You should work in the two files, number-guessing-game.js and word-mask-game.js. Both are loaded by the browser when you open the file lab5.html.

Read over both files thoroughly before starting to write code. You can work on the games in either order. The number-guessing game is probably easier to implement, but slightly more of the word-mask game has been implemented for you.

To complete the number game, you need to solve these tasks:

  1. Add code to numberGuessingGame(low, high) so that executing that function plays a very crude version of the game. You only need add a few lines in the body of the if. As an example of what to add, see wordMaskGame in word-mask-game.js.

  2. Complete readRange(low, high) to make it a REPL that repeatedly prompts the user for an integer in the range between low (inclusive) and high (exclusive) until the user enters a valid integer in that range in which case it returns that integer. If the user cancels the prompt or leaves the prompt empty then the function should confirm that the user wanted to quit, and, if so, return null. You can use Number() to convert a string to a number instead of parseFloat. You can test if a number is an integer by checking the remainder of the number divided by 1.

  3. Complete respondToGuess(secret, guess) so that it returns a string indicating if the guess was correct, too low, or too high, where secret is the number to be guessed.

  4. Add code to guessLoop(secret, low, high) so that it can better serve as the central game loop: repeatedly ask the user to guess the number (secret) that is assumed to be between low (inclusive) and high (exclusive). It should call readRange and respondToGuess. It should return the number of guesses taken until reaching the correct answer or the negation of that number if the player chose to quit instead.

  5. Add code to finishNumberGuessingGame(x, guesses) so that it displays whether or not the player succeeded in finding the number (x) to be guessed. If guesses is positive then it represents the number of guesses it took to reach the answer; if not it indicates that the user failed to reach the answer. (It can be assumed if it is a negative number it represents the negation of the number of guesses attempted before the player gave up.)

To complete the word-mask game, you need to solve these tasks:

  1. Complete readChar(pattern, guessesMade, guessesLeft) so that it is a REPL that asks the user (player 2) to enter a single letter and then returns an uppercase version of that letter. If the user cancels then it should confirm that the user wanted to quit, and, if so, return null.

  2. Complete readWord() so that it is a REPL that asks the user (player 1) to enter a nonempty string that consists only of letters and then returns the uppercase version of that word. If user cancels then it should confirm that user wanted to quit, and, if so, return null. This function should be structurally similar to readChar except that you can (and should) make use of the supplied allUpper function.

  3. Add code to finishWordMaskGame(wordToGuess, guessesLeft) so it displays whether or not the player succeeded in correctly guessing wordToGuess. If the second argument (guessesLeft) is positive then it represents success and how many guesses the player had left. Otherwise, it indicates that the user failed to find the answer (before quitting or running out of guesses). In the latter case, the wordToGuess should be displayed as part of the losing message.

  4. Add code to wordMaskLoop(wordToGuess) so that it can better serve as the central game loop: repeatedly ask the user to guess for single letters to reveal if present in the word trying to be guessed. Returns the number of guesses that player had left upon success, or 0 if they ran out of guesses, or null if they quit. Observe that the key functionality of the game - revealing the letters in the word - has been implemented for you in these two lines:

     let unmaskedGuess = unmaskChar(wordToGuess, guess);
     let newMasked = mesh(unmaskedGuess, masked);

    and that the familiar countOccurrences function has been supplied for you which you can call to both test whether a letter has been guessed before (by counting the number of occurrence in the variable guesses which represents a string of all previous guesses) and whether or not a guess is successful by counting the number of occurrences in wordToGuess.


As usual, to experiment directly with my solution, you can open up a console while viewing this page and try examples such as:

> respondToGuess(37, 43)
  "Too big!"