Lab #6


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.

Getting started

Create a new project for the assignment. Add the "BoggleGUI.java" file from the Course Materials folder.

A little background on Boggle®

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.

How the Boggle program works

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!).

What you need to implement

In order for the game to work, you must implement a public class named 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:

Hints & Suggestions

In a project of this complexity, it is important that you get an early start and work consistently toward your goal. To be sure that you are making progress, it also helps to divide up the work into manageable pieces, each of which has identifiable milestones. Here is a suggested plan of attack that breaks the problem down into phases:
  1. Design a Lexicon data structure: The buildLexicon() method will be passed a Set of Strings to populate the lexicon; also a text file wordlist will be made available that you can use directly for testing, or you can create your own. In any case, you will need a data structure that will allow you to quickly determine if a String is in the lexicon or not. In addition, you may find it useful for the lexicon to return additional information in case of a failed lookup; or you may find it useful for the lexicon itself to direct search of the game board, instead of the game board directing search of the lexicon.
  2. Implement a Boggle board representation: The GUI application will call your setBoard() method with an array of Strings specifying a random Boggle board; you can also write your own test driver to pass it a known board. In any case, in order to simplify your logic (and your life), you should design a class (or classes) that you can use to represent the layout of the letters on the Boggle board.
  3. Implement 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.
  4. Implement 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.
Keep in mind that in order to implement the 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!