Wordle

In this assignment, you'll write code to play Wordle in the web browser.

Purpose

In this assignment, you'll show your command of these concepts and skills

  • responding to user input
  • dynamically building content
  • using delegated handlers

Solution

To see the general organization of the solution, you are welcome to look at my solution

You can play the game in the usual way. You can either click the keyboard elements to "type" your guess, or you can just type.

Note that I have "obfuscated" the code for game.js. That allows you to run my code and see what your code is supposed to do without seeing my solution code.

Do not reverse engineer my solution code. You are to write your own code. I will consider it a violation of the honor code to attempt to reverse engineer my code.

The Provided Functions

Take a moment to explore the code in provided.js. (Find it using the solution above.)

Do not copy this code into your files. Just load my file into your html file, using the script tag that is already in the game.htmlfile, below.

Reference Information

This assignment is mostly about dynamically creating elements, namely the HTML elements to show a particular letter that the user has guessed. They will typically look like this:

<span class="letter">e</span>

I've supplied a CSS file that makes that look okay, but feel free to customize with the CSS file.

A collectionof guessed letters will look like:

<div class="guess">
<span class="letter">s</span>
<span class="letter">l</span>
<span class="letter">a</span>
<span class="letter">t</span>
<span class="letter">e</span>
</div>

It is okay to use the dev tools inspector to look at the stuff my solution builds.

To Do

Note that this solution will be in your cs304-assignments folder. (Scott will create this.)

  1. make a working directory for this assignment in your cs304-assignments folder: wordle
  2. create an game.html file in that folder; you can copy the HTML source code from my solution, above.
  3. create your own, empty, game.js file
  4. Implement the functions above, as described in the next sections

In step 2 above, you can copy my HTML and CSS file to get started:

~cs304node/public_html/assignments/wordle/solution/game.html
~cs304node/public_html/assignments/wordle/solution/game.css

Feel free to customize/personalize things.

Word Source

I got a bunch of words (2309) and put them in a global variable called wordleWords. The array is set by the file words.js. There's no need for you to modify that file; just load it.

In your game play, you'll choose a random word from that array and use it as your target WORD.

Plan

There are two important aspects of this assignment:

  1. CORE: assessing a guess, comparing it to the target and deciding on green/yellow/gray for correct, misplaced, and wrong letters.
  2. UI: collecting user input into a string, dynamically placing things on the page, responding to a guess, etc.

For lack of better terms (feel free to suggest terminology), I've called the core and UI (for "user interface").

Core

In my solution, I wrote a function that took a guessed word and a target word and returned an array of three values:

  • the number of correct letters. 5 correct means the game is over
  • HTML code to replace the HTML for the guesses
  • a "code" string where 2=correct/green, 1=misplaced/yellow, and 0=wrong/gray

(There are other ways to do this core functionality, but that's how I did it.)

The first return value can tell the caller whether to congratulate them for success or to set up for the next guess (or if they've run out of guesses, tell them the word).

That code string is useful in testing your function. I've given you a testing function for you in the provided.js file. Here it is:

function computeLetterResponsesTesting(responder) {
    if( typeof responder != "function" ) {
        throw new Error("argument must be a function");
    }
    function test1(guess, target, correctCode) {
        let [ num, resp, code ] = responder(guess, target);
        if( code != correctCode ) {
            console.error('failed', target, guess, output, guess2);
        } else {
            console.log('success', target, guess, output);
        }
    }
    test1('slate', 'leper', '01001');
    test1('slate', 'least', '11211');
    test1('slate', 'stale', '21212');
    test1('slate', 'choir', '00000');
    test1('teeth', 'edict', '11000');
    test1('teeth', 'agree', '01100');
    test1('puppy', 'happy', '00222');
    test1('puppy', 'strap', '10000');
}

There are some sample I/O values there.

Take a minute to understand that testing function. It takes your core function as an argument. I called it responder. It defines a helper function called test1 to test a single word pair. The test1 function invokes your function on a guess and a target, and captures the three return values using a destructuring assignment. Finally test1 compares the "code" string returned by your function with the correct code string, and reports success or failure.

You should have a call to this function in your game.js file, so that I can open the JS console and see that it passes these tests.

If you decide on a different API, that's fine. Adjust the testing function and invoke your modified function.

There are some useful classes in the CSS file:

.correct {
    background-color: green;
}

.misplaced {
    background-color: orange;
}

.wrong {
    background-color: gray;
}

Feel free to customize the colors if you'd like.

UI

The UI is tricky, but here are the conceptual steps:

  • at the beginning of each guess, there's an empty <div class="guess"></div> on the page
  • each time a letter is clicked, you'll create a span for it and add it to the above container
  • if the user gives too many letters, you can shake the container
  • when they click the "enter" key, submit the guess.
  • if the guess is not in the Wordle word list, you can shake the container
  • respond to the guess, replacing the div.guess with the response HTML from your function.
  • if the guess is correct, tell the user, maybe with a congratulatory message in p#emotion. I used these words:
    • "Incredible",
    • "Amazing",
    • "Excellent",
    • "Great",
    • "Good",
    • "Phew!"

I've provided a function to shake an element. Feel free to read it and modify it if you'd like.

Suggested approach: Create a function that takes one letter/input as its argument and processes it. There are the 26 letters of the alphabet, all of which are treated identically, plus the string "enter" and the string "delete".

You must set up an event handler to handle "click" events on the letter elements show on the page in the #keyboard" element. This must be a delegated handler. It can extract the thing that was clicked (a suitable argument to the function above) from the data-key attribute of the element.

You should also allow the user to be able to type their answer. To make that easier, I've provided a function called setupKeyHandler that does that. It takes as an argument a function like the letter-processing one I suggested, and invokes that function when the user types one of those letters. It ignores other letters.

You might create other helper functions for the UI; I did.

You'll also need to create a function to start the game or a new game. Attach it to the obvious button on the page.

Strict Mode

Your solution should use strict mode. Just put this at the top of your file(s):

'use strict';

Documentation

Each function should be documented:

  • the arguments, if any, and their types
  • the return value, if any, and its type
  • the effects, if any

Remember, documentation is about what something does, not how it does it. Your documentation should not mention anything about the internal workings. Consider the function an opaque box.

Event Handlers

You can and should test all the functions yourself in the JS console, but it's also nice to attach them to the buttons I provided.

Do that: attach the functions you implemented to the appropriate button.

Optional Stuff

This is pretty challenging, so there are some things you don't have to do (but you might choose to):

  • backspace/delete. You don't have to implement that behavior. If you do, keep it simple: remove the last character in the guess, and re-generate all the <span> elements.
  • end the game at 6 guesses, announcing the solution. This isn't hard, but it's not essential.

Hints

  • Most of the structure we are building in this game is fairly small. I did not find I needed cloning.
  • I did find the jQuery replaceWith method useful for replacing one element with another. (The guessed letters with the feedback).

Random Elements

Here's how to choose a random element from an array. First, generate a random index into the array. If the array length is N, a random index is an integer in the range [0,N) where the brackets means inclusive of zero and exclusive of N. Here's how:

  • Generate a random floating-point number in the range [0,1). Every random number generator in various languages can do that. In JS, it's Math.random()
  • Multiply that by N, to get a floating-point number in the range [0,N).
  • Take the floor of that number to get an integer in the range [0,N): Math.floor()
  • index the array
function randElt(array) {
    const N = array.length;
    const i = Math.floor(N * Math.random());
    return array[i];
}

// testing code. Call this several times
randElt([1,2,3,4,5,6,7,8]); // D8 for you D&D fans
// works with any array
randElt(['heads', 'tails']);

Final Checklist

  • author name(s) at the top of each .js file
  • all functions documented
  • passes testing function (put this call in your .js file)
  • game works
  • running code:
    • If this was solo work, the running code will be in your own cs304-assignments folder
    • if this was pair work, comment at the top of your game.js file saying where (which partner's cs304-assignments folder) I can find the working code.

How to turn this in

We will grade the code you have in your account. However, I've decided to try this as a Gradescope programming assignment, which means I'll ask you to upload your game.js file to Gradescope. I think this will allow me to comment directly on your code.

Solution

Tutors can look at the sample solution