long post - need help with beginner level EBKAC logic error

T

theronnightstar

I am writing an anagram program for my fiance. Figured it would be an
excellent task to learn from. The way it is supposed to work is it
reads in a word list from a file into a temporary vector<string>. From
that it selects a random word 6 letters or more long. That is the word
of the game - the one to make all the anagrams from. After it selects
a word, I initialize two more vector<string>'s - unplayed_anagrams and
played_anagrams. I want it to read the file a second time, testing
each line in to see if it an anagram of the game word, and if it is,
push it into a vector<string> that will contain the entire list of
possible anagrams. As the player inputs a word, check the word against
unplayed_anagrams and if it is a match remove the word from
unplayed_anagrams and move it to played_anagrams.

All of the parts of this work so far except one, the part that
populates unplayed_anagrams. Now I am sure there are about
305,657,828 better ways of doing this, but like I said - it is a
learning exercise. I am not familiar with the more advanced features
(read: classes and up) of C++ yet. I just want to get this working and
then refine it down as I learn more.

Oh - I want it to find the anagrams by loading the game word and the
line from the file into char arrays - word_array and test_word_array
(respectively.) After that I just flip through the elements in the
test_word_array and compare them to the elements in word_array one by
one. The elements that match I want to test against a vector<int> of
elements that have already been used. It should do that by comparing
the element from word_array against the vector<int> and if no match is
found, push it in to the vector<int> and decrease a running counters
of letters_left. If there letters_left == 0 then push the word onto
unplayed_anagrams. Rinse, repeat - one for every line. That is the
point of all the nests (really really nasty nests, but like I said -
still learning). That was how it was supposed to work anyways. Guess
what - nada. It tests each letter ok, but doesn't work in the
comparison to the vector<int>. It fails to check the numbers
correctly, as well as keep any word from filtering through.

Here is the lone broken function:

//code

void populate( vector<string>& unplayed_anagrams, string& word,
ifstream& word_file )
{
const int max_size = word.size() + 1;
int letters_left;
char word_array[max_size];
char test_word_array[max_size];
string measure_word;
vector<int> used_letters;
vector<int>::iterator iter;

used_letters.clear();
memset( word_array, '\0', max_size);
strcpy( word_array, word.c_str() );

cout << "word_array in populate() is: "; //debug code
for(int z = 0; z < max_size; ++z) //debug code
{ //debug code
cout << word_array[z]; //debug code
} //debug code
cout << endl; //debug code

cout << "\nPlease wait... Populating the arrays." << endl;


while( getline(word_file, measure_word) )
{
letters_left = (max_size - 1 ) ;
used_letters.clear();
if( measure_word.size() > word.size() )
{
cout << "Stepping into the if." << endl; //
debug code
continue;
}
else if( measure_word.size() < 3 )
{
cout << "Stepping in to the first else if." <<
endl; //debug code
continue;
}
else if( measure_word == word )
{
cout << "Stepping in to the second else if." <<
endl;//debug code
continue;
}
//int size_m = measure_word.size();
//memset( test_word_array, '\0', size_m );
strcpy(test_word_array, measure_word.c_str());

cout << "word is: " << word << endl;//debug code
cout << "test_word_array is: "; //debug code
for( int x = 0; x < measure_word.size(); ++x ) //
debug code
{ //debug code
cout << test_word_array[x];//debug code
} //debug code
cout << endl; //debug code

for( int x1 = 0; x1 < max_size; ++x1) //word_array
{
cout << "This is in the first for (x1)." <<
endl; //debug code
for( int x2 = 0; x2 < max_size; ++x2 ) //
test_word_array
{
cout << "This is in the second for (x2)."
<< endl; //debug code
if( test_word_array[x2] ==
word_array[x1] ) //test if letter in test_word_array is the same as
the letter in word_array
{
for( iter = used_letters.begin();
iter != used_letters.end(); ++iter ) //this chuck checks to make sure
the letters

{ //
that match aren't matching to an
cout << "Checking vector of
used letters." << endl; //debug code
cout << "used_letters *iter
is: " << *iter << endl; //debug code
if( x2 !=
*iter ) //
element that has been previously matched.
{
continue;
}
else
{
break;
}
}
if( iter ==
used_letters.end() ) //if no matches are found, place the element
that matched into used_letters
{
int break_out = 0;
while( iter !=
used_letters.begin() )
{
iter -= 1;
if( x1== *iter )
{
break_out = 1;
break;
}
else
{
continue;
}
}
if( break_out == 1 )
{
break;
}
used_letters.push_back(x1);
--letters_left;
}
else
{
continue;
}

}
else
{
continue;
}
}
}
cout << "letters_left is: " << letters_left << endl; //
debug code
if( letters_left == 0 )
{
string blah = test_word_array;
cout << "blah is: " << blah << endl;//debug code
unplayed_anagrams.push_back(blah);
}
else
{

cout << "used_letters is: "; //debug code
for( iter = used_letters.begin(); iter !=
used_letters.end(); ++iter ) //debug code
{ //debug code
cout << *iter; //debug code
} //debug code
cout << endl; //debug code

continue;
}
}
cout << "\nDone." << endl;
}

//code

If you need I can post the calling test code. Thanks for any help or
information.

Raymond
 
D

David Harmon

On 11 Mar 2007 10:54:38 -0700 in comp.lang.c++,
(e-mail address removed) wrote,
I am writing an anagram program for my fiance. Figured it would be an
excellent task to learn from.

I'm afraid I did not figure out exactly what is not working in your
code, but maybe I can make some suggestions.

You start with std::string holding your word. That's very good, I'd
stick with that and use nothing but std::string to hold your words and
anagrams. No char arrays, no int vectors. Don't forget string supports
operator[] and a lot more.

Next, your nested loops. Too complicated. Say you have two strings and
you wish to do something depending on the relationship between them.
That would look like

if (adverb(game_word, test_word)) {

where adverb() is a small function you supply (with an appropriate name)
that encapsulates the relationship you are looking for and gives it a
name. Unless, of course, the relationship is pre-coded like
string::eek:perator==(). Not some inline loop looking char-by, leading to
hundred-line functions with nested loops six levels deep.

Working with anagrams you almost always encounter a point where it is
useful to sort the characters of a word; for example that allows you to
easily check if one word is an anagram of another. A function that does
that:
std::string sorted(std::string const & word)
{
std::string result(word);
std::sort(result.begin(), result.end());
return result;
}

Example usage:
bool anagram_match(std::string const &first, std::string const &second)
{
return sorted(first) == sorted(second);
}

Example usage of that:
if(anagram_match(game_word, test_word)) ...

Giving particles like that reasonable makes the code easier to
understand the bigger picture, and short functions make it easier to
tell if the code does what the name says,.
 
T

theronnightstar

Next, your nested loops. Too complicated. Say you have two strings and
you wish to do something depending on the relationship between them.
That would look like

if (adverb(game_word, test_word)) {

where adverb() is a small function you supply (with an appropriate name)
that encapsulates the relationship you are looking for and gives it a
name. Unless, of course, the relationship is pre-coded like
string::eek:perator==(). Not some inline loop looking char-by, leading to
hundred-line functions with nested loops six levels deep.

Actually, I felt like someone had hit me with the stupid stick when I
thought of that last night. Sat on my lunch and completely re-wrote
that rat's nest into cleaner functions. Made it easier to understand
too.
Working with anagrams you almost always encounter a point where it is
useful to sort the characters of a word; for example that allows you to
easily check if one word is an anagram of another. A function that does
that:
std::string sorted(std::string const & word)
{
std::string result(word);
std::sort(result.begin(), result.end());
return result;

}

That's nice to know - that will make it soooo much easier. Thanks for
the heads up.

Raymond
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,995
Messages
2,570,230
Members
46,819
Latest member
masterdaster

Latest Threads

Top