Computer Science 150
Our goal is to design a program to simulate a game of Boggle. The program will display a randomly chosen board, allow the user to enter as many words as he or she can find. The software will check that each entered word is legitimate. When the user is done entering words, the software should also produce a list of all other words that could have been found on that board.
For this assignment, you are allowed to work with one other student if you wish (in fact, we suggest that you do so). If any student wishes to have a partner but has not been able to locate one, please let the instructor know so that we can match up partners.
Please make sure you adhere to the policies on academic integrity in this regard.
cp -R /Public/goldwasser/150/programs/boggle .
Alternatively, you can download boggleUtil.py, bogshort.txt, and boglong.txt from a browser.
boggleUtil.py is a module with
some utilities to generate new boards and to display them (details
below). The other two entries
are word lists: bogshort.txt contains
A Boggle board is comprised of 16 dice. Each side of a die is typically marked with a single letter from the English alphabet, though one dice has a side marked with 'Qu' (more about this later). To start the game, the dice are shaken up and then placed in a 4x4 grid. An example of such a game board is shown here.
A player is then asked to find as many words as possible on the game board. A word can be find by stepping from die to neighboring die, where this step can either be horizontal, vertical or diagonal. Such a path must be found so as to spell the word from beginning to end. But you may not use the same die twice when spelling a single word. For example, the word WALK can be found as shown in the following figure.
The goal of the player is to list as many words as possible that can be found on the board. More formally, for a player to get credit for a word, the following conditions must be satisfied:
In the multiplayer version of Boggle, players only get credit for words that they find that are not found by any other players. In our one-player version, we will let the human player take the first turn, getting credit for all words he or she finds; then we let the computer take the second turn, taking credit for all remaining words not used by the player. The scoring for the official game gives more points for longer words, based upon the following formula:
|Number of letters||3||4||5||6||7||8 or more|
Here is a sample run of our program. Note that your program does not need to match the precise formatting shown here, but this should demonstrate the spirit of the game and the expected interactions.
Welcome to Boggle. What is the name of the wordlist file? [default: bogshort.txt] What board number? [default: random] 180 R Qu I C U E R O I W Y K T D A L Please enter words, one per line. When you are done enter a blank line. walk lad tie die or -- Words must use at least three letters. ore core rice -- Sorry. That word cannot be formed on the gameboard. york -- Sorry. That word is not in the wordfile. cork quirk rock -- Sorry. That word cannot be formed on the gameboard. lawyer law yore ore -- You already used that word. year -- Sorry. That word cannot be formed on the gameboard. daddy -- Sorry. That word cannot be formed on the gameboard. day way tie -- You already used that word. wit ------------------------------------------ Player used 598.168277 seconds. You found 14 words worth a total of 17 points. core cork day die lad law lawyer ore quirk tie walk way wit yore Now it is the computer's turn... ------------------------------------------ Computer used 0.487780 seconds. The computer found 32 additional words for 39 points. adieu awe awry aye coy crew cry dye dyer ire irk kayo lady lay lye lyric okay query quirky royal rue rye tid tidal tidy tier wad wadi weir wry yak yaw ------------------------------------------ Would you like to play again? [default: Y] n Okay. Thanks for playing!
We will be starting you off with some utilities for generating and
representing a game board. The game board is viewed as a
two-dimensional structure. This can be naturally modeled in Python as
a list of lists. That is, the board can be thought of as a list
of columns, where each column is then a list of dice. For example, on
the board diagramed earlier in this description, the first column can
be viewed as a list
Syntactically, if we have a variable board representing such
a list of lists, then we can refer to an individual die using a syntax
such as board which is the die 'A' in our example.
Namely, the simpler expression, board would represent the
Given such a representation of a board, I have provided three utility functions for you to use:
By default, will randomly generate a new board structure and return it to the caller. However it first prompts the user for a 'game number' and if provided, will give the user a particular game board rather than a new randomly generated one (for example board 180 is the one displayed above).
In this form, the board is drawn in pure text on the standard output screen.
In this form, a picture of the board is displayed on the given Canvas.
(See next blurb about the representation of the dice.) This simply clears the highlights for all of the dice.
Rather than representing the board directly as such a two-dimensional list of strings, we have created a class Die to represent each of the dice. The operations supported by a die are:
returns a string representing the visible side of the die. Note that the text will be all lower-case (even though our figures show them as upper case).
Requests that this die be displayed in 'highlighted' form when the board is subsequently drawn.
Requests that this die no longer be displayed in 'highlighted' form when the board is subsequently drawn.
The major challenges are:
Basic straightforward code to control the flow of a game.
Checking aspects of validity of a player's word, such as the length, whether it is in the dictionary, and whether it has been used already.
Checking the validity of a player's word as to whether it can legally be formed on a game board. Moreso, to be able to highlight the location of a valid word visually, you will need to keep track of the locations of the dice used for that word.
This task can be accomplished with the careful use of recursion. The key is to get the correct signature for modeling the problem. The goal might be to have a routine such as find(word), but the problem is that for the general recursion, you need to be able to find a partial word and to avoid using dice that have already been used. Therefore, we recommend the following signature:
def find(suffix, board, used, lastspot): """ Determines whether or not the suffix can be found on the board, while avoiding the used dice, and starting the remaining path with a neighbor of the lastspot die. If successful, return the overall list of dice used. If unsuccessful, returns None and ensures that 'used' is unchanged. """
The ability to report all words that the player missed (and to do so efficiently, even on the large dictionary).
There are really two ways to find all such words. The first way is a word-based search. Presuming that you have a working function to check whether a given word appears on the game board, you can simply loop through all the words in the official dictionary and check whether each appears on the board. This takes minimal effort in terms of coding, but unfortunately you will find that it is quite slow, even on the shorter dictionary.
A completely different approach is one we will term path-based. That is discussed as an extra credit challenge.
Please submit your sourcecode, boggle.py as well as a separate 'readme' file. If you worked as a pair, please make this clear and briefly describe the contributions of each person in the effort. Please see details regarding the submission process from the general programming web page, as well as a discussion of the late policy.
The efficiency of the automated player can be greatly improved by changing the high-level approach. Rather than testing every word in the dictionary indivdiually, we use the following path-based search.
We can try to form paths on the board and then check whether such a path leads you to a word in the dictionary. To make this efficient, the idea is to build short paths and then before going on, check whether the prefix you have actually occurs in the dictionary. That is, if you start tracing a path starting with "TRG" and you find that there are no words anywhere in the official dictionary starting with "TRG" then there is no need to continue spending time exploring this path.
Therefore, you will need to write a separate routine to be able to effectively check whether a given prefix occurs in the official dictionary. Since the words are kept alphabetized in a list, we can use binary search to accomplish this task. Checking whether a prefix occurs is very similar to checking whether an actual word occurs. With some minor adjustments, the binary search code we have already seen can be adapted to suit this task (see Chapter 11).