Homework 7 - Anagrams.js
Due: Wednesday, April 16, 2025 at 11:59pm
Purpose:
- Gain experience writing in JavaScript
- Handle form data and manipulate the DOM in JavaScript
- Maintain persistent storage with localStorage
Overview
Based on the success of our earlier Anagrams game from Homework 5, we’ll again implement an Anagrams-like game—this time, in JavaScript! For this homework, you may work alone or with another student in this course.
Specifically, you will implement a game that displays seven letters (shuffled) and requires the user to use those letters to name words. It then provides feedback on if the word guessed is a valid word (that has not been entered before) and keeps track of an overall score. The game will end when the user correctly guesses the valid seven-letter target word. You may use the logic from your Homework 5 (or 6) as a starting point, or you may implement everything from scratch. However, unlike Homework 5, in this version the entire game will be played client-side using JavaScript.
Anagrams.js Requirements
Review Homework 5 for the description of how the Anagrams game is played. This client-side version will consist of only one page, index.html
, and will display the game screen as well as the user’s game stats. For the game, the user will be presented with a large display of 7 letters from a target word. The user may enter a guess word or choose to re-shuffle the letters. For each guess the user enters, the game page will be updated with information about whether the guess is valid, and if so, add it to a displayed list of words guessed and update the user’s score. Additionally, the input box will be cleared so that the user can enter their next guess.
For this assignment, you must implement the following components. (You may implement more functionality if you wish, but remember that we’ll be grading on effort in implementing these components below.)
- Your
index.html
should have at least the following three sections (i.e., portions of the page) for the user. You may choose to include more.- Game. This section will display information about the current in-progress game. It will include a form with the following input and functionality. Note that the
action
of the form should not be a PHP page, you should have an event handler instead to update the page when the user submits the form.- Instructions asking the user to enter a guess using only the letters displayed.
- The list of 7 letters from the target word, randomly shuffled, displayed prominently.
- An input box that allows the user to enter their guess.
- A button for the user to submit the current guess.
- A button for the user to shuffle (or randomize) the letters of the target word.
- A list of all the user’s prior correctly-guessed words, grouped by word length. Please be creative! You are encouraged to determine how best to organize the display.
- The current score of the game
- An option (link, button, etc) for the user to start a new game (which will end the current game, if applicable).
- User Game Statistics. This section will display the user’s game statistics:
- The number of games played
- The highest score on any one game
- The lowest score on any one game
- Average number of correct words guessed per game
- Average number of incorrect words guessed per game
- Clear History. In a separate section, provide the users a button to clear out their data from the application.
- Game. This section will display information about the current in-progress game. It will include a form with the following input and functionality. Note that the
- You must implement the following event handlers in JavaScript:
- New game functionality. The user must be able to start a new game.
- When the user clicks the new game button/link, the event handler should load a new target word using the provided
getRandomWord()
function (see below) and redraw the game screen. - If a game was currently in progress when this event handler is called:
- Update the game statistics using the number of words guessed in the current game. Hint: you may want to keep track of the overall number of guesses.
- Remove any display of the prior guesses and score for the in-progress game
- Update the game statistics to increase the number of games played
- When the user clicks the new game button/link, the event handler should load a new target word using the provided
- Guess word functionality. The user must be able to make a guess.
- When the user enters their guess, their guess must be compared with the letters in the target word to determine (1) if it’s a valid guess, (2) if it’s a dictionary word, and (3) if it is the target word.
- In particular, this event handler should calculate:
- if the letters of the guess are all in the target word (using JavaScript),
- if the guessed word is in the dictionary for words of that length (by making an AJAX call to our API (see below)), and
- if the entire guessed word matches exactly the target word (using JavaScript).
- Clear the input box so that the user can enter their next guess.
- Provide feedback if the user enters a word that is not valid and why (i.e., if they used disallowed letters, which letters were invalid; or if they entered an invalid word).
- Update the list of prior correct word guesses if the entered word is valid (i.e., contains only allowed letters and is a word in the dictionary) and update the score based on the list below:
- one-letter word: 1 point
- two-letter word: 2 points
- three-letter word: 4 points
- four-letter word: 8 points
- five-letter word: 15 points
- six-letter word: 30 points
- If the user correctly guesses the target word, update the game statistics, hide the target letters and guessed words for this game, and disable the submission and randomize buttons until the user starts a new game.
- Page load and unload. The user’s data must be stored between views of the page.
- When the page unloads, store the current game and game statistics in
localStorage
. - When the page loads, if there is a game or game statistics stored in
localStorage
, then repopulate the display with the stored version.
- When the page unloads, store the current game and game statistics in
- Clear history. The user must be able to clear the game statistics (and any current game) from the browser.
- When the user clicks the clear history button, your application should remove any game and game statistics information stored in
localStorage
, clear the stats from the DOM, and start a new game.
- When the user clicks the clear history button, your application should remove any game and game statistics information stored in
- New game functionality. The user must be able to start a new game.
- You should use an object or array object to store the game and game statistics. By creating an object to store them, you will be able to store the current state more easily in localStorage by converting the object to a JSON string. See
JSON.stringify()
andJSON.parse()
. - Download and include the following
anagrams.js
JavaScript into yourindex.html
file. This JavaScript library contains a function,getRandomWord()
, that queries our 7-letter word list and returns a random word. You should use this function to get a new word when starting a new game. Note: this function uses the XMLHttpRequest method for sending an AJAX request, along with explicit Promises, which we will not discuss in class, but it may be helpful to see these.- anagrams.js
- You must write a separate function that handles the setup of the new game. This function must take one parameter: an object that contains the target word to start the game.
- You may view (as JSON) an example of the object that will be passed to your function here: Our anagrams create game API endpoint
- In the event handler for when the user chooses to start a new game, call
getRandomWord()
and pass in your separate function above as the only parameter.getRandomWord()
will then call your function with the new object.
- We have provided a second endpoint that will allow you to verify that a word is in the dictionary. Why? We don’t want to load the large dictionary from Homework 5 into the user’s browser!
- Our anagrams check word API endpoint
- You should use the Fetch API to send your request. This API is newer and much quicker to implement than the XMLHttpRequest method exhibited above.
- Write an asynchronous function that will make an AJAX request to
https://cs4640.cs.virginia.edu/homework/checkword.php
. This function will need to await for the response from the server, but we do not want the browser to hang while we wait.async function checkDictionaryWord(word) { ... }
- In this function,
await
the response from a call tofetch()
, thenawait
the response’s.json()
method to read the JSON from our API as an object. - You must create a POST request with the following JSON object in the body of the request:
{ "word":"your-guess-here" }
- The server API will respond with the following object, where
valid
is either true if the word is in the dictionary or false otherwise:{ "result": "success", "word": "your-guess-repeated-here", "valid": true }
- You can see an example response by clicking the link above.
- Write an asynchronous function that will make an AJAX request to
Note: as the user is playing the game, your application must not require the browser to reload the page or redirect the user to a different page. All interactions of the user with the game must stay on index.html
until the user decides to leave the game.
NOTE: We have explicitly left some requirements of the assignment vague to provide freedom of design. You are encouraged to be creative in your implementations!
Additional JavaScript Notes
- You may include your JavaScript code directly in your
index.html
file or write a separate.js
file and include it inindex.html
. - For this submission, you may NOT use jQuery.
Submission
The submission will consist of two parts:
- Submit your code (HTML, CSS, JavaScript, etc) to Gradescope in the “Homework 7” submission. You may choose to upload the files individually, upload a zip folder, or upload from a GitHub repository.
- You must include a link to your published version in the comments of your
index.html
page
- You must include a link to your published version in the comments of your
- Publish your web site to the cs4640 server under a folder titled “hw7”. Therefore, we should be able to access your work at
https://cs4640.cs.virginia.edu/yourid/hw7
. If you work with a partner, each person should publish the work to their web space.
Grading Rubric
This homework is worth 50 points, based on the following rubric:
- 5 points - Game display
- 5 points - User Stats display
- 10 points - New game event handler
- 10 points - Guess/submit word event handler (including AJAX)
- 5 points - Shuffle words event handler
- 5 points - Clear history event handler
- 5 points - Maintain state in Local Storage across page loads
- 5 points - Publishing your site to the cs4640 server
Extra Credit Opportunity
5 points: Add event handlers to the large display of the letters in the target word so that the user can click those letters to add them to their guess (as an alternative to typing them on the keyboard). When the user clicks the letter, your event handler should change the display of the letter to indicate to the user that it is unavailable to be used again, then add that letter to the input text box for the guess. When the user submits their guess, reset the display of the letters.
Academic Integrity
For this assignment, you are welcome to share/publish your website! You’ll be doing that on our cs4640 server as well. We only ask that you not make any GitHub projects public until after the deadline.
Note: You must cite any sources you use in a comment at the top of your index.html
file. For example:
<!DOCTYPE html>
<!--
Sources used: https://cs4640.cs.virginia.edu, ...
-->
<html lang="en">
<head>
...
Use of Generative AI
For Homework 7, you are not allowed to use generative AI tools to help you solve this problem.
Other Notes
In case you are interested, here is the PHP code of our API endpoints:
New Game Endpoint
<?php
// Allow Cross-Origin Scripting so that we can develop
// on our local Docker environments
header("Access-Control-Allow-Origin: *");
header("Access-Control-Allow-Headers: X-Requested-With, Content-Type, Origin, Authorization, Accept, Client-Security-Token, Accept-Encoding");
header("Access-Control-Max-Age: 1000");
header("Access-Control-Allow-Methods: GET, OPTIONS");
// Let the browser know we're sending back JSON instead of HTML
header("Content-Type: application/json");
// Load seven-letter words
$data = file("words7.txt", FILE_IGNORE_NEW_LINES);
// Pick random word
$word = $data[array_rand($data, 1)];
// Build the return data structure
$output = [
"result"=> "success",
"word"=> $word
];
// Print out JSON
echo json_encode($output, JSON_PRETTY_PRINT);
Check Word Endpoing
<?php
// Allow Cross-Origin Scripting so that we can develop
// on our local Docker environments
header("Access-Control-Allow-Origin: *");
header("Access-Control-Allow-Headers: X-Requested-With, Content-Type, Origin, Authorization, Accept, Client-Security-Token, Accept-Encoding");
header("Access-Control-Max-Age: 1000");
header("Access-Control-Allow-Methods: GET, POST, OPTIONS");
// Let the browser know we're sending back JSON instead of HTML
header("Content-Type: application/json");
// Load dictionary
$data = json_decode(file_get_contents("word_bank.json"), true);
// Build the return data structure
$output = [
"result" => "failure",
"word" => "NOT GIVEN",
"valid" => false
];
// Read JSON data from the BODY of the HTTP POST request
// from PHP's standard input
$json = file_get_contents("php://input");
$input = json_decode($json, true);
// Check if user gave a word
if ($input !== false && isset($input["word"])) {
$word = trim($input["word"]);
$i = strlen($word);
// Update output to note word was provided
$output["result"] = "success";
$output["word"] = $word;
// Set valid true if word was in dictionary
if (in_array($word, $data[$i]))
$output["valid"] = true;
}
// Print out JSON
echo json_encode($output, JSON_PRETTY_PRINT);