In this project your goal is to make an unbeatable Boggle player by storing every word in the English language in your fastest Data Structures.
Before we move on to the actual programming...
Let's review how to play Boggle.
Boggle consists of 25 dice, each of which have different letters on the six faces (one face of one die has a "Qu").
The dice are rolled, and placed at random in a 5x5 grid, so that they look something like this:
Players then have 1 minute to find as many words in the letters as they can, moving horizontally, vertically, or diagonally one space. For example, the above board has the word "TIN," starting in the upper right, moving to the left one spot, then moving diagonally, down and to the right. Dice may not be reused in a given word. For example, the above does not have the word "TINT," because we may not reuse the "T" in the upper right in a given word. Additionally, proper nouns are not allowed.
Scoring depends upon the number of letters in the word. Words with 3-4 letters get 1 point, words with 5 letters get 2, 6 letters gets 3, 7 letters gets 5, and 8+ letters gets 11.
The below table lists all the letters on the sides of the 25 Boggle Dice.
AAAFRS | AAEEEE | AAFIRS | ADENNN | AEEEEM |
AEEGMU | AEGMNN | AFIRSY | BJKQXZ | CCENST |
CEIILT | CEILPT | CEIPST | DDHNOT | DHHLOR |
DHLNOR | DHLNOR | EIIITT | EMOTTT | ENSSSU |
FIPRSY | GORRVW | IPRRRY | NOOTUW | OOOTTU |
To get you started, your solution consists of two primary classes with the following interfaces.
class BoggleDie{
public:
BoggleDie(string f); //accepts a 6-character string like "CEILPT" where each character is one face of a die
void roll(); //randomly selects one face of the die to be 'up'
char get() const; //returns the face of the die that is 'up'
friend ostream& operator<<(ostream& out, const BoggleDie& d); //sends the 'up' face of a die to the ostream
private:
//that's up to you
};
class Boggle{
public:
Boggle(); //constructs a standard game of Boggle
Boggle(string); //constructs a custom game of Boggle; used for testing; accepts a 25-character string of all of the 'up' faces, in order
void roll(); //rolls all of the dice and randomly places their position
friend ostream& operator<<(ostream& out, const Boggle& bb); //sends a text representation of the boggle to the ostream
private:
//that's up to you
//but it must have 25 BoggleDie (maybe a container of them?)
//to be a true Object Oriented representation of Boggle
};
Overloading operator<< should produce output that looks like one of the following:
Don't forget there is one BoggleDie that will be constructed with the 6-character string "BJKQXZ", but there is actually a "Qu" on the face of that BoggleDie which should be printed to the terminal.
Write you own Makefile to go with your code. At a minimum, it should work so that typing make
in the terminal automatically compiles your project, and typing make run
in the terminal automatically runs your program. You may create additional make commands as you deem useful. Take two screenshots demonstrating use of your Makefile, one for compiling and one for running. Name the files compile.png
& execute.png
.
Note: If you complete Part3 below, then your screenshots should be of compiling and running your final solution.
You must write and inclued a README file that provides:
To get you started, this new class must have the following interface.
class BoggleSolver{
public:
BoggleSolver(string); //creates our BoggleSolver using the filename of our dictionary text file
set<string> solve(Boggle); //finds all valid words in the given Boggle acording to the dictionary with which it was created
private:
//that's up to you
//but there are hints below
};
int main(){
Boggle boggle;
BoggleSolver genius("american-english");
set<string> answers = genius.solve(boggle);
}
int main(){
Boggle boggle("HTONELQLHDEEAAPEATNYEIVHA");
BoggleSolver genius("american-english");
set<string> answers = genius.solve(boggle);
}
An algorithm for a program to find all the words in a boggle might have the following steps:
Note: Steps 1 and 2 are interchangeable.
Hopefully you've realized that the trick to this problem is how to accomplish steps 4-6 in the pseudocode above. To help you with this, below is a prototype for a private recursive function you might have in the BoggleSolver class to accomplishes these steps. What would our base case be? Since the likelihood of finding a word with a length greater than 10 in Boggle is extremely low, you can use this as one base case. Are there others? We will talk more about this function in class.
set<string> findWords(string soFar, int row, int col, const vector<vector<char>>& letters, vector<vector<bool>>& used);
Note: You may want/need to make your BoggleSolver a friend of your Boggle class.
However, you may not have realized that another important part to getting your solution to run efficiently (quickly) is highly dependent on your choice of data structure for your dictionary. First, you're going to have to build the dictionary, which is going to take time. A poorly chosen/designed data structure would take a lot of time to accomplish this. Second, you're also going to be accessing it often to determine if your string is in the dictionary, so again, a poor choice will cause your program to run extremely slow. You're welcome to use any STL container you choose, or develop your own data structure specifically for this purpose. More on our dictionary below.
I wonder if there exists a data structure that would support our dictionary AND the internal workings of the BoggleSolver?
We'll use this file as our official dictionary of valid words:
american-english
There are 64,117 words in this text file that use the standard 26 letters of the english alphabet (no accented letters). The list is almost, but not entirely, in alphabetical order.
Below is sample code for reading a file as input. You will need to include the fstream
library.
int main(){
ifstream infile;
infile.open("inputFile.txt");
string str;
while(!infile.eof()){ //continues to the end of the file
infile >> str; //just use it like you would cin
//do something with your string...
}
}
As we work on finding an efficient solution, we want to measure the speed of our program for comparison against other implementations. Below is an example. You'll need to include the ctime
library.
int main(){
auto time = clock();
Boggle boggle;
BoggleSolver genius("american-english");
set<string> answers = genius.solve(boggle);
time = clock() - time;
cout << "Elapsed Time: " << (long double)time/CLOCKS_PER_SEC << " seconds " << endl;
}
What's the point of solving the Boggle if you don't output the answers and the score that your BoggleSolver achieved? So, in addition to the Elapsed Time above, your program should output results that look like the following (assuming that you implemented the advanced version of operator<<):
Here's a sample main that would produce the above at runtime:
#include "BoggleDie.h"
#include "Boggle.h"
#include "BoggleSolver.h"
#include <vector>
#include <iostream>
#include <ctime>
using namespace std;
int main(){
srand (time(NULL));
clock_t time = clock();
Boggle boggle("AAIAEENABENNETNTLTHLYWPTU"); //specific boggle for testing
BoggleSolver genius("american-english");
set<string> answers = genius.solve(boggle);
time = clock() - time;
cout << boggle << endl;
unsigned int score = 0;
cout << "Found the following " << answers.size() << " words:" << endl;
unsigned int count = 0;
for (string s : answers){
unsigned int wordLen = s.length();
if(wordLen >= 8) score += 11;
else if (wordLen == 7) score += 5;
else if (wordLen == 6) score += 3;
else if (wordLen == 5) score += 2;
else if (wordLen >= 3) score += 1;
else ;
cout << s << " ";
if (++count % 10 == 0) cout << endl;
}
cout << endl;
cout << "Elapsed Time: " << (long double)time/CLOCKS_PER_SEC << " seconds" << endl;
cout << "Score: " << score << endl;
return 0;
}
Don't forget there is one BoggleDie that will be constructed with the 6-character string "BJKQXZ", but there is actually a "Qu" on the face of that BoggleDie, so you'll have to make sure that the "u" is included in the strings you're building.
C++ String | Box Symbol | C++ String | Box Symbol | |
"\u256d" | ╭ | "\u252c" | ┬ | |
"\u2500" | ─ | "\u251c" | ├ | |
"\u256e" | ╮ | "\u253c" | ┼ | |
"\u2502" | │ | "\u2524" | ┤ | |
"\u2570" | ╰ | "\u2534" | ┴ | |
"\u256f" | ╯ |
For more box drawing options see: https://www.fileformat.info/info/unicode/block/box_drawing/list.htm
Standard deductions will apply as they always have. You will be evaluated on the accuracy/performance of your solution, and up to 10% of your grade is dependent on compliance with the course coding standards.
Your code must compile. You will receive a zero if it does not.
Partial credit for incomplete parts will be applied under the following guidelines:
Implement the advanced output version of operator<<
Implement your own custom data structure to improve the performance of your BoggleSolver. You must demonstrate a working solution to the instructor before attempting this Extra Credit. This will require research on your own, and you must discuss your chosen data structure with your instructor before attempting it. Be sure to document all resources used. You must implement the data structure yourself, you cannot simply use one that someone else has already developed.
Take the creative license and turn your program into an interactive game. Points will be awarded based on creativity, difficulty, and positive experiences when playing your game.
Submit all .cpp and .h files containing the source code for your solution, your Makefile, your README, and the screen captures showing your code compiling and running (compile.png
& execute.png
) via the the submisison website: submit.cs.usna.edu.
In a terminal window from your project03 folder, use the following command to submit your solution:
~/bin/submit -c=SI221 -p=Project03 *.cpp *.h README* Makefile compile.png execute.png
Do not submit any .o or executable files!
Complete and submit a signed copy of this cover sheet / survey after submitting your project electronically. You may bring it to the Final Exam period. If you are not complete with your solution by the Final Exam, then turn it in to my office the by the end of the next work day after submitting your solution.