Jump to content
BrainDen.com - Brain Teasers
  • 0


unreality
 Share

Question

I was going to upload the file but the board won't let me here (same with the actual executable), so I'll post the code in here. I did however upload fivelet.txt which is a pretty decently sized dictionary file for 5 letter words in the desired format my program wants. fivelet.txt (You're going to want to put that in the same directory as rollo_champ.cpp).

Here's the code:

:("ABCDEFGHIJKLMNOPQRSTUVWXYZ")); if (permissible.find_first_of(toupper(c)) == string::npos) return false; else return true; } void makeUpper(string & g) { for (int j=0; j<g.size(); j++) g[j] = toupper(g[j]); } bool matchTest(string & g, vector < pair< string, int > > * f) { for (int q=0; q<f->size(); q++) { if (scoreWord(f->at(q).first, g) != f->at(q).second) { return false; } } return true; } int scoreWord(string & testWord, string & theWord) { if (testWord.size() != theWord.size()) return -1; int score = 0; for (int x=0; x<testWord.size(); x++) { if (testWord.at(x) == theWord.at(x)) score++; } return score; } bool matchGivenLetters(string & g, string & csa) { for (int y=0; y<g.size(); y++) { if (csa.at(y) != '?' && csa.at(y) != g.at(y)) return false; } return true; }

/* ROLLO CHAMP (rollo_champ.cpp)

   by Unreality (N.R.)

   Mon Mar 7, 2011 through Sun Mar 13, 2011

*/


using namespace std;

#include <iostream>

#include <fstream>

#include <string>

#include <vector>



bool guessTest(string &, int, bool);

bool guessCharTest(char,bool);

void makeUpper(string &);

bool matchTest(string &, vector < pair< string, int > > *);

int scoreWord(string &,string &);

bool matchGivenLetters(string &, string &);


int main()

{

	// Phase I: retrieve dictionary

	///////////////////////////////

	cout << endl;

	fstream inf;

	bool prompt = true;

	string fname;

	while (prompt)

    {

		cout << "Enter filename of your space-delimited ROLLO dictionary file (enter a dot to use fivelet.txt)\n\t";

		cin >> fname; if (fname==".") fname="fivelet.txt";

		// attempt to open file

		inf.open(fname.c_str());

		// valid?

		prompt = inf.fail();

		if (prompt) cout << "\nThat file does not exist!\n";

    }


	// Phase II: retrieve gamestate

	///////////////////////////////

	int numL=5; string numLS;

	cout << "Number of Letters per ROLLO word (default 5): ";

	cin >> numLS;

	numL = atoi(numLS.c_str());

	if (numL < 1) numL = 5;

	cout << "Enter the " << numL << "-lettered word as it is known, using question marks for unknown letters:\n";

	cout << endl;

	prompt = true;

	string cs;

	while (prompt)

	{

		cout << "   "; for (int iz=0; iz<numL; iz++) cout << "_"; cout << "\n>: ";

		cin >> cs;

		makeUpper(cs);

		prompt = !guessTest(cs, numL, true);

		if (prompt) cout << "\nMust be a valid (A-Z or '?') " << numL << "-lettered word... try again.\n";

	}


	cout << "\n\nNow enter the words guessed so far and their scores.";

	cout << "\n\nEnter a " << numL << " for the score to cancel adding the guess (if you make a mistake).";

	cout << "\n\nEnter just a tilde to analyze current guesses. Enter a hyphen to analyze and then quit.";

	cout << "\n\nTo edit a prior guess, enter a $ followed by the word, then a colon, then the new guess value. Enter " << numL << " for the guess value to delete that entry.\n\n";

	string guess=""; int guessval=0;

	vector < pair< string, int > > guesses;

	vector<string> fit;

	bool dontQuit = true, firstTime = true, getGuesses, addWord, commencePhaseThree, reopenFile;

	while(dontQuit)

	{

		getGuesses = true;

		commencePhaseThree = true;

		reopenFile = false;

		int guessesAdded = 0;

		// collect guesses / more guesses

		while (getGuesses)

		{

			prompt = true; 

			while (prompt)

			{

				// get the guess

				cout << "Guess:\t";

				cin >> guess;


				// process the guess

				if (guess == "-")      { prompt = false; getGuesses = false;  dontQuit = false; }

				else if (guess == "~") { prompt = false; getGuesses = false;                    }

				else if (guess.at(0) == '$')

				{

					if (guess.size() < 3+numL)

					{

						cout << "An edit string should be of the form $word:newscore";

						if (guesses.size() > 0) cout << ", e.g. $" << guesses.at(0).first << ":" << ( (guesses.at(0).second == 1) ? "2" : "1" );

						else cout << ".";

						cout << "\nOr have newscore be " << numL << " to delete the guess.\n";

						prompt = false; getGuesses = false; commencePhaseThree = false;

					}

					else

					{

						makeUpper(guess);

						int newGuessVal = atoi(guess.substr(numL+2).c_str());

						if (newGuessVal == numL)

						{

							// delete the guess

							vector < pair< string, int > > newguesses;

							bool foundGuess = false;

							for (int myit = 0; myit < guesses.size(); myit++)

							{

								if (guesses.at(myit).first != guess.substr(1,numL))

								{

									newguesses.push_back(guesses.at(myit));

								}

								else

								{

									foundGuess = true;

								}

							}

							guesses = newguesses;

							if (foundGuess)

								{ cout << "(Deleted " << guess.substr(1,numL) << ")\n"; reopenFile = true; }

							else

								{ cout << "Guess Not Found\n"; commencePhaseThree = false; }

						}

						else if (newGuessVal >= 0 && newGuessVal < numL)

						{

							// edit the guess

							bool foundGuess=false;

							for (int myit = 0; myit < guesses.size(); myit++)

								{ if (guesses.at(myit).first == guess.substr(1,numL))

									{ foundGuess=true; guesses.at(myit).second = newGuessVal; } }

							if (foundGuess)

								{ cout << "(Score of " << guess.substr(1,numL) << " changed to " << newGuessVal << ")\n"; reopenFile = true; }

							else

								{ cout << "Guess Not Found\n"; commencePhaseThree = false; }

						}

						else { cout << "That's out of the range of possible scores. No change occurred.\n"; commencePhaseThree = false; }

						prompt = false; getGuesses = false;

					}

				}

				else

				{

					prompt = !guessTest(guess, numL, false);

					if (prompt) cout << "Invalid Guess, try again.\n";

				}

			}

			if (getGuesses)

			{

				// guess is valid : attach a score to it

				makeUpper(guess);

				prompt = true;

				while (prompt)

				{

					cout << "Score of Guess (" << guess << "):\t";

					cin >> numLS;

					// Because of the annoying nature of atoi (returning 0 for non-numerics),

					// there's no way to distinguish an invalid string from one in which you wanted to say was zero.

					// That means the way to actually say a guess scored 0 letters is to type just exactly 0 for the input.

					if (numLS=="0") { guessval = 0; prompt = false; addWord = true; }

					else

					{

						// zero isn't the score so now atoi can be checked for equality with zero

						// in order to catch non-numeric inputs...

						guessval = atoi(numLS.c_str());

						if (guessval <= 0 || guessval > numL) { cout << "That's not a feasible score, try again. Enter " << numL << " for the score to cancel adding this word.\n"; }

						else if (guessval == numL) { cout << "Word not added.\n"; prompt = false; addWord = false; }

						else { prompt = false; addWord = true; }

					}

				}

				// anything that sets prompt false in the above While loop must also decide on a value for addWord

				if (addWord) { guesses.push_back(make_pair(guess, guessval)); guessesAdded++; }

				cout << endl;

			}

		}



		// Phase III: reduce possibilities with logic and linguistics (based on dictionary file)

		// begin by reducing the dictionary to include only words that fit the already known letters

		// and would score correctly given the guesses so far.

		// If the dictionary has already been scanned, then just look at the guesses added and make

		// sure the words match up to them, removing words that don't satisfy the new guesses' requirements.

		// (Unless a previous guess has been edited or deleted; this changes everything and needs a re-read from the dictionary file).

		//

		// I have proved that this method extracts the maximum information from the known situation, as far as you can logic (it would be pure logic

		// if the dictionary file contained all 26^(numL) "words", but linguistic logic is factored in too because the dictionary

		// is already its own filter from the getgo, deciding which words are acceptable.


		if (commencePhaseThree)

		{

			cout << "\nSummary of Guesses\n";

			int constCompare = guesses.size() - guessesAdded;

			for (int i=0; i<guesses.size(); i++)

			{

				cout << guesses.at(i).first << " (" << guesses.at(i).second << ")" << ( (i >= constCompare) ? (" *\n") : ("\n") );

			}

			if (guessesAdded > 0) cout << "*";

			cout << "(Added " << guessesAdded << " guess" << ( (guessesAdded == 1) ? ("") : ("es") ) << ")\n";


			string wd;

			vector < pair< string, int > > * ff = &guesses;

			if (firstTime) // used the very first time the eligible words are calculated (future times just remove words that no longer match all guesses)

			{

				while (!inf.eof())

				{

					inf >> wd;

					makeUpper(wd);

					if (guessTest(wd, numL, false) && matchGivenLetters(wd,/*scored*/cs) && matchTest(wd, ff))  fit.push_back(wd);

				}

				inf.close();

				firstTime=false;

			}

			else if (reopenFile) // used after an edit or deletion of an already made guess (because that changes everything so the file needs re-reading)

			{

				fit.clear();

				inf.open(fname.c_str());

				while (!inf.eof())

				{

					inf >> wd;

					makeUpper(wd);

					if (guessTest(wd, numL, false) && matchGivenLetters(wd,cs) && matchTest(wd, ff))  fit.push_back(wd);

				}

				inf.close();

			}

			else // remove words that no longer match with all the guesses

			{

				int remcount = 0;

				bool * keepWords = new bool[fit.size()];

				for (int ndex=0; ndex<fit.size(); ndex++)

				{

					if (!matchTest(fit.at(ndex), ff))

					{

						cout << "Removed " << fit.at(ndex) << endl;

						remcount++;

						keepWords[ndex] = false;

					}

					else keepWords[ndex] = true;

				}

				// remove them (can't remove them in the above loop because that would change fit's size and indices while fit is being looped over, a big no no)

				vector<string> newfit;

				for (int ndex=0; ndex<fit.size(); ndex++) if (keepWords[ndex]) newfit.push_back(fit.at(ndex));

				fit = newfit;

				// announce the removal

				if (remcount > 0) cout << "(Removed " << remcount << " word" << ( (remcount==1) ? ("") : ("s") ) << ")" << endl;

			}


			cout << "\nPossibilities\n";

			for (int i=0; i<fit.size(); i++) cout << fit[i] << endl;

			if (fit.size() == 0) cout << "NONE" << endl;

			else cout << "Count: " << fit.size() << endl << endl;

		}

		//////////////////////////



	} // the only way to get out of here is for dontQuit to be false, which is only if they guessed a hyphen


	// program finished

	cout << "\nThanks for using Rollo Champ.\tby N. R. [Unreality] 2011\n";

	return 0;

}


bool guessTest(string & g, int n, bool questionMarkAllowed)

{

	if (g.size() != n) return false;

	for (int j=0; j<n; j++)

    {

		if (!guessCharTest(g.at(j), questionMarkAllowed)) return false;

    }

	return true;

}


bool guessCharTest(char c, bool questionMarkAllowed)

{

	string permissible = ((questionMarkAllowed)?("ABCDEFGHIJKLMNOPQRSTUVWXYZ?")
Compile this with your favorite c++ compiler (works fine with make and g++ and I'm sure most other if not all compilers, assuming you have the standard libraries and such). If you have make (esp on the OSX) you can just do this:
make rollo_champ
or with g++ (which is more common, make just calls that anyway)
g++ rollo_champ.cpp -o rollo_champ

Then run the executable (./rollo_champ)

I've been working at it to make sure it's entirely people-friendly. There's only so many things I could've anticipated though, so if you download it help me out and try to break it with faulty inputs :lol:

I know something like this has the potential to take the fun out of ROLLO but I thought it was interesting to make anyway so why not share it I guess. Basically you just give it the dictionary file and then enter the guesses and their scores as given by the host (you can edit & remove guesses too, and continually update it, etc) to narrow down the dictionary. Maybe the tool could be helpful in other games or situations, idk. (at the least it's portable to rollo games played with not 5 letters). Anyway enjoy :)

Link to comment
Share on other sites

5 answers to this question

Recommended Posts

  • 0

The 5-letter-word dictionary I uploaded isn't as hefty as it probably could be though... if anyone has a better one, the format is for the file to just have all the words together, separated by spaces (it doesn't matter whether the words are lower or upper case) and nothing else. If your format is significantly different, let me know and I can easily extend the code to read in different types of formats. (I.e. if your dictionary has commas or newlines between every word that's an easy fix -- either a mass Find+Replace on your end or a code adjustment on mine).

And actually if the words in your dictionary are separated by newlines, tabs, spaces, or any other arbitrary series of combinations of whitespace, it will already work with my code

Link to comment
Share on other sites

  • 0
Computational rollo aid...

Not to compete but rather to have another option, yesterday I made an Excel wordlist (8642 five letter words) with duplicate checking, filtering capability and letter frequency totalling.

Someone else might appreciate it... but be aware it is 8.78Mb.

Rollo Excel Wordlist

Note: This was constructed from a few wordlists freely available online (thats why I added the duplicate checking) and its constructed in such a manner that all you have to do is INSERT a new row as a copy of an existing row and edit the "WORD" and all of the stats will be automatically updated.

Link to comment
Share on other sites

  • 0

I hadn't used an aid before the weekend but got caught out by a word I'd never heard of; so sought out some word lists.

Having done so, I then had to work out how to make use of them best and the spreadsheet was what I came up with.

It's not a sophisticated as rollo champ but it helps a bit:

The letter count provides some input to QM word choice;

The letter/position frequencies helps initial guessing; and

Letter filtering narrows down options for final guesses.

Edited by WombatBreath
Link to comment
Share on other sites

  • 0
<...Rollo aid stuff...>

You may be interested in this site for word lists, which seems quite good... Scrabble Word Lists

I use Windoze and my partner who's a C++/Delphi developer tried unsuccessfully to compile your code as a console app with C++ Builder (needs lots of libraries). When she examined my excel solution to see what I was trying to achieve, she "poo-pooed" my feeble attempts but was inspired to write a solution and built me a flexible little Windoze app.

Features: Windows UI with display of guesses, answer, dictionary & possible word list; selected dictionary determines word length (<11 letters so can be used to assist Masterword as well); stores guesses & answer in XML 'db' so has data-store between sessions.

It's not designed to take all of the logic'ing out of the user's hands but it does deal with the brute force grunt dictionary filtering. I've specified some refinements which are currently being worked on :D

If you're interested I can share - just let me know.

Link to comment
Share on other sites

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.

Guest
Answer this question...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

Loading...
 Share

  • Recently Browsing   0 members

    • No registered users viewing this page.
×
×
  • Create New...