//! @brief read a text Bow file and fills a lexicon //! @param fileIn the file to read //! @param reader the file reader //! @param lex the lexicon to fill //! @param propertyAccessor //! @param referenceProperties void readBowFileText(ifstream& fileIn, BoWBinaryReader& reader, Lexicon& lex, const PropertyAccessor& propertyAccessor, set<LinguisticCode>& referenceProperties ) { BoWText text; reader.readBoWText(fileIn,text); bool filterCategory = false; if ( referenceProperties.size() > 0 ) { filterCategory = true; } BoWTokenIterator it(text); while (! it.isAtEnd()) { const BoWToken& token = *(it.getElement()); if (filterCategory) { set<LinguisticCode>::const_iterator referencePropertyIt = referenceProperties.find(propertyAccessor.readValue(token.getCategory())); if ( referencePropertyIt != referenceProperties.end() ) { lex.add(getStringDecomp(&token),token.getIndexString()); } } else { lex.add(getStringDecomp(&token),token.getIndexString()); } it++; } }
int main() { Lexicon english ("EnglishWords.dat"); Lexicon usedWords; // need to check the unique word Queue<Vector<string>> result; string firstWord, secondWord; while(true){ readWords (firstWord, secondWord, english); createFirstLadder(result, firstWord); usedWords.add(firstWord); while(!result.isEmpty ()){ Vector<string> firstLadder = result.dequeue (); if(firstLadder.get (firstLadder.size () - 1) == secondWord){ display(firstLadder); result.clear(); usedWords.clear (); break; } string currentWord = firstLadder.get(firstLadder.size ()-1); usedWords.add(currentWord); createNextLadder(currentWord, firstLadder, usedWords, result, english); } /* If the ladder of the two entered words is impossible */ if(!usedWords.isEmpty ()){ cout << "Sorry, this ladder is impossible..." << endl; } } return 0; }
void streamInsertionLexiconTest() { Lexicon lex; cout << "empty lexicon: " << lex << endl; lex.add("alpher"); cout << "1-item lexicon: " << lex << endl; lex.add("beter"); lex.add("gammer"); cout << "3-item lexicon: " << lex << endl; cout << "looping over lexicon..." << endl; for (string s : lex) { cout << s << endl; } }
/* The function to solve the problem * Parameters: * start, dest => the two words to connect (MUST BE VALID WORDS) * dict => Lexicon restores words * Return: The ladder / an empty Vector (when there is no solution) * No side effects */ Vector<string> find_ladder(const string & start, const string & dest, const Lexicon & dict) { Vector<LadderStep> steps; //keep answers Lexicon appeared; //word that has appeared Queue<int> queue; //the queue, saves the labels of steps //init steps.push_back(LadderStep(start,NO_MORE_STEP)); appeared.add(start); queue.enqueue(0); int last = NO_MORE_STEP; //the last step of the answer //main loop while(!queue.isEmpty()){ int cur = queue.dequeue(); if (steps[cur].str == dest) //arrives destination { last = cur; //mark position break; } for (int i = 0; i < steps[cur].str.size(); ++i){ for (char c = 'a'; c <= 'z'; ++c){ //generate all possible steps string next(steps[cur].str); next[i] = c; //A valid word that hasn't appeared yet? if (dict.contains(next)&& !appeared.contains(next)){ //enqueue appeared.add(next); steps.push_back(LadderStep(next, cur)); queue.enqueue(steps.size() - 1); } } } } Vector<string> tmp; //the answer, reversed while(last != NO_MORE_STEP){ //has more steps? tmp.push_back(steps[last].str); last = steps[last].forward; //go forward } //reverse to get the answer Vector<string> res; for (int i = tmp.size() - 1; i>=0; --i){ res.push_back(tmp[i]); } return res; }
/** * Function: oneHopAway * This helper function loops through each letter of the alphabet * at each position for a word passed through, checking whether * the newly formed word is both English and hasn't been used * previously. The latter check is maintained by a Lexicon * passed through by reference. * Parameters: dictionary cleared in main as constant reference, Lexicon of used words * passed by reference since it can be altered, constant reference to the word * looking to build off of */ static Lexicon oneHopAway(const Lexicon& dictionary, Lexicon& usedWords, const string& topWord) { Lexicon oneHopAway; string alphabet = "abcdefghijklmnopqrstuvwxyz"; for(int i = 0; i < topWord.length(); i++) { for(int j = 0; j < alphabet.length(); j++) { string testWord = topWord; testWord[i] = alphabet[j]; if(dictionary.contains(testWord) && !usedWords.contains(testWord)) { oneHopAway.add(testWord); usedWords.add(testWord); } } } return oneHopAway; }
TIMED_TEST(LexiconTests, hashCodeTest_Lexicon, TEST_TIMEOUT_DEFAULT) { Lexicon lex; lex.add("a"); lex.add("bc"); assertEqualsInt("hashcode of self lexicon", hashCode(lex), hashCode(lex)); Lexicon copy = lex; assertEqualsInt("hashcode of copy lexicon", hashCode(lex), hashCode(copy)); Lexicon lex2; // empty // shouldn't add two copies of same lexicon HashSet<Lexicon> hashlex {lex, copy, lex2}; assertEqualsInt("hashset of lexicon size", 2, hashlex.size()); }
//return a string vector as the shortest ladder, if found //return an empty vector, if not found Vector<string> bfs(string &startingWord, string &endingWord) { Lexicon english("EnglishWords.dat"); Lexicon wordUsed; Queue<Vector<string>> queue; Vector<string> ladder; ladder.push_back(startingWord); queue.enqueue(ladder); while (!queue.isEmpty()) { Vector<string> front = queue.dequeue(); if (front.get(front.size() - 1) == endingWord) return front; string current = front.get(front.size() - 1); for (int i = 0; i < current.size(); i++) for (char j = 'a'; j <= 'z'; j++) if (current[i] != j){ string next = current; next[i] = j; if (!english.contains(next)) continue; if (wordUsed.contains(next)) continue; wordUsed.add(next); Vector<string> nextLadder = front; nextLadder.push_back(next); queue.enqueue(nextLadder); } } Vector<string> empty; return empty; }
/* * Function: InputGuesses * ------------------------- * Allows the user to input guesses. Runs checks on user guess to see if it meets all boggle requirements. */ void InputGuesses(Grid<char> boggleBoard, Lexicon wordList, Lexicon &usedWords, Grid<bool> usedDice) { cout << endl << "Ok, take all the time you want and find all the words you can!" << endl; cout << "Signal that you're finished by entering an empty line." << endl << endl; while (true) { int row= 0, col = 0; string userGuess = CheckUserGuess(wordList, usedWords); //checks if format rules are met if (userGuess == "") break; //checks if sentinel of user hitting return has been occured while (true) { if (FindUserGuessOnBoard(boggleBoard, row, col, "", userGuess, usedDice)) { //checks if user guess can be created from boggleBoard usedWords.add(userGuess); //records user guess in lexicon of used words RecordWordForPlayer(userGuess, Human); UnhighlightBoard(boggleBoard); PlayNamedSound("excellent.wav"); break; } if (!AdjacentPoint(boggleBoard.numRows(), boggleBoard.numCols(), row, col)) { //checks if end of board has been reached without finding appropriate dice config cout << "You can't make that word! " << RandomizeResponse() << endl; PlayNamedSound("whoops.wav"); break; } } } }
string findWordLadder(string startWord, string endWord, Lexicon& wordsLexicon) { Queue<Vector<string>> ladderQueue; Lexicon usedWords; Vector<string> startingLadder; startingLadder.add(startWord); ladderQueue.enqueue(startingLadder); usedWords.add(startWord); while(ladderQueue.size() > 0) { Vector<string> wordLadder = ladderQueue.dequeue(); string lastWord = wordLadder[wordLadder.size() - 1]; if(lastWord == endWord) { string returnValue = "Ladder found:"; foreach(string word in wordLadder) { returnValue += " " + word; } return returnValue; }
Lexicon humanPlays(Grid<char> & board, Lexicon & english, Lexicon & usedWords){ cout<<"\n\n\n\nAlright, you can go first. Type any words that you find and press Enter so I can check them. "<< "Pressing Enter on its own will end your turn. Good luck!\n\n\n"<<endl; //loop forever to accept words while(true){ Grid<bool> usedLetters(board.numRows(),board.numCols()); //to flag string word = toUpperCase(getLine()); //quit statement if (word == "")break; //check word validity if (isValid(word, board, usedLetters, usedWords, english)){ //add to usedWords list and also to the scoring system usedWords.add(word); recordWordForPlayer(word, HUMAN); //highlight the letters for (int row = 0; row < usedLetters.numRows(); row++) { for (int col = 0; col < usedLetters.numCols(); col++) { highlightCube(row, col, usedLetters[row][col]); } } pause(1000); //leave them highlighted long enough to see //unhighlight the letters for (int row = 0; row < usedLetters.numRows(); row++) { for (int col = 0; col < usedLetters.numCols(); col++) { highlightCube(row, col, false); } } } } return usedWords; }
TIMED_TEST(LexiconTests, compareTest_Lexicon, TEST_TIMEOUT_DEFAULT) { Lexicon lex; lex.add("a"); lex.add("ab"); lex.add("bc"); Lexicon lex2; lex2.add("a"); lex2.add("b"); lex2.add("c"); Lexicon lex3; compareTestHelper(lex, lex2, "Lexicon", /* compareTo */ -1); compareTestHelper(lex2, lex, "Lexicon", /* compareTo */ 1); compareTestHelper(lex, lex, "Lexicon", /* compareTo */ 0); Set<Lexicon> slex {lex, lex2, lex3}; assertEqualsString("slex", "{{}, {\"a\", \"ab\", \"bc\"}, {\"a\", \"b\", \"c\"}}", slex.toString()); }
void checkLexicon(string indexLetters, Lexicon & lex) { string lowerCase = UpToLow(indexLetters); foreach (string word in lex) { Lexicon newLex; newLex.add(word); if(newLex.containsPrefix(indexLetters) || newLex.containsPrefix(lowerCase)) { cout << word << endl; } }
TIMED_TEST(LexiconTests, basicTest_Lexicon, TEST_TIMEOUT_DEFAULT) { std::initializer_list<std::string> words = { "a", "ab", "aab", "aaab", "aardvark", "b", "banana" }; std::initializer_list<std::string> badWords = { "abb", "ad", "and", "aaardvark", "aardvarks", }; std::initializer_list<std::string> badPrefixes = { "aaaa", "abb", "aardvarz", "bb", "bananas", "c", "r", "z" }; Lexicon lex; for (std::string word : words) { lex.add(word); } assertEquals("Lexicon size", words.size(), lex.size()); for (std::string word : words) { assertTrue("Lexicon contains " + word, lex.contains(word)); } for (std::string word : badWords) { assertFalse("Lexicon contains " + word, lex.contains(word)); } for (std::string word : words) { for (int i = 0; i < (int) word.length(); i++) { std::string prefix = word.substr(0, i); assertTrue("Lexicon containsPrefix " + word, lex.containsPrefix(word)); } } for (std::string word : badPrefixes) { assertFalse("Lexicon containsPrefix " + word, lex.containsPrefix(word)); } }
void loadLexiconFromFile(Lexicon& lexicon, string filename) { ifstream infile; infile.open(filename.c_str()); string line; while(getline(infile, line)) { lexicon.add(line); } infile.close(); }
int main() { Queue<Vector<string> > queue; string start, end; Vector<string> currentLadder; Lexicon lex("EnglishWords.dat"); Lexicon used; cout << "Enter starting word: "; start = getLine(); cout << "Enter ending word: "; end = getLine(); used.add(start); currentLadder.add(start); queue.enqueue(currentLadder); while (!queue.isEmpty()) { currentLadder = queue.dequeue(); string lastWordInLadder = currentLadder[currentLadder.size() - 1]; if (lastWordInLadder == end) { printLadder(currentLadder); return 0; } Vector<string> oneHopList; findOneHopList(lastWordInLadder, oneHopList, lex); foreach(string word in oneHopList) { if (!isInLexicon(word, used)) { used.add(word); Vector<string> newLadder = currentLadder; newLadder.add(word); queue.enqueue(newLadder); } } } cout << "Your word \"" << start << "\" has no match in the lexicon." << endl; return 0; }
string wordLadder(string start, string destination, Lexicon& english){ Queue< Vector<string> > ladderQueue; Lexicon usedWords; Vector<string> ladder, newLadder; string lastWordInLadder, newWord; int n; ladder.add(start); usedWords.add(start); ladderQueue.enqueue(ladder); while(!ladderQueue.isEmpty()){ ladder = ladderQueue.dequeue(); lastWordInLadder = ladder[ladder.size() - 1]; if(lastWordInLadder == destination)return printLadder(ladder); for( n = 0; n < lastWordInLadder.length(); n++){ newWord = lastWordInLadder; for(char c = 'a'; c <= 'z' ; c++){ newWord[n] = c; if(english.contains(newWord) && !usedWords.contains(newWord)){ newLadder = ladder; newLadder.add(newWord); usedWords.add(newWord); ladderQueue.enqueue(newLadder); } } } } return "No ladder found" ; }
static void generateLadder(Lexicon& english, string start, string end) { Lexicon usedWord; Queue<Vector<string> > queue; Vector<string> initialWordLadder; initialWordLadder.add(start); usedWord.add(start); queue.enqueue(initialWordLadder); while (!queue.isEmpty()) { Vector<string> wordLadder = queue.dequeue(); string topWord = wordLadder.get(wordLadder.size() - 1); if (topWord == end) { cout << "Found Ladder: "; for (int i = 0; i < wordLadder.size(); i++) { cout << wordLadder.get(i) << " "; } cout << endl << endl; break; } else { for (int i = 0; i < topWord.length(); i++) { for (int j = 'a'; j <= 'z'; j++) { if (topWord.at(i) != j) { string newWord = topWord.substr(0, i) + char(j) + topWord.substr(i + 1, topWord.length() - i - 1); if (english.contains(newWord) && !usedWord.contains(newWord)) { Vector<string> wordLadderClone = wordLadder; wordLadderClone.add(newWord); queue.enqueue(wordLadderClone); usedWord.add(newWord); } } } } } } }
Lexicon findAllWords(Lexicon &dictionary, Grid<char> &charGrid, int gSize) { Lexicon result; for(int i = 0; i < gSize; i++) { for(int j = 0; j < gSize; j++) { string word; word = charGrid[i][j]; Lexicon computerWords; Lexicon temp; Grid<bool> boolGrid(gSize, gSize); wordSearch(dictionary, computerWords, charGrid, boolGrid, word, i, j); temp = computerWords; foreach(word in temp) { result.add(word); } } }
TIMED_TEST(LexiconTests, forEachTest_Lexicon, TEST_TIMEOUT_DEFAULT) { Lexicon lex; lex.add("a"); lex.add("aba"); lex.add("cc"); lex.add("bbb"); lex.add("c"); lex.add("bart"); std::initializer_list<std::string> list {"a", "aba", "bart", "bbb", "c", "cc"}; assertCollection("foreach Lexicon", list, lex); }
/* * Function: FindWordsonBoard * ------------------------------ * Recursively searchs for all possible words that can be created from dice configuration of boggleBoard starting from * the specified location. * *@return bool true if the char arrangement found is an actual word. * false if all possibilities have been exhausted and no word is created. */ bool FindWordsOnBoard(Grid<char> boggleBoard, int row, int col, string partialWord, Grid<bool> usedDice, Lexicon wordList, Lexicon &usedWords) { int newRow, newCol; if (OffBoard(boggleBoard, row, col) || usedDice.getAt(row, col) == true) return false; partialWord += boggleBoard.getAt(row, col); //keeps track of current char arrangement if (!wordList.containsPrefix(partialWord)) return false; //checks if partialWord is a prefix of any word in wordList usedDice.setAt(row, col, true); //marks the dice as used if (wordList.containsWord(partialWord) && partialWord.length() >= minWordLength && !usedWords.containsWord(partialWord)) { //checks if partialWord is an actual word meeting the minimum length and has not been used by either the player or computer RecordWordForPlayer(partialWord, Computer); usedWords.add(partialWord); //adds the word found to list of used words } for(int i = 0; i < 8; i++) { //there are 8 possible paths the char arrangement can take FindPossiblePath(newRow, newCol, row, col, i); if (FindWordsOnBoard(boggleBoard, newRow, newCol, partialWord, usedDice, wordList, usedWords)) return true; } usedDice.setAt(row, col, false); //unmarks the dice as unused when current char configuration turns out fruitless return false; }
/* * Function: humansTurn * Usage: humansTurn(Lexicon dictionary, Lexicon &usedWords, Grid<char> &charGrid, int gSize); * -------------------------- * Accepts a lexicon of an English dictionary, a lexicon to store used words, * a grid of the current letters displayed and the size of the board. * Implements the human players turn by first prompting them to input an word then * it runs a series of checks on the word. If the word meets all the criteria, it * it added to the players score. The player is allowed to enter words until the enter nothing. */ void humansTurn(Lexicon &dictionary, Lexicon &usedWords, Grid<char> &charGrid, int gSize) { cout << endl << "Take as long as you need to find as many words as you can within the Boggle display. " << endl; cout << endl << "Signal you are finished by entering an empty line. " << endl; string word = ""; word = getLine("Enter a word: "); for(int i = 0; i < word.size(); i++) { word[i] = toupper(word[i]); } while(word != "") { bool flag = true; if(word.length() < MIN_WORD_LENGTH) { cout << endl << "Please enter a word that is four letters or more." << endl; flag = false; } if(flag && !dictionary.contains(word)) { cout << endl << "This word is not found in the dictionary." << endl; flag = false; } if(flag && usedWords.contains(word)) { cout << endl << "You have already used this word." << endl; flag = false; } int count = 0; Grid<bool> boolGrid(gSize, gSize); if(flag && !checkWord(charGrid, boolGrid, gSize, word, count, 0, 0)) { cout << endl << "The word could not be found on the board." << endl; flag = false; } /* If all of the criteria is met (flags are true), the word it recorded. */ if(flag) { usedWords.add(word); recordWordForPlayer(word, HUMAN); displayWord(boolGrid, gSize); } word = getLine("Enter a word: "); for(int i = 0; i < word.size(); i++) { word[i] = toupper(word[i]); } } }
/** * Function: getWordLadder * getWordLadder does most of the heavy lifting in terms of finding the appropriate ladder, * enlisting oneHopAway at one point to return all English words with one character differing. * It follows the structure outlined in the spec, which at high-level puts in a queue * the possible ladders in ascending length, where ladders are a Vector of strings, and * checks the top of the queue (the last word in the shortest ladder) against the destination word passed in as * a constant reference. If that check fails, the function adds those words one hop away * to the queue via a vector. If the check succeeds, the comporting Vector of strings is returned. * Parameters: dictionary cleared in main as constant reference, user-inputted source and destination * words as constant references */ static Vector<string> getWordLadder(const Lexicon& dictionary, const string& sourceWord, const string& destinationWord) { Queue< Vector<string> > paths; Vector<string> wordLadder; Lexicon usedWords; wordLadder.add(sourceWord); usedWords.add(sourceWord); paths.enqueue(wordLadder); while(!paths.isEmpty()) { wordLadder = paths.dequeue(); string topWord = wordLadder[wordLadder.size()-1]; if(topWord == destinationWord) { break; } else { for(string word: oneHopAway(dictionary, usedWords, topWord)) { Vector<string> wordLadderClone = wordLadder; wordLadderClone.add(word); paths.enqueue(wordLadderClone); } } } return wordLadder; }
static int generateLadder(string start, string end) { // A queue of vector <string> holds data from breadth first search Queue < Vector <string> > wordLadder; // add a base case which just includes the start word Vector <string> base; base.add(start); wordLadder.enqueue(base); // Lexicon from data file Lexicon english("EnglishWords.dat"); // Lexicon holds words previously encountered Lexicon previousWords; previousWords.add(start); while(!wordLadder.isEmpty()){ Vector<string> currentVector = wordLadder.dequeue(); // if the last string in the Vector equals the end word, we have found a complete ladder if (currentVector[currentVector.size()-1]==end) { cout << "Found ladder: "; for (int i = 0; i < currentVector.size()-1; i++){ cout << currentVector[i] << " "; } cout << endl; return 1; } else { // for loop that goes through each character position in the word for (int i = 0; i < start.length(); i ++){ // loops through the letters of the alphabet for (char alphabet = 'a'; alphabet < '{'; alphabet++){ string wordAltered = currentVector[currentVector.size()-1]; // replacing the character in that index position with each of the 26 letters in turn wordAltered[i]=alphabet; // if end word isn't in dictionary but is found, cout ladder. if (wordAltered==end){ // N.B. don't use currentVector.size()-1 because the currentVector hasn't been updated with end word for (int i = 0; i < currentVector.size(); i++){ cout << currentVector[i] << " "; } cout << end << endl; return 1; } // if wordAltered is in dictionary and hasn't been reached before, update word ladder if (english.contains(wordAltered.c_str()) && !previousWords.contains(wordAltered.c_str())){ // copy currentVector, add the wordAltered to the newWords vector, update previous words Lexicon, enqueue newWords vector Vector <string> newWords = currentVector; newWords.add(wordAltered); previousWords.add(wordAltered); wordLadder.enqueue(newWords); } } } } } // if queue becomes empty, can't create a ladder. Ask user to play again if(wordLadder.isEmpty()){ cout << "Can't create a word ladder between " << start << " and " << end << endl; cout << "Try again" << endl; playWordLadder(); } return 0; }