Due 10am, Monday, 20 November 2017
In this prelab, you will familiarize yourself with some of the design and implementation issues of the upcoming lab 9. Please write or type up your solutions, and hand in a paper copy before class on Monday.
The game Boggle is played with 16 dice that have letters on all faces. The dice are randomly deposited into a four-by-four grid so that the players see the 16 letters on the top faces. For example, the board may look like this:
Each player has a limited amount of time to identify as many words as can be located on the board. Words can be formed using adjacent letters in any direction (including diagonals) but cannot reuse letters or wrap around the board. For example, the board below contains the words dent, hit, tine, tide, hub, bun, hide, raid, rain, etc. The location of "tide" is highlighted in blue. Players accumulate points based on the number of words found.
In this week's lab, you are going to write a program that lets the user play a one-person version of Boggle. The GUI will be provided for you; your job will be to write the program that rolls the dice, reads and stores a dictionary, finds all dictionary words on the board, and checks whether given guesses are on the board. There's plenty to do, so let's get on with it!
This week's lab will have you implement your own Trie class called MyTrie, which should be a subclass of AbstractSet<String>. If you need it, you can read these lecture notes for details on the use and implementation of Tries.
Each Trie instance should contain the following data members:
boolean isWord; // whether this trie node is the end of a word int size; // the number of words represented by this trie MyTrie[] children; // the children tries of this node
The no-argument constructor for a Trie should initialize an empty Trie. The result should be a single Trie node whose isWord flag is false and whose children array is an array of null pointers. (You need to instantiate the array, but not its individual entries.) Recall that the size of the array is determined by the number of characters in the alphabet; in our case, that will be 26. (This is a good place for the use of a "static final" variable to define a constant, so that you don't need to hard-code the number 26 in more than one place in your program.)
Note that most of these are recursive and refer to the trie rooted at the current node. For example, t.contains( "bob" ) is true if t.children[1].contains("ob") is true.
add(String string)
method described above. Think about your base case carefully, and check your pseudocode on some small examples to be sure it works correctly. This method should be less than, say, 10 lines of pseudocode.
contains(String string)
method would differ from the add(String string)
method you just wrote.
As discussed, a Boggle board consists of a four-by-four grid of dice. You will be given a Square class that represents a square on the boggle board; that is, the "showing" side of one of the dice.
Your next task will be to write the class Boggle that represents a Boggle board.
Each Boggle board will contain the following data members:
MyTrie lex; // The dictionary, stored in a Trie Square[][] board; // The 4x4 board MyTrie foundWords; // The dictionary words on the current board MyTrie guesses; // The valid words made so far by our one player String[] dice; // An array of dice -- explained later!
You will write a Boggle constructor that takes a single String parameter that represents the file name of your lexicon (i.e. dictionary), and creates a new Trie out of the words in that lexicon. You will also also "initialize" the dice (see the private fillDice
method).
guesses
.
word
and false otherwise.
contains
method for this.
guess
to the list of guesses, if it is in the dictionary.
w
w
starting from each square sq
in the board, and return any one list it may find.
squaresForWord(sq,w)
described below.
dice
from the file dice.txt.
dice
.
dice[i]
prefix
and can be completed in a valid way on the board starting at square sq
prefix
along some sequence of squares ending at sq
, and want to continue from this point to create more words with prefix prefix
.
foundWords
to contain all words on the board that are in the dictionary.
sq
in the board, and call search(sq,"")
from each one.
sq
that form the word w
.
search
method.
addGuess
method. This should take under 6 lines of pseudocode (and you should use both your dictionary lex
and your list of guesses guesses
).
search(Square sq, String prefix)
method. This should use recursion, and should take some thought. It is conceptually similar to one of breadth-first search or depth-first search (which?) (rhetorical question), where you are doing a search out from sq
, having already visited the squares forming prefix
. You may want to "mark" and "unmark" squares as you go along, to keep track of which squares are being used in the current word. This should take at most, I dunno, 12 lines of pseudocode.
For this lab, whenever you see a "q" on the board, you should treat is as "qu". You might give some thought to how you will do that, but you don't need to hand in those thoughts.