Maximum Points: 100 (+20 extra credit)
In this assignment you will be constructing an implementation of the Boggle^{®} word game. This will test, one more time, your understanding of data structures and algorithms and how to cast them into ML code. But it will also test your understanding of the module system, including functors, signature ascription, and where type instantiation. You must adhere to the following principles:
use "trie.sml"; use "random.sml"; use "read.sml"; use "board.sml"; use "boggle.sml";at the beginning of your file ass4.sml. However, please comment these lines out when handing in your assignment, so our test programs can run.
A trie is an efficient data structure for indexing data based on lists of ordered keys. A particularly useful instance of this idea considers a string as a list of characters.
Entries are found in a trie by starting at the node and following the appropriate branches until a labeled node is found. As an example, consider a trie indexed by lists of characters, where the data entry stored at a labeled node is the string representation of the word. For example, the string "badge" is found in the following tree by taking the path #"b", #"a", #"d", #"g", #"e".
In order to make searching tries more efficient the branches emanating from any node are sorted by their label.
Tries can implement all the operations of dictionaries (as considered in the previous assignment). For their efficient use, however, an implementation of tries should export at least one other operation, namely to extract the subtrie rooted at the node addressed by a key. We call this operation sub.
The construction of the signature of tries expresses concisely that every trie can be considered as a dictionary whose keys are lists. The signatures can also be found in the file trie.sml.
signature DICT = sig type key (* parameter *) type 'a entry = key * 'a type 'a dict (* abstract type *) val empty : 'a dict val insert : 'a dict -> 'a entry -> 'a dict val lookup : 'a dict -> key -> 'a option val foldl : ('a entry * 'b -> 'b) -> 'b -> 'a dict -> 'b val app : ('a entry -> unit) -> 'a dict -> unit end; (* signature DICT *) signature TRIE = sig type key1 (* parameter *) include DICT where type key = key1 list val sub : 'a dict -> key -> 'a dict option end; (* signature TRIE *)Implement a functor Trie which takes a structure of signature ORDER (see file trie.sml) and returns a structure implementing the signature TRIE satisfying the following specification.
Using the random number generator described on page 108 in Paulson implement a structure named Random containing a random number generator that conforms to the following signature:
signature RANDOM = sig type gen val init : int -> gen val randomNat : gen -> int -> int end; (* signature RANDOM *)
The signature is also contained in the file random.sml. Your implementation should satisfy the following specification.
In this problem you will program the "Big Boggle" equipment, which consist of a 5 by 5 grid and 25 letter cubes. After shaking the grid with the letter cubes under a dome, the cubes fall into the places in the grid and create a 5 by 5 layout of letters. The players then search for words as described in Problem 4.
Create a functor Board which, when given an implementation of dictionaries (satisfying some instance of the DICT signature) and an implementation of a random number generator (satisfying the signature RANDOM) creates a structure satisfying the signature BOARD given below. The signature can also be found in the file board.sml
signature BOARD = sig type board (* abstract *) val foldl : (((int * int) * char) * 'b -> 'b) -> 'b -> board -> 'b val lookup : board -> (int * int) -> char option val shake : unit -> board val show : board -> unit end; (* signature BOARD *)The implementation should satisfy the following specifications.
worvgr aeaeee eeeema oootut hhrlod qxbzkj stncec hdntdo syripf towonu magenn teliic lrnhod titeii geeuma sarafi ttetmo tcsiep elptic rdhonl ssunes ednann rrpryi fasraa fsyraiNote that the letter q above is actually shown as Qu on the cube. This should be taken into account when printing a board.
In this problem we assume an implementation of a board as specified above and write a search procedure to find all words on a given board longer than a given threshold (in the standard game, this threshold is fixed at 3).
A word may start on any square on the grid and continue with a letter on an adjacent cube (including diagonally adjacent). The word may continue in this way with arbitrary zig-zagging, but no cube may be used more than once. For example, in the situation
S O I L
we can make words SOIL, SILO, OIL, and OILS, but not SOILS (since the first S cannot be reused).
An implementation of a structure IOUtils and functors Read and Wordlist are provided in the file read.sml. The word list in the file ospd3.list is the Official Scrabble Players Dictionary^{®} as used for Scrabble tournament play and contains 172,000 entries, all of which are reported to be English words (excluding proper names, see the Scrabble FAQ for more information). The word list created by the function in Read is represented as a trie with keys as character lists and unit as the type of the data entries. This is because we are only interested in storing valid words, but not in associating any information with the words.
Implement the search for all words on a Boggle board as a functor Boggle which takes an implementation Board' of a board and Wordlist containing a word list, returning a structure satisfying the signature below. The signature can also be found in the file boggle.sml.
signature BOGGLE = sig structure Board : BOARD val words : Board.board * int -> int end; (* signature BOGGLE *)This must satisfy the following specification.
Hint: Implement the main search as a function with a failure continuation which accepts and returns a trie of all words found so far.
Since we will be applying your Boggle functor to our own board configurations for testing purposes, the functor must take two structure arguments with the names specified belowfunctor Boggle (structure Board' : BOARD structure Wordlist : WORDLIST) :> ... =
Now you need to apply the functors (either provided or programmed yourself) to create the structures which allow you to play the game. Create the following structures and any auxiliary structures you might need.
structure CharOrder :> ORDER where type key1 = char structure Trie :> TRIE where type key1 = char structure Read :> READ where type 'a Dict.dict = 'a Trie.dict structure OSPD3 :> WORDLIST where type 'a Trie.dict = 'a Trie.dict structure Board :> BOARD structure Boggle :> BOGGLE where type Board.board = Board.board
Hint: In order to create the Board structure you need a "dictionary" mapping grid squares to characters. Use your Trie functor over a different key1 type.
Extend the signature BOGGLE and its implementation to allow an interactive game. The function play : int -> int * int should shake the board, show it, and then read lines from standard input (see library structure TextIO). Each word should be checked, rejecting illegal words. When input is terminated by a line containing only a period "." the computer shows the words that were missed and gives the percentage of words found.
The argument to play is the minimum word length considered, and the result is a pair consisting of the number of words on the board and the number of words found by the human player.
Put your SML code into a single file named ass4.sml in your ass4 handin directory. The file as handed in should not repeat the provided signatures or redeclare them. Please keep a backup for your records.
Your handin file for this assignment is
/afs/andrew/scs/cs/15-212-ML/studentdir/<your andrew id>/ass4/ass4.sml