For this project, you will first create a dictionary data structure that can be used to spell-check documents. Next, you will use that dictionary to create a boggle solver.
Dictionary
The first part of this assignmet is to create the following methods for a dictionary class:- Dictionary() Constructor that creates an empty dictionary.
- Dictionary(String filename) Constructor that reads in a list of words from a file. You can assume that the file contains one word per line. Feel free to use java.util.scanner to help out with this. I only needed to use the hasNext() and nextLine() methods.
- void add(String word) Add word to the dictionary.
- boolean check(String word) Check to see if word is in the dictionary. This check should be case-insensitive!
- checkPrefix(String prefix) Check to see if the string prefix is a prefix of any word in the dictionary. This check should be case-insensitive!
- String suggest(String word)} Return an element in the dictionary as close as possible to word. If word is in the dictionary, then return word. If word is not in the dictionary, return the word that is "closest" in the dictionary.
If you only needed to write th constructor, add, and check, then the best data structure to use would be a hash table. (We will discuss hash tables, and how they work, a bit later in the semester.) However, getting checkPrefix or suggest to work correctly using a hash table would be quite difficult. Binary search may be a little better (since we can relatively easily find words that are close together), but operations on binary search trees take time O(lg n) if you're lucky -- and can be as bad as O(n) if you're not lucky. If keys are entered in sorted order (as the likely would be for a dictionary), then you will get the worst-case performance for a binary search tree.
Instead of a hash table or a binary search tree, you will use a trie, which is s 26-ary tree, where each node has child for each leter of the alphabet, and a valid bit. To check of a word is stored in a tree, start with the root. Follow the pointer associated with the first letter in the word (if this pointer is null, the word is not in the dictionary). From that node, follow the pointer associated with the second letter of the word (again, if the pointer is null, the word is not in the dictionary). Continue until you either reach a null pointer (in which case the word is not in the dictionary), or you get to the end of the word. If you get to the end of the word, check the valid bit to see if the word in the dictionary. For example, consider the following:

This dictionary structure has three main advangages:
- The methods add and check can be performed in constant time (with respect to the number of words in the dictionary -- both these operations are linear in the length of the word being added or checked)
- Suggest can be done (relatively) easily
- Determining if a string is a valid prefix of some word can be done in constant time (relative to the size of the dictionary)
To see more examples of a trie in action, take a look at the Trie Visualization.
Your dictionary class will need to be named Dictionary, in the file Dictionary.java, and will need to implement the methods described in the Dictionary DocumentationDictionary Implementation Details
Recursion
Recursion is your friend for implementing these dictionary methods. You will need to write recursive helper methods that take as one input parameter a tree, and your required methods should call these helper methods passing in the root of the tree - just like we did for binary search trees. So your add method will likely look like the following:void add(String word) { root = add(word, root) }
Of course, you will also need to write a private version of add that takes two paramters ....
Finding a word
Consider finding a word in a tree. The word "ask" is in the following tree:

Finding a Prefix
Once uyou have check, checkPrefix is easy -- you have one fewer check to make.Adding a word
Adding a word to the dictionary is is much like finding a word -- you should still recursively go down the tree until you get to the end of the word. There are two differences, however. First, when finding a word, you check to see if the valid bit is set when the end of the word is reached -- but when adding a word, you set the valid bit when the end of the word is reached. Second, when checking a word, if you come to a null pointer, you can stop looking, since the word is not in the dictionary. If you come to a null pointer when adding, however, you need to create a new node and link it into the tree.Removing a word
There are two steps for removing a word from the dictionary. First, you need to set the valid bit at the end of the word to false. This step will remove the word from the dictionary. Next, you need to remove any branches of the tree that have no valid bits set to true. Specifically, if you set the valid bit of a leaf to false, you need to remove that leaf from the tree. If removing the leaf causes another node to becode a leaf, and that leaf has its valid bit set to false, you need to remove that leaf -- and so on, until either a valid bit is true, or you don't create a leaf. Once again, recursion is your friend here.Hint: If you are having trouble with delete, you can get partial credit by only setting the valid bit to false, and not pruning branches with no valid bits set to true.
Suggest
The easiest way to implement suggest is to return an entry in the dictionary with the same prefix as the word that was passed in -- traverse the tree as you would for a check, and if you reach a null pointer (or you run out of word, and the current node does not have its valid bit set), then seach down any path until you find a valid bit set to true, and return that word.Printing the dictionary
To print out your dictionary, you will want to write a function print that takes two parameters: the tree to print, and the word built up so far. When you first call the print function, you would pass in the root of the tree and an empty string (""). We'll talk about this a bit more in class when the assignment is discussed.Indexing Child Array
The easiest way to have a child for each letter of the alphabet is to have each tree node store an array of 26 pointers: index 0 represents the 'a' child, index 1 represents the 'b' child, and so on. We will thus need to convert from a letter betwen 'a' and 'z' to a number between 0 and 25. If we cast a character to an integer, we will get the ASCII code for the character. To get this number in the range 0..25, we just need to subtract the ASCII code for 'a', as follows:
char ch = 'e';
int index = (int) ch - (int) 'a';
Boggle
Using a dictionary as a spellchecker is nice enough, but we'd like to do something a little more fun. Boggle is a word game, played on a 4 x 4 grid of letters. Players make works by connecting adjacent letters. To create a word, start at one cube, and then work through a chain of letters to form a word that meets the following conditions:- The word must be at least three letters long.
- The path traced out by the letters in the word must be connected horizontally, vertically, or diagonally. You can't skip over intervening cubes to get the next letter.
- Each cube may be used only once in a given word.

The word "PEACE" can be made as follows:

Note that the word "PLACE" is not legal, since after the "L" you would need to jump over the "H" to get to the "A". The same die cannot be resued in the same word (but can be resused again in a different word).
Longer words give more points -- 3 letter words are worth 1 point, 4-letter words are worth 2 points, and so on. The object is to find as many words as possible to get the highest possible score
Computer Boggle
Because the computer has a complete dictionary and you do not, we've tried to make the game a little more interesting by letting you find as many words as you can and then turning the computer loose to find the rest. If you're thorough, you can beat the computer because it is not allowed to count words you've already found. Most games, however, still end up as a rout, with the computer completley trouncing the human.Provided Files
In order to make this project a reasonable size, we have given you most of the code for Boggle. You only need to write two different methods (plus any helper methods required to get your methods to work correctly):-
public boolean validGuess(String guess)
Returns true ifguess
is a valid word on the Boggle board, and false otherwise.
To check if a word is legal:- Make sure it has at least 3 letters (many words in the provided dictionary have 2 or fewer letters!)
- Make sure it is in the dictionary
- Make sure it can be formed on the board
-
public int computerMove(Set
playerMove, Set computerMove)
Returns the score for the computer move, and (in the output parameter computerMove) the set of moves that the computer makes. The computer should find all valid words that are different from the player's moves.
Parameters:- playerMove The set of all words in the players guess
- computerMove An output parameter, the moves made by the computer. This should be a set of all words that can be found in the board that are not in the set playerMove
The score for the computer -- 1 point for each 3-letter word, 2 points for each 4 letter word, 3 points for each 5 letter word, and so on.
To find all words on the board: - Start with a letter, and start searching, keeping track of the word you are building up
- When you create a word (that is, the word that you've built up so far is in the dictionary) add it to a set of all generated words, and go on.
- If the word so far is not a prefix of any valid word (the Dictionary method checkPrefix is your friend here), you can stop
- Keep track of which positions you have used, so you don't reuse
them. Note that only the tiles in the current word you are
buiding up should be marked as used -- as you backtrack, you will need
to modify your markings of which tiles are used.
Support Files
- Dictionary Documentation
- BoardGUI.java The main file for the Boggle game. You shouldn't need to change this (documentation)
- BoggleDie.java A class to handle a single Boggle die. You shouldn't need to change this
- Board.java A class to handle a boggle
board. This is the file that you need to add the
funtions
validGuess
andcomputerMove
to. The stubs are already there, just fill them in (and add any helper methods that you need. You will need to add helper methods. (documentation) - DictionaryTest.java A test file for yor dictionary.
- words A (rather long!) list of words. Standard UNIX words file. The class BoggleGUI.java and the class DictionaryTest.java use this file to build the dictionary.
- dice.txt A decription of the boggle dice. The class Board uses this file.
- Output for Boggle for original board: output
Grading
Your project will be graded on the following criteria:- Dictionary
- add: 15 points
- check: 10 points
- checkPrefix: 5 points
- suggest: 15 points
- remove: 15 points
- constructors and misc. other: 5 points
- Boggle
- validGuess: 15 points
- computerMove: 20 points
Collaboration
It is OK for you to discuss solutions to this program with your classmates. However, no collaboration should ever involve looking at one of your classmate's source programs! It is usually extremely easy to determine that someone has copied a program, even when the individual doing the copying has changed identifier names and comments.Project Submission
Submit all the files required to run Boggle to your subversion directory, under the folder cs245/project2/:https://www.cs.usfca.edu/svn/username/cs245/project2/