In this assignment, you (and optionally a partner) will implement the back-end logic for a graphical version of the popular board game Boggle®. Specifically, you will design and implement the data structures and algorithmes necessary for a computer player to play against a human opponent. If you get everything right, the computer player should almost always "win" the game by a large margin, but it will be fun to play anyway.
The main focus of this assignment is designing and implementing
the data structures and operations on them that will efficiently find
words that appear in a Boggle board. Because your focus will be on the
back-end logic, you will be provided with a graphical display program,
BoggleGUI
. This program knows how to generate and render
a random Boggle board, interact with a human player, and display
results of the game. It will use your code to verify input from the
human player, and to obtain the computer player's results.
>>> Due Wednesday, October 30, 2:30pm
>>> Put working program in drop box with usual naming.
It's a good idea to plan to do the assignment well before the deadlines. Although the GUI component has been completed for you, there is still plenty left for you to do, so don't put this off until the last minute.
In doing this assignment, it's your responsibility to understand the course rules for integrity of scholarship.
Create a new project for the assignment. Add the "BoggleGUI.java" file from the Course Materials folder.
The game of Boggle® uses a board which is a 4-by-4 grid on which you randomly shake and distribute 16 dice. The 6-sided dice have letters rather than dots on the faces, creating a grid of letters in which you find words. In the original version, the players all start together and write down all of the words they can find by tracing paths through neighboring dice faces on the board. Two dice are neighbors if they are next to each other horizontally, vertically, or diagonally. (So there are up to eight neighbors of a die; dice on the edges of the grid have fewer neighbors.) A die can only be used once in a word, and a word must be at least 3 letters long. At the end of a three minute session, all players stop recording words. Words found by more than one player are then removed from the players' lists and the players receive points equal to the number of letters beyond the minimum word length found in their remaining words.
In the computer version of the game, the human player gets to go first. (Don't worry, the computer player will still trounce you.) The player proceeds to enter in the text area at the bottom of the window, one at a time, each word that she finds in the game board. A valid word must meet four requirements: (1) it must contain at least the minimum number of letters, (2) the word must not already have been entered by the player, (3) the word can be formed from the letters showing on the board following in order a path through neighboring dice without using the same die twice, and (4) the word must exist in the official lexicon of words. All valid words entered by the player are highlighted graphically on the board display. The computer player determines the validity of the words, but we assume it can be trusted to do so fairly.
Unlike the original version, there is no time limit here. Instead, the player indicates that she is through entering words by hitting a lone extra carriage return, as if entering an empty word. At this point, the computer gets to take its turn. The computer searches through the board looking for all the valid words it can find. The computer typically beats the human player mercilessly, but the player is free to try again by starting a new game. Scoring is as for the original version of the game, except that words are not removed from the players' lists (if they were, the human player would never have any words left!).
BogglePlayer
, which the BoggleGUI
front-end
uses to execute the required
back-end logic. Although you will probably implement other
methods too, your BogglePlayer
class must implement methods
with these exact signatures:
public void buildLexicon(Set wordList) public void setBoard(String[] letterArray) public SortedSet getAllValidWords(int minimumWordLength) public boolean isInLexicon(String wordToCheck) public List isOnBoard(String wordToCheck) public String[] getCustomBoard()In addition, the class must provide a public default constructor.
The semantics of these methods are stipulated as follows:
buildLexicon
: this method takes as argument a Set
containing the list of words specifying the official lexicion to be
used for the game. Each word in the Set will be a String consisting
of lowercase letters a-z only. This function will load the words into
an efficient data structure that will be used internally as needed by
the BogglePlayer.
setBoard
: this method takes in an array of Strings
of length N^2 specifying the layout of dice on the N-by-N board. (In
official standard Boggle® N is 4; but your BogglePlayer should
work for any square board.) The
elements of the array specify the letters found on dice going from
left to right, and top to bottom of the board. (So the element
indexed 0 is a String containing the letter(s) on the die at the
upper left corner;
on a 4x4 board,
the element indexed 3 is the top right letter, and index 15 gives you the
letter at the bottom right.) Each String may be upper or lower case,
and may contain one or more letters; for purposes of finding words
on the board, they should be considered lowercase. (In official Boggle, these
Strings will contain one character only, except for the double letter
die face "Qu"; but your BogglePlayer should work correctly for arbitrary
strings.) You will likely use this information to construct a
data structure representing the Boggle board in a way that lends
itself well to your search algorithms.
getAllValidWords
: this function returns,
as a SortedSet of Strings, all the words that (1) are of at least
the given minimum length, (2) are in the
lexicon specified by the most recent call to buildLexicon(), and (3)
can be found by following a simple path
on the board specified by the most recent call to setBoard().
If either buildLexicon() or setBoard() has not yet been called, this
method should return null.
isInLexicon
: this function takes in a String and
determines whether the String can be found in the lexicon specified by
the most recent call to buildLexicon(). The function returns true if
the word is in the lexicon and false if it is not in the lexicon. If
buildLexicon() has not yet been called, the behavior of this method is
undefined.
isOnBoard
: this function takes as argument a String and
determines whether the String can be found in the board specified by
the most recent call to setBoard(). The return type of this function
is a List object containing Integer
elements. If it is possible to find the word in the current board, the
function returns a list of Integers representing the locations of the
dice used to form the word, in order (using the same
mapping from integers to locations required by setBoard()). If is is
NOT possible to form the word, the function returns null. If
setBoard() has not yet been called, the behavior of this method is
undefined.
getCustomBoard
:
this is a function that will allow you to implement extra
functionality, should you choose to. This function will be called by
the GUI application when a choice of "custom", non-randomly selected
board layout is requested. This function should return an array of 16
Strings representing the desired dice layout based on the usual index
from 0 to 15.
isOnBoard: Now you will test your talent
for writing code to verify that the user's words can
actually be formed from letters on the board. Remember that a valid
word must correspond to a simple path according to the neighborhood relation
on the dice. You should search the board recursively, trying to find
a legal formation of the user's word. This recursion can be made what you might
call a "fail-fast" recursion: as soon as you realize you can't form
the word along a path, you can immediately backtrack or move on to the next
untried path start point.
Reject any word that cannot be formed from the letters
currently on the board.
getAllValidWords: Now it's time to implement the
world-class computer player. The computer should easily trounce a human
player; it can very quickly learn more words than any human knows,
and it can
very quickly and perfectly check them against the board.
The trick is to program the
machine to do that. Part of the problem is to have a good word list
to start with (the file "enable1.txt" contains such a list and is
provided in the Course Materials directory, though you may want to test on a
shorter list to start). But the hard part is implementing data
structures and algorithms to make the computer's search work
efficiently. It is easy to get lost in the recursive decomposition
and you should think carefully about how to proceed. Bear in mind that
you can significantly speed up this algorithm using "pruning" by
recognizing when you are going down a dead end, abandoning it, and
backtracking to where there are still live alternatives. For
example, if you have built a path starting with "zx", you could use an
isPrefix function implemented on your lexicon to determine that there
are no words in English beginning with that prefix. If you miss this
optimization, you may find yourself taking long coffee breaks while
the computer is busy checking out non-existent words like "zxgub" and
"zxaep", etc. Alternatively, if you have traversed your lexicon
starting with "ab" and your game board representation is able to tell you there
are no paths on the board starting with those letters, you know you
don't have to even consider any lexicon words that have "ab" as
prefix.
getAllValidWords()
and isOnBoard() functions, there are two types of
search necessary. For the former, you are searching for all words that
are on the board and in the lexicon and of the minimum length,
while for the latter, you search for a specific word on the board
and stop as soon
as you find it. It is possible to implement the former in part by using
multiple calls to the latter, though it is not the only approach.
The file BoggleGUI.java in the Course Materials directory is a GUI application that you can use as a nice interface when testing some things about your Boggle player. Note however that your BogglePlayer class must have the required functionality without the BoggleGUI code present. Also keep in mind that BoggleGUI only knows about 4x4 Boggle boards, and official Boggle dice, while your BogglePlayer needs to be able to handle any square board, and any Strings on the die faces.
The file BoggleGUI.jar in that directory is a partially correct solution to the assignment. (As a player, it it violates the spec by never finding words shorter than 5 or longer than 8 letters, but it lets you find them -- just to give you a fighting chance.)
Speed matters!